treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / staging / uwb / drp.c
blob869987bede7ba1b075ff6d8eec480ec42d87fb4c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Ultra Wide Band
4 * Dynamic Reservation Protocol handling
6 * Copyright (C) 2005-2006 Intel Corporation
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
9 */
10 #include <linux/kthread.h>
11 #include <linux/freezer.h>
12 #include <linux/slab.h>
13 #include <linux/delay.h>
14 #include "uwb-internal.h"
17 /* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */
18 enum uwb_drp_conflict_action {
19 /* Reservation is maintained, no action needed */
20 UWB_DRP_CONFLICT_MANTAIN = 0,
22 /* the device shall not transmit frames in conflicting MASs in
23 * the following superframe. If the device is the reservation
24 * target, it shall also set the Reason Code in its DRP IE to
25 * Conflict in its beacon in the following superframe.
27 UWB_DRP_CONFLICT_ACT1,
29 /* the device shall not set the Reservation Status bit to ONE
30 * and shall not transmit frames in conflicting MASs. If the
31 * device is the reservation target, it shall also set the
32 * Reason Code in its DRP IE to Conflict.
34 UWB_DRP_CONFLICT_ACT2,
36 /* the device shall not transmit frames in conflicting MASs in
37 * the following superframe. It shall remove the conflicting
38 * MASs from the reservation or set the Reservation Status to
39 * ZERO in its beacon in the following superframe. If the
40 * device is the reservation target, it shall also set the
41 * Reason Code in its DRP IE to Conflict.
43 UWB_DRP_CONFLICT_ACT3,
47 static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,
48 struct uwb_rceb *reply, ssize_t reply_size)
50 struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply;
51 unsigned long flags;
53 if (r != NULL) {
54 if (r->bResultCode != UWB_RC_RES_SUCCESS)
55 dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n",
56 uwb_rc_strerror(r->bResultCode), r->bResultCode);
57 } else
58 dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");
60 spin_lock_irqsave(&rc->rsvs_lock, flags);
61 if (rc->set_drp_ie_pending > 1) {
62 rc->set_drp_ie_pending = 0;
63 uwb_rsv_queue_update(rc);
64 } else {
65 rc->set_drp_ie_pending = 0;
67 spin_unlock_irqrestore(&rc->rsvs_lock, flags);
70 /**
71 * Construct and send the SET DRP IE
73 * @rc: UWB Host controller
74 * @returns: >= 0 number of bytes still available in the beacon
75 * < 0 errno code on error.
77 * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the
78 * device to include in its beacon at the same time. We thus have to
79 * traverse all reservations and include the DRP IEs of all PENDING
80 * and NEGOTIATED reservations in a SET DRP command for transmission.
82 * A DRP Availability IE is appended.
84 * rc->rsvs_mutex is held
86 * FIXME We currently ignore the returned value indicating the remaining space
87 * in beacon. This could be used to deny reservation requests earlier if
88 * determined that they would cause the beacon space to be exceeded.
90 int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
92 int result;
93 struct uwb_rc_cmd_set_drp_ie *cmd;
94 struct uwb_rsv *rsv;
95 struct uwb_rsv_move *mv;
96 int num_bytes = 0;
97 u8 *IEDataptr;
99 result = -ENOMEM;
100 /* First traverse all reservations to determine memory needed. */
101 list_for_each_entry(rsv, &rc->reservations, rc_node) {
102 if (rsv->drp_ie != NULL) {
103 num_bytes += rsv->drp_ie->hdr.length + 2;
104 if (uwb_rsv_has_two_drp_ies(rsv) &&
105 (rsv->mv.companion_drp_ie != NULL)) {
106 mv = &rsv->mv;
107 num_bytes +=
108 mv->companion_drp_ie->hdr.length + 2;
112 num_bytes += sizeof(rc->drp_avail.ie);
113 cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
114 if (cmd == NULL)
115 goto error;
116 cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
117 cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE);
118 cmd->wIELength = num_bytes;
119 IEDataptr = (u8 *)&cmd->IEData[0];
121 /* FIXME: DRV avail IE is not always needed */
122 /* put DRP avail IE first */
123 memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
124 IEDataptr += sizeof(struct uwb_ie_drp_avail);
126 /* Next traverse all reservations to place IEs in allocated memory. */
127 list_for_each_entry(rsv, &rc->reservations, rc_node) {
128 if (rsv->drp_ie != NULL) {
129 memcpy(IEDataptr, rsv->drp_ie,
130 rsv->drp_ie->hdr.length + 2);
131 IEDataptr += rsv->drp_ie->hdr.length + 2;
133 if (uwb_rsv_has_two_drp_ies(rsv) &&
134 (rsv->mv.companion_drp_ie != NULL)) {
135 mv = &rsv->mv;
136 memcpy(IEDataptr, mv->companion_drp_ie,
137 mv->companion_drp_ie->hdr.length + 2);
138 IEDataptr +=
139 mv->companion_drp_ie->hdr.length + 2;
144 result = uwb_rc_cmd_async(rc, "SET-DRP-IE",
145 &cmd->rccb, sizeof(*cmd) + num_bytes,
146 UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE,
147 uwb_rc_set_drp_cmd_done, NULL);
149 rc->set_drp_ie_pending = 1;
151 kfree(cmd);
152 error:
153 return result;
157 * Evaluate the action to perform using conflict resolution rules
159 * Return a uwb_drp_conflict_action.
161 static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot,
162 struct uwb_rsv *rsv, int our_status)
164 int our_tie_breaker = rsv->tiebreaker;
165 int our_type = rsv->type;
166 int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot;
168 int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie);
169 int ext_status = uwb_ie_drp_status(ext_drp_ie);
170 int ext_type = uwb_ie_drp_type(ext_drp_ie);
173 /* [ECMA-368 2nd Edition] 17.4.6 */
174 if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) {
175 return UWB_DRP_CONFLICT_MANTAIN;
178 /* [ECMA-368 2nd Edition] 17.4.6-1 */
179 if (our_type == UWB_DRP_TYPE_ALIEN_BP) {
180 return UWB_DRP_CONFLICT_MANTAIN;
183 /* [ECMA-368 2nd Edition] 17.4.6-2 */
184 if (ext_type == UWB_DRP_TYPE_ALIEN_BP) {
185 /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */
186 return UWB_DRP_CONFLICT_ACT1;
189 /* [ECMA-368 2nd Edition] 17.4.6-3 */
190 if (our_status == 0 && ext_status == 1) {
191 return UWB_DRP_CONFLICT_ACT2;
194 /* [ECMA-368 2nd Edition] 17.4.6-4 */
195 if (our_status == 1 && ext_status == 0) {
196 return UWB_DRP_CONFLICT_MANTAIN;
199 /* [ECMA-368 2nd Edition] 17.4.6-5a */
200 if (our_tie_breaker == ext_tie_breaker &&
201 our_beacon_slot < ext_beacon_slot) {
202 return UWB_DRP_CONFLICT_MANTAIN;
205 /* [ECMA-368 2nd Edition] 17.4.6-5b */
206 if (our_tie_breaker != ext_tie_breaker &&
207 our_beacon_slot > ext_beacon_slot) {
208 return UWB_DRP_CONFLICT_MANTAIN;
211 if (our_status == 0) {
212 if (our_tie_breaker == ext_tie_breaker) {
213 /* [ECMA-368 2nd Edition] 17.4.6-6a */
214 if (our_beacon_slot > ext_beacon_slot) {
215 return UWB_DRP_CONFLICT_ACT2;
217 } else {
218 /* [ECMA-368 2nd Edition] 17.4.6-6b */
219 if (our_beacon_slot < ext_beacon_slot) {
220 return UWB_DRP_CONFLICT_ACT2;
223 } else {
224 if (our_tie_breaker == ext_tie_breaker) {
225 /* [ECMA-368 2nd Edition] 17.4.6-7a */
226 if (our_beacon_slot > ext_beacon_slot) {
227 return UWB_DRP_CONFLICT_ACT3;
229 } else {
230 /* [ECMA-368 2nd Edition] 17.4.6-7b */
231 if (our_beacon_slot < ext_beacon_slot) {
232 return UWB_DRP_CONFLICT_ACT3;
236 return UWB_DRP_CONFLICT_MANTAIN;
239 static void handle_conflict_normal(struct uwb_ie_drp *drp_ie,
240 int ext_beacon_slot,
241 struct uwb_rsv *rsv,
242 struct uwb_mas_bm *conflicting_mas)
244 struct uwb_rc *rc = rsv->rc;
245 struct uwb_rsv_move *mv = &rsv->mv;
246 struct uwb_drp_backoff_win *bow = &rc->bow;
247 int action;
249 action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv));
251 if (uwb_rsv_is_owner(rsv)) {
252 switch(action) {
253 case UWB_DRP_CONFLICT_ACT2:
254 /* try move */
255 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED);
256 if (bow->can_reserve_extra_mases == false)
257 uwb_rsv_backoff_win_increment(rc);
259 break;
260 case UWB_DRP_CONFLICT_ACT3:
261 uwb_rsv_backoff_win_increment(rc);
262 /* drop some mases with reason modified */
263 /* put in the companion the mases to be dropped */
264 bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
265 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
266 default:
267 break;
269 } else {
270 switch(action) {
271 case UWB_DRP_CONFLICT_ACT2:
272 case UWB_DRP_CONFLICT_ACT3:
273 uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
274 default:
275 break;
282 static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot,
283 struct uwb_rsv *rsv, bool companion_only,
284 struct uwb_mas_bm *conflicting_mas)
286 struct uwb_rc *rc = rsv->rc;
287 struct uwb_drp_backoff_win *bow = &rc->bow;
288 struct uwb_rsv_move *mv = &rsv->mv;
289 int action;
291 if (companion_only) {
292 /* status of companion is 0 at this point */
293 action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0);
294 if (uwb_rsv_is_owner(rsv)) {
295 switch(action) {
296 case UWB_DRP_CONFLICT_ACT2:
297 case UWB_DRP_CONFLICT_ACT3:
298 uwb_rsv_set_state(rsv,
299 UWB_RSV_STATE_O_ESTABLISHED);
300 rsv->needs_release_companion_mas = false;
301 if (bow->can_reserve_extra_mases == false)
302 uwb_rsv_backoff_win_increment(rc);
303 uwb_drp_avail_release(rsv->rc,
304 &rsv->mv.companion_mas);
306 } else { /* rsv is target */
307 switch(action) {
308 case UWB_DRP_CONFLICT_ACT2:
309 case UWB_DRP_CONFLICT_ACT3:
310 uwb_rsv_set_state(rsv,
311 UWB_RSV_STATE_T_EXPANDING_CONFLICT);
312 /* send_drp_avail_ie = true; */
315 } else { /* also base part of the reservation is conflicting */
316 if (uwb_rsv_is_owner(rsv)) {
317 uwb_rsv_backoff_win_increment(rc);
318 /* remove companion part */
319 uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
321 /* drop some mases with reason modified */
323 /* put in the companion the mases to be dropped */
324 bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm,
325 conflicting_mas->bm, UWB_NUM_MAS);
326 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
327 } else { /* it is a target rsv */
328 uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
329 /* send_drp_avail_ie = true; */
334 static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv,
335 struct uwb_rc_evt_drp *drp_evt,
336 struct uwb_ie_drp *drp_ie,
337 struct uwb_mas_bm *conflicting_mas)
339 struct uwb_rsv_move *mv;
341 /* check if the conflicting reservation has two drp_ies */
342 if (uwb_rsv_has_two_drp_ies(rsv)) {
343 mv = &rsv->mv;
344 if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
345 UWB_NUM_MAS)) {
346 handle_conflict_expanding(drp_ie,
347 drp_evt->beacon_slot_number,
348 rsv, false, conflicting_mas);
349 } else {
350 if (bitmap_intersects(mv->companion_mas.bm,
351 conflicting_mas->bm, UWB_NUM_MAS)) {
352 handle_conflict_expanding(
353 drp_ie, drp_evt->beacon_slot_number,
354 rsv, true, conflicting_mas);
357 } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
358 UWB_NUM_MAS)) {
359 handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number,
360 rsv, conflicting_mas);
364 static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc,
365 struct uwb_rc_evt_drp *drp_evt,
366 struct uwb_ie_drp *drp_ie,
367 struct uwb_mas_bm *conflicting_mas)
369 struct uwb_rsv *rsv;
371 list_for_each_entry(rsv, &rc->reservations, rc_node) {
372 uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie,
373 conflicting_mas);
377 static void uwb_drp_process_target_accepted(struct uwb_rc *rc,
378 struct uwb_rsv *rsv, struct uwb_rc_evt_drp *drp_evt,
379 struct uwb_ie_drp *drp_ie, struct uwb_mas_bm *mas)
381 struct uwb_rsv_move *mv = &rsv->mv;
382 int status;
384 status = uwb_ie_drp_status(drp_ie);
386 if (rsv->state == UWB_RSV_STATE_T_CONFLICT) {
387 uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
388 return;
391 if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) {
392 /* drp_ie is companion */
393 if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
394 /* stroke companion */
395 uwb_rsv_set_state(rsv,
396 UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
398 } else {
399 if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
400 if (uwb_drp_avail_reserve_pending(rc, mas) == -EBUSY) {
401 /* FIXME: there is a conflict, find
402 * the conflicting reservations and
403 * take a sensible action. Consider
404 * that in drp_ie there is the
405 * "neighbour" */
406 uwb_drp_handle_all_conflict_rsv(rc, drp_evt,
407 drp_ie, mas);
408 } else {
409 /* accept the extra reservation */
410 bitmap_copy(mv->companion_mas.bm, mas->bm,
411 UWB_NUM_MAS);
412 uwb_rsv_set_state(rsv,
413 UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
415 } else {
416 if (status) {
417 uwb_rsv_set_state(rsv,
418 UWB_RSV_STATE_T_ACCEPTED);
426 * Based on the DRP IE, transition a target reservation to a new
427 * state.
429 static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
430 struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt)
432 struct device *dev = &rc->uwb_dev.dev;
433 struct uwb_rsv_move *mv = &rsv->mv;
434 int status;
435 enum uwb_drp_reason reason_code;
436 struct uwb_mas_bm mas;
438 status = uwb_ie_drp_status(drp_ie);
439 reason_code = uwb_ie_drp_reason_code(drp_ie);
440 uwb_drp_ie_to_bm(&mas, drp_ie);
442 switch (reason_code) {
443 case UWB_DRP_REASON_ACCEPTED:
444 uwb_drp_process_target_accepted(rc, rsv, drp_evt, drp_ie, &mas);
445 break;
447 case UWB_DRP_REASON_MODIFIED:
448 /* check to see if we have already modified the reservation */
449 if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
450 uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
451 break;
454 /* find if the owner wants to expand or reduce */
455 if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
456 /* owner is reducing */
457 bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm,
458 UWB_NUM_MAS);
459 uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
462 bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
463 uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED);
464 break;
465 default:
466 dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
467 reason_code, status);
471 static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv,
472 struct uwb_mas_bm *mas)
474 struct uwb_rsv_move *mv = &rsv->mv;
476 switch (rsv->state) {
477 case UWB_RSV_STATE_O_PENDING:
478 case UWB_RSV_STATE_O_INITIATED:
479 case UWB_RSV_STATE_O_ESTABLISHED:
480 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
481 break;
482 case UWB_RSV_STATE_O_MODIFIED:
483 if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
484 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
485 else
486 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
487 break;
489 case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */
490 if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
491 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
492 else
493 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
494 break;
495 case UWB_RSV_STATE_O_MOVE_EXPANDING:
496 if (bitmap_equal(mas->bm, mv->companion_mas.bm, UWB_NUM_MAS)) {
497 /* Companion reservation accepted */
498 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
499 } else {
500 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
502 break;
503 case UWB_RSV_STATE_O_MOVE_COMBINING:
504 if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
505 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
506 else
507 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
508 break;
509 default:
510 break;
514 * Based on the DRP IE, transition an owner reservation to a new
515 * state.
517 static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
518 struct uwb_dev *src, struct uwb_ie_drp *drp_ie,
519 struct uwb_rc_evt_drp *drp_evt)
521 struct device *dev = &rc->uwb_dev.dev;
522 int status;
523 enum uwb_drp_reason reason_code;
524 struct uwb_mas_bm mas;
526 status = uwb_ie_drp_status(drp_ie);
527 reason_code = uwb_ie_drp_reason_code(drp_ie);
528 uwb_drp_ie_to_bm(&mas, drp_ie);
530 if (status) {
531 switch (reason_code) {
532 case UWB_DRP_REASON_ACCEPTED:
533 uwb_drp_process_owner_accepted(rsv, &mas);
534 break;
535 default:
536 dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
537 reason_code, status);
539 } else {
540 switch (reason_code) {
541 case UWB_DRP_REASON_PENDING:
542 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING);
543 break;
544 case UWB_DRP_REASON_DENIED:
545 uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
546 break;
547 case UWB_DRP_REASON_CONFLICT:
548 /* resolve the conflict */
549 bitmap_complement(mas.bm, src->last_availability_bm,
550 UWB_NUM_MAS);
551 uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas);
552 break;
553 default:
554 dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
555 reason_code, status);
560 static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt)
562 unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US;
563 mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us));
566 static void uwb_cnflt_update_work(struct work_struct *work)
568 struct uwb_cnflt_alien *cnflt = container_of(work,
569 struct uwb_cnflt_alien,
570 cnflt_update_work);
571 struct uwb_cnflt_alien *c;
572 struct uwb_rc *rc = cnflt->rc;
574 unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
576 mutex_lock(&rc->rsvs_mutex);
578 list_del(&cnflt->rc_node);
580 /* update rc global conflicting alien bitmap */
581 bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
583 list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) {
584 bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm,
585 c->mas.bm, UWB_NUM_MAS);
588 queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work,
589 usecs_to_jiffies(delay_us));
591 kfree(cnflt);
592 mutex_unlock(&rc->rsvs_mutex);
595 static void uwb_cnflt_timer(struct timer_list *t)
597 struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer);
599 queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work);
603 * We have received an DRP_IE of type Alien BP and we need to make
604 * sure we do not transmit in conflicting MASs.
606 static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
608 struct device *dev = &rc->uwb_dev.dev;
609 struct uwb_mas_bm mas;
610 struct uwb_cnflt_alien *cnflt;
611 unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
613 uwb_drp_ie_to_bm(&mas, drp_ie);
615 list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
616 if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
617 /* Existing alien BP reservation conflicting
618 * bitmap, just reset the timer */
619 uwb_cnflt_alien_stroke_timer(cnflt);
620 return;
624 /* New alien BP reservation conflicting bitmap */
626 /* alloc and initialize new uwb_cnflt_alien */
627 cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL);
628 if (!cnflt) {
629 dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n");
630 return;
633 INIT_LIST_HEAD(&cnflt->rc_node);
634 timer_setup(&cnflt->timer, uwb_cnflt_timer, 0);
636 cnflt->rc = rc;
637 INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work);
639 bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS);
641 list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list);
643 /* update rc global conflicting alien bitmap */
644 bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS);
646 queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
648 /* start the timer */
649 uwb_cnflt_alien_stroke_timer(cnflt);
652 static void uwb_drp_process_not_involved(struct uwb_rc *rc,
653 struct uwb_rc_evt_drp *drp_evt,
654 struct uwb_ie_drp *drp_ie)
656 struct uwb_mas_bm mas;
658 uwb_drp_ie_to_bm(&mas, drp_ie);
659 uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
662 static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src,
663 struct uwb_rc_evt_drp *drp_evt,
664 struct uwb_ie_drp *drp_ie)
666 struct uwb_rsv *rsv;
668 rsv = uwb_rsv_find(rc, src, drp_ie);
669 if (!rsv) {
671 * No reservation? It's either for a recently
672 * terminated reservation; or the DRP IE couldn't be
673 * processed (e.g., an invalid IE or out of memory).
675 return;
679 * Do nothing with DRP IEs for reservations that have been
680 * terminated.
682 if (rsv->state == UWB_RSV_STATE_NONE) {
683 uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
684 return;
687 if (uwb_ie_drp_owner(drp_ie))
688 uwb_drp_process_target(rc, rsv, drp_ie, drp_evt);
689 else
690 uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt);
695 static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
697 return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0;
701 * Process a received DRP IE.
703 static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
704 struct uwb_dev *src, struct uwb_ie_drp *drp_ie)
706 if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP)
707 uwb_drp_handle_alien_drp(rc, drp_ie);
708 else if (uwb_drp_involves_us(rc, drp_ie))
709 uwb_drp_process_involved(rc, src, drp_evt, drp_ie);
710 else
711 uwb_drp_process_not_involved(rc, drp_evt, drp_ie);
715 * Process a received DRP Availability IE
717 static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src,
718 struct uwb_ie_drp_avail *drp_availability_ie)
720 bitmap_copy(src->last_availability_bm,
721 drp_availability_ie->bmp, UWB_NUM_MAS);
725 * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
726 * from a device.
728 static
729 void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
730 size_t ielen, struct uwb_dev *src_dev)
732 struct device *dev = &rc->uwb_dev.dev;
733 struct uwb_ie_hdr *ie_hdr;
734 void *ptr;
736 ptr = drp_evt->ie_data;
737 for (;;) {
738 ie_hdr = uwb_ie_next(&ptr, &ielen);
739 if (!ie_hdr)
740 break;
742 switch (ie_hdr->element_id) {
743 case UWB_IE_DRP_AVAILABILITY:
744 uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr);
745 break;
746 case UWB_IE_DRP:
747 uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr);
748 break;
749 default:
750 dev_warn(dev, "unexpected IE in DRP notification\n");
751 break;
755 if (ielen > 0)
756 dev_warn(dev, "%d octets remaining in DRP notification\n",
757 (int)ielen);
761 * uwbd_evt_handle_rc_drp - handle a DRP_IE event
762 * @evt: the DRP_IE event from the radio controller
764 * This processes DRP notifications from the radio controller, either
765 * initiating a new reservation or transitioning an existing
766 * reservation into a different state.
768 * DRP notifications can occur for three different reasons:
770 * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as
771 * the target or source have been received.
773 * These DRP IEs could be new or for an existing reservation.
775 * If the DRP IE for an existing reservation ceases to be to
776 * received for at least mMaxLostBeacons, the reservation should be
777 * considered to be terminated. Note that the TERMINATE reason (see
778 * below) may not always be signalled (e.g., the remote device has
779 * two or more reservations established with the RC).
781 * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon
782 * group conflict with the RC's reservations.
784 * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received
785 * from a device (i.e., it's terminated all reservations).
787 * Only the software state of the reservations is changed; the setting
788 * of the radio controller's DRP IEs is done after all the events in
789 * an event buffer are processed. This saves waiting multiple times
790 * for the SET_DRP_IE command to complete.
792 int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
794 struct device *dev = &evt->rc->uwb_dev.dev;
795 struct uwb_rc *rc = evt->rc;
796 struct uwb_rc_evt_drp *drp_evt;
797 size_t ielength, bytes_left;
798 struct uwb_dev_addr src_addr;
799 struct uwb_dev *src_dev;
801 /* Is there enough data to decode the event (and any IEs in
802 its payload)? */
803 if (evt->notif.size < sizeof(*drp_evt)) {
804 dev_err(dev, "DRP event: Not enough data to decode event "
805 "[%zu bytes left, %zu needed]\n",
806 evt->notif.size, sizeof(*drp_evt));
807 return 0;
809 bytes_left = evt->notif.size - sizeof(*drp_evt);
810 drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb);
811 ielength = le16_to_cpu(drp_evt->ie_length);
812 if (bytes_left != ielength) {
813 dev_err(dev, "DRP event: Not enough data in payload [%zu"
814 "bytes left, %zu declared in the event]\n",
815 bytes_left, ielength);
816 return 0;
819 memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr));
820 src_dev = uwb_dev_get_by_devaddr(rc, &src_addr);
821 if (!src_dev) {
823 * A DRP notification from an unrecognized device.
825 * This is probably from a WUSB device that doesn't
826 * have an EUI-48 and therefore doesn't show up in the
827 * UWB device database. It's safe to simply ignore
828 * these.
830 return 0;
833 mutex_lock(&rc->rsvs_mutex);
835 /* We do not distinguish from the reason */
836 uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
838 mutex_unlock(&rc->rsvs_mutex);
840 uwb_dev_put(src_dev);
841 return 0;