xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_fwol_tlv.c (revision 70a8e8a708a5f24e828d089a4c6df03e32b11c42)
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
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
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
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
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
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
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 
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
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
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
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
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
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 
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
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
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 
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
481 static void wmi_fwol_attach_thermal_stats_tlv(struct wmi_ops *ops)
482 {
483 }
484 #endif /* FW_THERMAL_THROTTLE_SUPPORT */
485 
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