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(struct vdev_create_params *param) 28 { 29 if (qdf_is_macaddr_zero((struct qdf_mac_addr *)param->mlo_mac)) 30 return WMI_TLV_HDR_SIZE; 31 32 return sizeof(wmi_vdev_create_mlo_params) + WMI_TLV_HDR_SIZE; 33 } 34 35 uint8_t *vdev_create_add_mlo_params(uint8_t *buf_ptr, 36 struct vdev_create_params *param) 37 { 38 wmi_vdev_create_mlo_params *mlo_params; 39 40 if (qdf_is_macaddr_zero((struct qdf_mac_addr *)param->mlo_mac)) { 41 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 42 return buf_ptr + WMI_TLV_HDR_SIZE; 43 } 44 45 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 46 sizeof(wmi_vdev_create_mlo_params)); 47 buf_ptr += sizeof(uint32_t); 48 49 mlo_params = (wmi_vdev_create_mlo_params *)buf_ptr; 50 WMITLV_SET_HDR(&mlo_params->tlv_header, 51 WMITLV_TAG_STRUC_wmi_vdev_create_mlo_params, 52 WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_create_mlo_params)); 53 54 WMI_CHAR_ARRAY_TO_MAC_ADDR(param->mlo_mac, &mlo_params->mld_macaddr); 55 56 wmi_debug("MLD Addr = "QDF_MAC_ADDR_FMT, 57 QDF_MAC_ADDR_REF(param->mlo_mac)); 58 return buf_ptr + sizeof(wmi_vdev_create_mlo_params); 59 } 60 61 size_t vdev_start_mlo_params_size(struct vdev_start_params *req) 62 { 63 size_t vdev_start_mlo_size; 64 65 vdev_start_mlo_size = sizeof(wmi_vdev_start_mlo_params) + 66 WMI_TLV_HDR_SIZE + 67 (req->mlo_partner.num_links * 68 sizeof(wmi_partner_link_params)) + 69 WMI_TLV_HDR_SIZE; 70 71 return vdev_start_mlo_size; 72 } 73 74 #ifdef WLAN_MCAST_MLO 75 static void vdev_start_add_mlo_mcast_params(uint32_t *mlo_flags, 76 struct vdev_start_params *req) 77 { 78 WMI_MLO_FLAGS_SET_MCAST_VDEV(*mlo_flags, 79 req->mlo_flags.mlo_mcast_vdev); 80 } 81 #else 82 #define vdev_start_add_mlo_mcast_params(mlo_flags, req) 83 #endif 84 85 uint8_t *vdev_start_add_mlo_params(uint8_t *buf_ptr, 86 struct vdev_start_params *req) 87 { 88 wmi_vdev_start_mlo_params *mlo_params; 89 90 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 91 sizeof(wmi_vdev_start_mlo_params)); 92 buf_ptr += sizeof(uint32_t); 93 94 mlo_params = (wmi_vdev_start_mlo_params *)buf_ptr; 95 WMITLV_SET_HDR(&mlo_params->tlv_header, 96 WMITLV_TAG_STRUC_wmi_vdev_start_mlo_params, 97 WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_start_mlo_params)); 98 99 mlo_params->mlo_flags.mlo_flags = 0; 100 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 101 req->mlo_flags.mlo_enabled); 102 WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags, 103 req->mlo_flags.mlo_assoc_link); 104 mlo_params->mlo_flags.emlsr_support = req->mlo_flags.emlsr_support; 105 106 vdev_start_add_mlo_mcast_params(&mlo_params->mlo_flags.mlo_flags, 107 req); 108 109 return buf_ptr + sizeof(wmi_vdev_start_mlo_params); 110 } 111 112 uint8_t *vdev_start_add_ml_partner_links(uint8_t *buf_ptr, 113 struct vdev_start_params *req) 114 { 115 wmi_partner_link_params *ml_partner_link; 116 struct mlo_vdev_start_partner_links *req_partner; 117 uint8_t i; 118 119 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 120 (req->mlo_partner.num_links * 121 sizeof(wmi_partner_link_params))); 122 buf_ptr += sizeof(uint32_t); 123 124 req_partner = &req->mlo_partner; 125 ml_partner_link = (wmi_partner_link_params *)buf_ptr; 126 for (i = 0; i < req->mlo_partner.num_links; i++) { 127 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 128 WMITLV_TAG_STRUC_wmi_partner_link_params, 129 WMITLV_GET_STRUCT_TLVLEN(wmi_partner_link_params)); 130 ml_partner_link->vdev_id = req_partner->partner_info[i].vdev_id; 131 ml_partner_link->hw_link_id = 132 req_partner->partner_info[i].hw_mld_link_id; 133 WMI_CHAR_ARRAY_TO_MAC_ADDR(req_partner->partner_info[i].mac_addr, 134 &ml_partner_link->vdev_macaddr); 135 ml_partner_link++; 136 } 137 138 return buf_ptr + 139 (req->mlo_partner.num_links * 140 sizeof(wmi_partner_link_params)); 141 } 142 143 size_t bcn_tmpl_mlo_param_size(struct beacon_tmpl_params *param) 144 { 145 return WMI_TLV_HDR_SIZE; 146 } 147 148 uint8_t *bcn_tmpl_add_ml_partner_links(uint8_t *buf_ptr, 149 struct beacon_tmpl_params *param) 150 { 151 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 152 return buf_ptr + WMI_TLV_HDR_SIZE; 153 } 154 155 size_t bcn_tmpl_ml_info_size(struct beacon_tmpl_params *param) 156 { 157 return (WMI_TLV_HDR_SIZE + sizeof(wmi_bcn_tmpl_ml_info)); 158 } 159 160 uint8_t *bcn_tmpl_add_ml_info(uint8_t *buf_ptr, 161 struct beacon_tmpl_params *param) 162 { 163 wmi_bcn_tmpl_ml_info *ml_info; 164 165 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 166 sizeof(wmi_bcn_tmpl_ml_info)); 167 buf_ptr += WMI_TLV_HDR_SIZE; 168 169 ml_info = (wmi_bcn_tmpl_ml_info *)buf_ptr; 170 171 WMITLV_SET_HDR(&ml_info->tlv_header, 172 WMITLV_TAG_STRUC_wmi_bcn_tmpl_ml_info, 173 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_ml_info)); 174 175 ml_info->hw_link_id = param->cu_ml_info.hw_link_id; 176 ml_info->cu_vdev_map_cat1_lo = param->cu_ml_info.cu_vdev_map_cat1_lo; 177 ml_info->cu_vdev_map_cat1_hi = param->cu_ml_info.cu_vdev_map_cat1_hi; 178 ml_info->cu_vdev_map_cat2_lo = param->cu_ml_info.cu_vdev_map_cat2_lo; 179 ml_info->cu_vdev_map_cat2_hi = param->cu_ml_info.cu_vdev_map_cat2_hi; 180 181 return buf_ptr + sizeof(wmi_bcn_tmpl_ml_info); 182 } 183 184 size_t peer_create_mlo_params_size(struct peer_create_params *req) 185 { 186 return sizeof(wmi_peer_create_mlo_params) + WMI_TLV_HDR_SIZE; 187 } 188 189 uint8_t *peer_create_add_mlo_params(uint8_t *buf_ptr, 190 struct peer_create_params *req) 191 { 192 wmi_peer_create_mlo_params *mlo_params; 193 194 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 195 sizeof(wmi_peer_create_mlo_params)); 196 buf_ptr += sizeof(uint32_t); 197 198 mlo_params = (wmi_peer_create_mlo_params *)buf_ptr; 199 WMITLV_SET_HDR(&mlo_params->tlv_header, 200 WMITLV_TAG_STRUC_wmi_peer_create_mlo_params, 201 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_create_mlo_params)); 202 203 mlo_params->mlo_flags.mlo_flags = 0; 204 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 205 req->mlo_enabled); 206 207 return buf_ptr + sizeof(wmi_peer_create_mlo_params); 208 } 209 210 size_t peer_assoc_mlo_params_size(struct peer_assoc_params *req) 211 { 212 size_t peer_assoc_mlo_size = sizeof(wmi_peer_assoc_mlo_params) + 213 WMI_TLV_HDR_SIZE + 214 (req->ml_links.num_links * 215 sizeof(wmi_peer_assoc_mlo_partner_link_params)) + 216 WMI_TLV_HDR_SIZE; 217 218 return peer_assoc_mlo_size; 219 } 220 221 uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr, 222 struct peer_assoc_params *req) 223 { 224 wmi_peer_assoc_mlo_params *mlo_params; 225 226 /* Add WMI peer assoc mlo params */ 227 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 228 sizeof(wmi_peer_assoc_mlo_params)); 229 buf_ptr += sizeof(uint32_t); 230 231 mlo_params = (wmi_peer_assoc_mlo_params *)buf_ptr; 232 WMITLV_SET_HDR(&mlo_params->tlv_header, 233 WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_params, 234 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_params)); 235 236 mlo_params->mlo_flags.mlo_flags = 0; 237 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 238 req->mlo_params.mlo_enabled); 239 WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags, 240 req->mlo_params.mlo_assoc_link); 241 WMI_MLO_FLAGS_SET_PRIMARY_UMAC(mlo_params->mlo_flags.mlo_flags, 242 req->mlo_params.mlo_primary_umac); 243 WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(mlo_params->mlo_flags.mlo_flags, 244 req->mlo_params.mlo_logical_link_index_valid); 245 WMI_MLO_FLAGS_SET_PEER_ID_VALID(mlo_params->mlo_flags.mlo_flags, 246 req->mlo_params.mlo_peer_id_valid); 247 mlo_params->mlo_flags.emlsr_support = req->mlo_params.emlsr_support; 248 249 mlo_params->mlo_flags.mlo_force_link_inactive = 250 req->mlo_params.mlo_force_link_inactive; 251 252 WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mld_mac, 253 &mlo_params->mld_macaddr); 254 mlo_params->logical_link_index = req->mlo_params.logical_link_index; 255 mlo_params->mld_peer_id = req->mlo_params.ml_peer_id; 256 257 mlo_params->ieee_link_id = req->mlo_params.ieee_link_id; 258 mlo_params->emlsr_trans_timeout_us = req->mlo_params.trans_timeout_us; 259 mlo_params->emlsr_trans_delay_us = req->mlo_params.emlsr_trans_delay_us; 260 mlo_params->emlsr_padding_delay_us = req->mlo_params.emlsr_pad_delay_us; 261 262 return buf_ptr + sizeof(wmi_peer_assoc_mlo_params); 263 } 264 265 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr, 266 struct peer_assoc_params *req) 267 { 268 wmi_peer_assoc_mlo_partner_link_params *ml_partner_link; 269 struct ml_partner_info *partner_info; 270 uint8_t i; 271 272 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 273 (req->ml_links.num_links * 274 sizeof(wmi_peer_assoc_mlo_partner_link_params))); 275 buf_ptr += sizeof(uint32_t); 276 277 ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr; 278 partner_info = req->ml_links.partner_info; 279 for (i = 0; i < req->ml_links.num_links; i++) { 280 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 281 WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params, 282 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params)); 283 ml_partner_link->vdev_id = partner_info[i].vdev_id; 284 ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id; 285 ml_partner_link++; 286 } 287 288 return buf_ptr + 289 (req->ml_links.num_links * 290 sizeof(wmi_peer_assoc_mlo_partner_link_params)); 291 } 292 293 size_t peer_delete_mlo_params_size(struct peer_delete_cmd_params *req) 294 { 295 if (!req->hw_link_id_bitmap) 296 return WMI_TLV_HDR_SIZE; 297 298 return sizeof(wmi_peer_delete_mlo_params) + WMI_TLV_HDR_SIZE; 299 } 300 301 uint8_t *peer_delete_add_mlo_params(uint8_t *buf_ptr, 302 struct peer_delete_cmd_params *req) 303 { 304 wmi_peer_delete_mlo_params *mlo_params; 305 306 if (!req->hw_link_id_bitmap) { 307 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 308 return buf_ptr + WMI_TLV_HDR_SIZE; 309 } 310 311 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 312 sizeof(wmi_peer_delete_mlo_params)); 313 buf_ptr += sizeof(uint32_t); 314 315 mlo_params = (wmi_peer_delete_mlo_params *)buf_ptr; 316 WMITLV_SET_HDR(&mlo_params->tlv_header, 317 WMITLV_TAG_STRUC_wmi_peer_delete_mlo_params, 318 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_delete_mlo_params)); 319 mlo_params->mlo_hw_link_id_bitmap = req->hw_link_id_bitmap; 320 return buf_ptr + sizeof(wmi_peer_delete_mlo_params); 321 } 322 323 /** 324 * force_mode_host_to_fw() - translate force mode for MLO link set active 325 * command 326 * @host_mode: force mode defined by host 327 * @fw_mode: buffer to store force mode defined by FW 328 * 329 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise 330 */ 331 static inline QDF_STATUS 332 force_mode_host_to_fw(enum mlo_link_force_mode host_mode, 333 WMI_MLO_LINK_FORCE_MODE *fw_mode) 334 { 335 switch (host_mode) { 336 case MLO_LINK_FORCE_MODE_ACTIVE: 337 *fw_mode = WMI_MLO_LINK_FORCE_ACTIVE; 338 break; 339 case MLO_LINK_FORCE_MODE_INACTIVE: 340 *fw_mode = WMI_MLO_LINK_FORCE_INACTIVE; 341 break; 342 case MLO_LINK_FORCE_MODE_ACTIVE_NUM: 343 *fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM; 344 break; 345 case MLO_LINK_FORCE_MODE_INACTIVE_NUM: 346 *fw_mode = WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM; 347 break; 348 case MLO_LINK_FORCE_MODE_NO_FORCE: 349 *fw_mode = WMI_MLO_LINK_NO_FORCE; 350 break; 351 default: 352 wmi_err("Invalid force mode: %d", host_mode); 353 return QDF_STATUS_E_INVAL; 354 } 355 356 return QDF_STATUS_SUCCESS; 357 } 358 359 /** 360 * force_reason_host_to_fw() - translate force reason for MLO link set active 361 * command 362 * @host_reason: force reason defined by host 363 * @fw_reason: buffer to store force reason defined by FW 364 * 365 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise 366 */ 367 static inline QDF_STATUS 368 force_reason_host_to_fw(enum mlo_link_force_reason host_reason, 369 WMI_MLO_LINK_FORCE_REASON *fw_reason) 370 { 371 switch (host_reason) { 372 case MLO_LINK_FORCE_REASON_CONNECT: 373 *fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT; 374 break; 375 case MLO_LINK_FORCE_REASON_DISCONNECT: 376 *fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT; 377 break; 378 default: 379 wmi_err("Invalid force reason: %d", host_reason); 380 return QDF_STATUS_E_INVAL; 381 } 382 383 return QDF_STATUS_SUCCESS; 384 } 385 386 /** 387 * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command 388 * @wmi_handle: wmi handle 389 * @param: Pointer to mlo link set active param 390 * 391 * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error 392 */ 393 static QDF_STATUS 394 send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle, 395 struct mlo_link_set_active_param *param) 396 { 397 QDF_STATUS status; 398 wmi_mlo_link_set_active_cmd_fixed_param *cmd; 399 wmi_mlo_set_active_link_number_param *link_num_param; 400 uint32_t *vdev_bitmap; 401 uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len; 402 wmi_buf_t buf; 403 uint8_t *buf_ptr; 404 uint32_t len; 405 int i; 406 WMITLV_TAG_ID tag_id; 407 WMI_MLO_LINK_FORCE_MODE force_mode; 408 WMI_MLO_LINK_FORCE_REASON force_reason; 409 410 if (!param->num_vdev_bitmap && !param->num_link_entry) { 411 wmi_err("No entry is provided vdev bit map %d link entry %d", 412 param->num_vdev_bitmap, 413 param->num_link_entry); 414 return QDF_STATUS_E_INVAL; 415 } 416 417 status = force_mode_host_to_fw(param->force_mode, &force_mode); 418 if (QDF_IS_STATUS_ERROR(status)) 419 return QDF_STATUS_E_INVAL; 420 421 status = force_reason_host_to_fw(param->reason, &force_reason); 422 if (QDF_IS_STATUS_ERROR(status)) 423 return QDF_STATUS_E_INVAL; 424 425 switch (force_mode) { 426 case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM: 427 case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM: 428 num_link_num_param = param->num_link_entry; 429 fallthrough; 430 case WMI_MLO_LINK_FORCE_ACTIVE: 431 case WMI_MLO_LINK_FORCE_INACTIVE: 432 case WMI_MLO_LINK_NO_FORCE: 433 num_vdev_bitmap = param->num_vdev_bitmap; 434 break; 435 } 436 437 len = sizeof(*cmd) + 438 WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param + 439 WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap; 440 441 buf = wmi_buf_alloc(wmi_handle, len); 442 if (!buf) 443 return QDF_STATUS_E_NOMEM; 444 445 buf_ptr = (uint8_t *)wmi_buf_data(buf); 446 cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr; 447 tlv_len = WMITLV_GET_STRUCT_TLVLEN 448 (wmi_mlo_link_set_active_cmd_fixed_param); 449 450 tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param; 451 WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len); 452 cmd->force_mode = force_mode; 453 cmd->reason = force_reason; 454 wmi_debug("mode %d reason %d num_link_num_param %d num_vdev_bitmap %d", 455 cmd->force_mode, cmd->reason, num_link_num_param, 456 num_vdev_bitmap); 457 buf_ptr += sizeof(*cmd); 458 459 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 460 sizeof(*link_num_param) * num_link_num_param); 461 buf_ptr += WMI_TLV_HDR_SIZE; 462 463 if (num_link_num_param) { 464 link_num_param = 465 (wmi_mlo_set_active_link_number_param *)buf_ptr; 466 tlv_len = WMITLV_GET_STRUCT_TLVLEN 467 (wmi_mlo_set_active_link_number_param); 468 for (i = 0; i < num_link_num_param; i++) { 469 WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len); 470 link_num_param->num_of_link = 471 param->link_num[i].num_of_link; 472 link_num_param->vdev_type = 473 param->link_num[i].vdev_type; 474 link_num_param->vdev_subtype = 475 param->link_num[i].vdev_subtype; 476 link_num_param->home_freq = 477 param->link_num[i].home_freq; 478 wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d", 479 i, link_num_param->num_of_link, 480 link_num_param->vdev_type, 481 link_num_param->vdev_subtype, 482 link_num_param->home_freq); 483 link_num_param++; 484 } 485 486 buf_ptr += sizeof(*link_num_param) * num_link_num_param; 487 } 488 489 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 490 sizeof(*vdev_bitmap) * num_vdev_bitmap); 491 buf_ptr += WMI_TLV_HDR_SIZE; 492 493 if (num_vdev_bitmap) { 494 vdev_bitmap = (A_UINT32 *)(buf_ptr); 495 for (i = 0; i < num_vdev_bitmap; i++) { 496 vdev_bitmap[i] = param->vdev_bitmap[i]; 497 wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ", 498 i, vdev_bitmap[i]); 499 } 500 501 buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap; 502 } 503 504 wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode); 505 status = wmi_unified_cmd_send(wmi_handle, buf, len, 506 WMI_MLO_LINK_SET_ACTIVE_CMDID); 507 if (QDF_IS_STATUS_ERROR(status)) { 508 wmi_err("Failed to send MLO link set active command to FW: %d", 509 status); 510 wmi_buf_free(buf); 511 } 512 513 return status; 514 } 515 516 /** 517 * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp 518 * from event 519 * @wmi_handle: wmi handle 520 * @evt_buf: pointer to event buffer 521 * @resp: Pointer to hold mlo link set active resp 522 * 523 * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error 524 */ 525 static QDF_STATUS 526 extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf, 527 struct mlo_link_set_active_resp *resp) 528 { 529 wmi_mlo_link_set_active_resp_event_fixed_param *evt; 530 WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf; 531 uint32_t entry_num, *bitmap; 532 int i; 533 534 param_buf = evt_buf; 535 if (!param_buf || !resp) { 536 wmi_err("Invalid param"); 537 return QDF_STATUS_E_INVAL; 538 } 539 540 evt = param_buf->fixed_param; 541 resp->status = evt->status; 542 wmi_debug("status: %u", resp->status); 543 544 bitmap = param_buf->force_active_vdev_bitmap; 545 entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap, 546 (uint32_t)MLO_VDEV_BITMAP_SZ); 547 resp->active_sz = entry_num; 548 for (i = 0; i < entry_num; i++) { 549 resp->active[i] = bitmap[i]; 550 wmi_debug("active[%d]: 0x%x", i, resp->active[i]); 551 } 552 553 bitmap = param_buf->force_inactive_vdev_bitmap; 554 entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap, 555 (uint32_t)MLO_VDEV_BITMAP_SZ); 556 resp->inactive_sz = entry_num; 557 for (i = 0; i < entry_num; i++) { 558 resp->inactive[i] = bitmap[i]; 559 wmi_debug("inactive[%d]: 0x%x", i, resp->inactive[i]); 560 } 561 562 return QDF_STATUS_SUCCESS; 563 } 564 565 #ifdef WLAN_FEATURE_11BE 566 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req) 567 { 568 size_t peer_assoc_t2lm_size = WMI_TLV_HDR_SIZE + 569 (req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS * 570 (sizeof(wmi_peer_assoc_tid_to_link_map))); 571 572 return peer_assoc_t2lm_size; 573 } 574 575 static void peer_assoc_populate_t2lm_tlv(wmi_peer_assoc_tid_to_link_map *cmd, 576 struct wlan_host_t2lm_of_tids *t2lm, 577 uint8_t tid_num) 578 { 579 WMITLV_SET_HDR(&cmd->tlv_header, 580 WMITLV_TAG_STRUC_wmi_peer_assoc_tid_to_link_map, 581 WMITLV_GET_STRUCT_TLVLEN( 582 wmi_peer_assoc_tid_to_link_map)); 583 584 /* Populate TID number */ 585 WMI_TID_TO_LINK_MAP_TID_NUM_SET(cmd->tid_to_link_map_info, tid_num); 586 587 /* Populate the direction */ 588 WMI_TID_TO_LINK_MAP_DIR_SET(cmd->tid_to_link_map_info, 589 t2lm->direction); 590 591 /* Populate the default link mapping value */ 592 WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET( 593 cmd->tid_to_link_map_info, 594 t2lm->default_link_mapping); 595 596 /* Populate the T2LM provisioned links for the corresponding TID 597 * number. 598 */ 599 WMI_TID_TO_LINK_MAP_LINK_MASK_SET( 600 cmd->tid_to_link_map_info, 601 t2lm->t2lm_provisioned_links[tid_num]); 602 603 wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x", 604 cmd->tid_to_link_map_info); 605 } 606 607 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr, 608 struct peer_assoc_params *req) 609 { 610 struct wmi_host_tid_to_link_map_params *t2lm_params = &req->t2lm_params; 611 wmi_peer_assoc_tid_to_link_map *cmd; 612 uint8_t dir = 0; 613 uint8_t tid_num = 0; 614 615 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 616 (req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS * 617 sizeof(wmi_peer_assoc_tid_to_link_map))); 618 buf_ptr += sizeof(uint32_t); 619 620 for (dir = 0; dir < t2lm_params->num_dir; dir++) { 621 wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d", 622 QDF_MAC_ADDR_REF(t2lm_params->peer_macaddr), 623 t2lm_params->t2lm_info[dir].direction); 624 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 625 cmd = (wmi_peer_assoc_tid_to_link_map *)buf_ptr; 626 peer_assoc_populate_t2lm_tlv( 627 cmd, &t2lm_params->t2lm_info[dir], 628 tid_num); 629 buf_ptr += sizeof(wmi_peer_assoc_tid_to_link_map); 630 } 631 } 632 633 return buf_ptr; 634 } 635 636 static QDF_STATUS send_mlo_peer_tid_to_link_map_cmd_tlv( 637 wmi_unified_t wmi_handle, 638 struct wmi_host_tid_to_link_map_params *params) 639 { 640 wmi_peer_tid_to_link_map_fixed_param *cmd; 641 wmi_tid_to_link_map *t2lm; 642 wmi_buf_t buf; 643 uint8_t *buf_ptr; 644 QDF_STATUS ret = QDF_STATUS_SUCCESS; 645 uint32_t buf_len = 0; 646 uint8_t dir = 0; 647 uint8_t tid_num = 0; 648 649 buf_len = sizeof(wmi_peer_tid_to_link_map_fixed_param) + 650 WMI_TLV_HDR_SIZE + (params->num_dir * T2LM_MAX_NUM_TIDS * 651 sizeof(wmi_tid_to_link_map)); 652 653 buf = wmi_buf_alloc(wmi_handle, buf_len); 654 if (!buf) { 655 wmi_err("wmi buf alloc failed for mlo_peer_mac: " 656 QDF_MAC_ADDR_FMT, 657 QDF_MAC_ADDR_REF(params->peer_macaddr)); 658 return QDF_STATUS_E_NOMEM; 659 } 660 661 buf_ptr = (uint8_t *)wmi_buf_data(buf); 662 cmd = (wmi_peer_tid_to_link_map_fixed_param *)buf_ptr; 663 664 WMITLV_SET_HDR(&cmd->tlv_header, 665 WMITLV_TAG_STRUC_wmi_peer_tid_to_link_map_fixed_param, 666 WMITLV_GET_STRUCT_TLVLEN( 667 wmi_peer_tid_to_link_map_fixed_param)); 668 669 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 670 wmi_handle, params->pdev_id); 671 672 WMI_CHAR_ARRAY_TO_MAC_ADDR(params->peer_macaddr, &cmd->link_macaddr); 673 674 buf_ptr += sizeof(wmi_peer_tid_to_link_map_fixed_param); 675 676 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 677 (params->num_dir * T2LM_MAX_NUM_TIDS * 678 sizeof(wmi_tid_to_link_map))); 679 buf_ptr += sizeof(uint32_t); 680 681 for (dir = 0; dir < params->num_dir; dir++) { 682 wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d", 683 QDF_MAC_ADDR_REF(params->peer_macaddr), 684 params->t2lm_info[dir].direction); 685 686 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 687 t2lm = (wmi_tid_to_link_map *)buf_ptr; 688 689 WMITLV_SET_HDR(&t2lm->tlv_header, 690 WMITLV_TAG_STRUC_wmi_tid_to_link_map, 691 WMITLV_GET_STRUCT_TLVLEN( 692 wmi_tid_to_link_map)); 693 694 /* Populate TID number */ 695 WMI_TID_TO_LINK_MAP_TID_NUM_SET( 696 t2lm->tid_to_link_map_info, tid_num); 697 698 /* Populate the direction */ 699 WMI_TID_TO_LINK_MAP_DIR_SET( 700 t2lm->tid_to_link_map_info, 701 params->t2lm_info[dir].direction); 702 703 /* Populate the default link mapping value */ 704 WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET( 705 t2lm->tid_to_link_map_info, 706 params->t2lm_info[dir].default_link_mapping); 707 708 /* Populate the T2LM provisioned links for the 709 * corresponding TID number. 710 */ 711 WMI_TID_TO_LINK_MAP_LINK_MASK_SET( 712 t2lm->tid_to_link_map_info, 713 params->t2lm_info[dir].t2lm_provisioned_links[tid_num]); 714 715 buf_ptr += sizeof(wmi_tid_to_link_map); 716 717 wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x", 718 t2lm->tid_to_link_map_info); 719 } 720 } 721 722 wmi_mtrace(WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID, cmd->pdev_id, 0); 723 ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len, 724 WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID); 725 if (ret) { 726 wmi_err("Failed to send T2LM command to FW: %d mlo_peer_mac: " QDF_MAC_ADDR_FMT, 727 ret, QDF_MAC_ADDR_REF(params->peer_macaddr)); 728 wmi_buf_free(buf); 729 } 730 731 return ret; 732 } 733 #else 734 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req) 735 { 736 return WMI_TLV_HDR_SIZE; 737 } 738 739 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr, 740 struct peer_assoc_params *req) 741 { 742 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 743 return buf_ptr + WMI_TLV_HDR_SIZE; 744 } 745 #endif /* WLAN_FEATURE_11BE */ 746 747 #ifdef WLAN_MLO_MULTI_CHIP 748 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle, 749 struct wmi_mlo_setup_params *param) 750 { 751 QDF_STATUS ret; 752 wmi_mlo_setup_cmd_fixed_param *cmd; 753 wmi_buf_t buf; 754 int32_t len; 755 uint8_t *buf_ptr; 756 uint32_t *partner_links; 757 uint8_t idx; 758 759 if (param->num_valid_hw_links > MAX_LINK_IN_MLO) 760 return QDF_STATUS_E_INVAL; 761 762 len = sizeof(*cmd) + 763 (param->num_valid_hw_links * sizeof(uint32_t)) + 764 WMI_TLV_HDR_SIZE; 765 766 buf = wmi_buf_alloc(wmi_handle, len); 767 if (!buf) 768 return QDF_STATUS_E_NOMEM; 769 770 cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf); 771 WMITLV_SET_HDR(&cmd->tlv_header, 772 WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param, 773 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param)); 774 775 cmd->mld_group_id = param->mld_grp_id; 776 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 777 wmi_handle, 778 param->pdev_id); 779 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 780 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 781 (sizeof(uint32_t) * param->num_valid_hw_links)); 782 partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); 783 for (idx = 0; idx < param->num_valid_hw_links; idx++) 784 partner_links[idx] = param->partner_links[idx]; 785 786 wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0); 787 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID); 788 if (QDF_IS_STATUS_ERROR(ret)) { 789 wmi_err("Failed to send MLO setup command ret = %d", ret); 790 wmi_buf_free(buf); 791 } 792 793 return ret; 794 } 795 796 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle, 797 struct wmi_mlo_ready_params *param) 798 { 799 QDF_STATUS ret; 800 wmi_mlo_ready_cmd_fixed_param *cmd; 801 wmi_buf_t buf; 802 int32_t len; 803 804 len = sizeof(*cmd); 805 806 buf = wmi_buf_alloc(wmi_handle, len); 807 if (!buf) 808 return QDF_STATUS_E_NOMEM; 809 810 cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf); 811 WMITLV_SET_HDR(&cmd->tlv_header, 812 WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param, 813 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param)); 814 815 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 816 wmi_handle, 817 param->pdev_id); 818 819 wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0); 820 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID); 821 if (QDF_IS_STATUS_ERROR(ret)) { 822 wmi_err("Failed to send MLO ready command ret = %d", ret); 823 wmi_buf_free(buf); 824 } 825 826 return ret; 827 } 828 829 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle, 830 struct wmi_mlo_teardown_params *param) 831 { 832 QDF_STATUS ret; 833 wmi_mlo_teardown_fixed_param *cmd; 834 wmi_buf_t buf; 835 int32_t len; 836 837 len = sizeof(*cmd); 838 839 buf = wmi_buf_alloc(wmi_handle, len); 840 if (!buf) 841 return QDF_STATUS_E_NOMEM; 842 843 cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf); 844 WMITLV_SET_HDR(&cmd->tlv_header, 845 WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param, 846 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param)); 847 848 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 849 wmi_handle, 850 param->pdev_id); 851 switch (param->reason) { 852 case WMI_MLO_TEARDOWN_REASON_SSR: 853 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON; 854 break; 855 case WMI_MLO_TEARDOWN_REASON_DOWN: 856 default: 857 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1; 858 break; 859 } 860 861 wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0); 862 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 863 WMI_MLO_TEARDOWN_CMDID); 864 if (QDF_IS_STATUS_ERROR(ret)) { 865 wmi_err("Failed to send MLO Teardown command ret = %d", ret); 866 wmi_buf_free(buf); 867 } 868 869 return ret; 870 } 871 872 QDF_STATUS 873 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle, 874 uint8_t *buf, 875 struct wmi_mlo_setup_complete_params *params) 876 { 877 WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf; 878 wmi_mlo_setup_complete_event_fixed_param *ev; 879 880 param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf; 881 if (!param_buf) { 882 wmi_err_rl("Param_buf is NULL"); 883 return QDF_STATUS_E_FAILURE; 884 } 885 ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param; 886 887 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 888 wmi_handle, 889 ev->pdev_id); 890 if (!ev->status) 891 params->status = WMI_MLO_SETUP_STATUS_SUCCESS; 892 else 893 params->status = WMI_MLO_SETUP_STATUS_FAILURE; 894 895 return QDF_STATUS_SUCCESS; 896 } 897 898 QDF_STATUS 899 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle, 900 uint8_t *buf, 901 struct wmi_mlo_teardown_cmpl_params *params) 902 { 903 WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf; 904 wmi_mlo_teardown_complete_fixed_param *ev; 905 906 param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf; 907 if (!param_buf) { 908 wmi_err_rl("Param_buf is NULL"); 909 return QDF_STATUS_E_FAILURE; 910 } 911 ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param; 912 913 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 914 wmi_handle, 915 ev->pdev_id); 916 if (!ev->status) 917 params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS; 918 else 919 params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE; 920 921 return QDF_STATUS_SUCCESS; 922 } 923 924 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 925 { 926 struct wmi_ops *ops = wmi_handle->ops; 927 928 ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv; 929 ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv; 930 ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv; 931 ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv; 932 ops->extract_mlo_teardown_cmpl_event = 933 extract_mlo_teardown_cmpl_event_tlv; 934 } 935 936 #else /*WLAN_MLO_MULTI_CHIP*/ 937 938 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 939 {} 940 941 #endif /*WLAN_MLO_MULTI_CHIP*/ 942 943 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) 944 { 945 struct wmi_ops *ops = wmi_handle->ops; 946 947 wmi_11be_attach_mlo_setup_tlv(wmi_handle); 948 ops->extract_mlo_link_set_active_resp = 949 extract_mlo_link_set_active_resp_tlv; 950 ops->send_mlo_link_set_active_cmd = 951 send_mlo_link_set_active_cmd_tlv; 952 #ifdef WLAN_FEATURE_11BE 953 ops->send_mlo_peer_tid_to_link_map = 954 send_mlo_peer_tid_to_link_map_cmd_tlv; 955 #endif /* WLAN_FEATURE_11BE */ 956 } 957