xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified_concurrency_tlv.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2013-2020 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 <wmi_unified_concurrency_api.h>
24 #ifdef WLAN_FEATURE_MCC_QUOTA
25 #include <wlan_p2p_mcc_quota_public_struct.h>
26 #endif
27 
28 /**
29  * send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv() -enable/disable
30  *							     mcc scheduler
31  * @wmi_handle: wmi handle
32  * @mcc_adaptive_scheduler: enable/disable
33  *
34  * This function enable/disable mcc adaptive scheduler in fw.
35  *
36  * Return: QDF_STATUS_SUCCESS for success or error code
37  */
38 static QDF_STATUS send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv(
39 		wmi_unified_t wmi_handle, uint32_t mcc_adaptive_scheduler,
40 		uint32_t pdev_id)
41 {
42 	QDF_STATUS ret;
43 	wmi_buf_t buf = 0;
44 	wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *cmd = NULL;
45 	uint16_t len =
46 		sizeof(wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param);
47 
48 	buf = wmi_buf_alloc(wmi_handle, len);
49 	if (!buf) {
50 		return QDF_STATUS_E_NOMEM;
51 	}
52 	cmd = (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *)
53 		wmi_buf_data(buf);
54 
55 	WMITLV_SET_HDR(&cmd->tlv_header,
56 		       WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param,
57 		       WMITLV_GET_STRUCT_TLVLEN
58 			       (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param));
59 	cmd->enable = mcc_adaptive_scheduler;
60 	cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target(
61 								wmi_handle,
62 								pdev_id);
63 
64 	wmi_mtrace(WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID, NO_SESSION, 0);
65 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
66 				   WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID);
67 	if (QDF_IS_STATUS_ERROR(ret)) {
68 		wmi_err("Failed to send enable/disable MCC"
69 			" adaptive scheduler command");
70 		wmi_buf_free(buf);
71 	}
72 
73 	return ret;
74 }
75 
76 /**
77  * send_set_mcc_channel_time_latency_cmd_tlv() -set MCC channel time latency
78  * @wmi: wmi handle
79  * @mcc_channel: mcc channel
80  * @mcc_channel_time_latency: MCC channel time latency.
81  *
82  * Currently used to set time latency for an MCC vdev/adapter using operating
83  * channel of it and channel number. The info is provided run time using
84  * iwpriv command: iwpriv <wlan0 | p2p0> setMccLatency <latency in ms>.
85  *
86  * Return: CDF status
87  */
88 static QDF_STATUS send_set_mcc_channel_time_latency_cmd_tlv(
89 					wmi_unified_t wmi_handle,
90 					uint32_t mcc_channel_freq,
91 					uint32_t mcc_channel_time_latency)
92 {
93 	QDF_STATUS ret;
94 	wmi_buf_t buf = 0;
95 	wmi_resmgr_set_chan_latency_cmd_fixed_param *cmdTL = NULL;
96 	uint16_t len = 0;
97 	uint8_t *buf_ptr = NULL;
98 	wmi_resmgr_chan_latency chan_latency;
99 	/* Note: we only support MCC time latency for a single channel */
100 	uint32_t num_channels = 1;
101 	uint32_t chan1_freq = mcc_channel_freq;
102 	uint32_t latency_chan1 = mcc_channel_time_latency;
103 
104 	/* If 0ms latency is provided, then FW will set to a default.
105 	 * Otherwise, latency must be at least 30ms.
106 	 */
107 	if ((latency_chan1 > 0) &&
108 	    (latency_chan1 < WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY)) {
109 		wmi_err("Invalid time latency for Channel #1 = %dms "
110 			 "Minimum is 30ms (or 0 to use default value by "
111 			 "firmware)", latency_chan1);
112 		return QDF_STATUS_E_INVAL;
113 	}
114 
115 	/*   Set WMI CMD for channel time latency here */
116 	len = sizeof(wmi_resmgr_set_chan_latency_cmd_fixed_param) +
117 	      WMI_TLV_HDR_SIZE +  /*Place holder for chan_time_latency array */
118 	      num_channels * sizeof(wmi_resmgr_chan_latency);
119 	buf = wmi_buf_alloc(wmi_handle, len);
120 	if (!buf) {
121 		return QDF_STATUS_E_NOMEM;
122 	}
123 	buf_ptr = (uint8_t *) wmi_buf_data(buf);
124 	cmdTL = (wmi_resmgr_set_chan_latency_cmd_fixed_param *)
125 		wmi_buf_data(buf);
126 	WMITLV_SET_HDR(&cmdTL->tlv_header,
127 		WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param,
128 		       WMITLV_GET_STRUCT_TLVLEN
129 		       (wmi_resmgr_set_chan_latency_cmd_fixed_param));
130 	cmdTL->num_chans = num_channels;
131 	/* Update channel time latency information for home channel(s) */
132 	buf_ptr += sizeof(*cmdTL);
133 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
134 		       num_channels * sizeof(wmi_resmgr_chan_latency));
135 	buf_ptr += WMI_TLV_HDR_SIZE;
136 	chan_latency.chan_mhz = chan1_freq;
137 	chan_latency.latency = latency_chan1;
138 	qdf_mem_copy(buf_ptr, &chan_latency, sizeof(chan_latency));
139 	wmi_mtrace(WMI_RESMGR_SET_CHAN_LATENCY_CMDID, NO_SESSION, 0);
140 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
141 				   WMI_RESMGR_SET_CHAN_LATENCY_CMDID);
142 	if (QDF_IS_STATUS_ERROR(ret)) {
143 		wmi_err("Failed to send MCC Channel Time Latency command");
144 		wmi_buf_free(buf);
145 		QDF_ASSERT(0);
146 	}
147 
148 	return ret;
149 }
150 
151 /**
152  * send_set_mcc_channel_time_quota_cmd_tlv() -set MCC channel time quota
153  * @wmi: wmi handle
154  * @adapter_1_chan_number: adapter 1 channel number
155  * @adapter_1_quota: adapter 1 quota
156  * @adapter_2_chan_number: adapter 2 channel number
157  *
158  * Return: CDF status
159  */
160 static QDF_STATUS send_set_mcc_channel_time_quota_cmd_tlv(
161 					wmi_unified_t wmi_handle,
162 					uint32_t adapter_1_chan_freq,
163 					uint32_t adapter_1_quota,
164 					uint32_t adapter_2_chan_freq)
165 {
166 	QDF_STATUS ret;
167 	wmi_buf_t buf = 0;
168 	uint16_t len = 0;
169 	uint8_t *buf_ptr = NULL;
170 	wmi_resmgr_set_chan_time_quota_cmd_fixed_param *cmdTQ = NULL;
171 	wmi_resmgr_chan_time_quota chan_quota;
172 	uint32_t quota_chan1 = adapter_1_quota;
173 	/* Knowing quota of 1st chan., derive quota for 2nd chan. */
174 	uint32_t quota_chan2 = 100 - quota_chan1;
175 	/* Note: setting time quota for MCC requires info for 2 channels */
176 	uint32_t num_channels = 2;
177 	uint32_t chan1_freq = adapter_1_chan_freq;
178 	uint32_t chan2_freq = adapter_2_chan_freq;
179 
180 	wmi_debug("freq1:%dMHz, Quota1:%dms, freq2:%dMHz, Quota2:%dms",
181 		 chan1_freq, quota_chan1, chan2_freq, quota_chan2);
182 
183 	/*
184 	 * Perform sanity check on time quota values provided.
185 	 */
186 	if (quota_chan1 < WMI_MCC_MIN_CHANNEL_QUOTA ||
187 	    quota_chan1 > WMI_MCC_MAX_CHANNEL_QUOTA) {
188 		wmi_err("Invalid time quota for Chan #1=%dms. Min: %dms, Max: %dms",
189 			quota_chan1, WMI_MCC_MIN_CHANNEL_QUOTA,
190 			WMI_MCC_MAX_CHANNEL_QUOTA);
191 		return QDF_STATUS_E_INVAL;
192 	}
193 	/* Set WMI CMD for channel time quota here */
194 	len = sizeof(wmi_resmgr_set_chan_time_quota_cmd_fixed_param) +
195 	      WMI_TLV_HDR_SIZE +       /* Place holder for chan_time_quota array */
196 	      num_channels * sizeof(wmi_resmgr_chan_time_quota);
197 	buf = wmi_buf_alloc(wmi_handle, len);
198 	if (!buf) {
199 		return QDF_STATUS_E_NOMEM;
200 	}
201 	buf_ptr = (uint8_t *) wmi_buf_data(buf);
202 	cmdTQ = (wmi_resmgr_set_chan_time_quota_cmd_fixed_param *)
203 		wmi_buf_data(buf);
204 	WMITLV_SET_HDR(&cmdTQ->tlv_header,
205 		       WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param,
206 		       WMITLV_GET_STRUCT_TLVLEN
207 			       (wmi_resmgr_set_chan_time_quota_cmd_fixed_param));
208 	cmdTQ->num_chans = num_channels;
209 
210 	/* Update channel time quota information for home channel(s) */
211 	buf_ptr += sizeof(*cmdTQ);
212 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
213 		       num_channels * sizeof(wmi_resmgr_chan_time_quota));
214 	buf_ptr += WMI_TLV_HDR_SIZE;
215 	chan_quota.chan_mhz = chan1_freq;
216 	chan_quota.channel_time_quota = quota_chan1;
217 	qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota));
218 	/* Construct channel and quota record for the 2nd MCC mode. */
219 	buf_ptr += sizeof(chan_quota);
220 	chan_quota.chan_mhz = chan2_freq;
221 	chan_quota.channel_time_quota = quota_chan2;
222 	qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota));
223 
224 	wmi_mtrace(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, NO_SESSION, 0);
225 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
226 				   WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID);
227 	if (QDF_IS_STATUS_ERROR(ret)) {
228 		wmi_err("Failed to send MCC Channel Time Quota command");
229 		wmi_buf_free(buf);
230 		QDF_ASSERT(0);
231 	}
232 
233 	return ret;
234 }
235 
236 #ifdef WLAN_FEATURE_MCC_QUOTA
237 /**
238  * convert_to_host_quota_type() - convert wmi quota type to host quota type
239  * @quota_type: wmi target quota type
240  *
241  * Return: enum mcc_quota_type
242  */
243 static enum mcc_quota_type convert_to_host_quota_type(uint32_t quota_type)
244 {
245 	switch (quota_type) {
246 	case WMI_RESMGR_QUOTA_TYPE_CLEAR:
247 		return QUOTA_TYPE_CLEAR;
248 	case WMI_RESMGR_QUOTA_TYPE_FIXED:
249 		return QUOTA_TYPE_FIXED;
250 	case WMI_RESMGR_QUOTA_TYPE_DYNAMIC:
251 		return QUOTA_TYPE_DYNAMIC;
252 	default:
253 		wmi_err("mcc quota unknown quota type %d", quota_type);
254 		return QUOTA_TYPE_UNKNOWN;
255 	}
256 }
257 
258 /**
259  * extract_mcc_quota_ev_param_tlv() - extract mcc quota information from wmi
260  *    event
261  * @wmi_handle: wmi handle
262  * @param evt_buf: pointer to event buffer
263  * @param param: Pointer to hold mcc quota info
264  *
265  * Return: QDF_STATUS_SUCCESS for success or error code
266  */
267 static QDF_STATUS
268 extract_mcc_quota_ev_param_tlv(wmi_unified_t wmi_handle,
269 			       void *evt_buf, struct mcc_quota_info *param)
270 {
271 	WMI_RESMGR_CHAN_TIME_QUOTA_CHANGED_EVENTID_param_tlvs *param_tlvs;
272 	wmi_resmgr_chan_time_quota_changed_event_fixed_param *fixed_param;
273 	uint8_t i;
274 	wmi_resmgr_chan_time_quota_tlv *wmi_mcc_quota_info;
275 
276 	if (!param) {
277 		wmi_err("mcc quota information param is null");
278 		return QDF_STATUS_E_INVAL;
279 	}
280 
281 	param_tlvs = evt_buf;
282 	if (!param_tlvs || !param_tlvs->fixed_param) {
283 		wmi_err("Invalid mcc quota event buffer");
284 		return QDF_STATUS_E_INVAL;
285 	}
286 	fixed_param = param_tlvs->fixed_param;
287 
288 	wmi_debug("mcc quota type %d, num %d",
289 		  fixed_param->quota_type, param_tlvs->num_chan_quota);
290 
291 	param->type = convert_to_host_quota_type(fixed_param->quota_type);
292 	if (param->type == QUOTA_TYPE_UNKNOWN)
293 		return QDF_STATUS_E_INVAL;
294 
295 	if (!param_tlvs->chan_quota) {
296 		param->num_chan_quota = 0;
297 		return QDF_STATUS_SUCCESS;
298 	}
299 
300 	if (param_tlvs->num_chan_quota > MAX_MCC_QUOTA_CH_NUM)
301 		wmi_warn("mcc quota num %d unexpected",
302 			 param_tlvs->num_chan_quota);
303 	param->num_chan_quota = qdf_min(param_tlvs->num_chan_quota,
304 					(uint32_t)MAX_MCC_QUOTA_CH_NUM);
305 	wmi_mcc_quota_info = param_tlvs->chan_quota;
306 	for (i = 0; i < param->num_chan_quota; i++) {
307 		param->chan_quota[i].chan_mhz =
308 			wmi_mcc_quota_info[i].chan_time_quota.chan_mhz;
309 		param->chan_quota[i].channel_time_quota =
310 			wmi_mcc_quota_info[i].chan_time_quota.channel_time_quota;
311 		wmi_debug("mcc quota [%d] chan %d, quota %d",
312 			  i, param->chan_quota[i].chan_mhz,
313 			  param->chan_quota[i].channel_time_quota);
314 	}
315 
316 	return QDF_STATUS_SUCCESS;
317 }
318 
319 static void wmi_mcc_quota_evt_attach_tlv(wmi_unified_t wmi_handle)
320 {
321 	struct wmi_ops *ops = wmi_handle->ops;
322 
323 	ops->extract_mcc_quota_ev_param = extract_mcc_quota_ev_param_tlv;
324 }
325 #else
326 static inline void wmi_mcc_quota_evt_attach_tlv(wmi_unified_t wmi_handle)
327 {
328 }
329 #endif
330 
331 void wmi_concurrency_attach_tlv(wmi_unified_t wmi_handle)
332 {
333 	struct wmi_ops *ops = wmi_handle->ops;
334 
335 	ops->send_set_enable_disable_mcc_adaptive_scheduler_cmd =
336 		send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv;
337 	ops->send_set_mcc_channel_time_latency_cmd =
338 		send_set_mcc_channel_time_latency_cmd_tlv;
339 	ops->send_set_mcc_channel_time_quota_cmd =
340 		send_set_mcc_channel_time_quota_cmd_tlv;
341 	wmi_mcc_quota_evt_attach_tlv(wmi_handle);
342 }
343