1 /* 2 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /** 18 * DOC: target_if_mlo_mgr.c 19 * 20 * This file provide definition for APIs registered through lmac Tx Ops 21 */ 22 23 #include <wmi_unified_11be_api.h> 24 #include <init_deinit_lmac.h> 25 #include "target_if_mlo_mgr.h" 26 #include <wlan_objmgr_peer_obj.h> 27 #include <wlan_mlo_t2lm.h> 28 29 /** 30 * target_if_mlo_link_set_active_resp_handler() - function to handle mlo link 31 * set active response from firmware. 32 * @scn: scn handle 33 * @data: data buffer for event 34 * @datalen: data length 35 * 36 * Return: 0 on success, else error on failure 37 */ 38 static int 39 target_if_mlo_link_set_active_resp_handler(ol_scn_t scn, uint8_t *data, 40 uint32_t datalen) 41 { 42 QDF_STATUS status; 43 struct wlan_objmgr_psoc *psoc; 44 struct wmi_unified *wmi_handle; 45 struct wlan_lmac_if_mlo_rx_ops *rx_ops; 46 struct mlo_link_set_active_resp resp; 47 48 if (!scn || !data) { 49 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 50 return -EINVAL; 51 } 52 53 psoc = target_if_get_psoc_from_scn_hdl(scn); 54 if (!psoc) { 55 target_if_err("null psoc"); 56 return -EINVAL; 57 } 58 59 rx_ops = target_if_mlo_get_rx_ops(psoc); 60 if (!rx_ops || !rx_ops->process_link_set_active_resp) { 61 target_if_err("callback not registered"); 62 return -EINVAL; 63 } 64 65 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 66 if (!wmi_handle) { 67 target_if_err("wmi_handle is null"); 68 return -EINVAL; 69 } 70 71 if (wmi_extract_mlo_link_set_active_resp(wmi_handle, data, &resp) != 72 QDF_STATUS_SUCCESS) { 73 target_if_err("Unable to extract mlo link set active resp"); 74 return -EINVAL; 75 } 76 77 status = rx_ops->process_link_set_active_resp(psoc, &resp); 78 79 return qdf_status_to_os_return(status); 80 } 81 82 /** 83 * target_if_mlo_link_removal_event_handler() - Handler for MLO link removal 84 * event sent by the FW 85 * @scn: scn handle 86 * @data: data buffer for event 87 * @datalen: data length 88 * 89 * Return: 0 on success, else error on failure 90 */ 91 static int 92 target_if_mlo_link_removal_event_handler(ol_scn_t scn, uint8_t *data, 93 uint32_t datalen) 94 { 95 struct wlan_objmgr_psoc *psoc; 96 struct wmi_unified *wmi_handle; 97 struct wlan_lmac_if_mlo_rx_ops *mlo_rx_ops; 98 QDF_STATUS status; 99 struct mlo_link_removal_evt_params evt_params; 100 101 if (!scn || !data) { 102 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); 103 return -EINVAL; 104 } 105 106 psoc = target_if_get_psoc_from_scn_hdl(scn); 107 if (!psoc) { 108 target_if_err("null psoc"); 109 return -EINVAL; 110 } 111 112 mlo_rx_ops = target_if_mlo_get_rx_ops(psoc); 113 if (!mlo_rx_ops || !mlo_rx_ops->mlo_link_removal_handler) { 114 target_if_err("callback not registered"); 115 return -EINVAL; 116 } 117 118 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 119 if (!wmi_handle) { 120 target_if_err("wmi_handle is null"); 121 return -EINVAL; 122 } 123 124 status = wmi_extract_mlo_link_removal_evt_fixed_param(wmi_handle, data, 125 &evt_params); 126 if (QDF_IS_STATUS_ERROR(status)) { 127 target_if_err("Unable to extract fixed param, ret = %d", 128 status); 129 goto exit; 130 } 131 132 status = wmi_extract_mlo_link_removal_tbtt_update( 133 wmi_handle, data, &evt_params.tbtt_info); 134 if (QDF_IS_STATUS_ERROR(status)) { 135 target_if_err("Unable to extract TBTT update TLV, ret = %d", 136 status); 137 goto exit; 138 } 139 140 status = mlo_rx_ops->mlo_link_removal_handler(psoc, &evt_params); 141 exit: 142 return qdf_status_to_os_return(status); 143 } 144 145 QDF_STATUS 146 target_if_extract_mlo_link_removal_info_mgmt_rx( 147 wmi_unified_t wmi_handle, 148 void *evt_buf, 149 struct mgmt_rx_event_params *rx_event) 150 { 151 QDF_STATUS status; 152 struct mgmt_rx_mlo_link_removal_info *link_removal_info; 153 154 if (!rx_event) { 155 target_if_err("Invalid rx_event"); 156 return QDF_STATUS_E_NULL_VALUE; 157 } 158 159 rx_event->link_removal_info = NULL; 160 if (!rx_event->num_link_removal_info) { 161 /** 162 * This is not an error. Only probe request frames will contain 163 * Link removal TLVs, that too only till the link removal TBTT 164 * countdown completion. 165 */ 166 target_if_debug("Link removal TLVs are not present"); 167 return QDF_STATUS_SUCCESS; 168 } 169 170 link_removal_info = qdf_mem_malloc(rx_event->num_link_removal_info * 171 sizeof(*link_removal_info)); 172 if (!link_removal_info) { 173 target_if_err("Couldn't allocate memory for link_removal_info"); 174 rx_event->num_link_removal_info = 0; 175 return QDF_STATUS_E_NOMEM; 176 } 177 178 status = wmi_extract_mgmt_rx_mlo_link_removal_info( 179 wmi_handle, evt_buf, 180 link_removal_info, 181 rx_event->num_link_removal_info); 182 if (QDF_IS_STATUS_ERROR(status)) { 183 target_if_err("Unable to extract link removal TLVs"); 184 rx_event->num_link_removal_info = 0; 185 qdf_mem_free(link_removal_info); 186 return status; 187 } 188 189 rx_event->link_removal_info = link_removal_info; 190 191 return QDF_STATUS_SUCCESS; 192 } 193 194 /** 195 * target_if_mlo_register_event_handler() - function to register handler for 196 * mlo related wmi event from firmware. 197 * @psoc: psoc pointer 198 * 199 * Return: QDF_STATUS 200 */ 201 static QDF_STATUS 202 target_if_mlo_register_event_handler(struct wlan_objmgr_psoc *psoc) 203 { 204 QDF_STATUS status; 205 struct wmi_unified *wmi_handle; 206 207 if (!psoc) { 208 target_if_err("PSOC is NULL!"); 209 return QDF_STATUS_E_NULL_VALUE; 210 } 211 212 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 213 if (!wmi_handle) { 214 target_if_err("wmi_handle is null"); 215 return QDF_STATUS_E_INVAL; 216 } 217 218 status = wmi_unified_register_event( 219 wmi_handle, 220 wmi_mlo_link_removal_eventid, 221 target_if_mlo_link_removal_event_handler); 222 if (QDF_IS_STATUS_ERROR(status)) 223 target_if_err("Couldn't register handler for Link removal WMI event %d", 224 status); 225 226 status = wmi_unified_register_event_handler( 227 wmi_handle, 228 wmi_mlo_link_set_active_resp_eventid, 229 target_if_mlo_link_set_active_resp_handler, 230 WMI_RX_WORK_CTX); 231 if (QDF_IS_STATUS_ERROR(status)) { 232 target_if_err("Register mlo link set active resp cb errcode %d", 233 status); 234 if (status == QDF_STATUS_E_NOSUPPORT) 235 status = QDF_STATUS_SUCCESS; 236 } 237 238 target_if_mlo_register_vdev_tid_to_link_map_event(wmi_handle); 239 240 return status; 241 } 242 243 /** 244 * target_if_mlo_unregister_event_handler() - function to unregister handler for 245 * mlo related wmi event from firmware. 246 * @psoc: psoc pointer 247 * 248 * Return: QDF_STATUS 249 */ 250 static QDF_STATUS 251 target_if_mlo_unregister_event_handler(struct wlan_objmgr_psoc *psoc) 252 { 253 struct wmi_unified *wmi_handle; 254 255 if (!psoc) { 256 target_if_err("PSOC is NULL!"); 257 return QDF_STATUS_E_INVAL; 258 } 259 260 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 261 if (!wmi_handle) { 262 target_if_err("wmi_handle is null"); 263 return QDF_STATUS_E_INVAL; 264 } 265 266 wmi_unified_unregister_event_handler(wmi_handle, 267 wmi_mlo_link_set_active_resp_eventid); 268 269 wmi_unified_unregister_event(wmi_handle, 270 wmi_mlo_link_removal_eventid); 271 272 target_if_mlo_unregister_vdev_tid_to_link_map_event(wmi_handle); 273 274 return QDF_STATUS_SUCCESS; 275 } 276 277 /** 278 * target_if_mlo_link_set_active() - Send WMI command for set mlo link active 279 * @psoc: psoc pointer 280 * @param: parameter for setting mlo link active 281 * 282 * Return: QDF_STATUS 283 */ 284 static QDF_STATUS 285 target_if_mlo_link_set_active(struct wlan_objmgr_psoc *psoc, 286 struct mlo_link_set_active_param *param) 287 { 288 QDF_STATUS ret; 289 struct wmi_unified *wmi_handle; 290 291 if (!psoc) { 292 target_if_err("null psoc"); 293 return QDF_STATUS_E_FAILURE; 294 } 295 296 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 297 if (!wmi_handle) { 298 target_if_err("null handle"); 299 return QDF_STATUS_E_FAILURE; 300 } 301 302 ret = wmi_send_mlo_link_set_active_cmd(wmi_handle, param); 303 if (QDF_IS_STATUS_ERROR(ret)) 304 target_if_err("wmi mlo link set active send failed: %d", ret); 305 306 return ret; 307 } 308 309 static int target_if_mlo_vdev_tid_to_link_map_event_handler( 310 ol_scn_t scn, uint8_t *event_buff, uint32_t len) 311 { 312 struct wlan_objmgr_psoc *psoc; 313 struct mlo_vdev_host_tid_to_link_map_resp event = {0}; 314 struct wmi_unified *wmi_handle; 315 struct wlan_lmac_if_mlo_rx_ops *rx_ops; 316 QDF_STATUS status; 317 318 if (!event_buff) { 319 mlme_err("Received NULL event ptr from FW"); 320 return -EINVAL; 321 } 322 323 psoc = target_if_get_psoc_from_scn_hdl(scn); 324 if (!psoc) { 325 mlme_err("PSOC is NULL"); 326 return -EINVAL; 327 } 328 329 rx_ops = target_if_mlo_get_rx_ops(psoc); 330 if (!rx_ops || !rx_ops->process_mlo_vdev_tid_to_link_map_event) { 331 target_if_err("callback not registered"); 332 return -EINVAL; 333 } 334 335 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 336 if (!wmi_handle) { 337 mlme_err("wmi_handle is null"); 338 return -EINVAL; 339 } 340 341 if (wmi_extract_mlo_vdev_tid_to_link_map_event(wmi_handle, event_buff, 342 &event)) { 343 mlme_err("Failed to extract TID-to-link mapping event"); 344 return -EINVAL; 345 } 346 347 status = rx_ops->process_mlo_vdev_tid_to_link_map_event(psoc, &event); 348 349 return qdf_status_to_os_return(status); 350 } 351 352 void target_if_mlo_register_vdev_tid_to_link_map_event( 353 struct wmi_unified *wmi_handle) 354 { 355 wmi_unified_register_event_handler( 356 wmi_handle, wmi_mlo_ap_vdev_tid_to_link_map_eventid, 357 target_if_mlo_vdev_tid_to_link_map_event_handler, 358 WMI_RX_EXECUTION_CTX); 359 } 360 361 void target_if_mlo_unregister_vdev_tid_to_link_map_event( 362 struct wmi_unified *wmi_handle) 363 { 364 wmi_unified_unregister_event_handler( 365 wmi_handle, wmi_mlo_ap_vdev_tid_to_link_map_eventid); 366 } 367 368 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 369 /** 370 * target_if_fill_provisioned_links() - API to fill the provisioned links 371 * @params: Pointer to T2LM params structure 372 * @t2lm: Pointer to T2LM info structure 373 * 374 * Return: none 375 */ 376 static inline void target_if_fill_provisioned_links( 377 struct wmi_host_tid_to_link_map_params *params, 378 struct wlan_t2lm_info *t2lm) 379 { 380 qdf_mem_copy(¶ms->t2lm_info[params->num_dir].t2lm_provisioned_links, 381 &t2lm->ieee_link_map_tid, 382 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS); 383 } 384 #else 385 static inline void target_if_fill_provisioned_links( 386 struct wmi_host_tid_to_link_map_params *params, 387 struct wlan_t2lm_info *t2lm) 388 { 389 qdf_mem_copy(¶ms->t2lm_info[params->num_dir].t2lm_provisioned_links, 390 &t2lm->hw_link_map_tid, 391 sizeof(uint16_t) * T2LM_MAX_NUM_TIDS); 392 } 393 #endif 394 395 static QDF_STATUS 396 target_if_mlo_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev, 397 struct wlan_t2lm_info *t2lm) 398 { 399 struct wmi_unified *wmi_handle = NULL; 400 struct wmi_host_tid_to_link_map_params params = {0}; 401 struct wlan_objmgr_pdev *pdev = NULL; 402 int tid = 0; 403 QDF_STATUS status; 404 405 pdev = wlan_vdev_get_pdev(vdev); 406 if (!pdev) { 407 t2lm_err("null pdev"); 408 return QDF_STATUS_E_NULL_VALUE; 409 } 410 411 wmi_handle = lmac_get_pdev_wmi_handle(pdev); 412 if (!wmi_handle) { 413 t2lm_err("null wmi handle"); 414 return QDF_STATUS_E_NULL_VALUE; 415 } 416 417 params.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 418 qdf_mem_copy(params.peer_macaddr, vdev->vdev_objmgr.bss_peer->macaddr, 419 QDF_MAC_ADDR_SIZE); 420 421 t2lm_debug("Fill T2LM WMI info for peer: " QDF_MAC_ADDR_FMT " pdev_id:%d", 422 QDF_MAC_ADDR_REF(params.peer_macaddr), params.pdev_id); 423 424 params.t2lm_info[params.num_dir].direction = t2lm->direction; 425 params.t2lm_info[params.num_dir].default_link_mapping = 426 t2lm->default_link_mapping; 427 428 if (!params.t2lm_info[params.num_dir].default_link_mapping) 429 target_if_fill_provisioned_links(¶ms, t2lm); 430 431 t2lm_debug("num_dir:%d direction:%d default_link_mapping:%d", 432 params.num_dir, params.t2lm_info[params.num_dir].direction, 433 params.t2lm_info[params.num_dir].default_link_mapping); 434 435 for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) { 436 t2lm_debug("tid:%d hw_link_map:%x ieee_link_map:%x", tid, 437 params.t2lm_info[params.num_dir].t2lm_provisioned_links[tid], 438 t2lm->ieee_link_map_tid[tid]); 439 } 440 441 params.num_dir++; 442 443 status = wmi_send_mlo_peer_tid_to_link_map_cmd(wmi_handle, ¶ms); 444 if (QDF_IS_STATUS_ERROR(status)) { 445 t2lm_err("Failed to send T2LM WMI command for pdev_id:%d peer_mac: " QDF_MAC_ADDR_FMT, 446 params.pdev_id, 447 QDF_MAC_ADDR_REF(params.peer_macaddr)); 448 return status; 449 } 450 451 return status; 452 } 453 454 QDF_STATUS target_if_mlo_send_link_removal_cmd( 455 struct wlan_objmgr_psoc *psoc, 456 const struct mlo_link_removal_cmd_params *param) 457 { 458 struct wmi_unified *wmi_handle; 459 460 if (!psoc) { 461 target_if_err("null psoc"); 462 return QDF_STATUS_E_NULL_VALUE; 463 } 464 465 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 466 if (!wmi_handle) { 467 target_if_err("null handle"); 468 return QDF_STATUS_E_FAILURE; 469 } 470 471 return wmi_send_mlo_link_removal_cmd(wmi_handle, param); 472 } 473 474 /** 475 * target_if_mlo_register_tx_ops() - lmac handler to register mlo tx ops 476 * callback functions 477 * @tx_ops: wlan_lmac_if_tx_ops object 478 * 479 * Return: QDF_STATUS 480 */ 481 QDF_STATUS 482 target_if_mlo_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 483 { 484 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 485 486 if (!tx_ops) { 487 target_if_err("lmac tx ops is NULL!"); 488 return QDF_STATUS_E_INVAL; 489 } 490 491 mlo_tx_ops = &tx_ops->mlo_ops; 492 if (!mlo_tx_ops) { 493 target_if_err("lmac tx ops is NULL!"); 494 return QDF_STATUS_E_FAILURE; 495 } 496 497 mlo_tx_ops->register_events = 498 target_if_mlo_register_event_handler; 499 mlo_tx_ops->unregister_events = 500 target_if_mlo_unregister_event_handler; 501 mlo_tx_ops->link_set_active = target_if_mlo_link_set_active; 502 mlo_tx_ops->send_tid_to_link_mapping = 503 target_if_mlo_send_tid_to_link_mapping; 504 mlo_tx_ops->send_link_removal_cmd = target_if_mlo_send_link_removal_cmd; 505 506 return QDF_STATUS_SUCCESS; 507 } 508 509