1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 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 30 #ifdef WLAN_MLO_MULTI_CHIP 31 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 32 uint8_t link_id, 33 uint16_t vdev_count) 34 { 35 struct wlan_mlo_dev_context *dev_ctx; 36 uint8_t pr_vdev_ids[WLAN_UMAC_MLO_MAX_VDEVS] = { CDP_INVALID_VDEV_ID }; 37 struct wlan_objmgr_psoc *psoc; 38 int i; 39 40 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 41 mlo_err("Invalid input"); 42 return false; 43 } 44 45 psoc = wlan_vdev_get_psoc(vdev); 46 if (!psoc) 47 return false; 48 49 dev_ctx = vdev->mlo_dev_ctx; 50 wlan_vdev_set_link_id(vdev, link_id); 51 wlan_vdev_mlme_set_mlo_vdev(vdev); 52 53 /* 54 * every link will trigger mlo_ap_vdev_attach, 55 * and they should provide the same vdev_count. 56 */ 57 mlo_dev_lock_acquire(dev_ctx); 58 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 59 mlo_dev_lock_release(dev_ctx); 60 61 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 62 if (dev_ctx->wlan_vdev_list[i]) 63 pr_vdev_ids[i] = wlan_vdev_get_id(dev_ctx->wlan_vdev_list[i]); 64 } 65 66 if (cdp_update_mlo_ptnr_list(wlan_psoc_get_dp_handle(psoc), 67 pr_vdev_ids, WLAN_UMAC_MLO_MAX_VDEVS, 68 wlan_vdev_get_id(vdev)) != QDF_STATUS_SUCCESS) { 69 mlo_debug("Failed to add vdev to partner vdev list, vdev id:%d", 70 wlan_vdev_get_id(vdev)); 71 } 72 73 return true; 74 } 75 #else 76 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 77 uint8_t link_id, 78 uint16_t vdev_count) 79 { 80 struct wlan_mlo_dev_context *dev_ctx; 81 82 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 83 mlo_err("Invalid input"); 84 return false; 85 } 86 87 dev_ctx = vdev->mlo_dev_ctx; 88 wlan_vdev_set_link_id(vdev, link_id); 89 wlan_vdev_mlme_set_mlo_vdev(vdev); 90 91 /* 92 * every link will trigger mlo_ap_vdev_attach, 93 * and they should provide the same vdev_count. 94 */ 95 mlo_dev_lock_acquire(dev_ctx); 96 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 97 mlo_dev_lock_release(dev_ctx); 98 99 return true; 100 } 101 #endif 102 103 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev, 104 uint16_t *vdev_count, 105 struct wlan_objmgr_vdev **wlan_vdev_list) 106 { 107 struct wlan_mlo_dev_context *dev_ctx; 108 int i; 109 QDF_STATUS status; 110 111 *vdev_count = 0; 112 113 if (!vdev || !vdev->mlo_dev_ctx) { 114 mlo_err("Invalid input"); 115 return; 116 } 117 118 dev_ctx = vdev->mlo_dev_ctx; 119 120 mlo_dev_lock_acquire(dev_ctx); 121 *vdev_count = 0; 122 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 123 if (dev_ctx->wlan_vdev_list[i] && 124 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) { 125 status = wlan_objmgr_vdev_try_get_ref( 126 dev_ctx->wlan_vdev_list[i], 127 WLAN_MLO_MGR_ID); 128 if (QDF_IS_STATUS_ERROR(status)) 129 break; 130 wlan_vdev_list[*vdev_count] = 131 dev_ctx->wlan_vdev_list[i]; 132 (*vdev_count) += 1; 133 } 134 } 135 mlo_dev_lock_release(dev_ctx); 136 } 137 138 void mlo_ap_get_partner_vdev_list_from_mld( 139 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 147 *vdev_count = 0; 148 149 if (!vdev || !vdev->mlo_dev_ctx) { 150 mlo_err("Invalid input"); 151 return; 152 } 153 154 dev_ctx = vdev->mlo_dev_ctx; 155 156 mlo_dev_lock_acquire(dev_ctx); 157 *vdev_count = 0; 158 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 159 if (dev_ctx->wlan_vdev_list[i] && 160 (QDF_SAP_MODE == 161 wlan_vdev_mlme_get_opmode(dev_ctx->wlan_vdev_list[i]))) { 162 status = wlan_objmgr_vdev_try_get_ref( 163 dev_ctx->wlan_vdev_list[i], 164 WLAN_MLO_MGR_ID); 165 if (QDF_IS_STATUS_ERROR(status)) 166 break; 167 wlan_vdev_list[*vdev_count] = 168 dev_ctx->wlan_vdev_list[i]; 169 (*vdev_count) += 1; 170 } 171 } 172 mlo_dev_lock_release(dev_ctx); 173 } 174 175 /** 176 * mlo_ap_vdev_is_start_resp_rcvd() - Is start response received on this vdev 177 * @vdev: vdev pointer 178 * 179 * Return: SUCCESS if start response is received, ERROR otherwise. 180 */ 181 static QDF_STATUS mlo_ap_vdev_is_start_resp_rcvd(struct wlan_objmgr_vdev *vdev) 182 { 183 enum wlan_vdev_state state; 184 185 if (!vdev) { 186 mlme_err("vdev is null"); 187 return QDF_STATUS_E_FAILURE; 188 } 189 190 if (!wlan_vdev_mlme_is_mlo_ap(vdev)) 191 return QDF_STATUS_E_FAILURE; 192 193 state = wlan_vdev_mlme_get_state(vdev); 194 if ((state == WLAN_VDEV_S_UP) || 195 (state == WLAN_VDEV_S_DFS_CAC_WAIT) || 196 (state == WLAN_VDEV_S_SUSPEND)) 197 return QDF_STATUS_SUCCESS; 198 199 return QDF_STATUS_E_FAILURE; 200 } 201 202 /** 203 * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up 204 * @vdev: vdev pointer 205 * 206 * Return: true if given ap is allowed to up, false otherwise. 207 */ 208 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev) 209 { 210 uint16_t vdev_count = 0; 211 struct wlan_mlo_dev_context *dev_ctx; 212 int i; 213 bool up_allowed = false; 214 215 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 216 mlo_err("Invalid input"); 217 return up_allowed; 218 } 219 220 dev_ctx = vdev->mlo_dev_ctx; 221 222 mlo_dev_lock_acquire(dev_ctx); 223 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 224 if (dev_ctx->wlan_vdev_list[i] && QDF_IS_STATUS_SUCCESS( 225 mlo_ap_vdev_is_start_resp_rcvd(dev_ctx->wlan_vdev_list[i]))) 226 vdev_count++; 227 } 228 229 if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs) 230 up_allowed = true; 231 mlo_dev_lock_release(dev_ctx); 232 233 return up_allowed; 234 } 235 236 /** 237 * mlo_pre_link_up() - Carry out preparation before bringing up the link 238 * @vdev: vdev pointer 239 * 240 * Return: true if preparation is done successfully 241 */ 242 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev) 243 { 244 if (!vdev) { 245 mlo_err("vdev is NULL"); 246 return false; 247 } 248 249 if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) && 250 (wlan_vdev_mlme_get_substate(vdev) == 251 WLAN_VDEV_SS_MLO_SYNC_WAIT)) 252 return true; 253 254 return false; 255 } 256 257 /** 258 * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not. 259 * If it is allowed, for every link in the 260 * WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver 261 * event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE. 262 * 263 * This function is triggered once a link gets start response or enters 264 * LAN_VDEV_SS_MLO_SYNC_WAIT state 265 * 266 * @vdev: vdev pointer 267 * 268 * Return: None 269 */ 270 static void mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev) 271 { 272 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL}; 273 uint16_t num_links = 0; 274 uint8_t i; 275 276 if (!vdev || !vdev->mlo_dev_ctx) { 277 mlo_err("Invalid input"); 278 return; 279 } 280 281 if (!mlo_is_ap_vdev_up_allowed(vdev)) 282 return; 283 284 mlo_ap_get_vdev_list(vdev, &num_links, vdev_list); 285 if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) { 286 mlo_err("Invalid number of VDEVs under AP-MLD"); 287 return; 288 } 289 290 for (i = 0; i < num_links; i++) { 291 if (mlo_pre_link_up(vdev_list[i])) 292 wlan_vdev_mlme_sm_deliver_evt_sync( 293 vdev_list[i], 294 WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE, 295 0, NULL); 296 /* Release ref taken as part of mlo_ap_get_vdev_list */ 297 mlo_release_vdev_ref(vdev_list[i]); 298 } 299 } 300 301 void mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev) 302 { 303 mlo_handle_link_ready(vdev); 304 } 305 306 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev) 307 { 308 mlo_handle_link_ready(vdev); 309 } 310 311 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev) 312 { 313 if (!vdev || !vdev->mlo_dev_ctx) { 314 mlo_err("Invalid input"); 315 return; 316 } 317 wlan_vdev_mlme_clear_mlo_vdev(vdev); 318 } 319 320 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev) 321 { 322 mlo_ap_vdev_detach(vdev); 323 } 324 325 uint16_t mlo_ap_ml_peerid_alloc(void) 326 { 327 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 328 uint16_t i; 329 330 ml_peerid_lock_acquire(mlo_ctx); 331 for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) { 332 if (qdf_test_bit(i, mlo_ctx->mlo_peer_id_bmap)) 333 continue; 334 335 qdf_set_bit(i, mlo_ctx->mlo_peer_id_bmap); 336 break; 337 } 338 ml_peerid_lock_release(mlo_ctx); 339 340 if (i == mlo_ctx->max_mlo_peer_id) 341 return MLO_INVALID_PEER_ID; 342 343 mlo_debug(" ML peer id %d is allocated", i + 1); 344 345 return i + 1; 346 } 347 348 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id) 349 { 350 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 351 352 if ((mlo_peer_id == 0) || (mlo_peer_id == MLO_INVALID_PEER_ID)) { 353 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 354 return; 355 } 356 357 if (mlo_peer_id > mlo_ctx->max_mlo_peer_id) { 358 mlo_err(" ML peer id %d is invalid", mlo_peer_id); 359 QDF_BUG(0); 360 return; 361 } 362 363 ml_peerid_lock_acquire(mlo_ctx); 364 if (qdf_test_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap)) 365 qdf_clear_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap); 366 367 ml_peerid_lock_release(mlo_ctx); 368 369 mlo_debug(" ML peer id %d is freed", mlo_peer_id); 370 } 371 372 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev) 373 { 374 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 375 uint8_t idx; 376 377 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 378 return; 379 380 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 381 if (idx == MLO_INVALID_LINK_IDX) 382 return; 383 384 mlo_debug("Quiet set for PSOC:%d vdev:%d", 385 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 386 wlan_vdev_get_id(vdev)); 387 388 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 389 idx, 1); 390 } 391 392 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev) 393 { 394 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 395 uint8_t idx; 396 397 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 398 return; 399 400 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 401 if (idx == MLO_INVALID_LINK_IDX) 402 return; 403 404 mlo_debug("Quiet clear for PSOC:%d vdev:%d", 405 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 406 wlan_vdev_get_id(vdev)); 407 408 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 409 idx, 0); 410 } 411 412 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev) 413 { 414 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 415 416 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 417 return false; 418 419 return wlan_util_map_is_any_index_set( 420 mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 421 sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap)); 422 } 423 424 #ifdef UMAC_SUPPORT_MLNAWDS 425 QDF_STATUS 426 mlo_peer_create_get_frm_buf( 427 struct wlan_mlo_peer_context *ml_peer, 428 struct peer_create_notif_s *peer_create, 429 qdf_nbuf_t frm_buf) 430 { 431 if (ml_peer->is_nawds_ml_peer) { 432 peer_create->frm_buf = NULL; 433 return QDF_STATUS_SUCCESS; 434 } 435 436 peer_create->frm_buf = qdf_nbuf_clone(frm_buf); 437 if (!peer_create->frm_buf) 438 return QDF_STATUS_E_NOMEM; 439 440 return QDF_STATUS_SUCCESS; 441 } 442 443 void mlo_peer_populate_nawds_params( 444 struct wlan_mlo_peer_context *ml_peer, 445 struct mlo_partner_info *ml_info) 446 { 447 uint8_t i; 448 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00, 449 0x00, 0x00, 0x00}; 450 struct mlnawds_config nawds_config; 451 452 mlo_peer_lock_acquire(ml_peer); 453 ml_peer->is_nawds_ml_peer = false; 454 for (i = 0; i < ml_info->num_partner_links; i++) { 455 nawds_config = ml_info->partner_link_info[i].nawds_config; 456 /** 457 * if ml_info->partner_link_info[i].nawds_config has valid 458 * config(check for non-null mac or non-0 caps), then mark 459 * ml_peer's is_nawds_ml_peer true & copy the config 460 */ 461 if ((nawds_config.caps) || 462 (qdf_mem_cmp(null_mac, 463 nawds_config.mac, 464 sizeof(null_mac)))) { 465 ml_peer->is_nawds_ml_peer = true; 466 ml_peer->nawds_config[i] = nawds_config; 467 } 468 } 469 mlo_peer_lock_release(ml_peer); 470 } 471 #else 472 QDF_STATUS 473 mlo_peer_create_get_frm_buf( 474 struct wlan_mlo_peer_context *ml_peer, 475 struct peer_create_notif_s *peer_create, 476 qdf_nbuf_t frm_buf) 477 { 478 peer_create->frm_buf = qdf_nbuf_clone(frm_buf); 479 if (!peer_create->frm_buf) 480 return QDF_STATUS_E_NOMEM; 481 482 return QDF_STATUS_SUCCESS; 483 } 484 #endif 485