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 mlo_params->msd_dur_us = req->mlo_params.medium_sync_duration; 263 mlo_params->msd_ofdm_ed_thr = 264 req->mlo_params.medium_sync_ofdm_ed_thresh; 265 mlo_params->msd_max_num_txops = 266 req->mlo_params.medium_sync_max_txop_num; 267 268 return buf_ptr + sizeof(wmi_peer_assoc_mlo_params); 269 } 270 271 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr, 272 struct peer_assoc_params *req) 273 { 274 wmi_peer_assoc_mlo_partner_link_params *ml_partner_link; 275 struct ml_partner_info *partner_info; 276 uint8_t i; 277 278 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 279 (req->ml_links.num_links * 280 sizeof(wmi_peer_assoc_mlo_partner_link_params))); 281 buf_ptr += sizeof(uint32_t); 282 283 ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr; 284 partner_info = req->ml_links.partner_info; 285 for (i = 0; i < req->ml_links.num_links; i++) { 286 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 287 WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params, 288 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params)); 289 ml_partner_link->vdev_id = partner_info[i].vdev_id; 290 ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id; 291 ml_partner_link++; 292 } 293 294 return buf_ptr + 295 (req->ml_links.num_links * 296 sizeof(wmi_peer_assoc_mlo_partner_link_params)); 297 } 298 299 size_t peer_delete_mlo_params_size(struct peer_delete_cmd_params *req) 300 { 301 if (!req->hw_link_id_bitmap) 302 return WMI_TLV_HDR_SIZE; 303 304 return sizeof(wmi_peer_delete_mlo_params) + WMI_TLV_HDR_SIZE; 305 } 306 307 uint8_t *peer_delete_add_mlo_params(uint8_t *buf_ptr, 308 struct peer_delete_cmd_params *req) 309 { 310 wmi_peer_delete_mlo_params *mlo_params; 311 312 if (!req->hw_link_id_bitmap) { 313 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 314 return buf_ptr + WMI_TLV_HDR_SIZE; 315 } 316 317 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 318 sizeof(wmi_peer_delete_mlo_params)); 319 buf_ptr += sizeof(uint32_t); 320 321 mlo_params = (wmi_peer_delete_mlo_params *)buf_ptr; 322 WMITLV_SET_HDR(&mlo_params->tlv_header, 323 WMITLV_TAG_STRUC_wmi_peer_delete_mlo_params, 324 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_delete_mlo_params)); 325 mlo_params->mlo_hw_link_id_bitmap = req->hw_link_id_bitmap; 326 return buf_ptr + sizeof(wmi_peer_delete_mlo_params); 327 } 328 329 /** 330 * force_mode_host_to_fw() - translate force mode for MLO link set active 331 * command 332 * @host_mode: force mode defined by host 333 * @fw_mode: buffer to store force mode defined by FW 334 * 335 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise 336 */ 337 static inline QDF_STATUS 338 force_mode_host_to_fw(enum mlo_link_force_mode host_mode, 339 WMI_MLO_LINK_FORCE_MODE *fw_mode) 340 { 341 switch (host_mode) { 342 case MLO_LINK_FORCE_MODE_ACTIVE: 343 *fw_mode = WMI_MLO_LINK_FORCE_ACTIVE; 344 break; 345 case MLO_LINK_FORCE_MODE_INACTIVE: 346 *fw_mode = WMI_MLO_LINK_FORCE_INACTIVE; 347 break; 348 case MLO_LINK_FORCE_MODE_ACTIVE_NUM: 349 *fw_mode = WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM; 350 break; 351 case MLO_LINK_FORCE_MODE_INACTIVE_NUM: 352 *fw_mode = WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM; 353 break; 354 case MLO_LINK_FORCE_MODE_NO_FORCE: 355 *fw_mode = WMI_MLO_LINK_NO_FORCE; 356 break; 357 default: 358 wmi_err("Invalid force mode: %d", host_mode); 359 return QDF_STATUS_E_INVAL; 360 } 361 362 return QDF_STATUS_SUCCESS; 363 } 364 365 /** 366 * force_reason_host_to_fw() - translate force reason for MLO link set active 367 * command 368 * @host_reason: force reason defined by host 369 * @fw_reason: buffer to store force reason defined by FW 370 * 371 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL otherwise 372 */ 373 static inline QDF_STATUS 374 force_reason_host_to_fw(enum mlo_link_force_reason host_reason, 375 WMI_MLO_LINK_FORCE_REASON *fw_reason) 376 { 377 switch (host_reason) { 378 case MLO_LINK_FORCE_REASON_CONNECT: 379 *fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT; 380 break; 381 case MLO_LINK_FORCE_REASON_DISCONNECT: 382 *fw_reason = WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT; 383 break; 384 default: 385 wmi_err("Invalid force reason: %d", host_reason); 386 return QDF_STATUS_E_INVAL; 387 } 388 389 return QDF_STATUS_SUCCESS; 390 } 391 392 /** 393 * send_mlo_link_set_active_cmd_tlv() - send mlo link set active command 394 * @wmi_handle: wmi handle 395 * @param: Pointer to mlo link set active param 396 * 397 * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error 398 */ 399 static QDF_STATUS 400 send_mlo_link_set_active_cmd_tlv(wmi_unified_t wmi_handle, 401 struct mlo_link_set_active_param *param) 402 { 403 QDF_STATUS status; 404 wmi_mlo_link_set_active_cmd_fixed_param *cmd; 405 wmi_mlo_set_active_link_number_param *link_num_param; 406 uint32_t *vdev_bitmap; 407 uint32_t num_link_num_param = 0, num_vdev_bitmap = 0, tlv_len; 408 wmi_buf_t buf; 409 uint8_t *buf_ptr; 410 uint32_t len; 411 int i; 412 WMITLV_TAG_ID tag_id; 413 WMI_MLO_LINK_FORCE_MODE force_mode; 414 WMI_MLO_LINK_FORCE_REASON force_reason; 415 416 if (!param->num_vdev_bitmap && !param->num_link_entry) { 417 wmi_err("No entry is provided vdev bit map %d link entry %d", 418 param->num_vdev_bitmap, 419 param->num_link_entry); 420 return QDF_STATUS_E_INVAL; 421 } 422 423 status = force_mode_host_to_fw(param->force_mode, &force_mode); 424 if (QDF_IS_STATUS_ERROR(status)) 425 return QDF_STATUS_E_INVAL; 426 427 status = force_reason_host_to_fw(param->reason, &force_reason); 428 if (QDF_IS_STATUS_ERROR(status)) 429 return QDF_STATUS_E_INVAL; 430 431 switch (force_mode) { 432 case WMI_MLO_LINK_FORCE_ACTIVE_LINK_NUM: 433 case WMI_MLO_LINK_FORCE_INACTIVE_LINK_NUM: 434 num_link_num_param = param->num_link_entry; 435 fallthrough; 436 case WMI_MLO_LINK_FORCE_ACTIVE: 437 case WMI_MLO_LINK_FORCE_INACTIVE: 438 case WMI_MLO_LINK_NO_FORCE: 439 num_vdev_bitmap = param->num_vdev_bitmap; 440 break; 441 } 442 443 len = sizeof(*cmd) + 444 WMI_TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param + 445 WMI_TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap; 446 447 buf = wmi_buf_alloc(wmi_handle, len); 448 if (!buf) 449 return QDF_STATUS_E_NOMEM; 450 451 buf_ptr = (uint8_t *)wmi_buf_data(buf); 452 cmd = (wmi_mlo_link_set_active_cmd_fixed_param *)buf_ptr; 453 tlv_len = WMITLV_GET_STRUCT_TLVLEN 454 (wmi_mlo_link_set_active_cmd_fixed_param); 455 456 tag_id = WMITLV_TAG_STRUC_wmi_mlo_link_set_active_cmd_fixed_param; 457 WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len); 458 cmd->force_mode = force_mode; 459 cmd->reason = force_reason; 460 wmi_debug("mode %d reason %d num_link_num_param %d num_vdev_bitmap %d", 461 cmd->force_mode, cmd->reason, num_link_num_param, 462 num_vdev_bitmap); 463 buf_ptr += sizeof(*cmd); 464 465 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 466 sizeof(*link_num_param) * num_link_num_param); 467 buf_ptr += WMI_TLV_HDR_SIZE; 468 469 if (num_link_num_param) { 470 link_num_param = 471 (wmi_mlo_set_active_link_number_param *)buf_ptr; 472 tlv_len = WMITLV_GET_STRUCT_TLVLEN 473 (wmi_mlo_set_active_link_number_param); 474 for (i = 0; i < num_link_num_param; i++) { 475 WMITLV_SET_HDR(&link_num_param->tlv_header, 0, tlv_len); 476 link_num_param->num_of_link = 477 param->link_num[i].num_of_link; 478 link_num_param->vdev_type = 479 param->link_num[i].vdev_type; 480 link_num_param->vdev_subtype = 481 param->link_num[i].vdev_subtype; 482 link_num_param->home_freq = 483 param->link_num[i].home_freq; 484 wmi_debug("entry[%d]: num_of_link %d vdev type %d subtype %d freq %d", 485 i, link_num_param->num_of_link, 486 link_num_param->vdev_type, 487 link_num_param->vdev_subtype, 488 link_num_param->home_freq); 489 link_num_param++; 490 } 491 492 buf_ptr += sizeof(*link_num_param) * num_link_num_param; 493 } 494 495 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 496 sizeof(*vdev_bitmap) * num_vdev_bitmap); 497 buf_ptr += WMI_TLV_HDR_SIZE; 498 499 if (num_vdev_bitmap) { 500 vdev_bitmap = (A_UINT32 *)(buf_ptr); 501 for (i = 0; i < num_vdev_bitmap; i++) { 502 vdev_bitmap[i] = param->vdev_bitmap[i]; 503 wmi_debug("entry[%d]: vdev_id_bitmap 0x%x ", 504 i, vdev_bitmap[i]); 505 } 506 507 buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap; 508 } 509 510 wmi_mtrace(WMI_MLO_LINK_SET_ACTIVE_CMDID, 0, cmd->force_mode); 511 status = wmi_unified_cmd_send(wmi_handle, buf, len, 512 WMI_MLO_LINK_SET_ACTIVE_CMDID); 513 if (QDF_IS_STATUS_ERROR(status)) { 514 wmi_err("Failed to send MLO link set active command to FW: %d", 515 status); 516 wmi_buf_free(buf); 517 } 518 519 return status; 520 } 521 522 /** 523 * extract_mlo_link_set_active_resp_tlv() - extract mlo link set active resp 524 * from event 525 * @wmi_handle: wmi handle 526 * @evt_buf: pointer to event buffer 527 * @resp: Pointer to hold mlo link set active resp 528 * 529 * Return: QDF_STATUS_SUCCESS for success or QDF_STATUS_E_* for error 530 */ 531 static QDF_STATUS 532 extract_mlo_link_set_active_resp_tlv(wmi_unified_t wmi_handle, void *evt_buf, 533 struct mlo_link_set_active_resp *resp) 534 { 535 wmi_mlo_link_set_active_resp_event_fixed_param *evt; 536 WMI_MLO_LINK_SET_ACTIVE_RESP_EVENTID_param_tlvs *param_buf; 537 uint32_t entry_num, *bitmap; 538 int i; 539 540 param_buf = evt_buf; 541 if (!param_buf || !resp) { 542 wmi_err("Invalid param"); 543 return QDF_STATUS_E_INVAL; 544 } 545 546 evt = param_buf->fixed_param; 547 resp->status = evt->status; 548 wmi_debug("status: %u", resp->status); 549 550 bitmap = param_buf->force_active_vdev_bitmap; 551 entry_num = qdf_min(param_buf->num_force_active_vdev_bitmap, 552 (uint32_t)MLO_VDEV_BITMAP_SZ); 553 resp->active_sz = entry_num; 554 for (i = 0; i < entry_num; i++) { 555 resp->active[i] = bitmap[i]; 556 wmi_debug("active[%d]: 0x%x", i, resp->active[i]); 557 } 558 559 bitmap = param_buf->force_inactive_vdev_bitmap; 560 entry_num = qdf_min(param_buf->num_force_inactive_vdev_bitmap, 561 (uint32_t)MLO_VDEV_BITMAP_SZ); 562 resp->inactive_sz = entry_num; 563 for (i = 0; i < entry_num; i++) { 564 resp->inactive[i] = bitmap[i]; 565 wmi_debug("inactive[%d]: 0x%x", i, resp->inactive[i]); 566 } 567 568 return QDF_STATUS_SUCCESS; 569 } 570 571 #ifdef WLAN_FEATURE_11BE 572 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req) 573 { 574 size_t peer_assoc_t2lm_size = WMI_TLV_HDR_SIZE + 575 (req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS * 576 (sizeof(wmi_peer_assoc_tid_to_link_map))); 577 578 return peer_assoc_t2lm_size; 579 } 580 581 static void peer_assoc_populate_t2lm_tlv(wmi_peer_assoc_tid_to_link_map *cmd, 582 struct wlan_host_t2lm_of_tids *t2lm, 583 uint8_t tid_num) 584 { 585 WMITLV_SET_HDR(&cmd->tlv_header, 586 WMITLV_TAG_STRUC_wmi_peer_assoc_tid_to_link_map, 587 WMITLV_GET_STRUCT_TLVLEN( 588 wmi_peer_assoc_tid_to_link_map)); 589 590 /* Populate TID number */ 591 WMI_TID_TO_LINK_MAP_TID_NUM_SET(cmd->tid_to_link_map_info, tid_num); 592 593 /* Populate the direction */ 594 WMI_TID_TO_LINK_MAP_DIR_SET(cmd->tid_to_link_map_info, 595 t2lm->direction); 596 597 /* Populate the default link mapping value */ 598 WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET( 599 cmd->tid_to_link_map_info, 600 t2lm->default_link_mapping); 601 602 /* Populate the T2LM provisioned links for the corresponding TID 603 * number. 604 */ 605 WMI_TID_TO_LINK_MAP_LINK_MASK_SET( 606 cmd->tid_to_link_map_info, 607 t2lm->t2lm_provisioned_links[tid_num]); 608 609 wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x", 610 cmd->tid_to_link_map_info); 611 } 612 613 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr, 614 struct peer_assoc_params *req) 615 { 616 struct wmi_host_tid_to_link_map_params *t2lm_params = &req->t2lm_params; 617 wmi_peer_assoc_tid_to_link_map *cmd; 618 uint8_t dir = 0; 619 uint8_t tid_num = 0; 620 621 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 622 (req->t2lm_params.num_dir * T2LM_MAX_NUM_TIDS * 623 sizeof(wmi_peer_assoc_tid_to_link_map))); 624 buf_ptr += sizeof(uint32_t); 625 626 for (dir = 0; dir < t2lm_params->num_dir; dir++) { 627 wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d", 628 QDF_MAC_ADDR_REF(t2lm_params->peer_macaddr), 629 t2lm_params->t2lm_info[dir].direction); 630 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 631 cmd = (wmi_peer_assoc_tid_to_link_map *)buf_ptr; 632 peer_assoc_populate_t2lm_tlv( 633 cmd, &t2lm_params->t2lm_info[dir], 634 tid_num); 635 buf_ptr += sizeof(wmi_peer_assoc_tid_to_link_map); 636 } 637 } 638 639 return buf_ptr; 640 } 641 642 static QDF_STATUS send_mlo_peer_tid_to_link_map_cmd_tlv( 643 wmi_unified_t wmi_handle, 644 struct wmi_host_tid_to_link_map_params *params) 645 { 646 wmi_peer_tid_to_link_map_fixed_param *cmd; 647 wmi_tid_to_link_map *t2lm; 648 wmi_buf_t buf; 649 uint8_t *buf_ptr; 650 QDF_STATUS ret = QDF_STATUS_SUCCESS; 651 uint32_t buf_len = 0; 652 uint8_t dir = 0; 653 uint8_t tid_num = 0; 654 655 buf_len = sizeof(wmi_peer_tid_to_link_map_fixed_param) + 656 WMI_TLV_HDR_SIZE + (params->num_dir * T2LM_MAX_NUM_TIDS * 657 sizeof(wmi_tid_to_link_map)); 658 659 buf = wmi_buf_alloc(wmi_handle, buf_len); 660 if (!buf) { 661 wmi_err("wmi buf alloc failed for mlo_peer_mac: " 662 QDF_MAC_ADDR_FMT, 663 QDF_MAC_ADDR_REF(params->peer_macaddr)); 664 return QDF_STATUS_E_NOMEM; 665 } 666 667 buf_ptr = (uint8_t *)wmi_buf_data(buf); 668 cmd = (wmi_peer_tid_to_link_map_fixed_param *)buf_ptr; 669 670 WMITLV_SET_HDR(&cmd->tlv_header, 671 WMITLV_TAG_STRUC_wmi_peer_tid_to_link_map_fixed_param, 672 WMITLV_GET_STRUCT_TLVLEN( 673 wmi_peer_tid_to_link_map_fixed_param)); 674 675 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 676 wmi_handle, params->pdev_id); 677 678 WMI_CHAR_ARRAY_TO_MAC_ADDR(params->peer_macaddr, &cmd->link_macaddr); 679 680 buf_ptr += sizeof(wmi_peer_tid_to_link_map_fixed_param); 681 682 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 683 (params->num_dir * T2LM_MAX_NUM_TIDS * 684 sizeof(wmi_tid_to_link_map))); 685 buf_ptr += sizeof(uint32_t); 686 687 for (dir = 0; dir < params->num_dir; dir++) { 688 wmi_debug("Add T2LM TLV for peer: " QDF_MAC_ADDR_FMT " direction:%d", 689 QDF_MAC_ADDR_REF(params->peer_macaddr), 690 params->t2lm_info[dir].direction); 691 692 for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { 693 t2lm = (wmi_tid_to_link_map *)buf_ptr; 694 695 WMITLV_SET_HDR(&t2lm->tlv_header, 696 WMITLV_TAG_STRUC_wmi_tid_to_link_map, 697 WMITLV_GET_STRUCT_TLVLEN( 698 wmi_tid_to_link_map)); 699 700 /* Populate TID number */ 701 WMI_TID_TO_LINK_MAP_TID_NUM_SET( 702 t2lm->tid_to_link_map_info, tid_num); 703 704 /* Populate the direction */ 705 WMI_TID_TO_LINK_MAP_DIR_SET( 706 t2lm->tid_to_link_map_info, 707 params->t2lm_info[dir].direction); 708 709 /* Populate the default link mapping value */ 710 WMI_TID_TO_LINK_MAP_DEFAULT_MAPPING_SET( 711 t2lm->tid_to_link_map_info, 712 params->t2lm_info[dir].default_link_mapping); 713 714 /* Populate the T2LM provisioned links for the 715 * corresponding TID number. 716 */ 717 WMI_TID_TO_LINK_MAP_LINK_MASK_SET( 718 t2lm->tid_to_link_map_info, 719 params->t2lm_info[dir].t2lm_provisioned_links[tid_num]); 720 721 buf_ptr += sizeof(wmi_tid_to_link_map); 722 723 wmi_debug("Add T2LM TLV: tid_to_link_map_info:%x", 724 t2lm->tid_to_link_map_info); 725 } 726 } 727 728 wmi_mtrace(WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID, cmd->pdev_id, 0); 729 ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len, 730 WMI_MLO_PEER_TID_TO_LINK_MAP_CMDID); 731 if (ret) { 732 wmi_err("Failed to send T2LM command to FW: %d mlo_peer_mac: " QDF_MAC_ADDR_FMT, 733 ret, QDF_MAC_ADDR_REF(params->peer_macaddr)); 734 wmi_buf_free(buf); 735 } 736 737 return ret; 738 } 739 #else 740 size_t peer_assoc_t2lm_params_size(struct peer_assoc_params *req) 741 { 742 return WMI_TLV_HDR_SIZE; 743 } 744 745 uint8_t *peer_assoc_add_tid_to_link_map(uint8_t *buf_ptr, 746 struct peer_assoc_params *req) 747 { 748 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); 749 return buf_ptr + WMI_TLV_HDR_SIZE; 750 } 751 #endif /* WLAN_FEATURE_11BE */ 752 753 #ifdef WLAN_MLO_MULTI_CHIP 754 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle, 755 struct wmi_mlo_setup_params *param) 756 { 757 QDF_STATUS ret; 758 wmi_mlo_setup_cmd_fixed_param *cmd; 759 wmi_buf_t buf; 760 int32_t len; 761 uint8_t *buf_ptr; 762 uint32_t *partner_links; 763 uint8_t idx; 764 765 if (param->num_valid_hw_links > MAX_LINK_IN_MLO) 766 return QDF_STATUS_E_INVAL; 767 768 len = sizeof(*cmd) + 769 (param->num_valid_hw_links * sizeof(uint32_t)) + 770 WMI_TLV_HDR_SIZE; 771 772 buf = wmi_buf_alloc(wmi_handle, len); 773 if (!buf) 774 return QDF_STATUS_E_NOMEM; 775 776 cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf); 777 WMITLV_SET_HDR(&cmd->tlv_header, 778 WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param, 779 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param)); 780 781 cmd->mld_group_id = param->mld_grp_id; 782 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 783 wmi_handle, 784 param->pdev_id); 785 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 786 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 787 (sizeof(uint32_t) * param->num_valid_hw_links)); 788 partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); 789 for (idx = 0; idx < param->num_valid_hw_links; idx++) 790 partner_links[idx] = param->partner_links[idx]; 791 792 wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0); 793 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID); 794 if (QDF_IS_STATUS_ERROR(ret)) { 795 wmi_err("Failed to send MLO setup command ret = %d", ret); 796 wmi_buf_free(buf); 797 } 798 799 return ret; 800 } 801 802 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle, 803 struct wmi_mlo_ready_params *param) 804 { 805 QDF_STATUS ret; 806 wmi_mlo_ready_cmd_fixed_param *cmd; 807 wmi_buf_t buf; 808 int32_t len; 809 810 len = sizeof(*cmd); 811 812 buf = wmi_buf_alloc(wmi_handle, len); 813 if (!buf) 814 return QDF_STATUS_E_NOMEM; 815 816 cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf); 817 WMITLV_SET_HDR(&cmd->tlv_header, 818 WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param, 819 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param)); 820 821 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 822 wmi_handle, 823 param->pdev_id); 824 825 wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0); 826 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID); 827 if (QDF_IS_STATUS_ERROR(ret)) { 828 wmi_err("Failed to send MLO ready command ret = %d", ret); 829 wmi_buf_free(buf); 830 } 831 832 return ret; 833 } 834 835 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle, 836 struct wmi_mlo_teardown_params *param) 837 { 838 QDF_STATUS ret; 839 wmi_mlo_teardown_fixed_param *cmd; 840 wmi_buf_t buf; 841 int32_t len; 842 843 len = sizeof(*cmd); 844 845 buf = wmi_buf_alloc(wmi_handle, len); 846 if (!buf) 847 return QDF_STATUS_E_NOMEM; 848 849 cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf); 850 WMITLV_SET_HDR(&cmd->tlv_header, 851 WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param, 852 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param)); 853 854 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 855 wmi_handle, 856 param->pdev_id); 857 switch (param->reason) { 858 case WMI_MLO_TEARDOWN_REASON_SSR: 859 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON; 860 break; 861 case WMI_MLO_TEARDOWN_REASON_DOWN: 862 default: 863 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1; 864 break; 865 } 866 867 wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0); 868 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 869 WMI_MLO_TEARDOWN_CMDID); 870 if (QDF_IS_STATUS_ERROR(ret)) { 871 wmi_err("Failed to send MLO Teardown command ret = %d", ret); 872 wmi_buf_free(buf); 873 } 874 875 return ret; 876 } 877 878 QDF_STATUS 879 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle, 880 uint8_t *buf, 881 struct wmi_mlo_setup_complete_params *params) 882 { 883 WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf; 884 wmi_mlo_setup_complete_event_fixed_param *ev; 885 886 param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf; 887 if (!param_buf) { 888 wmi_err_rl("Param_buf is NULL"); 889 return QDF_STATUS_E_FAILURE; 890 } 891 ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param; 892 893 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 894 wmi_handle, 895 ev->pdev_id); 896 if (!ev->status) 897 params->status = WMI_MLO_SETUP_STATUS_SUCCESS; 898 else 899 params->status = WMI_MLO_SETUP_STATUS_FAILURE; 900 901 return QDF_STATUS_SUCCESS; 902 } 903 904 QDF_STATUS 905 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle, 906 uint8_t *buf, 907 struct wmi_mlo_teardown_cmpl_params *params) 908 { 909 WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf; 910 wmi_mlo_teardown_complete_fixed_param *ev; 911 912 param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf; 913 if (!param_buf) { 914 wmi_err_rl("Param_buf is NULL"); 915 return QDF_STATUS_E_FAILURE; 916 } 917 ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param; 918 919 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 920 wmi_handle, 921 ev->pdev_id); 922 if (!ev->status) 923 params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS; 924 else 925 params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE; 926 927 return QDF_STATUS_SUCCESS; 928 } 929 930 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 931 { 932 struct wmi_ops *ops = wmi_handle->ops; 933 934 ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv; 935 ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv; 936 ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv; 937 ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv; 938 ops->extract_mlo_teardown_cmpl_event = 939 extract_mlo_teardown_cmpl_event_tlv; 940 } 941 942 #else /*WLAN_MLO_MULTI_CHIP*/ 943 944 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 945 {} 946 947 #endif /*WLAN_MLO_MULTI_CHIP*/ 948 949 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) 950 { 951 struct wmi_ops *ops = wmi_handle->ops; 952 953 wmi_11be_attach_mlo_setup_tlv(wmi_handle); 954 ops->extract_mlo_link_set_active_resp = 955 extract_mlo_link_set_active_resp_tlv; 956 ops->send_mlo_link_set_active_cmd = 957 send_mlo_link_set_active_cmd_tlv; 958 #ifdef WLAN_FEATURE_11BE 959 ops->send_mlo_peer_tid_to_link_map = 960 send_mlo_peer_tid_to_link_map_cmd_tlv; 961 #endif /* WLAN_FEATURE_11BE */ 962 } 963