1 /* 2 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "osdep.h" 20 #include "wmi.h" 21 #include "wmi_unified_priv.h" 22 #include "wlan_fwol_public_structs.h" 23 #include "wmi_unified_fwol_api.h" 24 25 #ifdef WLAN_FEATURE_ELNA 26 /** 27 * send_set_elna_bypass_cmd_tlv() - send set elna bypass cmd to fw 28 * @wmi_handle: wmi handle 29 * @req: set eLNA bypass request 30 * 31 * Send WMI_SET_ELNA_BYPASS_CMDID to fw. 32 * 33 * Return: QDF_STATUS 34 */ 35 static QDF_STATUS 36 send_set_elna_bypass_cmd_tlv(wmi_unified_t wmi_handle, 37 struct set_elna_bypass_request *req) 38 { 39 wmi_buf_t buf; 40 wmi_set_elna_bypass_cmd_fixed_param *cmd; 41 uint16_t len = sizeof(*cmd); 42 QDF_STATUS ret; 43 44 buf = wmi_buf_alloc(wmi_handle, len); 45 if (!buf) { 46 wmi_err("Failed to allocate wmi buffer"); 47 return QDF_STATUS_E_NOMEM; 48 } 49 50 cmd = (wmi_set_elna_bypass_cmd_fixed_param *)wmi_buf_data(buf); 51 WMITLV_SET_HDR(&cmd->tlv_header, 52 WMITLV_TAG_STRUC_wmi_set_elna_bypass_cmd_fixed_param, 53 WMITLV_GET_STRUCT_TLVLEN 54 (wmi_set_elna_bypass_cmd_fixed_param)); 55 cmd->vdev_id = req->vdev_id; 56 cmd->en_dis = req->en_dis; 57 wmi_mtrace(WMI_SET_ELNA_BYPASS_CMDID, req->vdev_id, req->en_dis); 58 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 59 WMI_SET_ELNA_BYPASS_CMDID); 60 if (QDF_IS_STATUS_ERROR(ret)) { 61 wmi_err("Failed to send set param command ret = %d", ret); 62 wmi_buf_free(buf); 63 } 64 65 return ret; 66 } 67 68 /** 69 * send_get_elna_bypass_cmd_tlv() - send get elna bypass cmd to fw 70 * @wmi_handle: wmi handle 71 * @req: get eLNA bypass request 72 * 73 * Send WMI_GET_ELNA_BYPASS_CMDID to fw. 74 * 75 * Return: QDF_STATUS 76 */ 77 static QDF_STATUS 78 send_get_elna_bypass_cmd_tlv(wmi_unified_t wmi_handle, 79 struct get_elna_bypass_request *req) 80 { 81 wmi_buf_t buf; 82 wmi_get_elna_bypass_cmd_fixed_param *cmd; 83 uint16_t len = sizeof(*cmd); 84 QDF_STATUS ret; 85 86 buf = wmi_buf_alloc(wmi_handle, len); 87 if (!buf) { 88 wmi_err("Failed to allocate wmi buffer"); 89 return QDF_STATUS_E_NOMEM; 90 } 91 92 cmd = (wmi_get_elna_bypass_cmd_fixed_param *)wmi_buf_data(buf); 93 WMITLV_SET_HDR(&cmd->tlv_header, 94 WMITLV_TAG_STRUC_wmi_get_elna_bypass_cmd_fixed_param, 95 WMITLV_GET_STRUCT_TLVLEN 96 (wmi_get_elna_bypass_cmd_fixed_param)); 97 cmd->vdev_id = req->vdev_id; 98 wmi_mtrace(WMI_GET_ELNA_BYPASS_CMDID, req->vdev_id, 0); 99 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 100 WMI_GET_ELNA_BYPASS_CMDID); 101 if (QDF_IS_STATUS_ERROR(ret)) { 102 wmi_err("Failed to send set param command ret = %d", ret); 103 wmi_buf_free(buf); 104 } 105 106 return ret; 107 } 108 109 /** 110 * extract_get_elna_bypass_resp_tlv() - Extract WMI get eLNA bypass response 111 * @wmi_handle: wmi handle 112 * @resp_buf: response buffer 113 * @resp: get eLNA bypass response 114 * 115 * Extract WMI get eLNA bypass response from firmware. 116 * 117 * Return: QDF_STATUS 118 */ 119 static QDF_STATUS 120 extract_get_elna_bypass_resp_tlv(struct wmi_unified *wmi_handle, void *resp_buf, 121 struct get_elna_bypass_response *resp) 122 { 123 WMI_GET_ELNA_BYPASS_EVENTID_param_tlvs *param_buf; 124 wmi_get_elna_bypass_event_fixed_param *evt; 125 126 param_buf = resp_buf; 127 evt = param_buf->fixed_param; 128 if (!evt) { 129 wmi_err("Invalid get elna bypass event"); 130 return QDF_STATUS_E_INVAL; 131 } 132 133 wmi_debug("Get elna bypass %d from vdev %d", evt->en_dis, evt->vdev_id); 134 135 resp->vdev_id = evt->vdev_id; 136 resp->en_dis = evt->en_dis; 137 138 return QDF_STATUS_SUCCESS; 139 } 140 #endif /* WLAN_FEATURE_ELNA */ 141 142 #ifdef WLAN_FEATURE_ELNA 143 static void wmi_fwol_attach_elna_tlv(struct wmi_ops *ops) 144 { 145 ops->send_set_elna_bypass_cmd = send_set_elna_bypass_cmd_tlv; 146 ops->send_get_elna_bypass_cmd = send_get_elna_bypass_cmd_tlv; 147 ops->extract_get_elna_bypass_resp = extract_get_elna_bypass_resp_tlv; 148 } 149 #else 150 static void wmi_fwol_attach_elna_tlv(struct wmi_ops *ops) 151 { 152 } 153 #endif /* WLAN_FEATURE_ELNA */ 154 155 #ifdef WLAN_SEND_DSCP_UP_MAP_TO_FW 156 /** 157 * send_dscp_tid_map_cmd_tlv() - send dscp to tid map cmd to fw 158 * @wmi_handle: wmi handle 159 * @dscp_to_tid_map: array of dscp to tid map values 160 * 161 * Send WMI_PDEV_SET_DSCP_TID_MAP_CMDID to fw. 162 * 163 * Return: QDF_STATUS 164 */ 165 static QDF_STATUS 166 send_dscp_tid_map_cmd_tlv(wmi_unified_t wmi_handle, 167 uint32_t *dscp_to_tid_map) 168 { 169 QDF_STATUS status; 170 wmi_pdev_set_dscp_tid_map_cmd_fixed_param *cmd; 171 wmi_buf_t buf; 172 uint16_t len = sizeof(*cmd); 173 174 buf = wmi_buf_alloc(wmi_handle, len); 175 if (!buf) { 176 wmi_err("Failed to allocate wmi buffer"); 177 return QDF_STATUS_E_NOMEM; 178 } 179 180 cmd = (wmi_pdev_set_dscp_tid_map_cmd_fixed_param *)wmi_buf_data(buf); 181 WMITLV_SET_HDR( 182 &cmd->tlv_header, 183 WMITLV_TAG_STRUC_wmi_pdev_set_dscp_tid_map_cmd_fixed_param, 184 WMITLV_GET_STRUCT_TLVLEN 185 (wmi_pdev_set_dscp_tid_map_cmd_fixed_param)); 186 cmd->reserved0 = WMI_PDEV_ID_SOC; 187 qdf_mem_copy(&cmd->dscp_to_tid_map, dscp_to_tid_map, 188 sizeof(uint32_t) * WMI_DSCP_MAP_MAX); 189 190 status = wmi_unified_cmd_send(wmi_handle, buf, len, 191 WMI_PDEV_SET_DSCP_TID_MAP_CMDID); 192 if (status) { 193 wmi_err("Failed to send dscp_up_map_to_fw %d", status); 194 wmi_buf_free(buf); 195 } 196 197 return status; 198 } 199 200 static void wmi_fwol_attach_dscp_tid_tlv(struct wmi_ops *ops) 201 { 202 ops->send_dscp_tid_map_cmd = send_dscp_tid_map_cmd_tlv; 203 } 204 #else 205 static void wmi_fwol_attach_dscp_tid_tlv(struct wmi_ops *ops) 206 { 207 } 208 #endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */ 209 210 #ifdef WLAN_FEATURE_MDNS_OFFLOAD 211 /** 212 * send_set_mdns_fqdn_cmd_tlv() - send set mDNS FQDN cmd to fw 213 * @wmi_handle: wmi handle 214 * @mdns_info: mDNS config info 215 * 216 * Send WMI_MDNS_SET_FQDN_CMDID to fw. 217 * 218 * Return: QDF_STATUS 219 */ 220 static QDF_STATUS 221 send_set_mdns_fqdn_cmd_tlv(wmi_unified_t wmi_handle, 222 struct mdns_config_info *mdns_info) 223 { 224 wmi_buf_t buf; 225 uint8_t *buf_ptr; 226 wmi_mdns_set_fqdn_cmd_fixed_param *cmd; 227 uint16_t len = sizeof(*cmd); 228 uint16_t fqdn_len_aligned; 229 QDF_STATUS ret; 230 231 fqdn_len_aligned = roundup(mdns_info->fqdn_len, sizeof(uint32_t)); 232 if (fqdn_len_aligned < mdns_info->fqdn_len) { 233 wmi_err_rl("integer overflow while rounding up data_len"); 234 return QDF_STATUS_E_FAILURE; 235 } 236 237 if (fqdn_len_aligned > WMI_SVC_MSG_MAX_SIZE - WMI_TLV_HDR_SIZE) { 238 wmi_err_rl("wmi_max_msg_size overflow for given data_len"); 239 return QDF_STATUS_E_FAILURE; 240 } 241 242 len += WMI_TLV_HDR_SIZE + fqdn_len_aligned; 243 buf = wmi_buf_alloc(wmi_handle, len); 244 if (!buf) { 245 wmi_err_rl("Failed to allocate wmi buffer"); 246 return QDF_STATUS_E_NOMEM; 247 } 248 249 buf_ptr = wmi_buf_data(buf); 250 cmd = (wmi_mdns_set_fqdn_cmd_fixed_param *)buf_ptr; 251 WMITLV_SET_HDR(&cmd->tlv_header, 252 WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param, 253 WMITLV_GET_STRUCT_TLVLEN 254 (wmi_mdns_set_fqdn_cmd_fixed_param)); 255 cmd->vdev_id = mdns_info->vdev_id; 256 cmd->type = mdns_info->fqdn_type; 257 cmd->fqdn_len = mdns_info->fqdn_len; 258 buf_ptr += sizeof(*cmd); 259 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, fqdn_len_aligned); 260 buf_ptr += WMI_TLV_HDR_SIZE; 261 qdf_mem_copy(buf_ptr, mdns_info->fqdn_data, cmd->fqdn_len); 262 263 wmi_mtrace(WMI_MDNS_SET_FQDN_CMDID, mdns_info->vdev_id, 264 mdns_info->fqdn_type); 265 266 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 267 WMI_MDNS_SET_FQDN_CMDID); 268 if (QDF_IS_STATUS_ERROR(ret)) 269 wmi_buf_free(buf); 270 271 return ret; 272 } 273 274 /** 275 * send_set_mdns_response_cmd_tlv() - send set mDNS response cmd to fw 276 * @wmi_handle: wmi handle 277 * @mdns_info: mDNS config info 278 * 279 * Send WMI_MDNS_SET_RESPONSE_CMDID to fw. 280 * 281 * Return: QDF_STATUS 282 */ 283 static QDF_STATUS 284 send_set_mdns_response_cmd_tlv(wmi_unified_t wmi_handle, 285 struct mdns_config_info *mdns_info) 286 { 287 wmi_buf_t buf; 288 uint8_t *buf_ptr; 289 wmi_mdns_set_resp_cmd_fixed_param *cmd; 290 uint16_t len = sizeof(*cmd); 291 uint16_t resp_len_aligned; 292 QDF_STATUS ret; 293 294 resp_len_aligned = roundup(mdns_info->answer_payload_len, sizeof(uint32_t)); 295 if (resp_len_aligned < mdns_info->answer_payload_len) { 296 wmi_err_rl("integer overflow while rounding up data_len"); 297 return QDF_STATUS_E_FAILURE; 298 } 299 300 if (resp_len_aligned > WMI_SVC_MSG_MAX_SIZE - WMI_TLV_HDR_SIZE) { 301 wmi_err_rl("wmi_max_msg_size overflow for given data_len"); 302 return QDF_STATUS_E_FAILURE; 303 } 304 305 len += WMI_TLV_HDR_SIZE + resp_len_aligned; 306 buf = wmi_buf_alloc(wmi_handle, len); 307 if (!buf) { 308 wmi_err_rl("Failed to allocate wmi buffer"); 309 return QDF_STATUS_E_NOMEM; 310 } 311 312 buf_ptr = wmi_buf_data(buf); 313 cmd = (wmi_mdns_set_resp_cmd_fixed_param *)buf_ptr; 314 WMITLV_SET_HDR(&cmd->tlv_header, 315 WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param, 316 WMITLV_GET_STRUCT_TLVLEN 317 (wmi_mdns_set_resp_cmd_fixed_param)); 318 cmd->vdev_id = mdns_info->vdev_id; 319 cmd->AR_count = mdns_info->resource_record_count; 320 cmd->resp_len = mdns_info->answer_payload_len; 321 buf_ptr += sizeof(*cmd); 322 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, resp_len_aligned); 323 buf_ptr += WMI_TLV_HDR_SIZE; 324 qdf_mem_copy(buf_ptr, mdns_info->answer_payload_data, cmd->resp_len); 325 326 wmi_mtrace(WMI_MDNS_SET_RESPONSE_CMDID, mdns_info->vdev_id, 0); 327 328 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 329 WMI_MDNS_SET_RESPONSE_CMDID); 330 if (QDF_IS_STATUS_ERROR(ret)) 331 wmi_buf_free(buf); 332 333 return ret; 334 } 335 336 /** 337 * send_set_mdns_offload_cmd_tlv() - send set mDNS offload cmd to fw 338 * @wmi_handle: wmi handle 339 * @mdns_info: mDNS config info 340 * 341 * Send WMI_MDNS_OFFLOAD_ENABLE_CMDID to fw. 342 * 343 * Return: QDF_STATUS 344 */ 345 static QDF_STATUS 346 send_set_mdns_offload_cmd_tlv(wmi_unified_t wmi_handle, 347 struct mdns_config_info *mdns_info) 348 { 349 wmi_buf_t buf; 350 wmi_mdns_offload_cmd_fixed_param *cmd; 351 uint16_t len = sizeof(*cmd); 352 QDF_STATUS ret; 353 354 buf = wmi_buf_alloc(wmi_handle, len); 355 if (!buf) { 356 wmi_err_rl("Failed to allocate wmi buffer"); 357 return QDF_STATUS_E_NOMEM; 358 } 359 360 cmd = (wmi_mdns_offload_cmd_fixed_param *)wmi_buf_data(buf); 361 WMITLV_SET_HDR(&cmd->tlv_header, 362 WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param, 363 WMITLV_GET_STRUCT_TLVLEN 364 (wmi_mdns_offload_cmd_fixed_param)); 365 cmd->vdev_id = mdns_info->vdev_id; 366 cmd->enable = mdns_info->enable; 367 368 wmi_mtrace(WMI_MDNS_OFFLOAD_ENABLE_CMDID, mdns_info->vdev_id, 0); 369 370 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 371 WMI_MDNS_OFFLOAD_ENABLE_CMDID); 372 if (QDF_IS_STATUS_ERROR(ret)) 373 wmi_buf_free(buf); 374 375 return ret; 376 } 377 378 /** 379 * send_set_mdns_config_cmd_tlv() - send set mDNS config cmd to fw 380 * @wmi_handle: wmi handle 381 * @mdns_info: mdns config info 382 * 383 * Return: QDF_STATUS 384 */ 385 static QDF_STATUS 386 send_set_mdns_config_cmd_tlv(wmi_unified_t wmi_handle, 387 struct mdns_config_info *mdns_info) 388 { 389 QDF_STATUS ret; 390 391 if (!mdns_info->enable) { 392 ret = send_set_mdns_offload_cmd_tlv(wmi_handle, mdns_info); 393 if (QDF_IS_STATUS_ERROR(ret)) 394 wmi_err_rl("Failed to send mDNS offload command. ret = %d", ret); 395 396 return ret; 397 } 398 399 ret = send_set_mdns_fqdn_cmd_tlv(wmi_handle, mdns_info); 400 if (QDF_IS_STATUS_ERROR(ret)) { 401 wmi_err_rl("Failed to send set fqdn command. ret = %d", ret); 402 return ret; 403 } 404 405 ret = send_set_mdns_response_cmd_tlv(wmi_handle, mdns_info); 406 if (QDF_IS_STATUS_ERROR(ret)) { 407 wmi_err_rl("Failed to send set mDNS response command. ret = %d", ret); 408 return ret; 409 } 410 411 ret = send_set_mdns_offload_cmd_tlv(wmi_handle, mdns_info); 412 if (QDF_IS_STATUS_ERROR(ret)) { 413 wmi_err_rl("Failed to send set mDNS offload command. ret = %d", ret); 414 return ret; 415 } 416 417 return ret; 418 } 419 420 static void wmi_fwol_attach_mdns_tlv(struct wmi_ops *ops) 421 { 422 ops->send_set_mdns_config_cmd = send_set_mdns_config_cmd_tlv; 423 } 424 #else 425 static void wmi_fwol_attach_mdns_tlv(struct wmi_ops *ops) 426 { 427 } 428 #endif /* WLAN_FEATURE_MDNS_OFFLOAD */ 429 430 #ifdef THERMAL_STATS_SUPPORT 431 /** 432 * send_get_thermal_stats_cmd_tlv() - send get thermal stats cmd to fw 433 * @wmi_handle: wmi handle 434 * @req_type: req type 435 * @temp_offset: temperature offset 436 * 437 * Send WMI_REQUEST_THERMAL_STATS_CMDID to fw. 438 * 439 * Return: QDF_STATUS 440 */ 441 static QDF_STATUS 442 send_get_thermal_stats_cmd_tlv(wmi_unified_t wmi_handle, 443 enum thermal_stats_request_type req_type, 444 uint8_t temp_offset) 445 { 446 wmi_buf_t buf; 447 wmi_thermal_stats_cmd_fixed_param *cmd; 448 uint16_t len = sizeof(*cmd); 449 QDF_STATUS ret; 450 451 buf = wmi_buf_alloc(wmi_handle, len); 452 if (!buf) { 453 wmi_err("Failed to allocate wmi buffer"); 454 return QDF_STATUS_E_NOMEM; 455 } 456 457 cmd = (wmi_thermal_stats_cmd_fixed_param *)wmi_buf_data(buf); 458 WMITLV_SET_HDR(&cmd->tlv_header, 459 WMITLV_TAG_STRUC_wmi_thermal_stats_cmd_fixed_param, 460 WMITLV_GET_STRUCT_TLVLEN 461 (wmi_thermal_stats_cmd_fixed_param)); 462 cmd->thermal_action = req_type; 463 cmd->thermal_offset = temp_offset; 464 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 465 WMI_REQUEST_THERMAL_STATS_CMDID); 466 if (QDF_IS_STATUS_ERROR(ret)) { 467 wmi_err("Failed to send get thermal stats cmd = %d", ret); 468 wmi_buf_free(buf); 469 } 470 471 return ret; 472 } 473 474 static void wmi_fwol_attach_thermal_stats_tlv(struct wmi_ops *ops) 475 { 476 ops->send_get_thermal_stats_cmd = send_get_thermal_stats_cmd_tlv; 477 } 478 #else 479 static void wmi_fwol_attach_thermal_stats_tlv(struct wmi_ops *ops) 480 { 481 } 482 #endif /* FW_THERMAL_THROTTLE_SUPPORT */ 483 484 void wmi_fwol_attach_tlv(wmi_unified_t wmi_handle) 485 { 486 struct wmi_ops *ops = wmi_handle->ops; 487 488 wmi_fwol_attach_elna_tlv(ops); 489 wmi_fwol_attach_dscp_tid_tlv(ops); 490 wmi_fwol_attach_mdns_tlv(ops); 491 wmi_fwol_attach_thermal_stats_tlv(ops); 492 } 493