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