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 392 ml_peerid_lock_acquire(mlo_ctx); 393 for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) { 394 if (qdf_test_bit(i, mlo_ctx->mlo_peer_id_bmap)) 395 continue; 396 397 qdf_set_bit(i, mlo_ctx->mlo_peer_id_bmap); 398 break; 399 } 400 ml_peerid_lock_release(mlo_ctx); 401 402 if (i == mlo_ctx->max_mlo_peer_id) 403 return MLO_INVALID_PEER_ID; 404 405 mlo_debug(" ML peer id %d is allocated", i + 1); 406 407 return i + 1; 408 } 409 410 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id) 411 { 412 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 413 414 if ((mlo_peer_id == 0) || (mlo_peer_id == MLO_INVALID_PEER_ID)) { 415 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 416 return; 417 } 418 419 if (mlo_peer_id > mlo_ctx->max_mlo_peer_id) { 420 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 421 QDF_BUG(0); 422 return; 423 } 424 425 ml_peerid_lock_acquire(mlo_ctx); 426 if (qdf_test_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap)) 427 qdf_clear_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap); 428 429 ml_peerid_lock_release(mlo_ctx); 430 431 mlo_debug(" ML peer id %d is freed", mlo_peer_id); 432 } 433 434 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev) 435 { 436 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 437 uint8_t idx; 438 439 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 440 return; 441 442 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 443 if (idx == MLO_INVALID_LINK_IDX) 444 return; 445 446 mlo_debug("Quiet set for PSOC:%d vdev:%d", 447 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 448 wlan_vdev_get_id(vdev)); 449 450 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 451 idx, 1); 452 } 453 454 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev) 455 { 456 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 457 uint8_t idx; 458 459 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 460 return; 461 462 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 463 if (idx == MLO_INVALID_LINK_IDX) 464 return; 465 466 mlo_debug("Quiet clear for PSOC:%d vdev:%d", 467 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 468 wlan_vdev_get_id(vdev)); 469 470 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 471 idx, 0); 472 } 473 474 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev) 475 { 476 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 477 478 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 479 return false; 480 481 return wlan_util_map_is_any_index_set( 482 mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 483 sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap)); 484 } 485 486 QDF_STATUS 487 mlo_peer_create_get_frm_buf( 488 struct wlan_mlo_peer_context *ml_peer, 489 struct peer_create_notif_s *peer_create, 490 qdf_nbuf_t frm_buf) 491 { 492 if (wlan_mlo_peer_is_nawds(ml_peer) || 493 wlan_mlo_peer_is_mesh(ml_peer)) { 494 peer_create->frm_buf = NULL; 495 return QDF_STATUS_SUCCESS; 496 } 497 498 if (!frm_buf) 499 return QDF_STATUS_E_FAILURE; 500 501 peer_create->frm_buf = qdf_nbuf_clone(frm_buf); 502 if (!peer_create->frm_buf) 503 return QDF_STATUS_E_NOMEM; 504 505 return QDF_STATUS_SUCCESS; 506 } 507 508 #ifdef UMAC_SUPPORT_MLNAWDS 509 void mlo_peer_populate_nawds_params( 510 struct wlan_mlo_peer_context *ml_peer, 511 struct mlo_partner_info *ml_info) 512 { 513 uint8_t i; 514 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00, 515 0x00, 0x00, 0x00}; 516 struct mlnawds_config nawds_config; 517 518 mlo_peer_lock_acquire(ml_peer); 519 ml_peer->is_nawds_ml_peer = false; 520 for (i = 0; i < ml_info->num_partner_links; i++) { 521 nawds_config = ml_info->partner_link_info[i].nawds_config; 522 /* 523 * if ml_info->partner_link_info[i].nawds_config has valid 524 * config(check for non-null mac or non-0 caps), then mark 525 * ml_peer's is_nawds_ml_peer true & copy the config 526 */ 527 if ((nawds_config.caps) || 528 (qdf_mem_cmp(null_mac, 529 nawds_config.mac, 530 sizeof(null_mac)))) { 531 ml_peer->is_nawds_ml_peer = true; 532 ml_peer->nawds_config[i] = nawds_config; 533 } 534 } 535 mlo_peer_lock_release(ml_peer); 536 } 537 #endif 538 539 #ifdef MESH_MODE_SUPPORT 540 void mlo_peer_populate_mesh_params( 541 struct wlan_mlo_peer_context *ml_peer, 542 struct mlo_partner_info *ml_info) 543 { 544 uint8_t i; 545 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0}; 546 struct mlnawds_config mesh_config; 547 548 mlo_peer_lock_acquire(ml_peer); 549 ml_peer->is_mesh_ml_peer = false; 550 for (i = 0; i < ml_info->num_partner_links; i++) { 551 mesh_config = ml_info->partner_link_info[i].mesh_config; 552 /* 553 * if ml_info->partner_link_info[i].mesh_config has valid 554 * config(check for non-null mac or non-0 caps), then mark 555 * ml_peer's is_mesh_ml_peer true & copy the config 556 */ 557 if ((mesh_config.caps) || 558 (qdf_mem_cmp(null_mac, 559 mesh_config.mac, 560 sizeof(null_mac)))) { 561 ml_peer->is_mesh_ml_peer = true; 562 ml_peer->mesh_config[i] = mesh_config; 563 } 564 } 565 mlo_peer_lock_release(ml_peer); 566 } 567 #endif 568