1 // SPDX-License-Identifier: BSD-3-Clause-Clear 2 /* 3 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 4 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 5 */ 6 7 #include "core.h" 8 #include "dp_peer.h" 9 #include "debug.h" 10 #include "debugfs.h" 11 12 void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer) 13 { 14 list_del(&peer->list); 15 16 kfree(peer->peer_stats.rx_stats); 17 kfree(peer); 18 } 19 20 struct ath12k_dp_link_peer * 21 ath12k_dp_link_peer_find_by_vdev_and_addr(struct ath12k_dp *dp, 22 int vdev_id, const u8 *addr) 23 { 24 struct ath12k_dp_link_peer *peer; 25 26 lockdep_assert_held(&dp->dp_lock); 27 28 list_for_each_entry(peer, &dp->peers, list) { 29 if (peer->vdev_id != vdev_id) 30 continue; 31 if (!ether_addr_equal(peer->addr, addr)) 32 continue; 33 34 return peer; 35 } 36 37 return NULL; 38 } 39 40 struct ath12k_dp_link_peer * 41 ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp *dp, u8 pdev_idx, 42 const u8 *addr) 43 { 44 struct ath12k_dp_link_peer *peer; 45 46 lockdep_assert_held(&dp->dp_lock); 47 48 list_for_each_entry(peer, &dp->peers, list) { 49 if (peer->pdev_idx != pdev_idx) 50 continue; 51 if (!ether_addr_equal(peer->addr, addr)) 52 continue; 53 54 return peer; 55 } 56 57 return NULL; 58 } 59 60 struct ath12k_dp_link_peer * 61 ath12k_dp_link_peer_find_by_addr(struct ath12k_dp *dp, const u8 *addr) 62 { 63 lockdep_assert_held(&dp->dp_lock); 64 65 return rhashtable_lookup_fast(dp->rhead_peer_addr, addr, 66 dp->rhash_peer_addr_param); 67 } 68 EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_addr); 69 70 static struct ath12k_dp_link_peer * 71 ath12k_dp_link_peer_find_by_ml_id(struct ath12k_dp *dp, int ml_peer_id) 72 { 73 struct ath12k_dp_link_peer *peer; 74 75 lockdep_assert_held(&dp->dp_lock); 76 77 list_for_each_entry(peer, &dp->peers, list) 78 if (ml_peer_id == peer->ml_id) 79 return peer; 80 81 return NULL; 82 } 83 84 static struct ath12k_dp_link_peer * 85 ath12k_dp_link_peer_search_by_id(struct ath12k_dp *dp, int peer_id) 86 { 87 struct ath12k_dp_link_peer *peer; 88 89 lockdep_assert_held(&dp->dp_lock); 90 91 if (peer_id == HAL_INVALID_PEERID) 92 return NULL; 93 94 if (peer_id & ATH12K_PEER_ML_ID_VALID) 95 return ath12k_dp_link_peer_find_by_ml_id(dp, peer_id); 96 97 list_for_each_entry(peer, &dp->peers, list) 98 if (peer_id == peer->peer_id) 99 return peer; 100 101 return NULL; 102 } 103 104 bool ath12k_dp_link_peer_exist_by_vdev_id(struct ath12k_dp *dp, int vdev_id) 105 { 106 struct ath12k_dp_link_peer *peer; 107 108 spin_lock_bh(&dp->dp_lock); 109 110 list_for_each_entry(peer, &dp->peers, list) { 111 if (vdev_id == peer->vdev_id) { 112 spin_unlock_bh(&dp->dp_lock); 113 return true; 114 } 115 } 116 spin_unlock_bh(&dp->dp_lock); 117 return false; 118 } 119 120 struct ath12k_dp_link_peer * 121 ath12k_dp_link_peer_find_by_ast(struct ath12k_dp *dp, int ast_hash) 122 { 123 struct ath12k_dp_link_peer *peer; 124 125 lockdep_assert_held(&dp->dp_lock); 126 127 list_for_each_entry(peer, &dp->peers, list) 128 if (ast_hash == peer->ast_hash) 129 return peer; 130 131 return NULL; 132 } 133 134 void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id) 135 { 136 struct ath12k_dp_link_peer *peer; 137 struct ath12k_dp *dp = ath12k_ab_to_dp(ab); 138 139 spin_lock_bh(&dp->dp_lock); 140 141 peer = ath12k_dp_link_peer_search_by_id(dp, peer_id); 142 if (!peer) { 143 ath12k_warn(ab, "peer-unmap-event: unknown peer id %d\n", 144 peer_id); 145 goto exit; 146 } 147 148 ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n", 149 peer->vdev_id, peer->addr, peer_id); 150 151 ath12k_dp_link_peer_free(peer); 152 wake_up(&ab->peer_mapping_wq); 153 154 exit: 155 spin_unlock_bh(&dp->dp_lock); 156 } 157 158 void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id, 159 u8 *mac_addr, u16 ast_hash, u16 hw_peer_id) 160 { 161 struct ath12k_dp_link_peer *peer; 162 struct ath12k_dp *dp = ath12k_ab_to_dp(ab); 163 struct ath12k *ar; 164 165 spin_lock_bh(&dp->dp_lock); 166 peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr); 167 if (!peer) { 168 peer = kzalloc_obj(*peer, GFP_ATOMIC); 169 if (!peer) 170 goto exit; 171 172 peer->vdev_id = vdev_id; 173 peer->peer_id = peer_id; 174 peer->ast_hash = ast_hash; 175 peer->hw_peer_id = hw_peer_id; 176 ether_addr_copy(peer->addr, mac_addr); 177 178 rcu_read_lock(); 179 ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); 180 if (ar && ath12k_debugfs_is_extd_rx_stats_enabled(ar) && 181 !peer->peer_stats.rx_stats) { 182 peer->peer_stats.rx_stats = kzalloc_obj(*peer->peer_stats.rx_stats, 183 GFP_ATOMIC); 184 } 185 rcu_read_unlock(); 186 187 list_add(&peer->list, &dp->peers); 188 wake_up(&ab->peer_mapping_wq); 189 ewma_avg_rssi_init(&peer->avg_rssi); 190 } 191 ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n", 192 vdev_id, mac_addr, peer_id); 193 194 exit: 195 spin_unlock_bh(&dp->dp_lock); 196 } 197 198 struct ath12k_link_sta *ath12k_dp_link_peer_to_link_sta(struct ath12k_base *ab, 199 struct ath12k_dp_link_peer *peer) 200 { 201 struct ath12k_sta *ahsta; 202 struct ath12k_link_sta *arsta; 203 204 RCU_LOCKDEP_WARN(!rcu_read_lock_held(), 205 "ath12k_dp_link_peer to ath12k_link_sta called without rcu lock"); 206 207 if (!peer->sta) 208 return NULL; 209 210 ahsta = ath12k_sta_to_ahsta(peer->sta); 211 if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) { 212 if (!(ahsta->links_map & BIT(peer->link_id))) { 213 ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n", 214 peer->addr, peer->peer_id, peer->link_id, 215 ahsta->links_map); 216 return NULL; 217 } 218 arsta = rcu_dereference(ahsta->link[peer->link_id]); 219 if (!arsta) 220 return NULL; 221 } else { 222 arsta = &ahsta->deflink; 223 } 224 return arsta; 225 } 226 227 static int ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp *dp) 228 { 229 struct ath12k_base *ab = dp->ab; 230 struct rhashtable_params *param; 231 struct rhashtable *rhash_addr_tbl; 232 int ret; 233 234 lockdep_assert_held(&dp->link_peer_rhash_tbl_lock); 235 236 rhash_addr_tbl = kzalloc_obj(*dp->rhead_peer_addr); 237 if (!rhash_addr_tbl) 238 return -ENOMEM; 239 240 param = &dp->rhash_peer_addr_param; 241 242 param->key_offset = offsetof(struct ath12k_dp_link_peer, addr); 243 param->head_offset = offsetof(struct ath12k_dp_link_peer, rhash_addr); 244 param->key_len = sizeof_field(struct ath12k_dp_link_peer, addr); 245 param->automatic_shrinking = true; 246 param->nelem_hint = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab); 247 248 ret = rhashtable_init(rhash_addr_tbl, param); 249 if (ret) { 250 ath12k_warn(ab, "failed to init peer addr rhash table %d\n", ret); 251 goto err_free; 252 } 253 254 dp->rhead_peer_addr = rhash_addr_tbl; 255 256 return 0; 257 258 err_free: 259 kfree(rhash_addr_tbl); 260 261 return ret; 262 } 263 264 int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp) 265 { 266 int ret; 267 268 mutex_lock(&dp->link_peer_rhash_tbl_lock); 269 ret = ath12k_dp_link_peer_rhash_addr_tbl_init(dp); 270 mutex_unlock(&dp->link_peer_rhash_tbl_lock); 271 272 return ret; 273 } 274 275 void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp) 276 { 277 guard(mutex)(&dp->link_peer_rhash_tbl_lock); 278 279 if (!dp->rhead_peer_addr) 280 return; 281 282 rhashtable_destroy(dp->rhead_peer_addr); 283 kfree(dp->rhead_peer_addr); 284 dp->rhead_peer_addr = NULL; 285 } 286 287 static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp, 288 struct ath12k_dp_link_peer *peer) 289 { 290 struct ath12k_dp_link_peer *tmp; 291 292 lockdep_assert_held(&dp->dp_lock); 293 294 tmp = rhashtable_lookup_get_insert_fast(dp->rhead_peer_addr, &peer->rhash_addr, 295 dp->rhash_peer_addr_param); 296 if (!tmp) 297 return 0; 298 else if (IS_ERR(tmp)) 299 return PTR_ERR(tmp); 300 else 301 return -EEXIST; 302 } 303 304 static int ath12k_dp_link_peer_rhash_remove(struct ath12k_dp *dp, 305 struct ath12k_dp_link_peer *peer) 306 { 307 int ret; 308 309 lockdep_assert_held(&dp->dp_lock); 310 311 ret = rhashtable_remove_fast(dp->rhead_peer_addr, &peer->rhash_addr, 312 dp->rhash_peer_addr_param); 313 if (ret && ret != -ENOENT) 314 return ret; 315 316 return 0; 317 } 318 319 int ath12k_dp_link_peer_rhash_add(struct ath12k_dp *dp, 320 struct ath12k_dp_link_peer *peer) 321 { 322 int ret; 323 324 lockdep_assert_held(&dp->dp_lock); 325 326 ret = ath12k_dp_link_peer_rhash_insert(dp, peer); 327 if (ret) 328 ath12k_warn(dp, "failed to add peer %pM with id %d in rhash_addr ret %d\n", 329 peer->addr, peer->peer_id, ret); 330 331 return ret; 332 } 333 334 void ath12k_dp_link_peer_rhash_delete(struct ath12k_dp *dp, 335 struct ath12k_dp_link_peer *peer) 336 { 337 /* No failure handling and hence return type is void */ 338 int ret; 339 340 lockdep_assert_held(&dp->dp_lock); 341 342 ret = ath12k_dp_link_peer_rhash_remove(dp, peer); 343 if (ret) 344 ath12k_warn(dp, "failed to remove peer %pM with id %d in rhash_addr ret %d\n", 345 peer->addr, peer->peer_id, ret); 346 } 347 348 struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr(struct ath12k_dp_hw *dp_hw, u8 *addr) 349 { 350 struct ath12k_dp_peer *peer; 351 352 lockdep_assert_held(&dp_hw->peer_lock); 353 354 list_for_each_entry(peer, &dp_hw->dp_peers_list, list) { 355 if (ether_addr_equal(peer->addr, addr)) 356 return peer; 357 } 358 359 return NULL; 360 } 361 EXPORT_SYMBOL(ath12k_dp_peer_find_by_addr); 362 363 struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr_and_sta(struct ath12k_dp_hw *dp_hw, 364 u8 *addr, 365 struct ieee80211_sta *sta) 366 { 367 struct ath12k_dp_peer *dp_peer; 368 369 lockdep_assert_held(&dp_hw->peer_lock); 370 371 list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) { 372 if (ether_addr_equal(dp_peer->addr, addr) && (dp_peer->sta == sta)) 373 return dp_peer; 374 } 375 376 return NULL; 377 } 378 379 static struct ath12k_dp_peer *ath12k_dp_peer_create_find(struct ath12k_dp_hw *dp_hw, 380 u8 *addr, 381 struct ieee80211_sta *sta, 382 bool mlo_peer) 383 { 384 struct ath12k_dp_peer *dp_peer; 385 386 lockdep_assert_held(&dp_hw->peer_lock); 387 388 list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) { 389 if (ether_addr_equal(dp_peer->addr, addr)) { 390 if (!sta || mlo_peer || dp_peer->is_mlo || 391 dp_peer->sta == sta) 392 return dp_peer; 393 } 394 } 395 396 return NULL; 397 } 398 399 /* 400 * Index of ath12k_dp_peer for MLO client is same as peer id of ath12k_dp_peer, 401 * while for ath12k_dp_link_peer(mlo and non-mlo) and ath12k_dp_peer for 402 * Non-MLO client it is derived as ((DEVICE_ID << 10) | (10 bits of peer id)). 403 * 404 * This is done because ml_peer_id and peer_id_table are at hw granularity, 405 * while link_peer_id is at device granularity, hence in order to avoid 406 * conflict this approach is followed. 407 */ 408 #define ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT 10 409 410 u16 ath12k_dp_peer_get_peerid_index(struct ath12k_dp *dp, u16 peer_id) 411 { 412 return (peer_id & ATH12K_PEER_ML_ID_VALID) ? peer_id : 413 ((dp->device_id << ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT) | peer_id); 414 } 415 416 struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, 417 u16 peer_id) 418 { 419 u16 index; 420 struct ath12k_dp *dp = dp_pdev->dp; 421 422 RCU_LOCKDEP_WARN(!rcu_read_lock_held(), 423 "ath12k dp peer find by peerid index called without rcu lock"); 424 425 if (peer_id >= ATH12K_DP_PEER_ID_INVALID) 426 return NULL; 427 428 index = ath12k_dp_peer_get_peerid_index(dp, peer_id); 429 430 return rcu_dereference(dp_pdev->dp_hw->dp_peers[index]); 431 } 432 EXPORT_SYMBOL(ath12k_dp_peer_find_by_peerid); 433 434 struct ath12k_dp_link_peer * 435 ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id) 436 { 437 struct ath12k_dp_peer *dp_peer = NULL; 438 u8 link_id; 439 440 RCU_LOCKDEP_WARN(!rcu_read_lock_held(), 441 "ath12k dp link peer find by peerid index called without rcu lock"); 442 443 if (dp_pdev->hw_link_id >= ATH12K_GROUP_MAX_RADIO) 444 return NULL; 445 446 dp_peer = ath12k_dp_peer_find_by_peerid(dp_pdev, peer_id); 447 if (!dp_peer) 448 return NULL; 449 450 link_id = dp_peer->hw_links[dp_pdev->hw_link_id]; 451 452 return rcu_dereference(dp_peer->link_peers[link_id]); 453 } 454 EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_peerid); 455 456 int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr, 457 struct ath12k_dp_peer_create_params *params) 458 { 459 struct ath12k_dp_peer *dp_peer; 460 461 spin_lock_bh(&dp_hw->peer_lock); 462 dp_peer = ath12k_dp_peer_create_find(dp_hw, addr, params->sta, params->is_mlo); 463 if (dp_peer) { 464 spin_unlock_bh(&dp_hw->peer_lock); 465 return -EEXIST; 466 } 467 spin_unlock_bh(&dp_hw->peer_lock); 468 469 dp_peer = kzalloc_obj(*dp_peer, GFP_ATOMIC); 470 if (!dp_peer) 471 return -ENOMEM; 472 473 ether_addr_copy(dp_peer->addr, addr); 474 dp_peer->sta = params->sta; 475 dp_peer->is_mlo = params->is_mlo; 476 477 /* 478 * For MLO client, the ML peer ID, either known or PENDING, needs to be 479 * initialized here since the following logic depends on it. 480 * 481 * For non-MLO client, host gets link peer ID from firmware and will be 482 * assigned at the time of link peer creation 483 */ 484 dp_peer->peer_id = params->is_mlo ? params->peer_id : ATH12K_DP_PEER_ID_INVALID; 485 dp_peer->ucast_ra_only = params->ucast_ra_only; 486 487 dp_peer->sec_type = HAL_ENCRYPT_TYPE_OPEN; 488 dp_peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN; 489 dp_peer->ucast_ra_only = params->ucast_ra_only; 490 491 spin_lock_bh(&dp_hw->peer_lock); 492 493 list_add(&dp_peer->list, &dp_hw->dp_peers_list); 494 495 /* 496 * For an MLO client whose ML peer ID is allocated by the host, the 497 * peer_id is known here and the dp_peer can be added to the RCU 498 * table using it. For an MLO client on chips where the firmware 499 * allocates the ID, peer_id is ATH12K_MLO_PEER_ID_PENDING and the 500 * RCU table publish is deferred to the 501 * HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP handler. For a non-MLO client 502 * the publish happens later, at the time of assignment of 503 * ath12k_dp_link_peer to ath12k_dp_peer. 504 */ 505 if (dp_peer->is_mlo && 506 dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING) 507 rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], dp_peer); 508 509 spin_unlock_bh(&dp_hw->peer_lock); 510 511 return 0; 512 } 513 514 void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr, 515 struct ieee80211_sta *sta) 516 { 517 struct ath12k_dp_peer *dp_peer; 518 519 spin_lock_bh(&dp_hw->peer_lock); 520 521 dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, addr, sta); 522 if (!dp_peer) { 523 spin_unlock_bh(&dp_hw->peer_lock); 524 return; 525 } 526 527 if (dp_peer->is_mlo && 528 dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING) 529 rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL); 530 531 list_del(&dp_peer->list); 532 533 spin_unlock_bh(&dp_hw->peer_lock); 534 535 synchronize_rcu(); 536 kfree(dp_peer); 537 } 538 539 int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw, 540 u8 vdev_id, struct ieee80211_sta *sta, u8 *addr, 541 u8 link_id, u32 hw_link_id) 542 { 543 struct ath12k_dp_peer *dp_peer; 544 struct ath12k_dp_link_peer *peer, *temp_peer; 545 u16 peerid_index; 546 int ret = -EINVAL; 547 u8 *dp_peer_mac = !sta ? addr : sta->addr; 548 549 spin_lock_bh(&dp->dp_lock); 550 551 peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr); 552 if (!peer) { 553 ath12k_warn(dp, "failed to find dp_link_peer with mac %pM on vdev %u\n", 554 addr, vdev_id); 555 ret = -ENOENT; 556 goto err_peer; 557 } 558 559 spin_lock_bh(&dp_hw->peer_lock); 560 561 dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, dp_peer_mac, sta); 562 if (!dp_peer) { 563 ath12k_warn(dp, "failed to find dp_peer with mac %pM\n", dp_peer_mac); 564 ret = -ENOENT; 565 goto err_dp_peer; 566 } 567 568 /* 569 * Set peer_id in dp_peer for non-mlo client, peer_id for mlo client is 570 * set during dp_peer create 571 */ 572 if (!dp_peer->is_mlo) 573 dp_peer->peer_id = peer->peer_id; 574 575 peer->dp_peer = dp_peer; 576 peer->hw_link_id = hw_link_id; 577 578 dp_peer->hw_links[peer->hw_link_id] = link_id; 579 580 peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id); 581 582 rcu_assign_pointer(dp_peer->link_peers[peer->link_id], peer); 583 WRITE_ONCE(dp_peer->link_peers_map, 584 READ_ONCE(dp_peer->link_peers_map) | BIT(peer->link_id)); 585 586 rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer); 587 588 spin_unlock_bh(&dp_hw->peer_lock); 589 590 /* 591 * In case of Split PHY and roaming scenario, pdev idx 592 * might differ but both the pdev will share same rhash 593 * table. In that case update the rhash table if link_peer is 594 * already present 595 */ 596 temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr); 597 if (temp_peer && temp_peer->hw_link_id != hw_link_id) 598 ath12k_dp_link_peer_rhash_delete(dp, temp_peer); 599 600 ret = ath12k_dp_link_peer_rhash_add(dp, peer); 601 if (ret) { 602 /* 603 * If new entry addition failed, add back old entry 604 * If old entry addition also fails, then nothing 605 * can be done, simply proceed 606 */ 607 if (temp_peer) 608 ath12k_dp_link_peer_rhash_add(dp, temp_peer); 609 } 610 611 spin_unlock_bh(&dp->dp_lock); 612 613 return ret; 614 615 err_dp_peer: 616 spin_unlock_bh(&dp_hw->peer_lock); 617 618 err_peer: 619 spin_unlock_bh(&dp->dp_lock); 620 621 return ret; 622 } 623 624 void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw, 625 u8 vdev_id, u8 *addr, u32 hw_link_id) 626 { 627 struct ath12k_dp_peer *dp_peer; 628 struct ath12k_dp_link_peer *peer, *temp_peer; 629 u16 peerid_index; 630 631 spin_lock_bh(&dp->dp_lock); 632 633 peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr); 634 if (!peer || !peer->dp_peer) { 635 spin_unlock_bh(&dp->dp_lock); 636 return; 637 } 638 639 spin_lock_bh(&dp_hw->peer_lock); 640 641 dp_peer = peer->dp_peer; 642 dp_peer->hw_links[peer->hw_link_id] = 0; 643 644 peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id); 645 646 rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL); 647 WRITE_ONCE(dp_peer->link_peers_map, 648 READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id)); 649 650 rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL); 651 652 spin_unlock_bh(&dp_hw->peer_lock); 653 654 /* To handle roaming and split phy scenario */ 655 temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr); 656 if (temp_peer && temp_peer->hw_link_id == hw_link_id) 657 ath12k_dp_link_peer_rhash_delete(dp, peer); 658 659 spin_unlock_bh(&dp->dp_lock); 660 661 synchronize_rcu(); 662 } 663 664 void 665 ath12k_dp_link_peer_get_sta_rate_info_stats(struct ath12k_dp *dp, const u8 *addr, 666 struct ath12k_dp_link_peer_rate_info *info) 667 { 668 struct ath12k_dp_link_peer *link_peer; 669 670 guard(spinlock_bh)(&dp->dp_lock); 671 672 link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr); 673 if (!link_peer) 674 return; 675 676 info->rx_duration = link_peer->rx_duration; 677 info->tx_duration = link_peer->tx_duration; 678 info->txrate.legacy = link_peer->txrate.legacy; 679 info->txrate.mcs = link_peer->txrate.mcs; 680 info->txrate.nss = link_peer->txrate.nss; 681 info->txrate.bw = link_peer->txrate.bw; 682 info->txrate.he_gi = link_peer->txrate.he_gi; 683 info->txrate.he_dcm = link_peer->txrate.he_dcm; 684 info->txrate.he_ru_alloc = link_peer->txrate.he_ru_alloc; 685 info->txrate.flags = link_peer->txrate.flags; 686 info->rssi_comb = link_peer->rssi_comb; 687 info->signal_avg = ewma_avg_rssi_read(&link_peer->avg_rssi); 688 } 689 690 void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr) 691 { 692 struct ath12k_rx_peer_stats *rx_stats; 693 struct ath12k_dp_link_peer *link_peer; 694 695 guard(spinlock_bh)(&dp->dp_lock); 696 697 link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr); 698 if (!link_peer || !link_peer->peer_stats.rx_stats) 699 return; 700 701 rx_stats = link_peer->peer_stats.rx_stats; 702 if (rx_stats) 703 memset(rx_stats, 0, sizeof(*rx_stats)); 704 } 705 706 int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab, 707 const u8 *peer_addr, u16 peer_id) 708 { 709 struct ath12k_dp_link_peer *link_peer; 710 struct ath12k_dp_peer *dp_peer = NULL; 711 struct ath12k_hw_group *ag = ab->ag; 712 struct ath12k_dp_hw *dp_hw = NULL; 713 struct ath12k_hw *ah; 714 int i; 715 716 if (peer_id >= (ATH12K_PEER_ML_ID_VALID | ATH12K_MAX_MLO_PEERS)) 717 return -EINVAL; 718 719 for (i = 0; i < ag->num_hw; i++) { 720 ah = ag->ah[i]; 721 if (!ah) 722 continue; 723 724 spin_lock_bh(&ah->dp_hw.peer_lock); 725 dp_peer = ath12k_dp_peer_find_by_addr(&ah->dp_hw, 726 (u8 *)peer_addr); 727 if (dp_peer) { 728 dp_hw = &ah->dp_hw; 729 break; 730 } 731 spin_unlock_bh(&ah->dp_hw.peer_lock); 732 } 733 734 if (!dp_peer) 735 return -ENOENT; 736 737 /* dp_hw->peer_lock is held */ 738 739 dp_peer->peer_id = peer_id; 740 rcu_assign_pointer(dp_hw->dp_peers[peer_id], dp_peer); 741 742 for (i = 0; i < ATH12K_NUM_MAX_LINKS; i++) { 743 link_peer = rcu_dereference_protected(dp_peer->link_peers[i], 744 lockdep_is_held(&dp_hw->peer_lock)); 745 if (link_peer) 746 link_peer->ml_id = peer_id; 747 } 748 749 ath12k_sta_to_ahsta(dp_peer->sta)->ml_peer_id = peer_id; 750 751 spin_unlock_bh(&dp_hw->peer_lock); 752 753 complete(&ah->peer_ml_id_done); 754 755 return 0; 756 } 757