1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * DOC: contains MLO manager ap related functionality 20 */ 21 #include "wlan_objmgr_vdev_obj.h" 22 #include "wlan_mlo_mgr_ap.h" 23 #include <wlan_mlo_mgr_cmn.h> 24 #include <wlan_mlo_mgr_main.h> 25 #include <wlan_utility.h> 26 #ifdef WLAN_MLO_MULTI_CHIP 27 #include "cdp_txrx_mlo.h" 28 #endif 29 #include "wlan_mlo_mgr_peer.h" 30 31 #ifdef WLAN_MLO_MULTI_CHIP 32 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 33 uint8_t link_id, 34 uint16_t vdev_count) 35 { 36 struct wlan_mlo_dev_context *dev_ctx; 37 uint8_t pr_vdev_ids[WLAN_UMAC_MLO_MAX_VDEVS] = { CDP_INVALID_VDEV_ID }; 38 struct wlan_objmgr_psoc *psoc; 39 int i; 40 41 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 42 mlo_err("Invalid input"); 43 return false; 44 } 45 46 psoc = wlan_vdev_get_psoc(vdev); 47 if (!psoc) 48 return false; 49 50 dev_ctx = vdev->mlo_dev_ctx; 51 wlan_vdev_set_link_id(vdev, link_id); 52 wlan_vdev_mlme_set_mlo_vdev(vdev); 53 54 /* 55 * every link will trigger mlo_ap_vdev_attach, 56 * and they should provide the same vdev_count. 57 */ 58 mlo_dev_lock_acquire(dev_ctx); 59 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 60 mlo_dev_lock_release(dev_ctx); 61 62 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 63 if (dev_ctx->wlan_vdev_list[i]) 64 pr_vdev_ids[i] = wlan_vdev_get_id(dev_ctx->wlan_vdev_list[i]); 65 } 66 67 if (cdp_update_mlo_ptnr_list(wlan_psoc_get_dp_handle(psoc), 68 pr_vdev_ids, WLAN_UMAC_MLO_MAX_VDEVS, 69 wlan_vdev_get_id(vdev)) != QDF_STATUS_SUCCESS) { 70 mlo_debug("Failed to add vdev to partner vdev list, vdev id:%d", 71 wlan_vdev_get_id(vdev)); 72 } 73 74 return true; 75 } 76 #else 77 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 78 uint8_t link_id, 79 uint16_t vdev_count) 80 { 81 struct wlan_mlo_dev_context *dev_ctx; 82 83 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 84 mlo_err("Invalid input"); 85 return false; 86 } 87 88 dev_ctx = vdev->mlo_dev_ctx; 89 wlan_vdev_set_link_id(vdev, link_id); 90 wlan_vdev_mlme_set_mlo_vdev(vdev); 91 92 /* 93 * every link will trigger mlo_ap_vdev_attach, 94 * and they should provide the same vdev_count. 95 */ 96 mlo_dev_lock_acquire(dev_ctx); 97 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 98 mlo_dev_lock_release(dev_ctx); 99 100 return true; 101 } 102 #endif 103 104 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev, 105 uint16_t *vdev_count, 106 struct wlan_objmgr_vdev **wlan_vdev_list) 107 { 108 struct wlan_mlo_dev_context *dev_ctx; 109 int i; 110 QDF_STATUS status; 111 112 *vdev_count = 0; 113 114 if (!vdev || !vdev->mlo_dev_ctx) { 115 mlo_err("Invalid input"); 116 return; 117 } 118 119 dev_ctx = vdev->mlo_dev_ctx; 120 121 mlo_dev_lock_acquire(dev_ctx); 122 *vdev_count = 0; 123 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 124 if (dev_ctx->wlan_vdev_list[i] && 125 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) { 126 status = wlan_objmgr_vdev_try_get_ref( 127 dev_ctx->wlan_vdev_list[i], 128 WLAN_MLO_MGR_ID); 129 if (QDF_IS_STATUS_ERROR(status)) 130 break; 131 wlan_vdev_list[*vdev_count] = 132 dev_ctx->wlan_vdev_list[i]; 133 (*vdev_count) += 1; 134 } 135 } 136 mlo_dev_lock_release(dev_ctx); 137 } 138 139 void mlo_ap_get_active_vdev_list(struct wlan_objmgr_vdev *vdev, 140 uint16_t *vdev_count, 141 struct wlan_objmgr_vdev **wlan_vdev_list) 142 { 143 struct wlan_mlo_dev_context *dev_ctx; 144 int i; 145 QDF_STATUS status; 146 struct wlan_objmgr_vdev *partner_vdev = NULL; 147 148 *vdev_count = 0; 149 150 if (!vdev || !vdev->mlo_dev_ctx) { 151 mlo_err("Invalid input"); 152 return; 153 } 154 155 dev_ctx = vdev->mlo_dev_ctx; 156 157 mlo_dev_lock_acquire(dev_ctx); 158 *vdev_count = 0; 159 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 160 partner_vdev = dev_ctx->wlan_vdev_list[i]; 161 if (partner_vdev && 162 wlan_vdev_mlme_is_mlo_ap(partner_vdev)) { 163 if (wlan_vdev_chan_config_valid(partner_vdev) != 164 QDF_STATUS_SUCCESS) 165 continue; 166 167 status = wlan_objmgr_vdev_try_get_ref(partner_vdev, 168 WLAN_MLO_MGR_ID); 169 if (QDF_IS_STATUS_ERROR(status)) 170 break; 171 wlan_vdev_list[*vdev_count] = partner_vdev; 172 (*vdev_count) += 1; 173 } 174 } 175 mlo_dev_lock_release(dev_ctx); 176 } 177 178 void mlo_ap_get_partner_vdev_list_from_mld( 179 struct wlan_objmgr_vdev *vdev, 180 uint16_t *vdev_count, 181 struct wlan_objmgr_vdev **wlan_vdev_list) 182 { 183 struct wlan_mlo_dev_context *dev_ctx; 184 int i; 185 QDF_STATUS status; 186 187 *vdev_count = 0; 188 189 if (!vdev || !vdev->mlo_dev_ctx) { 190 mlo_err("Invalid input"); 191 return; 192 } 193 194 dev_ctx = vdev->mlo_dev_ctx; 195 196 mlo_dev_lock_acquire(dev_ctx); 197 *vdev_count = 0; 198 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 199 if (dev_ctx->wlan_vdev_list[i] && 200 (QDF_SAP_MODE == 201 wlan_vdev_mlme_get_opmode(dev_ctx->wlan_vdev_list[i]))) { 202 status = wlan_objmgr_vdev_try_get_ref( 203 dev_ctx->wlan_vdev_list[i], 204 WLAN_MLO_MGR_ID); 205 if (QDF_IS_STATUS_ERROR(status)) 206 break; 207 wlan_vdev_list[*vdev_count] = 208 dev_ctx->wlan_vdev_list[i]; 209 (*vdev_count) += 1; 210 } 211 } 212 mlo_dev_lock_release(dev_ctx); 213 } 214 215 /** 216 * mlo_ap_vdev_is_start_resp_rcvd() - Is start response received on this vdev 217 * @vdev: vdev pointer 218 * 219 * Return: SUCCESS if start response is received, ERROR otherwise. 220 */ 221 static QDF_STATUS mlo_ap_vdev_is_start_resp_rcvd(struct wlan_objmgr_vdev *vdev) 222 { 223 enum wlan_vdev_state state; 224 225 if (!vdev) { 226 mlme_err("vdev is null"); 227 return QDF_STATUS_E_FAILURE; 228 } 229 230 if (!wlan_vdev_mlme_is_mlo_ap(vdev)) 231 return QDF_STATUS_E_FAILURE; 232 233 state = wlan_vdev_mlme_get_state(vdev); 234 if ((state == WLAN_VDEV_S_UP) || 235 (state == WLAN_VDEV_S_DFS_CAC_WAIT) || 236 (state == WLAN_VDEV_S_SUSPEND)) 237 return QDF_STATUS_SUCCESS; 238 239 return QDF_STATUS_E_FAILURE; 240 } 241 242 uint16_t wlan_mlo_ap_get_active_links(struct wlan_objmgr_vdev *vdev) 243 { 244 uint16_t vdev_count = 0; 245 struct wlan_mlo_dev_context *dev_ctx; 246 int i; 247 248 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 249 mlo_err("Invalid input"); 250 return vdev_count; 251 } 252 253 dev_ctx = vdev->mlo_dev_ctx; 254 255 mlo_dev_lock_acquire(dev_ctx); 256 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 257 if (dev_ctx->wlan_vdev_list[i] && QDF_IS_STATUS_SUCCESS( 258 mlo_ap_vdev_is_start_resp_rcvd(dev_ctx->wlan_vdev_list[i]))) 259 vdev_count++; 260 } 261 262 mlo_dev_lock_release(dev_ctx); 263 264 return vdev_count; 265 } 266 267 /** 268 * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up 269 * @vdev: vdev pointer 270 * 271 * Return: true if given ap is allowed to up, false otherwise. 272 */ 273 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev) 274 { 275 uint16_t vdev_count = 0; 276 bool up_allowed = false; 277 struct wlan_mlo_dev_context *dev_ctx; 278 279 if (!vdev) { 280 mlo_err("Invalid input"); 281 return up_allowed; 282 } 283 284 dev_ctx = vdev->mlo_dev_ctx; 285 286 vdev_count = wlan_mlo_ap_get_active_links(vdev); 287 if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs) 288 up_allowed = true; 289 290 return up_allowed; 291 } 292 293 /** 294 * mlo_pre_link_up() - Carry out preparation before bringing up the link 295 * @vdev: vdev pointer 296 * 297 * Return: true if preparation is done successfully 298 */ 299 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev) 300 { 301 if (!vdev) { 302 mlo_err("vdev is NULL"); 303 return false; 304 } 305 306 if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) && 307 (wlan_vdev_mlme_get_substate(vdev) == 308 WLAN_VDEV_SS_MLO_SYNC_WAIT)) 309 return true; 310 311 return false; 312 } 313 314 /** 315 * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not. 316 * If it is allowed, for every link in the 317 * WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver 318 * event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE. 319 * 320 * This function is triggered once a link gets start response or enters 321 * WLAN_VDEV_SS_MLO_SYNC_WAIT state 322 * 323 * @vdev: vdev pointer 324 * 325 * Return: true if MLO_SYNC_COMPLETE is posted, else false 326 */ 327 static bool mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev) 328 { 329 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL}; 330 uint16_t num_links = 0; 331 uint8_t i; 332 333 if (!vdev || !vdev->mlo_dev_ctx) { 334 mlo_err("Invalid input"); 335 return false; 336 } 337 338 if (!mlo_is_ap_vdev_up_allowed(vdev)) 339 return false; 340 341 mlo_ap_get_vdev_list(vdev, &num_links, vdev_list); 342 if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) { 343 mlo_err("Invalid number of VDEVs under AP-MLD"); 344 return false; 345 } 346 347 mlo_ap_lock_acquire(vdev->mlo_dev_ctx->ap_ctx); 348 for (i = 0; i < num_links; i++) { 349 if (mlo_pre_link_up(vdev_list[i])) { 350 if (vdev_list[i] != vdev) 351 wlan_vdev_mlme_sm_deliver_evt( 352 vdev_list[i], 353 WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE, 354 0, NULL); 355 } 356 /* Release ref taken as part of mlo_ap_get_vdev_list */ 357 mlo_release_vdev_ref(vdev_list[i]); 358 } 359 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx); 360 return true; 361 } 362 363 bool mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev) 364 { 365 return mlo_handle_link_ready(vdev); 366 } 367 368 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev) 369 { 370 mlo_handle_link_ready(vdev); 371 } 372 373 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev) 374 { 375 if (!vdev || !vdev->mlo_dev_ctx) { 376 mlo_err("Invalid input"); 377 return; 378 } 379 wlan_vdev_mlme_clear_mlo_vdev(vdev); 380 } 381 382 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev) 383 { 384 mlo_ap_vdev_detach(vdev); 385 } 386 387 uint16_t mlo_ap_ml_peerid_alloc(void) 388 { 389 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 390 uint16_t i; 391 uint16_t mlo_peer_id; 392 393 ml_peerid_lock_acquire(mlo_ctx); 394 mlo_peer_id = mlo_ctx->last_mlo_peer_id; 395 for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) { 396 mlo_peer_id = (mlo_peer_id + 1) % mlo_ctx->max_mlo_peer_id; 397 398 if (!mlo_peer_id) 399 continue; 400 401 if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap)) 402 continue; 403 404 qdf_set_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap); 405 break; 406 } 407 mlo_ctx->last_mlo_peer_id = mlo_peer_id; 408 ml_peerid_lock_release(mlo_ctx); 409 410 if (i == mlo_ctx->max_mlo_peer_id) 411 return MLO_INVALID_PEER_ID; 412 413 mlo_debug(" ML peer id %d is allocated", mlo_peer_id); 414 415 return mlo_peer_id; 416 } 417 418 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id) 419 { 420 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 421 422 if ((mlo_peer_id == 0) || (mlo_peer_id == MLO_INVALID_PEER_ID)) { 423 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 424 return; 425 } 426 427 if (mlo_peer_id > mlo_ctx->max_mlo_peer_id) { 428 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 429 QDF_BUG(0); 430 return; 431 } 432 433 ml_peerid_lock_acquire(mlo_ctx); 434 if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap)) 435 qdf_clear_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap); 436 437 ml_peerid_lock_release(mlo_ctx); 438 439 mlo_debug(" ML peer id %d is freed", mlo_peer_id); 440 } 441 442 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev) 443 { 444 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 445 uint8_t idx; 446 447 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 448 return; 449 450 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 451 if (idx == MLO_INVALID_LINK_IDX) 452 return; 453 454 mlo_debug("Quiet set for PSOC:%d vdev:%d", 455 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 456 wlan_vdev_get_id(vdev)); 457 458 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 459 idx, 1); 460 } 461 462 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev) 463 { 464 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 465 uint8_t idx; 466 467 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 468 return; 469 470 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 471 if (idx == MLO_INVALID_LINK_IDX) 472 return; 473 474 mlo_debug("Quiet clear for PSOC:%d vdev:%d", 475 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 476 wlan_vdev_get_id(vdev)); 477 478 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 479 idx, 0); 480 } 481 482 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev) 483 { 484 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 485 486 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 487 return false; 488 489 return wlan_util_map_is_any_index_set( 490 mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 491 sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap)); 492 } 493 494 QDF_STATUS 495 mlo_peer_create_get_frm_buf( 496 struct wlan_mlo_peer_context *ml_peer, 497 struct peer_create_notif_s *peer_create, 498 qdf_nbuf_t frm_buf) 499 { 500 if (wlan_mlo_peer_is_nawds(ml_peer) || 501 wlan_mlo_peer_is_mesh(ml_peer)) { 502 peer_create->frm_buf = NULL; 503 return QDF_STATUS_SUCCESS; 504 } 505 506 if (!frm_buf) 507 return QDF_STATUS_E_FAILURE; 508 509 peer_create->frm_buf = qdf_nbuf_clone(frm_buf); 510 if (!peer_create->frm_buf) 511 return QDF_STATUS_E_NOMEM; 512 513 return QDF_STATUS_SUCCESS; 514 } 515 516 #ifdef UMAC_SUPPORT_MLNAWDS 517 void mlo_peer_populate_nawds_params( 518 struct wlan_mlo_peer_context *ml_peer, 519 struct mlo_partner_info *ml_info) 520 { 521 uint8_t i; 522 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00, 523 0x00, 0x00, 0x00}; 524 struct mlnawds_config nawds_config; 525 526 mlo_peer_lock_acquire(ml_peer); 527 ml_peer->is_nawds_ml_peer = false; 528 for (i = 0; i < ml_info->num_partner_links; i++) { 529 nawds_config = ml_info->partner_link_info[i].nawds_config; 530 /* 531 * if ml_info->partner_link_info[i].nawds_config has valid 532 * config(check for non-null mac or non-0 caps), then mark 533 * ml_peer's is_nawds_ml_peer true & copy the config 534 */ 535 if ((nawds_config.caps) || 536 (qdf_mem_cmp(null_mac, 537 nawds_config.mac, 538 sizeof(null_mac)))) { 539 ml_peer->is_nawds_ml_peer = true; 540 ml_peer->nawds_config[i] = nawds_config; 541 } 542 } 543 mlo_peer_lock_release(ml_peer); 544 } 545 #endif 546 547 #ifdef MESH_MODE_SUPPORT 548 void mlo_peer_populate_mesh_params( 549 struct wlan_mlo_peer_context *ml_peer, 550 struct mlo_partner_info *ml_info) 551 { 552 uint8_t i; 553 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0}; 554 struct mlnawds_config mesh_config; 555 556 mlo_peer_lock_acquire(ml_peer); 557 ml_peer->is_mesh_ml_peer = false; 558 for (i = 0; i < ml_info->num_partner_links; i++) { 559 mesh_config = ml_info->partner_link_info[i].mesh_config; 560 /* 561 * if ml_info->partner_link_info[i].mesh_config has valid 562 * config(check for non-null mac or non-0 caps), then mark 563 * ml_peer's is_mesh_ml_peer true & copy the config 564 */ 565 if ((mesh_config.caps) || 566 (qdf_mem_cmp(null_mac, 567 mesh_config.mac, 568 sizeof(null_mac)))) { 569 ml_peer->is_mesh_ml_peer = true; 570 ml_peer->mesh_config[i] = mesh_config; 571 } 572 } 573 mlo_peer_lock_release(ml_peer); 574 } 575 #endif 576