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