1 // SPDX-License-Identifier: GPL-2.0-only
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.
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
;
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
);
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
);
65 rc
->set_drp_ie_pending
= 0;
67 spin_unlock_irqrestore(&rc
->rsvs_lock
, flags
);
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
)
93 struct uwb_rc_cmd_set_drp_ie
*cmd
;
95 struct uwb_rsv_move
*mv
;
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
)) {
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
);
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
)) {
136 memcpy(IEDataptr
, mv
->companion_drp_ie
,
137 mv
->companion_drp_ie
->hdr
.length
+ 2);
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;
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
;
218 /* [ECMA-368 2nd Edition] 17.4.6-6b */
219 if (our_beacon_slot
< ext_beacon_slot
) {
220 return UWB_DRP_CONFLICT_ACT2
;
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
;
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
,
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
;
249 action
= evaluate_conflict_action(drp_ie
, ext_beacon_slot
, rsv
, uwb_rsv_status(rsv
));
251 if (uwb_rsv_is_owner(rsv
)) {
253 case UWB_DRP_CONFLICT_ACT2
:
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
);
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
);
271 case UWB_DRP_CONFLICT_ACT2
:
272 case UWB_DRP_CONFLICT_ACT3
:
273 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_T_CONFLICT
);
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
;
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
)) {
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 */
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
)) {
344 if (bitmap_intersects(rsv
->mas
.bm
, conflicting_mas
->bm
,
346 handle_conflict_expanding(drp_ie
,
347 drp_evt
->beacon_slot_number
,
348 rsv
, false, conflicting_mas
);
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
,
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
)
371 list_for_each_entry(rsv
, &rc
->reservations
, rc_node
) {
372 uwb_drp_handle_conflict_rsv(rc
, rsv
, drp_evt
, drp_ie
,
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
;
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
);
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
);
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
406 uwb_drp_handle_all_conflict_rsv(rc
, drp_evt
,
409 /* accept the extra reservation */
410 bitmap_copy(mv
->companion_mas
.bm
, mas
->bm
,
412 uwb_rsv_set_state(rsv
,
413 UWB_RSV_STATE_T_EXPANDING_ACCEPTED
);
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
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
;
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
);
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
);
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
,
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
);
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
);
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
);
486 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_O_MODIFIED
);
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
);
493 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_O_MOVE_REDUCING
);
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
);
500 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_O_MOVE_EXPANDING
);
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
);
507 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_O_MOVE_COMBINING
);
514 * Based on the DRP IE, transition an owner reservation to a new
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
;
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
);
531 switch (reason_code
) {
532 case UWB_DRP_REASON_ACCEPTED
:
533 uwb_drp_process_owner_accepted(rsv
, &mas
);
536 dev_warn(dev
, "ignoring invalid DRP IE state (%d/%d)\n",
537 reason_code
, status
);
540 switch (reason_code
) {
541 case UWB_DRP_REASON_PENDING
:
542 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_O_PENDING
);
544 case UWB_DRP_REASON_DENIED
:
545 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_NONE
);
547 case UWB_DRP_REASON_CONFLICT
:
548 /* resolve the conflict */
549 bitmap_complement(mas
.bm
, src
->last_availability_bm
,
551 uwb_drp_handle_conflict_rsv(rc
, rsv
, drp_evt
, drp_ie
, &mas
);
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
,
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
));
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
);
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
);
629 dev_err(dev
, "failed to alloc uwb_cnflt_alien struct\n");
633 INIT_LIST_HEAD(&cnflt
->rc_node
);
634 timer_setup(&cnflt
->timer
, uwb_cnflt_timer
, 0);
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
)
668 rsv
= uwb_rsv_find(rc
, src
, drp_ie
);
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).
679 * Do nothing with DRP IEs for reservations that have been
682 if (rsv
->state
== UWB_RSV_STATE_NONE
) {
683 uwb_rsv_set_state(rsv
, UWB_RSV_STATE_NONE
);
687 if (uwb_ie_drp_owner(drp_ie
))
688 uwb_drp_process_target(rc
, rsv
, drp_ie
, drp_evt
);
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
);
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)
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
;
736 ptr
= drp_evt
->ie_data
;
738 ie_hdr
= uwb_ie_next(&ptr
, &ielen
);
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
);
747 uwb_drp_process(rc
, drp_evt
, src_dev
, (struct uwb_ie_drp
*)ie_hdr
);
750 dev_warn(dev
, "unexpected IE in DRP notification\n");
756 dev_warn(dev
, "%d octets remaining in DRP notification\n",
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
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
));
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
);
819 memcpy(src_addr
.data
, &drp_evt
->src_addr
, sizeof(src_addr
));
820 src_dev
= uwb_dev_get_by_devaddr(rc
, &src_addr
);
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
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
);