1 /* 2 * Copyright (c) 2021, The Linux Foundation. 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 #include <osdep.h> 18 #include "wmi.h" 19 #include "wmi_unified_priv.h" 20 #include "wmi_unified_api.h" 21 #ifdef WLAN_MLO_MULTI_CHIP 22 #include "wmi_unified_11be_setup_api.h" 23 #endif 24 #include "wmi_unified_11be_tlv.h" 25 26 size_t vdev_create_mlo_params_size(void) 27 { 28 return sizeof(wmi_vdev_create_mlo_params) + WMI_TLV_HDR_SIZE; 29 } 30 31 uint8_t *vdev_create_add_mlo_params(uint8_t *buf_ptr, 32 struct vdev_create_params *param) 33 { 34 wmi_vdev_create_mlo_params *mlo_params; 35 36 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 37 sizeof(wmi_vdev_create_mlo_params)); 38 buf_ptr += sizeof(uint32_t); 39 40 mlo_params = (wmi_vdev_create_mlo_params *)buf_ptr; 41 WMITLV_SET_HDR(&mlo_params->tlv_header, 42 WMITLV_TAG_STRUC_wmi_vdev_create_mlo_params, 43 WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_create_mlo_params)); 44 45 WMI_CHAR_ARRAY_TO_MAC_ADDR(param->mlo_mac, &mlo_params->mld_macaddr); 46 47 wmi_debug("MLD Addr = "QDF_MAC_ADDR_FMT, 48 QDF_MAC_ADDR_REF(param->mlo_mac)); 49 return buf_ptr + sizeof(wmi_vdev_create_mlo_params); 50 } 51 52 size_t vdev_start_mlo_params_size(struct vdev_start_params *req) 53 { 54 size_t vdev_start_mlo_size; 55 56 vdev_start_mlo_size = sizeof(wmi_vdev_start_mlo_params) + 57 WMI_TLV_HDR_SIZE + 58 (req->mlo_partner.num_links * 59 sizeof(wmi_partner_link_params)) + 60 WMI_TLV_HDR_SIZE; 61 62 return vdev_start_mlo_size; 63 } 64 65 uint8_t *vdev_start_add_mlo_params(uint8_t *buf_ptr, 66 struct vdev_start_params *req) 67 { 68 wmi_vdev_start_mlo_params *mlo_params; 69 70 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 71 sizeof(wmi_vdev_start_mlo_params)); 72 buf_ptr += sizeof(uint32_t); 73 74 mlo_params = (wmi_vdev_start_mlo_params *)buf_ptr; 75 WMITLV_SET_HDR(&mlo_params->tlv_header, 76 WMITLV_TAG_STRUC_wmi_vdev_start_mlo_params, 77 WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_start_mlo_params)); 78 79 mlo_params->mlo_flags.mlo_flags = 0; 80 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 81 req->mlo_flags.mlo_enabled); 82 WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags, 83 req->mlo_flags.mlo_assoc_link); 84 85 return buf_ptr + sizeof(wmi_vdev_start_mlo_params); 86 } 87 88 uint8_t *vdev_start_add_ml_partner_links(uint8_t *buf_ptr, 89 struct vdev_start_params *req) 90 { 91 wmi_partner_link_params *ml_partner_link; 92 struct mlo_vdev_start_partner_links *req_partner; 93 uint8_t i; 94 95 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 96 (req->mlo_partner.num_links * 97 sizeof(wmi_partner_link_params))); 98 buf_ptr += sizeof(uint32_t); 99 100 req_partner = &req->mlo_partner; 101 ml_partner_link = (wmi_partner_link_params *)buf_ptr; 102 for (i = 0; i < req->mlo_partner.num_links; i++) { 103 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 104 WMITLV_TAG_STRUC_wmi_partner_link_params, 105 WMITLV_GET_STRUCT_TLVLEN(wmi_partner_link_params)); 106 ml_partner_link->vdev_id = req_partner->partner_info[i].vdev_id; 107 ml_partner_link->hw_link_id = 108 req_partner->partner_info[i].hw_mld_link_id; 109 WMI_CHAR_ARRAY_TO_MAC_ADDR(req_partner->partner_info[i].mac_addr, 110 &ml_partner_link->vdev_macaddr); 111 ml_partner_link++; 112 } 113 114 return buf_ptr + 115 (req->mlo_partner.num_links * 116 sizeof(wmi_partner_link_params)); 117 } 118 119 uint8_t *bcn_tmpl_add_ml_partner_links(uint8_t *buf_ptr, 120 struct beacon_tmpl_params *param) 121 { 122 wmi_bcn_tmpl_ml_params *ml_partner_link; 123 struct mlo_bcn_templ_partner_links *ml_bcn_tmpl; 124 uint8_t i; 125 126 if (param->mlo_partner.num_links > WLAN_UMAC_MLO_MAX_VDEVS) { 127 wmi_err("mlo_partner.num_link(%d) are greater than supported partner links(%d)", 128 param->mlo_partner.num_links, WLAN_UMAC_MLO_MAX_VDEVS); 129 return buf_ptr; 130 } 131 132 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 133 (param->mlo_partner.num_links * 134 sizeof(wmi_bcn_tmpl_ml_params))); 135 buf_ptr += sizeof(uint32_t); 136 137 ml_bcn_tmpl = ¶m->mlo_partner; 138 ml_partner_link = (wmi_bcn_tmpl_ml_params *)buf_ptr; 139 for (i = 0; i < ml_bcn_tmpl->num_links; i++) { 140 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 141 WMITLV_TAG_STRUC_wmi_bcn_tmpl_ml_params, 142 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_ml_params) 143 ); 144 ml_partner_link->vdev_id = ml_bcn_tmpl->partner_info[i].vdev_id; 145 ml_partner_link->hw_link_id = 146 ml_bcn_tmpl->partner_info[i].hw_link_id; 147 ml_partner_link->beacon_interval = 148 ml_bcn_tmpl->partner_info[i].beacon_interval; 149 ml_partner_link->csa_switch_count_offset = 150 ml_bcn_tmpl->partner_info[i].csa_switch_count_offset; 151 ml_partner_link->ext_csa_switch_count_offset = 152 ml_bcn_tmpl->partner_info[i].ext_csa_switch_count_offset; 153 ml_partner_link++; 154 } 155 156 return buf_ptr + 157 (param->mlo_partner.num_links * 158 sizeof(wmi_bcn_tmpl_ml_params)); 159 } 160 161 size_t peer_create_mlo_params_size(struct peer_create_params *req) 162 { 163 return sizeof(wmi_peer_create_mlo_params) + WMI_TLV_HDR_SIZE; 164 } 165 166 uint8_t *peer_create_add_mlo_params(uint8_t *buf_ptr, 167 struct peer_create_params *req) 168 { 169 wmi_peer_create_mlo_params *mlo_params; 170 171 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 172 sizeof(wmi_peer_create_mlo_params)); 173 buf_ptr += sizeof(uint32_t); 174 175 mlo_params = (wmi_peer_create_mlo_params *)buf_ptr; 176 WMITLV_SET_HDR(&mlo_params->tlv_header, 177 WMITLV_TAG_STRUC_wmi_peer_create_mlo_params, 178 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_create_mlo_params)); 179 180 mlo_params->mlo_flags.mlo_flags = 0; 181 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 182 req->mlo_enabled); 183 184 return buf_ptr + sizeof(wmi_peer_create_mlo_params); 185 } 186 187 size_t peer_assoc_mlo_params_size(struct peer_assoc_params *req) 188 { 189 size_t peer_assoc_mlo_size = sizeof(wmi_peer_assoc_mlo_params) + 190 WMI_TLV_HDR_SIZE + 191 (req->ml_links.num_links * 192 sizeof(wmi_peer_assoc_mlo_partner_link_params)) + 193 WMI_TLV_HDR_SIZE; 194 195 return peer_assoc_mlo_size; 196 } 197 198 uint8_t *peer_assoc_add_mlo_params(uint8_t *buf_ptr, 199 struct peer_assoc_params *req) 200 { 201 wmi_peer_assoc_mlo_params *mlo_params; 202 203 /* Add WMI peer assoc mlo params */ 204 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 205 sizeof(wmi_peer_assoc_mlo_params)); 206 buf_ptr += sizeof(uint32_t); 207 208 mlo_params = (wmi_peer_assoc_mlo_params *)buf_ptr; 209 WMITLV_SET_HDR(&mlo_params->tlv_header, 210 WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_params, 211 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_params)); 212 213 mlo_params->mlo_flags.mlo_flags = 0; 214 WMI_MLO_FLAGS_SET_ENABLED(mlo_params->mlo_flags.mlo_flags, 215 req->mlo_params.mlo_enabled); 216 WMI_MLO_FLAGS_SET_ASSOC_LINK(mlo_params->mlo_flags.mlo_flags, 217 req->mlo_params.mlo_assoc_link); 218 WMI_MLO_FLAGS_SET_PRIMARY_UMAC(mlo_params->mlo_flags.mlo_flags, 219 req->mlo_params.mlo_primary_umac); 220 WMI_MLO_FLAGS_SET_LINK_INDEX_VALID(mlo_params->mlo_flags.mlo_flags, 221 req->mlo_params.mlo_logical_link_index_valid); 222 WMI_MLO_FLAGS_SET_PEER_ID_VALID(mlo_params->mlo_flags.mlo_flags, 223 req->mlo_params.mlo_peer_id_valid); 224 225 WMI_CHAR_ARRAY_TO_MAC_ADDR(req->mlo_params.mld_mac, 226 &mlo_params->mld_macaddr); 227 mlo_params->logical_link_index = req->mlo_params.logical_link_index; 228 mlo_params->mld_peer_id = req->mlo_params.ml_peer_id; 229 230 return buf_ptr + sizeof(wmi_peer_assoc_mlo_params); 231 } 232 233 uint8_t *peer_assoc_add_ml_partner_links(uint8_t *buf_ptr, 234 struct peer_assoc_params *req) 235 { 236 wmi_peer_assoc_mlo_partner_link_params *ml_partner_link; 237 struct ml_partner_info *partner_info; 238 uint8_t i; 239 240 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 241 (req->ml_links.num_links * 242 sizeof(wmi_peer_assoc_mlo_partner_link_params))); 243 buf_ptr += sizeof(uint32_t); 244 245 ml_partner_link = (wmi_peer_assoc_mlo_partner_link_params *)buf_ptr; 246 partner_info = req->ml_links.partner_info; 247 for (i = 0; i < req->ml_links.num_links; i++) { 248 WMITLV_SET_HDR(&ml_partner_link->tlv_header, 249 WMITLV_TAG_STRUC_wmi_peer_assoc_mlo_partner_link_params, 250 WMITLV_GET_STRUCT_TLVLEN(wmi_peer_assoc_mlo_partner_link_params)); 251 ml_partner_link->vdev_id = partner_info[i].vdev_id; 252 ml_partner_link->hw_mld_link_id = partner_info[i].hw_mld_link_id; 253 ml_partner_link++; 254 } 255 256 return buf_ptr + 257 (req->ml_links.num_links * 258 sizeof(wmi_peer_assoc_mlo_partner_link_params)); 259 } 260 261 #ifdef WLAN_MLO_MULTI_CHIP 262 QDF_STATUS mlo_setup_cmd_send_tlv(struct wmi_unified *wmi_handle, 263 struct wmi_mlo_setup_params *param) 264 { 265 QDF_STATUS ret; 266 wmi_mlo_setup_cmd_fixed_param *cmd; 267 wmi_buf_t buf; 268 int32_t len; 269 uint8_t *buf_ptr; 270 uint32_t *partner_links; 271 uint8_t idx; 272 273 if (param->num_valid_hw_links > MAX_LINK_IN_MLO) 274 return QDF_STATUS_E_INVAL; 275 276 len = sizeof(*cmd) + 277 (param->num_valid_hw_links * sizeof(uint32_t)) + 278 WMI_TLV_HDR_SIZE; 279 280 buf = wmi_buf_alloc(wmi_handle, len); 281 if (!buf) 282 return QDF_STATUS_E_NOMEM; 283 284 cmd = (wmi_mlo_setup_cmd_fixed_param *)wmi_buf_data(buf); 285 WMITLV_SET_HDR(&cmd->tlv_header, 286 WMITLV_TAG_STRUC_wmi_mlo_setup_cmd_fixed_param, 287 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_setup_cmd_fixed_param)); 288 289 cmd->mld_group_id = param->mld_grp_id; 290 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 291 wmi_handle, 292 param->pdev_id); 293 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 294 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 295 (sizeof(uint32_t) * param->num_valid_hw_links)); 296 partner_links = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); 297 for (idx = 0; idx < param->num_valid_hw_links; idx++) 298 partner_links[idx] = param->partner_links[idx]; 299 300 wmi_mtrace(WMI_MLO_SETUP_CMDID, NO_SESSION, 0); 301 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_SETUP_CMDID); 302 if (QDF_IS_STATUS_ERROR(ret)) { 303 wmi_err("Failed to send MLO setup command ret = %d", ret); 304 wmi_buf_free(buf); 305 } 306 307 return ret; 308 } 309 310 QDF_STATUS mlo_ready_cmd_send_tlv(struct wmi_unified *wmi_handle, 311 struct wmi_mlo_ready_params *param) 312 { 313 QDF_STATUS ret; 314 wmi_mlo_ready_cmd_fixed_param *cmd; 315 wmi_buf_t buf; 316 int32_t len; 317 318 len = sizeof(*cmd); 319 320 buf = wmi_buf_alloc(wmi_handle, len); 321 if (!buf) 322 return QDF_STATUS_E_NOMEM; 323 324 cmd = (wmi_mlo_ready_cmd_fixed_param *)wmi_buf_data(buf); 325 WMITLV_SET_HDR(&cmd->tlv_header, 326 WMITLV_TAG_STRUC_wmi_mlo_ready_cmd_fixed_param, 327 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_ready_cmd_fixed_param)); 328 329 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 330 wmi_handle, 331 param->pdev_id); 332 333 wmi_mtrace(WMI_MLO_READY_CMDID, NO_SESSION, 0); 334 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_MLO_READY_CMDID); 335 if (QDF_IS_STATUS_ERROR(ret)) { 336 wmi_err("Failed to send MLO ready command ret = %d", ret); 337 wmi_buf_free(buf); 338 } 339 340 return ret; 341 } 342 343 QDF_STATUS mlo_teardown_cmd_send_tlv(struct wmi_unified *wmi_handle, 344 struct wmi_mlo_teardown_params *param) 345 { 346 QDF_STATUS ret; 347 wmi_mlo_teardown_fixed_param *cmd; 348 wmi_buf_t buf; 349 int32_t len; 350 351 len = sizeof(*cmd); 352 353 buf = wmi_buf_alloc(wmi_handle, len); 354 if (!buf) 355 return QDF_STATUS_E_NOMEM; 356 357 cmd = (wmi_mlo_teardown_fixed_param *)wmi_buf_data(buf); 358 WMITLV_SET_HDR(&cmd->tlv_header, 359 WMITLV_TAG_STRUC_wmi_mlo_teardown_fixed_param, 360 WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_teardown_fixed_param)); 361 362 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 363 wmi_handle, 364 param->pdev_id); 365 switch (param->reason) { 366 case WMI_MLO_TEARDOWN_REASON_SSR: 367 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON; 368 break; 369 case WMI_MLO_TEARDOWN_REASON_DOWN: 370 default: 371 cmd->reason_code = WMI_MLO_TEARDOWN_SSR_REASON + 1; 372 break; 373 } 374 375 wmi_mtrace(WMI_MLO_TEARDOWN_CMDID, NO_SESSION, 0); 376 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 377 WMI_MLO_TEARDOWN_CMDID); 378 if (QDF_IS_STATUS_ERROR(ret)) { 379 wmi_err("Failed to send MLO Teardown command ret = %d", ret); 380 wmi_buf_free(buf); 381 } 382 383 return ret; 384 } 385 386 QDF_STATUS 387 extract_mlo_setup_cmpl_event_tlv(struct wmi_unified *wmi_handle, 388 uint8_t *buf, 389 struct wmi_mlo_setup_complete_params *params) 390 { 391 WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *param_buf; 392 wmi_mlo_setup_complete_event_fixed_param *ev; 393 394 param_buf = (WMI_MLO_SETUP_COMPLETE_EVENTID_param_tlvs *)buf; 395 if (!param_buf) { 396 wmi_err_rl("Param_buf is NULL"); 397 return QDF_STATUS_E_FAILURE; 398 } 399 ev = (wmi_mlo_setup_complete_event_fixed_param *)param_buf->fixed_param; 400 401 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 402 wmi_handle, 403 ev->pdev_id); 404 if (!ev->status) 405 params->status = WMI_MLO_SETUP_STATUS_SUCCESS; 406 else 407 params->status = WMI_MLO_SETUP_STATUS_FAILURE; 408 409 return QDF_STATUS_SUCCESS; 410 } 411 412 QDF_STATUS 413 extract_mlo_teardown_cmpl_event_tlv(struct wmi_unified *wmi_handle, 414 uint8_t *buf, 415 struct wmi_mlo_teardown_cmpl_params *params) 416 { 417 WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *param_buf; 418 wmi_mlo_teardown_complete_fixed_param *ev; 419 420 param_buf = (WMI_MLO_TEARDOWN_COMPLETE_EVENTID_param_tlvs *)buf; 421 if (!param_buf) { 422 wmi_err_rl("Param_buf is NULL"); 423 return QDF_STATUS_E_FAILURE; 424 } 425 ev = (wmi_mlo_teardown_complete_fixed_param *)param_buf->fixed_param; 426 427 params->pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( 428 wmi_handle, 429 ev->pdev_id); 430 if (!ev->status) 431 params->status = WMI_MLO_TEARDOWN_STATUS_SUCCESS; 432 else 433 params->status = WMI_MLO_TEARDOWN_STATUS_FAILURE; 434 435 return QDF_STATUS_SUCCESS; 436 } 437 438 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 439 { 440 struct wmi_ops *ops = wmi_handle->ops; 441 442 ops->mlo_setup_cmd_send = mlo_setup_cmd_send_tlv; 443 ops->mlo_teardown_cmd_send = mlo_teardown_cmd_send_tlv; 444 ops->mlo_ready_cmd_send = mlo_ready_cmd_send_tlv; 445 ops->extract_mlo_setup_cmpl_event = extract_mlo_setup_cmpl_event_tlv; 446 ops->extract_mlo_teardown_cmpl_event = 447 extract_mlo_teardown_cmpl_event_tlv; 448 } 449 450 #else /*WLAN_MLO_MULTI_CHIP*/ 451 452 static void wmi_11be_attach_mlo_setup_tlv(wmi_unified_t wmi_handle) 453 {} 454 455 #endif /*WLAN_MLO_MULTI_CHIP*/ 456 457 void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) 458 { 459 wmi_11be_attach_mlo_setup_tlv(wmi_handle); 460 } 461