Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.2-rc7 842 lines 24 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Ultra Wide Band 4 * Dynamic Reservation Protocol handling 5 * 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" 15 16 17/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */ 18enum uwb_drp_conflict_action { 19 /* Reservation is maintained, no action needed */ 20 UWB_DRP_CONFLICT_MANTAIN = 0, 21 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. 26 */ 27 UWB_DRP_CONFLICT_ACT1, 28 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. 33 */ 34 UWB_DRP_CONFLICT_ACT2, 35 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. 42 */ 43 UWB_DRP_CONFLICT_ACT3, 44}; 45 46 47static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg, 48 struct uwb_rceb *reply, ssize_t reply_size) 49{ 50 struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply; 51 unsigned long flags; 52 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"); 59 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; 66 } 67 spin_unlock_irqrestore(&rc->rsvs_lock, flags); 68} 69 70/** 71 * Construct and send the SET DRP IE 72 * 73 * @rc: UWB Host controller 74 * @returns: >= 0 number of bytes still available in the beacon 75 * < 0 errno code on error. 76 * 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. 81 * 82 * A DRP Availability IE is appended. 83 * 84 * rc->rsvs_mutex is held 85 * 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. 89 */ 90int uwb_rc_send_all_drp_ie(struct uwb_rc *rc) 91{ 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; 98 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; 109 } 110 } 111 } 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]; 120 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); 125 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; 132 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; 140 } 141 } 142 } 143 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); 148 149 rc->set_drp_ie_pending = 1; 150 151 kfree(cmd); 152error: 153 return result; 154} 155 156/* 157 * Evaluate the action to perform using conflict resolution rules 158 * 159 * Return a uwb_drp_conflict_action. 160 */ 161static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot, 162 struct uwb_rsv *rsv, int our_status) 163{ 164 int our_tie_breaker = rsv->tiebreaker; 165 int our_type = rsv->type; 166 int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot; 167 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); 171 172 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; 176 } 177 178 /* [ECMA-368 2nd Edition] 17.4.6-1 */ 179 if (our_type == UWB_DRP_TYPE_ALIEN_BP) { 180 return UWB_DRP_CONFLICT_MANTAIN; 181 } 182 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; 187 } 188 189 /* [ECMA-368 2nd Edition] 17.4.6-3 */ 190 if (our_status == 0 && ext_status == 1) { 191 return UWB_DRP_CONFLICT_ACT2; 192 } 193 194 /* [ECMA-368 2nd Edition] 17.4.6-4 */ 195 if (our_status == 1 && ext_status == 0) { 196 return UWB_DRP_CONFLICT_MANTAIN; 197 } 198 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; 203 } 204 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; 209 } 210 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; 216 } 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; 221 } 222 } 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; 228 } 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; 233 } 234 } 235 } 236 return UWB_DRP_CONFLICT_MANTAIN; 237} 238 239static 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) 243{ 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; 248 249 action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv)); 250 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); 258 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; 268 } 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; 276 } 277 278 } 279 280} 281 282static 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) 285{ 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; 290 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); 305 } 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; */ 313 } 314 } 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); 320 321 /* drop some mases with reason modified */ 322 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; */ 330 } 331 } 332} 333 334static 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) 338{ 339 struct uwb_rsv_move *mv; 340 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); 355 } 356 } 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); 361 } 362} 363 364static 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) 368{ 369 struct uwb_rsv *rsv; 370 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); 374 } 375} 376 377static 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) 380{ 381 struct uwb_rsv_move *mv = &rsv->mv; 382 int status; 383 384 status = uwb_ie_drp_status(drp_ie); 385 386 if (rsv->state == UWB_RSV_STATE_T_CONFLICT) { 387 uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT); 388 return; 389 } 390 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); 397 } 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); 414 } 415 } else { 416 if (status) { 417 uwb_rsv_set_state(rsv, 418 UWB_RSV_STATE_T_ACCEPTED); 419 } 420 } 421 422 } 423} 424 425/* 426 * Based on the DRP IE, transition a target reservation to a new 427 * state. 428 */ 429static 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) 431{ 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; 437 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); 441 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; 446 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; 452 } 453 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); 460 } 461 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); 468 } 469} 470 471static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv, 472 struct uwb_mas_bm *mas) 473{ 474 struct uwb_rsv_move *mv = &rsv->mv; 475 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; 488 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); 501 } 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; 511 } 512} 513/* 514 * Based on the DRP IE, transition an owner reservation to a new 515 * state. 516 */ 517static 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) 520{ 521 struct device *dev = &rc->uwb_dev.dev; 522 int status; 523 enum uwb_drp_reason reason_code; 524 struct uwb_mas_bm mas; 525 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); 529 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); 538 } 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); 556 } 557 } 558} 559 560static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt) 561{ 562 unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US; 563 mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us)); 564} 565 566static void uwb_cnflt_update_work(struct work_struct *work) 567{ 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; 573 574 unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE; 575 576 mutex_lock(&rc->rsvs_mutex); 577 578 list_del(&cnflt->rc_node); 579 580 /* update rc global conflicting alien bitmap */ 581 bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS); 582 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); 586 } 587 588 queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, 589 usecs_to_jiffies(delay_us)); 590 591 kfree(cnflt); 592 mutex_unlock(&rc->rsvs_mutex); 593} 594 595static void uwb_cnflt_timer(struct timer_list *t) 596{ 597 struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer); 598 599 queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work); 600} 601 602/* 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. 605 */ 606static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie) 607{ 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; 612 613 uwb_drp_ie_to_bm(&mas, drp_ie); 614 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; 621 } 622 } 623 624 /* New alien BP reservation conflicting bitmap */ 625 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; 631 } 632 633 INIT_LIST_HEAD(&cnflt->rc_node); 634 timer_setup(&cnflt->timer, uwb_cnflt_timer, 0); 635 636 cnflt->rc = rc; 637 INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work); 638 639 bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS); 640 641 list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list); 642 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); 645 646 queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us)); 647 648 /* start the timer */ 649 uwb_cnflt_alien_stroke_timer(cnflt); 650} 651 652static 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) 655{ 656 struct uwb_mas_bm mas; 657 658 uwb_drp_ie_to_bm(&mas, drp_ie); 659 uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas); 660} 661 662static 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) 665{ 666 struct uwb_rsv *rsv; 667 668 rsv = uwb_rsv_find(rc, src, drp_ie); 669 if (!rsv) { 670 /* 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). 674 */ 675 return; 676 } 677 678 /* 679 * Do nothing with DRP IEs for reservations that have been 680 * terminated. 681 */ 682 if (rsv->state == UWB_RSV_STATE_NONE) { 683 uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); 684 return; 685 } 686 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); 691 692} 693 694 695static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie) 696{ 697 return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0; 698} 699 700/* 701 * Process a received DRP IE. 702 */ 703static 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) 705{ 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); 712} 713 714/* 715 * Process a received DRP Availability IE 716 */ 717static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src, 718 struct uwb_ie_drp_avail *drp_availability_ie) 719{ 720 bitmap_copy(src->last_availability_bm, 721 drp_availability_ie->bmp, UWB_NUM_MAS); 722} 723 724/* 725 * Process all the DRP IEs (both DRP IEs and the DRP Availability IE) 726 * from a device. 727 */ 728static 729void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, 730 size_t ielen, struct uwb_dev *src_dev) 731{ 732 struct device *dev = &rc->uwb_dev.dev; 733 struct uwb_ie_hdr *ie_hdr; 734 void *ptr; 735 736 ptr = drp_evt->ie_data; 737 for (;;) { 738 ie_hdr = uwb_ie_next(&ptr, &ielen); 739 if (!ie_hdr) 740 break; 741 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; 752 } 753 } 754 755 if (ielen > 0) 756 dev_warn(dev, "%d octets remaining in DRP notification\n", 757 (int)ielen); 758} 759 760/** 761 * uwbd_evt_handle_rc_drp - handle a DRP_IE event 762 * @evt: the DRP_IE event from the radio controller 763 * 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. 767 * 768 * DRP notifications can occur for three different reasons: 769 * 770 * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as 771 * the target or source have been received. 772 * 773 * These DRP IEs could be new or for an existing reservation. 774 * 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). 780 * 781 * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon 782 * group conflict with the RC's reservations. 783 * 784 * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received 785 * from a device (i.e., it's terminated all reservations). 786 * 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. 791 */ 792int uwbd_evt_handle_rc_drp(struct uwb_event *evt) 793{ 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; 800 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; 808 } 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; 817 } 818 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) { 822 /* 823 * A DRP notification from an unrecognized device. 824 * 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. 829 */ 830 return 0; 831 } 832 833 mutex_lock(&rc->rsvs_mutex); 834 835 /* We do not distinguish from the reason */ 836 uwb_drp_process_all(rc, drp_evt, ielength, src_dev); 837 838 mutex_unlock(&rc->rsvs_mutex); 839 840 uwb_dev_put(src_dev); 841 return 0; 842}