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