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 #include <osdep.h> 19 #include "wmi.h" 20 #include "wmi_unified_priv.h" 21 #include "wmi_unified_api.h" 22 #ifdef WLAN_MLO_MULTI_CHIP 23 #include "wmi_unified_11be_setup_api.h" 24 #endif 25 #include "wmi_unified_11be_tlv.h" 26 27 size_t vdev_create_mlo_params_size(void) 28 { 29 return sizeof(wmi_vdev_create_mlo_params) + WMI_TLV_HDR_SIZE; 30 } 31 32 uint8_t *vdev_create_add_mlo_params(uint8_t *buf_ptr, 33 struct vdev_create_params *param) 34 { 35 wmi_vdev_create_mlo_params *mlo_params; 36 37 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 38 sizeof(wmi_vdev_create_mlo_params)); 39 buf_ptr += sizeof(uint32_t); 40 41 mlo_params = (wmi_vdev_create_mlo_params *)buf_ptr; 42 WMITLV_SET_HDR(&mlo_params->tlv_header, 43 WMITLV_TAG_STRUC_wmi_vdev_create_mlo_params, 44 WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_create_mlo_params)); 45 46 WMI_CHAR_ARRAY_TO_MAC_ADDR(param->mlo_mac, &mlo_params->mld_macaddr); 47 48 wmi_debug("MLD Addr = "QDF_MAC_ADDR_FMT, 49 QDF_MAC_ADDR_REF(param->mlo_mac)); 50 return buf_ptr + sizeof(wmi_vdev_create_mlo_params); 51 } 52 53 size_t vdev_start_mlo_params_size(struct vdev_start_params *req) 54 { 55 size_t vdev_start_mlo_size; 56 57 vdev_start_mlo_size = sizeof(wmi_vdev_start_mlo_params) + 58 WMI_TLV_HDR_SIZE + 59 (req->mlo_partner.num_links * 60 sizeof(wmi_partner_link_params)) + 61 WMI_TLV_HDR_SIZE; 62 63 return vdev_start_mlo_size; 64 } 65 66 #ifdef WLAN_MCAST_MLO 67 static void vdev_start_add_mlo_mcast_params(uint32_t *mlo_flags, 68 struct vdev_start_params *req) 69 { 70 WMI_MLO_FLAGS_SET_MCAST_VDEV(*mlo_flags, 71 req->mlo_flags.mlo_mcast_vdev); 72 } 73 #else 74 #define vdev_start_add_mlo_mcast_params(mlo_flags, req) 75 #endif 76 77 uint8_t *vdev_start_add_mlo_params(uint8_t *buf_ptr, 78 struct vdev_start_params *req) 79 { 80 wmi_vdev_start_mlo_params *mlo_params; 81 82 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 83 sizeof(wmi_vdev_start_mlo_params)); 84 buf_ptr += sizeof(uint32_t); 85 86 mlo_params = (wmi_vdev_start_mlo_params *)buf_ptr; 87 WMITLV_SET_HDR(&mlo_params->tlv_header, 88 WMITLV_TAG_STRUC_wmi_vdev_start_mlo_params, 89 WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_start_mlo_params)); 90 91 mlo_params->mlo_flags.mlo_flags = 0; 92 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 93 req->mlo_flags.mlo_enabled); 94 WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags, 95 req->mlo_flags.mlo_assoc_link); 96 97 vdev_start_add_mlo_mcast_params(&mlo_params->mlo_flags.mlo_flags, 98 req); 99 100 return buf_ptr + sizeof(wmi_vdev_start_mlo_params); 101 } 102 103 uint8_t *vdev_start_add_ml_partner_links(uint8_t *buf_ptr, 104 struct vdev_start_params *req) 105 { 106 wmi_partner_link_params *ml_partner_link; 107 struct mlo_vdev_start_partner_links *req_partner; 108 uint8_t i; 109 110 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 111 (req->mlo_partner.num_links * 112 sizeof(wmi_partner_link_params))); 113 buf_ptr += sizeof(uint32_t); 114 115 req_partner = &req->mlo_partner; 116 ml_partner_link = (wmi_partner_link_params *)buf_ptr; 117 for (i = 0; i < req->mlo_partner.num_links; i++) { 118 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 119 WMITLV_TAG_STRUC_wmi_partner_link_params, 120 WMITLV_GET_STRUCT_TLVLEN(wmi_partner_link_params)); 121 ml_partner_link->vdev_id = req_partner->partner_info[i].vdev_id; 122 ml_partner_link->hw_link_id = 123 req_partner->partner_info[i].hw_mld_link_id; 124 WMI_CHAR_ARRAY_TO_MAC_ADDR(req_partner->partner_info[i].mac_addr, 125 &ml_partner_link->vdev_macaddr); 126 ml_partner_link++; 127 } 128 129 return buf_ptr + 130 (req->mlo_partner.num_links * 131 sizeof(wmi_partner_link_params)); 132 } 133 134 uint8_t *bcn_tmpl_add_ml_partner_links(uint8_t *buf_ptr, 135 struct beacon_tmpl_params *param) 136 { 137 wmi_bcn_tmpl_ml_params *ml_partner_link; 138 struct mlo_bcn_templ_partner_links *ml_bcn_tmpl; 139 uint8_t i; 140 141 if (param->mlo_partner.num_links > WLAN_UMAC_MLO_MAX_VDEVS) { 142 wmi_err("mlo_partner.num_link(%d) are greater than supported partner links(%d)", 143 param->mlo_partner.num_links, WLAN_UMAC_MLO_MAX_VDEVS); 144 return buf_ptr; 145 } 146 147 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 148 (param->mlo_partner.num_links * 149 sizeof(wmi_bcn_tmpl_ml_params))); 150 buf_ptr += sizeof(uint32_t); 151 152 ml_bcn_tmpl = ¶m->mlo_partner; 153 ml_partner_link = (wmi_bcn_tmpl_ml_params *)buf_ptr; 154 for (i = 0; i < ml_bcn_tmpl->num_links; i++) { 155 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 156 WMITLV_TAG_STRUC_wmi_bcn_tmpl_ml_params, 157 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_ml_params) 158 ); 159 ml_partner_link->vdev_id = ml_bcn_tmpl->partner_info[i].vdev_id; 160 ml_partner_link->hw_link_id = 161 ml_bcn_tmpl->partner_info[i].hw_link_id; 162 ml_partner_link->beacon_interval = 163 ml_bcn_tmpl->partner_info[i].beacon_interval; 164 ml_partner_link->csa_switch_count_offset = 165 ml_bcn_tmpl->partner_info[i].csa_switch_count_offset; 166 ml_partner_link->ext_csa_switch_count_offset = 167 ml_bcn_tmpl->partner_info[i].ext_csa_switch_count_offset; 168 ml_partner_link->per_sta_profile_offset = 169 ml_bcn_tmpl->partner_info[i].per_sta_profile_offset; 170 ml_partner_link->quiet_ie_offset = 171 ml_bcn_tmpl->partner_info[i].quiet_ie_offset; 172 ml_partner_link->is_other_ie_present = 173 ml_bcn_tmpl->partner_info[i].is_other_ie_present; 174 ml_partner_link++; 175 } 176 177 return buf_ptr + 178 (param->mlo_partner.num_links * 179 sizeof(wmi_bcn_tmpl_ml_params)); 180 } 181 182 size_t peer_create_mlo_params_size(struct peer_create_params *req) 183 { 184 return sizeof(wmi_peer_create_mlo_params) + WMI_TLV_HDR_SIZE; 185 } 186 187 uint8_t *peer_create_add_mlo_params(uint8_t *buf_ptr, 188 struct peer_create_params *req) 189 { 190 wmi_peer_create_mlo_params *mlo_params; 191 192 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 193 sizeof(wmi_peer_create_mlo_params)); 194 buf_ptr += sizeof(uint32_t); 195 196 mlo_params = (wmi_peer_create_mlo_params *)buf_ptr; 197 WMITLV_SET_HDR(&mlo_params->tlv_header, 198 WMITLV_TAG_STRUC_wmi_peer_create_mlo_params, 199 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_create_mlo_params)); 200 201 mlo_params->mlo_flags.mlo_flags = 0; 202 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 203 req->mlo_enabled); 204 205 return buf_ptr + sizeof(wmi_peer_create_mlo_params); 206 } 207 208 size_t peer_assoc_mlo_params_size(struct peer_assoc_params *req) 209 { 210 size_t peer_assoc_mlo_size = sizeof(wmi_peer_assoc_mlo_params) + 211 WMI_TLV_HDR_SIZE + 212 (req->ml_links.num_links * 213 sizeof(wmi_peer_assoc_mlo_partner_link_params)) + 214 WMI_TLV_HDR_SIZE; 215 216 return peer_assoc_mlo_size; 217 } 218 219 uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr, 220 struct peer_assoc_params *req) 221 { 222 wmi_peer_assoc_mlo_params *mlo_params; 223 224 /* Add WMI peer assoc mlo params */ 225 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 226 sizeof(wmi_peer_assoc_mlo_params)); 227 buf_ptr += sizeof(uint32_t); 228 229 mlo_params = (wmi_peer_assoc_mlo_params *)buf_ptr; 230 WMITLV_SET_HDR(&mlo_params->tlv_header, 231 WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_params, 232 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_params)); 233 234 mlo_params->mlo_flags.mlo_flags = 0; 235 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 236 req->mlo_params.mlo_enabled); 237 WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags, 238 req->mlo_params.mlo_assoc_link); 239 WMI_MLO_FLAGS_SET_PRIMARY_UMAC(mlo_params->mlo_flags.mlo_flags, 240 req->mlo_params.mlo_primary_umac); 241 WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(mlo_params->mlo_flags.mlo_flags, 242 req->mlo_params.mlo_logical_link_index_valid); 243 WMI_MLO_FLAGS_SET_PEER_ID_VALID(mlo_params->mlo_flags.mlo_flags, 244 req->mlo_params.mlo_peer_id_valid); 245 246 WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mld_mac, 247 &mlo_params->mld_macaddr); 248 mlo_params->logical_link_index = req->mlo_params.logical_link_index; 249 mlo_params->mld_peer_id = req->mlo_params.ml_peer_id; 250 251 return buf_ptr + sizeof(wmi_peer_assoc_mlo_params); 252 } 253 254 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr, 255 struct peer_assoc_params *req) 256 { 257 wmi_peer_assoc_mlo_partner_link_params *ml_partner_link; 258 struct ml_partner_info *partner_info; 259 uint8_t i; 260 261 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 262 (req->ml_links.num_links * 263 sizeof(wmi_peer_assoc_mlo_partner_link_params))); 264 buf_ptr += sizeof(uint32_t); 265 266 ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr; 267 partner_info = req->ml_links.partner_info; 268 for (i = 0; i < req->ml_links.num_links; i++) { 269 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 270 WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params, 271 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params)); 272 ml_partner_link->vdev_id = partner_info[i].vdev_id; 273 ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id; 274 ml_partner_link++; 275 } 276 277 return buf_ptr + 278 (req->ml_links.num_links * 279 sizeof(wmi_peer_assoc_mlo_partner_link_params)); 280 } 281 282 /** 283 * force_mode_host_to_fw() - translate force mode for MLO link set active 284 * command 285 * @host_mode: force mode defined by host 286 * @fw_mode: buffer to store force mode defined by FW 287 * 288 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise 289 */ 290 static inline QDF_STATUS 291 force_mode_host_to_fw(enum mlo_link_force_mode host_mode, 292 WMI_MLO_LINK_FORCE_MODE *fw_mode) 293 { 294 switch (host_mode) { 295 case MLO_LINK_FORCE_MODE_ACTIVE: 296 *fw_mode = WMI_MLO_LINK_FORCE_ACTIVE; 297 break; 298 case MLO_LINK_FORCE_MODE_INACTIVE: 299 *fw_mode = WMI_MLO_LINK_FORCE_INACTIVE; 300 break; 301 case MLO_LINK_FORCE_MODE_ACTIVE_NUM: 302 *fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM; 303 break; 304 case MLO_LINK_FORCE_MODE_INACTIVE_NUM: 305 *fw_mode = WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM; 306 break; 307 case MLO_LINK_FORCE_MODE_NO_FORCE: 308 *fw_mode = WMI_MLO_LINK_NO_FORCE; 309 break; 310 default: 311 wmi_err("Invalid force mode: %d", host_mode); 312 return QDF_STATUS_E_INVAL; 313 } 314 315 return QDF_STATUS_SUCCESS; 316 } 317 318 /** 319 * force_reason_host_to_fw() - translate force reason for MLO link set active 320 * command 321 * @host_reason: force reason defined by host 322 * @fw_reason: buffer to store force reason defined by FW 323 * 324 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise 325 */ 326 static inline QDF_STATUS 327 force_reason_host_to_fw(enum mlo_link_force_reason host_reason, 328 WMI_MLO_LINK_FORCE_REASON *fw_reason) 329 { 330 switch (host_reason) { 331 case MLO_LINK_FORCE_REASON_CONNECT: 332 *fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT; 333 break; 334 case MLO_LINK_FORCE_REASON_DISCONNECT: 335 *fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT; 336 break; 337 default: 338 wmi_err("Invalid force reason: %d", host_reason); 339 return QDF_STATUS_E_INVAL; 340 } 341 342 return QDF_STATUS_SUCCESS; 343 } 344 345 /** 346 * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command 347 * @wmi_handle: wmi handle 348 * @param: Pointer to mlo link set active param 349 * 350 * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error 351 */ 352 static QDF_STATUS 353 send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle, 354 struct mlo_link_set_active_param *param) 355 { 356 QDF_STATUS status; 357 wmi_mlo_link_set_active_cmd_fixed_param *cmd; 358 wmi_mlo_set_active_link_number_param *link_num_param; 359 uint32_t *vdev_bitmap; 360 uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len; 361 wmi_buf_t buf; 362 uint8_t *buf_ptr; 363 uint32_t len; 364 int i; 365 WMITLV_TAG_ID tag_id; 366 WMI_MLO_LINK_FORCE_MODE force_mode; 367 WMI_MLO_LINK_FORCE_REASON force_reason; 368 369 if (!param->num_vdev_bitmap && !param->num_link_entry) { 370 wmi_err("No entry is provided vdev bit map %d link entry %d", 371 param->num_vdev_bitmap, 372 param->num_link_entry); 373 return QDF_STATUS_E_INVAL; 374 } 375 376 status = force_mode_host_to_fw(param->force_mode, &force_mode); 377 if (QDF_IS_STATUS_ERROR(status)) 378 return QDF_STATUS_E_INVAL; 379 380 status = force_reason_host_to_fw(param->reason, &force_reason); 381 if (QDF_IS_STATUS_ERROR(status)) 382 return QDF_STATUS_E_INVAL; 383 384 switch (force_mode) { 385 case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM: 386 case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM: 387 num_link_num_param = param->num_link_entry; 388 /* fallthrough */ 389 case WMI_MLO_LINK_FORCE_ACTIVE: 390 case WMI_MLO_LINK_FORCE_INACTIVE: 391 case WMI_MLO_LINK_NO_FORCE: 392 num_vdev_bitmap = param->num_vdev_bitmap; 393 break; 394 } 395 396 len = sizeof(*cmd) + 397 WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param + 398 WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap; 399 400 buf = wmi_buf_alloc(wmi_handle, len); 401 if (!buf) 402 return QDF_STATUS_E_NOMEM; 403 404 buf_ptr = (uint8_t *)wmi_buf_data(buf); 405 cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr; 406 tlv_len = WMITLV_GET_STRUCT_TLVLEN 407 (wmi_mlo_link_set_active_cmd_fixed_param); 408 409 tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param; 410 WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len); 411 cmd->force_mode = force_mode; 412 cmd->reason = force_reason; 413 wmi_debug("mode %d reason %d num_link_num_param %d num_vdev_bitmap %d", 414 cmd->force_mode, cmd->reason, num_link_num_param, 415 num_vdev_bitmap); 416 buf_ptr += sizeof(*cmd); 417 418 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 419 sizeof(*link_num_param) * num_link_num_param); 420 buf_ptr += WMI_TLV_HDR_SIZE; 421 422 if (num_link_num_param) { 423 link_num_param = 424 (wmi_mlo_set_active_link_number_param *)buf_ptr; 425 tlv_len = WMITLV_GET_STRUCT_TLVLEN 426 (wmi_mlo_set_active_link_number_param); 427 for (i = 0; i < num_link_num_param; i++) { 428 WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len); 429 link_num_param->num_of_link = 430 param->link_num[i].num_of_link; 431 link_num_param->vdev_type = 432 param->link_num[i].vdev_type; 433 link_num_param->vdev_subtype = 434 param->link_num[i].vdev_subtype; 435 link_num_param->home_freq = 436 param->link_num[i].home_freq; 437 wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d", 438 i, link_num_param->num_of_link, 439 link_num_param->vdev_type, 440 link_num_param->vdev_subtype, 441 link_num_param->home_freq); 442 link_num_param++; 443 } 444 445 buf_ptr += sizeof(*link_num_param) * num_link_num_param; 446 } 447 448 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 449 sizeof(*vdev_bitmap) * num_vdev_bitmap); 450 buf_ptr += WMI_TLV_HDR_SIZE; 451 452 if (num_vdev_bitmap) { 453 vdev_bitmap = (A_UINT32 *)(buf_ptr); 454 for (i = 0; i < num_vdev_bitmap; i++) { 455 vdev_bitmap[i] = param->vdev_bitmap[i]; 456 wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ", 457 i, vdev_bitmap[i]); 458 } 459 460 buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap; 461 } 462 463 wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode); 464 status = wmi_unified_cmd_send(wmi_handle, buf, len, 465 WMI_MLO_LINK_SET_ACTIVE_CMDID); 466 if (QDF_IS_STATUS_ERROR(status)) { 467 wmi_err("Failed to send MLO link set active command to FW: %d", 468 status); 469 wmi_buf_free(buf); 470 } 471 472 return status; 473 } 474 475 /** 476 * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp 477 * from event 478 * @wmi_handle: wmi handle 479 * @evt_buf: pointer to event buffer 480 * @resp: Pointer to hold mlo link set active resp 481 * 482 * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error 483 */ 484 static QDF_STATUS 485 extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf, 486 struct mlo_link_set_active_resp *resp) 487 { 488 wmi_mlo_link_set_active_resp_event_fixed_param *evt; 489 WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf; 490 uint32_t entry_num, *bitmap; 491 int i; 492 493 param_buf = evt_buf; 494 if (!param_buf || !resp) { 495 wmi_err("Invalid param"); 496 return QDF_STATUS_E_INVAL; 497 } 498 499 evt = param_buf->fixed_param; 500 resp->status = evt->status; 501 wmi_debug("status: %u", resp->status); 502 503 bitmap = param_buf->force_active_vdev_bitmap; 504 entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap, 505 (uint32_t)MLO_VDEV_BITMAP_SZ); 506 resp->active_sz = entry_num; 507 for (i = 0; i < entry_num; i++) { 508 resp->active[i] = bitmap[i]; 509 wmi_debug("active[%d]: 0x%x", i, resp->active[i]); 510 } 511 512 bitmap = param_buf->force_inactive_vdev_bitmap; 513 entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap, 514 (uint32_t)MLO_VDEV_BITMAP_SZ); 515 resp->inactive_sz = entry_num; 516 for (i = 0; i < entry_num; i++) { 517 resp->inactive[i] = bitmap[i]; 518 wmi_debug("inactive[%d]: 0x%x", i, resp->inactive[i]); 519 } 520 521 return QDF_STATUS_SUCCESS; 522 } 523 524 #ifdef WLAN_MLO_MULTI_CHIP 525 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle, 526 struct wmi_mlo_setup_params *param) 527 { 528 QDF_STATUS ret; 529 wmi_mlo_setup_cmd_fixed_param *cmd; 530 wmi_buf_t buf; 531 int32_t len; 532 uint8_t *buf_ptr; 533 uint32_t *partner_links; 534 uint8_t idx; 535 536 if (param->num_valid_hw_links > MAX_LINK_IN_MLO) 537 return QDF_STATUS_E_INVAL; 538 539 len = sizeof(*cmd) + 540 (param->num_valid_hw_links * sizeof(uint32_t)) + 541 WMI_TLV_HDR_SIZE; 542 543 buf = wmi_buf_alloc(wmi_handle, len); 544 if (!buf) 545 return QDF_STATUS_E_NOMEM; 546 547 cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf); 548 WMITLV_SET_HDR(&cmd->tlv_header, 549 WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param, 550 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param)); 551 552 cmd->mld_group_id = param->mld_grp_id; 553 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 554 wmi_handle, 555 param->pdev_id); 556 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 557 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 558 (sizeof(uint32_t) * param->num_valid_hw_links)); 559 partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); 560 for (idx = 0; idx < param->num_valid_hw_links; idx++) 561 partner_links[idx] = param->partner_links[idx]; 562 563 wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0); 564 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID); 565 if (QDF_IS_STATUS_ERROR(ret)) { 566 wmi_err("Failed to send MLO setup command ret = %d", ret); 567 wmi_buf_free(buf); 568 } 569 570 return ret; 571 } 572 573 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle, 574 struct wmi_mlo_ready_params *param) 575 { 576 QDF_STATUS ret; 577 wmi_mlo_ready_cmd_fixed_param *cmd; 578 wmi_buf_t buf; 579 int32_t len; 580 581 len = sizeof(*cmd); 582 583 buf = wmi_buf_alloc(wmi_handle, len); 584 if (!buf) 585 return QDF_STATUS_E_NOMEM; 586 587 cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf); 588 WMITLV_SET_HDR(&cmd->tlv_header, 589 WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param, 590 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param)); 591 592 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 593 wmi_handle, 594 param->pdev_id); 595 596 wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0); 597 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID); 598 if (QDF_IS_STATUS_ERROR(ret)) { 599 wmi_err("Failed to send MLO ready command ret = %d", ret); 600 wmi_buf_free(buf); 601 } 602 603 return ret; 604 } 605 606 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle, 607 struct wmi_mlo_teardown_params *param) 608 { 609 QDF_STATUS ret; 610 wmi_mlo_teardown_fixed_param *cmd; 611 wmi_buf_t buf; 612 int32_t len; 613 614 len = sizeof(*cmd); 615 616 buf = wmi_buf_alloc(wmi_handle, len); 617 if (!buf) 618 return QDF_STATUS_E_NOMEM; 619 620 cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf); 621 WMITLV_SET_HDR(&cmd->tlv_header, 622 WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param, 623 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param)); 624 625 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 626 wmi_handle, 627 param->pdev_id); 628 switch (param->reason) { 629 case WMI_MLO_TEARDOWN_REASON_SSR: 630 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON; 631 break; 632 case WMI_MLO_TEARDOWN_REASON_DOWN: 633 default: 634 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1; 635 break; 636 } 637 638 wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0); 639 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 640 WMI_MLO_TEARDOWN_CMDID); 641 if (QDF_IS_STATUS_ERROR(ret)) { 642 wmi_err("Failed to send MLO Teardown command ret = %d", ret); 643 wmi_buf_free(buf); 644 } 645 646 return ret; 647 } 648 649 QDF_STATUS 650 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle, 651 uint8_t *buf, 652 struct wmi_mlo_setup_complete_params *params) 653 { 654 WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf; 655 wmi_mlo_setup_complete_event_fixed_param *ev; 656 657 param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf; 658 if (!param_buf) { 659 wmi_err_rl("Param_buf is NULL"); 660 return QDF_STATUS_E_FAILURE; 661 } 662 ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param; 663 664 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 665 wmi_handle, 666 ev->pdev_id); 667 if (!ev->status) 668 params->status = WMI_MLO_SETUP_STATUS_SUCCESS; 669 else 670 params->status = WMI_MLO_SETUP_STATUS_FAILURE; 671 672 return QDF_STATUS_SUCCESS; 673 } 674 675 QDF_STATUS 676 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle, 677 uint8_t *buf, 678 struct wmi_mlo_teardown_cmpl_params *params) 679 { 680 WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf; 681 wmi_mlo_teardown_complete_fixed_param *ev; 682 683 param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf; 684 if (!param_buf) { 685 wmi_err_rl("Param_buf is NULL"); 686 return QDF_STATUS_E_FAILURE; 687 } 688 ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param; 689 690 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 691 wmi_handle, 692 ev->pdev_id); 693 if (!ev->status) 694 params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS; 695 else 696 params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE; 697 698 return QDF_STATUS_SUCCESS; 699 } 700 701 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 702 { 703 struct wmi_ops *ops = wmi_handle->ops; 704 705 ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv; 706 ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv; 707 ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv; 708 ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv; 709 ops->extract_mlo_teardown_cmpl_event = 710 extract_mlo_teardown_cmpl_event_tlv; 711 } 712 713 #else /*WLAN_MLO_MULTI_CHIP*/ 714 715 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 716 {} 717 718 #endif /*WLAN_MLO_MULTI_CHIP*/ 719 720 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) 721 { 722 struct wmi_ops *ops = wmi_handle->ops; 723 724 wmi_11be_attach_mlo_setup_tlv(wmi_handle); 725 ops->extract_mlo_link_set_active_resp = 726 extract_mlo_link_set_active_resp_tlv; 727 ops->send_mlo_link_set_active_cmd = 728 send_mlo_link_set_active_cmd_tlv; 729 } 730