1 /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-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 /**
21  * DOC: HDD WMM
22  *
23  * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation)
24  * houses all the logic for WMM in HDD.
25  *
26  * On the control path, it has the logic to setup QoS, modify QoS and delete
27  * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an
28  * explicit application invoked and an internal HDD invoked.  The implicit QoS
29  * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but
30  * which DO mark their traffic for priortization. It also has logic to start,
31  * update and stop the U-APSD trigger frame generation. It also has logic to
32  * read WMM related config parameters from the registry.
33  *
34  * On the data path, it has the logic to figure out the WMM AC of an egress
35  * packet and when to signal TL to serve a particular AC queue. It also has the
36  * logic to retrieve a packet based on WMM priority in response to a fetch from
37  * TL.
38  *
39  * The remaining functions are utility functions for information hiding.
40  */
41 
42 /* Include files */
43 #include <linux/netdevice.h>
44 #include <linux/skbuff.h>
45 #include <linux/etherdevice.h>
46 #include <linux/if_vlan.h>
47 #include <linux/ip.h>
48 #include <linux/semaphore.h>
49 #include <linux/ipv6.h>
50 #include "osif_sync.h"
51 #include "os_if_fwol.h"
52 #include <wlan_hdd_tx_rx.h>
53 #include <wlan_hdd_wmm.h>
54 #include <wlan_hdd_ether.h>
55 #include <wlan_hdd_hostapd.h>
56 #include <wlan_hdd_softap_tx_rx.h>
57 #include <cds_sched.h>
58 #include "sme_api.h"
59 #include "wlan_mlme_ucfg_api.h"
60 #include "cfg_ucfg_api.h"
61 #include "wlan_hdd_object_manager.h"
62 #include "wlan_hdd_cm_api.h"
63 #include "wlan_dp_ucfg_api.h"
64 
65 #define HDD_WMM_UP_TO_AC_MAP_SIZE 8
66 #define DSCP(x)	x
67 #define MIN_HANDLE_VALUE 5000
68 #define MAX_HANDLE_VALUE 6000
69 
70 const uint8_t hdd_wmm_up_to_ac_map[] = {
71 	SME_AC_BE,
72 	SME_AC_BK,
73 	SME_AC_BK,
74 	SME_AC_BE,
75 	SME_AC_VI,
76 	SME_AC_VI,
77 	SME_AC_VO,
78 	SME_AC_VO
79 };
80 
81 #define CONFIG_TSPEC_OPERATION \
82 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION
83 #define CONFIG_TSPEC_TSID \
84 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID
85 #define CONFIG_TSPEC_DIRECTION \
86 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION
87 #define CONFIG_TSPEC_APSD \
88 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD
89 #define CONFIG_TSPEC_USER_PRIORITY \
90 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY
91 #define CONFIG_TSPEC_ACK_POLICY \
92 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY
93 #define CONFIG_TSPEC_NOMINAL_MSDU_SIZE \
94 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE
95 #define CONFIG_TSPEC_MAXIMUM_MSDU_SIZE \
96 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE
97 #define CONFIG_TSPEC_MIN_SERVICE_INTERVAL \
98 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL
99 #define CONFIG_TSPEC_MAX_SERVICE_INTERVAL \
100 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL
101 #define CONFIG_TSPEC_INACTIVITY_INTERVAL \
102 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL
103 #define CONFIG_TSPEC_SUSPENSION_INTERVAL \
104 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL
105 #define CONFIG_TSPEC_MINIMUM_DATA_RATE \
106 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE
107 #define CONFIG_TSPEC_MEAN_DATA_RATE \
108 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE
109 #define CONFIG_TSPEC_PEAK_DATA_RATE \
110 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE
111 #define CONFIG_TSPEC_BURST_SIZE \
112 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE
113 #define CONFIG_TSPEC_MINIMUM_PHY_RATE \
114 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE
115 #define CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE \
116 	QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE
117 
118 const struct nla_policy
119 config_tspec_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1] = {
120 	[CONFIG_TSPEC_OPERATION] = {.type = NLA_U8},
121 	[CONFIG_TSPEC_TSID] = {.type = NLA_U8},
122 	[CONFIG_TSPEC_DIRECTION] = {.type = NLA_U8},
123 	[CONFIG_TSPEC_APSD] = {.type = NLA_FLAG},
124 	[CONFIG_TSPEC_USER_PRIORITY] = {.type = NLA_U8},
125 	[CONFIG_TSPEC_ACK_POLICY] = {.type = NLA_U8},
126 	[CONFIG_TSPEC_NOMINAL_MSDU_SIZE] = {.type = NLA_U16},
127 	[CONFIG_TSPEC_MAXIMUM_MSDU_SIZE] = {.type = NLA_U16},
128 	[CONFIG_TSPEC_MIN_SERVICE_INTERVAL] = {.type = NLA_U32},
129 	[CONFIG_TSPEC_MAX_SERVICE_INTERVAL] = {.type = NLA_U32},
130 	[CONFIG_TSPEC_INACTIVITY_INTERVAL] = {.type = NLA_U32},
131 	[CONFIG_TSPEC_SUSPENSION_INTERVAL] = {.type = NLA_U32},
132 	[CONFIG_TSPEC_MINIMUM_DATA_RATE] = {.type = NLA_U32},
133 	[CONFIG_TSPEC_MEAN_DATA_RATE] = {.type = NLA_U32},
134 	[CONFIG_TSPEC_PEAK_DATA_RATE] = {.type = NLA_U32},
135 	[CONFIG_TSPEC_BURST_SIZE] = {.type = NLA_U32},
136 	[CONFIG_TSPEC_MINIMUM_PHY_RATE] = {.type = NLA_U32},
137 	[CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE] = {.type = NLA_U16},
138 };
139 
140 #ifdef QCA_LL_TX_FLOW_CONTROL_V2
wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter * adapter)141 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter)
142 {
143 	uint8_t i;
144 
145 	netif_wake_subqueue(adapter->dev,
146 			    HDD_LINUX_AC_HI_PRIO * TX_QUEUES_PER_AC);
147 
148 	for (i = 0; i < TX_QUEUES_PER_AC; i++) {
149 		netif_stop_subqueue(adapter->dev,
150 				    TX_GET_QUEUE_IDX(HDD_LINUX_AC_VO, i));
151 		netif_stop_subqueue(adapter->dev,
152 				    TX_GET_QUEUE_IDX(HDD_LINUX_AC_VI, i));
153 		netif_stop_subqueue(adapter->dev,
154 				    TX_GET_QUEUE_IDX(HDD_LINUX_AC_BE, i));
155 		netif_stop_subqueue(adapter->dev,
156 				    TX_GET_QUEUE_IDX(HDD_LINUX_AC_BK, i));
157 	}
158 }
159 #else
wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter * adapter)160 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter)
161 {
162 }
163 #endif
164 
165 /* Linux based UP -> AC Mapping */
166 const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = {
167 	HDD_LINUX_AC_BE,
168 	HDD_LINUX_AC_BK,
169 	HDD_LINUX_AC_BK,
170 	HDD_LINUX_AC_BE,
171 	HDD_LINUX_AC_VI,
172 	HDD_LINUX_AC_VI,
173 	HDD_LINUX_AC_VO,
174 	HDD_LINUX_AC_VO
175 };
176 
177 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
178 /**
179  * hdd_wmm_enable_tl_uapsd() - function which decides whether and
180  * how to update UAPSD parameters in TL
181  *
182  * @qos_context: [in] the pointer the QoS instance control block
183  *
184  * Return: None
185  */
hdd_wmm_enable_tl_uapsd(struct hdd_wmm_qos_context * qos_context)186 static void hdd_wmm_enable_tl_uapsd(struct hdd_wmm_qos_context *qos_context)
187 {
188 	struct hdd_adapter *adapter = qos_context->adapter;
189 	sme_ac_enum_type ac_type = qos_context->ac_type;
190 	struct hdd_wmm_ac_status *ac = &adapter->hdd_wmm_status.ac_status[ac_type];
191 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
192 	QDF_STATUS status;
193 	uint32_t service_interval;
194 	uint32_t suspension_interval;
195 	enum sme_qos_wmm_dir_type direction;
196 	bool psb;
197 	uint32_t delayed_trgr_frm_int;
198 
199 	/* The TSPEC must be valid */
200 	if (ac->is_tspec_valid == false) {
201 		hdd_err("Invoked with invalid TSPEC");
202 		return;
203 	}
204 	/* determine the service interval */
205 	if (ac->tspec.min_service_interval) {
206 		service_interval = ac->tspec.min_service_interval;
207 	} else if (ac->tspec.max_service_interval) {
208 		service_interval = ac->tspec.max_service_interval;
209 	} else {
210 		/* no service interval is present in the TSPEC */
211 		/* this is OK, there just won't be U-APSD */
212 		hdd_debug("No service interval supplied");
213 		service_interval = 0;
214 	}
215 
216 	/* determine the suspension interval & direction */
217 	suspension_interval = ac->tspec.suspension_interval;
218 	direction = ac->tspec.ts_info.direction;
219 	psb = ac->tspec.ts_info.psb;
220 
221 	/* if we have previously enabled U-APSD, have any params changed? */
222 	if ((ac->is_uapsd_info_valid) &&
223 	    (ac->uapsd_service_interval == service_interval) &&
224 	    (ac->uapsd_suspension_interval == suspension_interval) &&
225 	    (ac->uapsd_direction == direction) &&
226 	    (ac->is_uapsd_enabled == psb)) {
227 		hdd_debug("No change in U-APSD parameters");
228 		return;
229 	}
230 
231 	ucfg_mlme_get_tl_delayed_trgr_frm_int(hdd_ctx->psoc,
232 					      &delayed_trgr_frm_int);
233 	/* everything is in place to notify TL */
234 	status =
235 		sme_enable_uapsd_for_ac(ac_type, ac->tspec.ts_info.tid,
236 					ac->tspec.ts_info.up,
237 					service_interval, suspension_interval,
238 					direction, psb,
239 					adapter->deflink->vdev_id,
240 					delayed_trgr_frm_int);
241 
242 	if (!QDF_IS_STATUS_SUCCESS(status)) {
243 		hdd_err("Failed to enable U-APSD for AC=%d", ac_type);
244 		return;
245 	}
246 	/* stash away the parameters that were used */
247 	ac->is_uapsd_info_valid = true;
248 	ac->uapsd_service_interval = service_interval;
249 	ac->uapsd_suspension_interval = suspension_interval;
250 	ac->uapsd_direction = direction;
251 	ac->is_uapsd_enabled = psb;
252 
253 	hdd_debug("Enabled UAPSD in TL srv_int=%d susp_int=%d dir=%d AC=%d",
254 		   service_interval, suspension_interval, direction, ac_type);
255 
256 }
257 
258 /**
259  * hdd_wmm_disable_tl_uapsd() - function which decides whether
260  * to disable UAPSD parameters in TL
261  *
262  * @qos_context: [in] the pointer the QoS instance control block
263  *
264  * Return: None
265  */
hdd_wmm_disable_tl_uapsd(struct hdd_wmm_qos_context * qos_context)266 static void hdd_wmm_disable_tl_uapsd(struct hdd_wmm_qos_context *qos_context)
267 {
268 	struct hdd_adapter *adapter = qos_context->adapter;
269 	sme_ac_enum_type ac_type = qos_context->ac_type;
270 	struct hdd_wmm_ac_status *ac = &adapter->hdd_wmm_status.ac_status[ac_type];
271 	QDF_STATUS status;
272 
273 	/* have we previously enabled UAPSD? */
274 	if (ac->is_uapsd_info_valid == true) {
275 		status = sme_disable_uapsd_for_ac(ac_type,
276 						  adapter->deflink->vdev_id);
277 
278 		if (!QDF_IS_STATUS_SUCCESS(status)) {
279 			hdd_err("Failed to disable U-APSD for AC=%d", ac_type);
280 		} else {
281 			/* TL no longer has valid UAPSD info */
282 			ac->is_uapsd_info_valid = false;
283 			hdd_debug("Disabled UAPSD in TL for AC=%d", ac_type);
284 		}
285 	}
286 }
287 
288 #endif
289 
290 /**
291  * hdd_wmm_free_context() - function which frees a QoS context
292  *
293  * @qos_context: [in] the pointer the QoS instance control block
294  *
295  * Return: None
296  */
hdd_wmm_free_context(struct hdd_wmm_qos_context * qos_context)297 static void hdd_wmm_free_context(struct hdd_wmm_qos_context *qos_context)
298 {
299 	struct hdd_adapter *adapter;
300 
301 	hdd_debug("Entered, context %pK", qos_context);
302 
303 	if (unlikely((!qos_context) ||
304 		     (HDD_WMM_CTX_MAGIC != qos_context->magic))) {
305 		/* must have been freed in another thread */
306 		return;
307 	}
308 	/* get pointer to the adapter context */
309 	adapter = qos_context->adapter;
310 
311 	/* take the mutex since we're manipulating the context list */
312 	mutex_lock(&adapter->hdd_wmm_status.mutex);
313 
314 	/* make sure nobody thinks this is a valid context */
315 	qos_context->magic = 0;
316 
317 	/* unlink the context */
318 	list_del(&qos_context->node);
319 
320 	/* done manipulating the list */
321 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
322 
323 	/* reclaim memory */
324 	qdf_mem_free(qos_context);
325 
326 }
327 
328 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
329 /**
330  * hdd_wmm_notify_app() - function which notifies an application
331  *			  of changes in state of it flow
332  *
333  * @qos_context: [in] the pointer the QoS instance control block
334  *
335  * Return: None
336  */
hdd_wmm_notify_app(struct hdd_wmm_qos_context * qos_context)337 static void hdd_wmm_notify_app(struct hdd_wmm_qos_context *qos_context)
338 {
339 #define MAX_NOTIFY_LEN 50
340 	struct hdd_adapter *adapter;
341 	union iwreq_data wrqu;
342 	char buf[MAX_NOTIFY_LEN + 1];
343 
344 	hdd_debug("Entered, context %pK", qos_context);
345 
346 	if (unlikely((!qos_context) ||
347 		     (HDD_WMM_CTX_MAGIC != qos_context->magic))) {
348 		hdd_err("Invalid QoS Context");
349 		return;
350 	}
351 
352 	/* create the event */
353 	memset(&wrqu, 0, sizeof(wrqu));
354 	memset(buf, 0, sizeof(buf));
355 
356 	snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]",
357 		 (unsigned int)qos_context->handle,
358 		 (unsigned int)qos_context->status);
359 
360 	wrqu.data.pointer = buf;
361 	wrqu.data.length = strlen(buf);
362 
363 	/* get pointer to the adapter */
364 	adapter = qos_context->adapter;
365 
366 	/* send the event */
367 	hdd_debug("Sending [%s]", buf);
368 	hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf);
369 }
370 
371 #ifdef FEATURE_WLAN_ESE
372 /**
373  * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function
374  *
375  * @user_data: opaque user data registered with the timer.  In the
376  * case of this timer, the associated wmm QoS context is registered.
377  *
378  * This timer handler function is called for every inactivity interval
379  * per AC. This function gets the current transmitted packets on the
380  * given AC, and checks if there was any TX activity from the previous
381  * interval. If there was no traffic then it would delete the TS that
382  * was negotiated on that AC.
383  *
384  * Return: None
385  */
hdd_wmm_inactivity_timer_cb(void * user_data)386 static void hdd_wmm_inactivity_timer_cb(void *user_data)
387 {
388 	struct hdd_wmm_qos_context *qos_context = user_data;
389 	struct hdd_adapter *adapter;
390 	struct hdd_wmm_ac_status *ac;
391 	hdd_wlan_wmm_status_e status;
392 	QDF_STATUS qdf_status;
393 	uint32_t traffic_count = 0;
394 	sme_ac_enum_type ac_type;
395 	unsigned int cpu;
396 	struct hdd_tx_rx_stats *tx_rx_stats;
397 
398 	if (!qos_context) {
399 		hdd_err("invalid user data");
400 		return;
401 	}
402 	ac_type = qos_context->ac_type;
403 
404 	adapter = qos_context->adapter;
405 	if ((!adapter) ||
406 	    (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
407 		hdd_err("invalid adapter: %pK", adapter);
408 		return;
409 	}
410 
411 	ac = &adapter->hdd_wmm_status.ac_status[ac_type];
412 	tx_rx_stats = &adapter->deflink->hdd_stats.tx_rx_stats;
413 	/* Get the Tx stats for this AC. */
414 	for (cpu = 0; cpu < NUM_CPUS; cpu++)
415 		traffic_count +=
416 		tx_rx_stats->per_cpu[cpu].tx_classified_ac[qos_context->ac_type];
417 
418 	hdd_warn("WMM inactivity check for AC=%d, count=%u, last=%u",
419 		 ac_type, traffic_count, ac->last_traffic_count);
420 	if (ac->last_traffic_count == traffic_count) {
421 		/* there is no traffic activity, delete the TSPEC for this AC */
422 		status = hdd_wmm_delts(adapter, qos_context->handle);
423 		hdd_warn("Deleted TS on AC %d, due to inactivity with status = %d!!!",
424 			 ac_type, status);
425 	} else {
426 		ac->last_traffic_count = traffic_count;
427 		if (ac->inactivity_timer.state == QDF_TIMER_STATE_STOPPED) {
428 			/* Restart the timer */
429 			qdf_status =
430 				qdf_mc_timer_start(&ac->inactivity_timer,
431 						   ac->inactivity_time);
432 			if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
433 				hdd_err("Restarting inactivity timer failed on AC %d",
434 					ac_type);
435 			}
436 		} else {
437 			QDF_ASSERT(qdf_mc_timer_get_current_state
438 					   (&ac->inactivity_timer) ==
439 				   QDF_TIMER_STATE_STOPPED);
440 		}
441 	}
442 }
443 
444 /**
445  * hdd_wmm_enable_inactivity_timer() -
446  *	function to enable the traffic inactivity timer for the given AC
447  *
448  * @qos_context: [in] pointer to qos_context
449  * @inactivity_time: [in] value of the inactivity interval in millisecs
450  *
451  * When a QoS-Tspec is successfully setup, if the inactivity interval
452  * time specified in the AddTS parameters is non-zero, this function
453  * is invoked to start a traffic inactivity timer for the given AC.
454  *
455  * Return: QDF_STATUS enumeration
456  */
457 static QDF_STATUS
hdd_wmm_enable_inactivity_timer(struct hdd_wmm_qos_context * qos_context,uint32_t inactivity_time)458 hdd_wmm_enable_inactivity_timer(struct hdd_wmm_qos_context *qos_context,
459 				uint32_t inactivity_time)
460 {
461 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
462 	struct hdd_adapter *adapter = qos_context->adapter;
463 	sme_ac_enum_type ac_type = qos_context->ac_type;
464 	struct hdd_wmm_ac_status *ac;
465 	unsigned int cpu;
466 	struct hdd_tx_rx_stats *tx_rx_stats;
467 
468 	adapter = qos_context->adapter;
469 	ac = &adapter->hdd_wmm_status.ac_status[ac_type];
470 
471 	qdf_status = qdf_mc_timer_init(&ac->inactivity_timer,
472 				       QDF_TIMER_TYPE_SW,
473 				       hdd_wmm_inactivity_timer_cb,
474 				       qos_context);
475 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
476 		hdd_err("Initializing inactivity timer failed on AC %d",
477 			  ac_type);
478 		return qdf_status;
479 	}
480 	/* Start the inactivity timer */
481 	qdf_status = qdf_mc_timer_start(&ac->inactivity_timer,
482 					inactivity_time);
483 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
484 		hdd_err("Starting inactivity timer failed on AC %d",
485 			  ac_type);
486 		qdf_status = qdf_mc_timer_destroy(&ac->inactivity_timer);
487 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
488 			hdd_err("Failed to destroy inactivity timer");
489 
490 		return qdf_status;
491 	}
492 	ac->inactivity_time = inactivity_time;
493 
494 	ac->last_traffic_count = 0;
495 	/* Initialize the current tx traffic count on this AC */
496 	tx_rx_stats = &adapter->deflink->hdd_stats.tx_rx_stats;
497 	for (cpu = 0; cpu < NUM_CPUS; cpu++) {
498 		ac->last_traffic_count +=
499 		tx_rx_stats->per_cpu[cpu].tx_classified_ac[qos_context->ac_type];
500 	}
501 	qos_context->is_inactivity_timer_running = true;
502 	return qdf_status;
503 }
504 
505 /**
506  * hdd_wmm_disable_inactivity_timer() -
507  *	function to disable the traffic inactivity timer for the given AC.
508  *
509  * @qos_context: [in] pointer to qos_context
510  *
511  * This function is invoked to disable the traffic inactivity timer
512  * for the given AC.  This is normally done when the TS is deleted.
513  *
514  * Return: QDF_STATUS enumeration
515  */
516 static QDF_STATUS
hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context * qos_context)517 hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *qos_context)
518 {
519 	struct hdd_adapter *adapter = qos_context->adapter;
520 	sme_ac_enum_type ac_type = qos_context->ac_type;
521 	struct hdd_wmm_ac_status *ac = &adapter->hdd_wmm_status.ac_status[ac_type];
522 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
523 
524 	/* Clear the timer and the counter */
525 	ac->inactivity_time = 0;
526 	ac->last_traffic_count = 0;
527 
528 	if (qos_context->is_inactivity_timer_running == true) {
529 		qos_context->is_inactivity_timer_running = false;
530 		qdf_status = qdf_mc_timer_stop(&ac->inactivity_timer);
531 		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
532 			hdd_err("Failed to stop inactivity timer");
533 			return qdf_status;
534 		}
535 		qdf_status = qdf_mc_timer_destroy(&ac->inactivity_timer);
536 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
537 			hdd_err("Failed to destroy inactivity timer:Timer started");
538 	}
539 
540 	return qdf_status;
541 }
542 #else
543 
544 static QDF_STATUS
hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context * qos_context)545 hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *qos_context)
546 {
547 	return QDF_STATUS_SUCCESS;
548 }
549 #endif /* FEATURE_WLAN_ESE */
550 
551 /**
552  * hdd_wmm_sme_callback() - callback for QoS notifications
553  *
554  * @mac_handle: [in] the MAC handle
555  * @context : [in] the HDD callback context
556  * @tspec_info : [in] the TSPEC params
557  * @sme_status : [in] the QoS related SME status
558  * @flow_id: [in] the unique identifier of the flow
559  *
560  * This callback is registered by HDD with SME for receiving QoS
561  * notifications. Even though this function has a static scope it
562  * gets called externally through some function pointer magic (so
563  * there is a need for rigorous parameter checking).
564  *
565  * Return: QDF_STATUS enumeration
566  */
hdd_wmm_sme_callback(mac_handle_t mac_handle,void * context,struct sme_qos_wmmtspecinfo * tspec_info,enum sme_qos_statustype sme_status,uint32_t flow_id)567 static QDF_STATUS hdd_wmm_sme_callback(mac_handle_t mac_handle,
568 			void *context,
569 			struct sme_qos_wmmtspecinfo *tspec_info,
570 			enum sme_qos_statustype sme_status,
571 			uint32_t flow_id)
572 {
573 	struct hdd_wmm_qos_context *qos_context = context;
574 	struct hdd_adapter *adapter;
575 	sme_ac_enum_type ac_type;
576 	struct hdd_wmm_ac_status *ac;
577 
578 	hdd_debug("Entered, context %pK", qos_context);
579 
580 	if (unlikely((!qos_context) ||
581 		     (HDD_WMM_CTX_MAGIC != qos_context->magic))) {
582 		hdd_err("Invalid QoS Context");
583 		return QDF_STATUS_E_FAILURE;
584 	}
585 
586 	adapter = qos_context->adapter;
587 	ac_type = qos_context->ac_type;
588 	ac = &adapter->hdd_wmm_status.ac_status[ac_type];
589 
590 	hdd_debug("status %d flowid %d info %pK",
591 		 sme_status, flow_id, tspec_info);
592 
593 	switch (sme_status) {
594 
595 	case SME_QOS_STATUS_SETUP_SUCCESS_IND:
596 		hdd_debug("Setup is complete");
597 
598 		/* there will always be a TSPEC returned with this
599 		 * status, even if a TSPEC is not exchanged OTA
600 		 */
601 		if (tspec_info) {
602 			ac->is_tspec_valid = true;
603 			memcpy(&ac->tspec,
604 			       tspec_info, sizeof(ac->tspec));
605 		}
606 		ac->is_access_allowed = true;
607 		ac->was_access_granted = true;
608 		ac->is_access_pending = false;
609 		ac->has_access_failed = false;
610 
611 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
612 
613 			hdd_debug("Explicit Qos, notifying user space");
614 
615 			/* this was triggered by an application */
616 			qos_context->status =
617 				HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
618 			hdd_wmm_notify_app(qos_context);
619 		}
620 
621 #ifdef FEATURE_WLAN_ESE
622 		/* Check if the inactivity interval is specified */
623 		if (tspec_info && tspec_info->inactivity_interval) {
624 			hdd_debug("Inactivity timer value = %d for AC=%d",
625 				  tspec_info->inactivity_interval, ac_type);
626 			hdd_wmm_enable_inactivity_timer(qos_context,
627 							tspec_info->
628 							inactivity_interval);
629 		}
630 #endif /* FEATURE_WLAN_ESE */
631 
632 		/* notify TL to enable trigger frames if necessary */
633 		hdd_wmm_enable_tl_uapsd(qos_context);
634 
635 		break;
636 
637 	case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
638 		hdd_debug("Setup is complete (U-APSD set previously)");
639 
640 		ac->is_access_allowed = true;
641 		ac->was_access_granted = true;
642 		ac->is_access_pending = false;
643 
644 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
645 
646 			hdd_debug("Explicit Qos, notifying user space");
647 
648 			/* this was triggered by an application */
649 			qos_context->status =
650 				HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
651 			hdd_wmm_notify_app(qos_context);
652 		}
653 
654 		break;
655 
656 	case SME_QOS_STATUS_SETUP_FAILURE_RSP:
657 		hdd_err("Setup failed");
658 		/* QoS setup failed */
659 
660 		ac->is_access_pending = false;
661 		ac->has_access_failed = true;
662 		ac->is_access_allowed = false;
663 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
664 
665 			hdd_debug("Explicit Qos, notifying user space");
666 
667 			/* this was triggered by an application */
668 			qos_context->status =
669 				HDD_WLAN_WMM_STATUS_SETUP_FAILED;
670 
671 			hdd_wmm_notify_app(qos_context);
672 		}
673 
674 		/* disable the inactivity timer */
675 		hdd_wmm_disable_inactivity_timer(qos_context);
676 
677 		/* Setting up QoS Failed, QoS context can be released.
678 		 * SME is releasing this flow information and if HDD
679 		 * doesn't release this context, next time if
680 		 * application uses the same handle to set-up QoS, HDD
681 		 * (as it has QoS context for this handle) will issue
682 		 * Modify QoS request to SME but SME will reject as now
683 		 * it has no information for this flow.
684 		 */
685 		hdd_wmm_free_context(qos_context);
686 		break;
687 
688 	case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
689 		hdd_err("Setup Invalid Params, notify TL");
690 		/* QoS setup failed */
691 		ac->is_access_allowed = false;
692 
693 		if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) {
694 
695 			/* we note the failure, but we also mark
696 			 * access as allowed so that the packets will
697 			 * flow.  Note that the MAC will "do the right
698 			 * thing"
699 			 */
700 			ac->is_access_pending = false;
701 			ac->has_access_failed = true;
702 			ac->is_access_allowed = true;
703 
704 		} else {
705 			hdd_debug("Explicit Qos, notifying user space");
706 
707 			/* this was triggered by an application */
708 			qos_context->status =
709 				HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
710 			hdd_wmm_notify_app(qos_context);
711 		}
712 		break;
713 
714 	case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
715 		hdd_err("Setup failed, not a QoS AP");
716 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
717 			hdd_info("Explicit Qos, notifying user space");
718 
719 			/* this was triggered by an application */
720 			qos_context->status =
721 				HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
722 			hdd_wmm_notify_app(qos_context);
723 		}
724 		break;
725 
726 	case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
727 		hdd_debug("Setup pending");
728 		/* not a callback status -- ignore if we get it */
729 		break;
730 
731 	case SME_QOS_STATUS_SETUP_MODIFIED_IND:
732 		hdd_debug("Setup modified");
733 		if (tspec_info) {
734 			/* update the TSPEC */
735 			ac->is_tspec_valid = true;
736 			memcpy(&ac->tspec,
737 			       tspec_info, sizeof(ac->tspec));
738 
739 			if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
740 				hdd_debug("Explicit Qos, notifying user space");
741 
742 				/* this was triggered by an application */
743 				qos_context->status =
744 					HDD_WLAN_WMM_STATUS_MODIFIED;
745 				hdd_wmm_notify_app(qos_context);
746 			}
747 			/* need to tell TL to update its UAPSD handling */
748 			hdd_wmm_enable_tl_uapsd(qos_context);
749 		}
750 		break;
751 
752 	case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
753 		if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) {
754 
755 			/* this was triggered by implicit QoS so we
756 			 * know packets are pending
757 			 */
758 			ac->is_access_pending = false;
759 			ac->was_access_granted = true;
760 			ac->is_access_allowed = true;
761 
762 		} else {
763 			hdd_debug("Explicit Qos, notifying user space");
764 
765 			/* this was triggered by an application */
766 			qos_context->status =
767 				HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
768 			hdd_wmm_notify_app(qos_context);
769 		}
770 		break;
771 
772 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
773 		/* nothing to do for now */
774 		break;
775 
776 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED:
777 		hdd_err("Setup successful but U-APSD failed");
778 
779 		if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) {
780 
781 			/* QoS setup was successful but setting U=APSD
782 			 * failed.  Since the OTA part of the request
783 			 * was successful, we don't mark this as a
784 			 * failure.  the packets will flow.  Note that
785 			 * the MAC will "do the right thing"
786 			 */
787 			ac->was_access_granted = true;
788 			ac->is_access_allowed = true;
789 			ac->has_access_failed = false;
790 			ac->is_access_pending = false;
791 
792 		} else {
793 			hdd_info("Explicit Qos, notifying user space");
794 
795 			/* this was triggered by an application */
796 			qos_context->status =
797 				HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED;
798 			hdd_wmm_notify_app(qos_context);
799 		}
800 
801 		/* Since U-APSD portion failed disabled trigger frame
802 		 * generation
803 		 */
804 		hdd_wmm_disable_tl_uapsd(qos_context);
805 
806 		break;
807 
808 	case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
809 		hdd_debug("Release is complete");
810 
811 		if (tspec_info) {
812 			hdd_debug("flows still active");
813 
814 			/* there is still at least one flow active for
815 			 * this AC so update the AC state
816 			 */
817 			memcpy(&ac->tspec,
818 			       tspec_info, sizeof(ac->tspec));
819 
820 			/* need to tell TL to update its UAPSD handling */
821 			hdd_wmm_enable_tl_uapsd(qos_context);
822 		} else {
823 			hdd_debug("last flow");
824 
825 			/* this is the last flow active for this AC so
826 			 * update the AC state
827 			 */
828 			ac->is_tspec_valid = false;
829 
830 			/* DELTS is successful, do not allow */
831 			ac->is_access_allowed = false;
832 
833 			/* need to tell TL to update its UAPSD handling */
834 			hdd_wmm_disable_tl_uapsd(qos_context);
835 		}
836 
837 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
838 			hdd_debug("Explicit Qos, notifying user space");
839 
840 			/* this was triggered by an application */
841 			qos_context->status =
842 				HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
843 			hdd_wmm_notify_app(qos_context);
844 		}
845 		/* disable the inactivity timer */
846 		hdd_wmm_disable_inactivity_timer(qos_context);
847 
848 		/* we are done with this flow */
849 		hdd_wmm_free_context(qos_context);
850 		break;
851 
852 	case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
853 		hdd_debug("Release failure");
854 
855 		/* we don't need to update our state or TL since
856 		 * nothing has changed
857 		 */
858 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
859 			hdd_debug("Explicit Qos, notifying user space");
860 
861 			/* this was triggered by an application */
862 			qos_context->status =
863 				HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
864 			hdd_wmm_notify_app(qos_context);
865 		}
866 
867 		break;
868 
869 	case SME_QOS_STATUS_RELEASE_QOS_LOST_IND:
870 		hdd_debug("QOS Lost indication received");
871 
872 		/* current TSPEC is no longer valid */
873 		ac->is_tspec_valid = false;
874 		/* AP has sent DELTS, do not allow */
875 		ac->is_access_allowed = false;
876 
877 		/* need to tell TL to update its UAPSD handling */
878 		hdd_wmm_disable_tl_uapsd(qos_context);
879 
880 		if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) {
881 			/* we no longer have implicit access granted */
882 			ac->was_access_granted = false;
883 			ac->has_access_failed = false;
884 		} else {
885 			hdd_debug("Explicit Qos, notifying user space");
886 
887 			/* this was triggered by an application */
888 			qos_context->status = HDD_WLAN_WMM_STATUS_LOST;
889 			hdd_wmm_notify_app(qos_context);
890 		}
891 
892 		/* disable the inactivity timer */
893 		hdd_wmm_disable_inactivity_timer(qos_context);
894 
895 		/* we are done with this flow */
896 		hdd_wmm_free_context(qos_context);
897 		break;
898 
899 	case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
900 		hdd_debug("Release pending");
901 		/* not a callback status -- ignore if we get it */
902 		break;
903 
904 	case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
905 		hdd_err("Release Invalid Params");
906 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
907 			/* this was triggered by an application */
908 			qos_context->status =
909 				HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
910 			hdd_wmm_notify_app(qos_context);
911 		}
912 		break;
913 
914 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND:
915 		hdd_debug("Modification is complete, notify TL");
916 
917 		/* there will always be a TSPEC returned with this
918 		 * status, even if a TSPEC is not exchanged OTA
919 		 */
920 		if (tspec_info) {
921 			ac->is_tspec_valid = true;
922 			memcpy(&ac->tspec,
923 			       tspec_info, sizeof(ac->tspec));
924 		}
925 
926 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
927 			/* this was triggered by an application */
928 			qos_context->status =
929 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS;
930 			hdd_wmm_notify_app(qos_context);
931 		}
932 		/* notify TL to enable trigger frames if necessary */
933 		hdd_wmm_enable_tl_uapsd(qos_context);
934 
935 		break;
936 
937 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
938 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
939 			/* this was triggered by an application */
940 			qos_context->status =
941 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
942 			hdd_wmm_notify_app(qos_context);
943 		}
944 		break;
945 
946 	case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
947 		/* the flow modification failed so we'll leave in
948 		 * place whatever existed beforehand
949 		 */
950 
951 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
952 			/* this was triggered by an application */
953 			qos_context->status =
954 				HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
955 			hdd_wmm_notify_app(qos_context);
956 		}
957 		break;
958 
959 	case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
960 		hdd_debug("modification pending");
961 		/* not a callback status -- ignore if we get it */
962 		break;
963 
964 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
965 		/* the flow modification was successful but no QoS
966 		 * changes required
967 		 */
968 
969 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
970 			/* this was triggered by an application */
971 			qos_context->status =
972 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
973 			hdd_wmm_notify_app(qos_context);
974 		}
975 		break;
976 
977 	case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
978 		/* invalid params -- notify the application */
979 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
980 			/* this was triggered by an application */
981 			qos_context->status =
982 				HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
983 			hdd_wmm_notify_app(qos_context);
984 		}
985 		break;
986 
987 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING:
988 		/* nothing to do for now.  when APSD is established we'll have work to do */
989 		break;
990 
991 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED:
992 		hdd_err("Modify successful but U-APSD failed");
993 
994 		/* QoS modification was successful but setting U=APSD
995 		 * failed.  This will always be an explicit QoS
996 		 * instance, so all we can do is notify the
997 		 * application and let it clean up.
998 		 */
999 		if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) {
1000 			/* this was triggered by an application */
1001 			qos_context->status =
1002 				HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED;
1003 			hdd_wmm_notify_app(qos_context);
1004 		}
1005 		/* Since U-APSD portion failed disabled trigger frame
1006 		 * generation
1007 		 */
1008 		hdd_wmm_disable_tl_uapsd(qos_context);
1009 
1010 		break;
1011 
1012 	case SME_QOS_STATUS_HANDING_OFF:
1013 		/* no roaming so we won't see this */
1014 		break;
1015 
1016 	case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND:
1017 		/* need to tell TL to stop trigger frame generation */
1018 		hdd_wmm_disable_tl_uapsd(qos_context);
1019 		break;
1020 
1021 	case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND:
1022 		/* need to tell TL to start sending trigger frames again */
1023 		hdd_wmm_enable_tl_uapsd(qos_context);
1024 		break;
1025 
1026 	default:
1027 		hdd_err("unexpected SME Status=%d", sme_status);
1028 		QDF_ASSERT(0);
1029 	}
1030 
1031 	/* if Tspec only allows downstream traffic then access is not
1032 	 * allowed
1033 	 */
1034 	if (ac->is_tspec_valid &&
1035 	    (ac->tspec.ts_info.direction ==
1036 	     SME_QOS_WMM_TS_DIR_DOWNLINK)) {
1037 		ac->is_access_allowed = false;
1038 	}
1039 	/* if we have valid Tpsec or if ACM bit is not set, allow access */
1040 	if ((ac->is_tspec_valid &&
1041 	     (ac->tspec.ts_info.direction !=
1042 	      SME_QOS_WMM_TS_DIR_DOWNLINK)) || !ac->is_access_required) {
1043 		ac->is_access_allowed = true;
1044 	}
1045 
1046 	hdd_debug("complete, access for TL AC %d is%sallowed",
1047 		   ac_type, ac->is_access_allowed ? " " : " not ");
1048 
1049 	return QDF_STATUS_SUCCESS;
1050 }
1051 #endif
1052 
1053 /**
1054  * hdd_wmmps_helper() - Function to set uapsd psb dynamically
1055  *
1056  * @adapter: [in] pointer to adapter structure
1057  * @ptr: [in] pointer to command buffer
1058  *
1059  * Return: Zero on success, appropriate error on failure.
1060  */
hdd_wmmps_helper(struct hdd_adapter * adapter,uint8_t * ptr)1061 int hdd_wmmps_helper(struct hdd_adapter *adapter, uint8_t *ptr)
1062 {
1063 	if (!adapter) {
1064 		hdd_err("adapter is NULL");
1065 		return -EINVAL;
1066 	}
1067 	if (!ptr) {
1068 		hdd_err("ptr is NULL");
1069 		return -EINVAL;
1070 	}
1071 	/* convert ASCII to integer */
1072 	adapter->configured_psb = ptr[9] - '0';
1073 	adapter->psb_changed = HDD_PSB_CHANGED;
1074 
1075 	return 0;
1076 }
1077 
1078 /**
1079  * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup
1080  *	QoS for any AC requiring it.
1081  * @qos_context: the QoS context to operate against
1082  *
1083  * Return: none
1084  */
__hdd_wmm_do_implicit_qos(struct hdd_wmm_qos_context * qos_context)1085 static void __hdd_wmm_do_implicit_qos(struct hdd_wmm_qos_context *qos_context)
1086 {
1087 	struct hdd_adapter *adapter;
1088 	sme_ac_enum_type ac_type;
1089 	struct hdd_wmm_ac_status *ac;
1090 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
1091 	enum sme_qos_statustype sme_status;
1092 #endif
1093 	struct sme_qos_wmmtspecinfo tspec;
1094 	struct hdd_context *hdd_ctx;
1095 	mac_handle_t mac_handle;
1096 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1097 	uint8_t dir_ac, mask = 0;
1098 	uint16_t nom_msdu_size_ac = 0;
1099 	uint32_t rate_ac = 0;
1100 	uint16_t sba_ac = 0;
1101 	uint32_t uapsd_value = 0;
1102 	bool is_ts_burst_enable;
1103 	enum mlme_ts_info_ack_policy ack_policy;
1104 
1105 	hdd_debug("Entered, context %pK", qos_context);
1106 
1107 	adapter = qos_context->adapter;
1108 
1109 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1110 	if (wlan_hdd_validate_context(hdd_ctx))
1111 		return;
1112 
1113 	mac_handle = hdd_ctx->mac_handle;
1114 
1115 	ac_type = qos_context->ac_type;
1116 	ac = &adapter->hdd_wmm_status.ac_status[ac_type];
1117 
1118 	hdd_debug("adapter %pK ac_type %d", adapter, ac_type);
1119 
1120 	if (!ac->is_access_needed) {
1121 		hdd_err("AC %d doesn't need service", ac_type);
1122 		qos_context->magic = 0;
1123 		qdf_mem_free(qos_context);
1124 		return;
1125 	}
1126 
1127 	ac->is_access_pending = true;
1128 	ac->is_access_needed = false;
1129 
1130 	memset(&tspec, 0, sizeof(tspec));
1131 
1132 	tspec.ts_info.psb = adapter->configured_psb;
1133 
1134 	switch (ac_type) {
1135 	case SME_AC_VO:
1136 		tspec.ts_info.up = SME_QOS_WMM_UP_VO;
1137 		/* Check if there is any valid configuration from framework */
1138 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1139 			status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc,
1140 							      &mask);
1141 			if (!QDF_IS_STATUS_SUCCESS(status)) {
1142 				hdd_err("Get uapsd_mask failed");
1143 				return;
1144 			}
1145 			tspec.ts_info.psb = (mask & SME_QOS_UAPSD_VO) ? 1 : 0;
1146 		}
1147 		status = ucfg_mlme_get_wmm_dir_ac_vo(hdd_ctx->psoc,
1148 						     &dir_ac);
1149 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1150 			hdd_err("Get infra_dir_ac_vo failed");
1151 			return;
1152 		}
1153 		tspec.ts_info.direction = dir_ac;
1154 
1155 		tspec.ts_info.tid = 255;
1156 
1157 		status = ucfg_mlme_get_wmm_uapsd_vo_srv_intv(hdd_ctx->psoc,
1158 							     &uapsd_value);
1159 		if (QDF_IS_STATUS_ERROR(status)) {
1160 			hdd_err("Get uapsd_srv_intv failed");
1161 			return;
1162 		}
1163 		tspec.min_service_interval = uapsd_value;
1164 
1165 		status = ucfg_mlme_get_wmm_uapsd_vo_sus_intv(hdd_ctx->psoc,
1166 							     &uapsd_value);
1167 		if (QDF_IS_STATUS_ERROR(status)) {
1168 			hdd_err("Get uapsd_vo_sus_intv failed");
1169 			return;
1170 		}
1171 		tspec.suspension_interval = uapsd_value;
1172 
1173 		status = ucfg_mlme_get_wmm_mean_data_rate_ac_vo(hdd_ctx->psoc,
1174 								&rate_ac);
1175 		if (QDF_IS_STATUS_ERROR(status)) {
1176 			hdd_err("Get mean_data_rate_ac_vo failed");
1177 			return;
1178 		}
1179 		tspec.mean_data_rate = rate_ac;
1180 
1181 		status = ucfg_mlme_get_wmm_min_phy_rate_ac_vo(hdd_ctx->psoc,
1182 							      &rate_ac);
1183 		if (QDF_IS_STATUS_ERROR(status)) {
1184 			hdd_err("Get min_phy_rate_ac_vo failed");
1185 			return;
1186 		}
1187 		tspec.min_phy_rate = rate_ac;
1188 
1189 		status = ucfg_mlme_get_wmm_nom_msdu_size_ac_vo(hdd_ctx->psoc,
1190 							     &nom_msdu_size_ac);
1191 		if (QDF_IS_STATUS_ERROR(status)) {
1192 			hdd_err("Get nom_msdu_size_ac_vo failed");
1193 			return;
1194 		}
1195 		tspec.nominal_msdu_size = nom_msdu_size_ac;
1196 
1197 		status = ucfg_mlme_get_wmm_sba_ac_vo(hdd_ctx->psoc,
1198 						     &sba_ac);
1199 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1200 			hdd_err("Get sba_ac_vo failed");
1201 			return;
1202 		}
1203 		tspec.surplus_bw_allowance = sba_ac;
1204 
1205 		break;
1206 	case SME_AC_VI:
1207 		tspec.ts_info.up = SME_QOS_WMM_UP_VI;
1208 		/* Check if there is any valid configuration from framework */
1209 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1210 			status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc,
1211 							      &mask);
1212 			if (!QDF_IS_STATUS_SUCCESS(status)) {
1213 				hdd_err("Get uapsd_mask failed");
1214 				return;
1215 			}
1216 			tspec.ts_info.psb = (mask & SME_QOS_UAPSD_VI) ? 1 : 0;
1217 		}
1218 		status = ucfg_mlme_get_wmm_dir_ac_vi(
1219 			hdd_ctx->psoc, &dir_ac);
1220 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1221 			hdd_err("Get infra_dir_ac_vi failed");
1222 			return;
1223 		}
1224 		tspec.ts_info.direction = dir_ac;
1225 
1226 		tspec.ts_info.tid = 255;
1227 		status = ucfg_mlme_get_wmm_uapsd_vi_srv_intv(
1228 			hdd_ctx->psoc, &uapsd_value);
1229 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1230 			hdd_err("Get uapsd_vi_srv_intv failed");
1231 			return;
1232 		}
1233 		tspec.min_service_interval = uapsd_value;
1234 
1235 		status = ucfg_mlme_get_wmm_uapsd_vi_sus_intv(
1236 			hdd_ctx->psoc, &uapsd_value);
1237 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1238 			hdd_err("Get uapsd_vi_sus_intv failed");
1239 			return;
1240 		}
1241 		tspec.suspension_interval = uapsd_value;
1242 
1243 		status = ucfg_mlme_get_wmm_mean_data_rate_ac_vi(
1244 			hdd_ctx->psoc, &rate_ac);
1245 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1246 			hdd_err("Get mean_data_rate_ac_vi failed");
1247 			return;
1248 		}
1249 		tspec.mean_data_rate = rate_ac;
1250 
1251 		status = ucfg_mlme_get_wmm_min_phy_rate_ac_vi(
1252 			hdd_ctx->psoc, &rate_ac);
1253 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1254 			hdd_err("Get min_phy_rate_ac_vi failed");
1255 			return;
1256 		}
1257 		tspec.min_phy_rate = rate_ac;
1258 
1259 		status = ucfg_mlme_get_wmm_nom_msdu_size_ac_vi(
1260 			hdd_ctx->psoc, &nom_msdu_size_ac);
1261 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1262 			hdd_err("Get nom_msdu_size_ac_vi failed");
1263 			return;
1264 		}
1265 		tspec.nominal_msdu_size = nom_msdu_size_ac;
1266 
1267 		status = ucfg_mlme_get_wmm_sba_ac_vi(
1268 			hdd_ctx->psoc, &sba_ac);
1269 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1270 			hdd_err("Get sba_ac_vi failed");
1271 			return;
1272 		}
1273 		tspec.surplus_bw_allowance = sba_ac;
1274 
1275 		break;
1276 	default:
1277 	case SME_AC_BE:
1278 		tspec.ts_info.up = SME_QOS_WMM_UP_BE;
1279 		/* Check if there is any valid configuration from framework */
1280 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1281 			status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc,
1282 							      &mask);
1283 			if (!QDF_IS_STATUS_SUCCESS(status)) {
1284 				hdd_err("Get uapsd_mask failed");
1285 				return;
1286 			}
1287 			tspec.ts_info.psb = (mask & SME_QOS_UAPSD_BE) ? 1 : 0;
1288 		}
1289 		status = ucfg_mlme_get_wmm_dir_ac_be(hdd_ctx->psoc, &dir_ac);
1290 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1291 			hdd_err("Get infra_dir_ac_be failed");
1292 			return;
1293 		}
1294 		tspec.ts_info.direction = dir_ac;
1295 
1296 		tspec.ts_info.tid = 255;
1297 		status = ucfg_mlme_get_wmm_uapsd_be_srv_intv(hdd_ctx->psoc,
1298 							     &uapsd_value);
1299 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1300 			hdd_err("Get uapsd_vi_srv_intv failed");
1301 			return;
1302 		}
1303 		tspec.min_service_interval = uapsd_value;
1304 
1305 		status = ucfg_mlme_get_wmm_uapsd_be_sus_intv(hdd_ctx->psoc,
1306 							     &uapsd_value);
1307 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1308 			hdd_err("Get uapsd_vi_sus_intv failed");
1309 			return;
1310 		}
1311 		tspec.suspension_interval = uapsd_value;
1312 
1313 		status = ucfg_mlme_get_wmm_mean_data_rate_ac_be(hdd_ctx->psoc,
1314 								&rate_ac);
1315 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1316 			hdd_err("Get mean_data_rate_ac_be failed");
1317 			return;
1318 		}
1319 		tspec.mean_data_rate = rate_ac;
1320 
1321 		status = ucfg_mlme_get_wmm_min_phy_rate_ac_be(hdd_ctx->psoc,
1322 							      &rate_ac);
1323 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1324 			hdd_err("Get min_phy_rate_ac_be failed");
1325 			return;
1326 		}
1327 		tspec.min_phy_rate = rate_ac;
1328 
1329 		status = ucfg_mlme_get_wmm_nom_msdu_size_ac_be(hdd_ctx->psoc,
1330 							    &nom_msdu_size_ac);
1331 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1332 			hdd_err("Get nom_msdu_size_ac_be failed");
1333 			return;
1334 		}
1335 		tspec.nominal_msdu_size = nom_msdu_size_ac;
1336 
1337 		status = ucfg_mlme_get_wmm_sba_ac_be(hdd_ctx->psoc, &sba_ac);
1338 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1339 			hdd_err("Get sba_ac_be failed");
1340 			return;
1341 		}
1342 		tspec.surplus_bw_allowance = sba_ac;
1343 
1344 		break;
1345 	case SME_AC_BK:
1346 		tspec.ts_info.up = SME_QOS_WMM_UP_BK;
1347 		/* Check if there is any valid configuration from framework */
1348 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1349 			status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc,
1350 							      &mask);
1351 			if (!QDF_IS_STATUS_SUCCESS(status)) {
1352 				hdd_err("Get uapsd_mask failed");
1353 				return;
1354 			}
1355 			tspec.ts_info.psb = (mask & SME_QOS_UAPSD_BK) ? 1 : 0;
1356 		}
1357 
1358 		status = ucfg_mlme_get_wmm_dir_ac_bk(hdd_ctx->psoc, &dir_ac);
1359 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1360 			hdd_err("Get infra_dir_ac_bk failed");
1361 			return;
1362 		}
1363 		tspec.ts_info.direction = dir_ac;
1364 
1365 		tspec.ts_info.tid = 255;
1366 		status = ucfg_mlme_get_wmm_uapsd_bk_srv_intv(hdd_ctx->psoc,
1367 							     &uapsd_value);
1368 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1369 			hdd_err("Get uapsd_bk_srv_intv failed");
1370 			return;
1371 		}
1372 		tspec.min_service_interval = uapsd_value;
1373 
1374 		status = ucfg_mlme_get_wmm_uapsd_bk_sus_intv(hdd_ctx->psoc,
1375 							     &uapsd_value);
1376 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1377 			hdd_err("Get uapsd_bk_sus_intv failed");
1378 			return;
1379 		}
1380 		tspec.suspension_interval = uapsd_value;
1381 
1382 		status = ucfg_mlme_get_wmm_mean_data_rate_ac_bk(hdd_ctx->psoc,
1383 								&rate_ac);
1384 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1385 			hdd_err("Get mean_data_rate_ac_bk failed");
1386 			return;
1387 		}
1388 		tspec.mean_data_rate = rate_ac;
1389 
1390 		status = ucfg_mlme_get_wmm_min_phy_rate_ac_bk(hdd_ctx->psoc,
1391 							      &rate_ac);
1392 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1393 			hdd_err("Get min_phy_rate_ac_bk failed");
1394 			return;
1395 		}
1396 		tspec.min_phy_rate = rate_ac;
1397 
1398 		status =
1399 		  ucfg_mlme_get_wmm_nom_msdu_size_ac_bk(hdd_ctx->psoc,
1400 							&nom_msdu_size_ac);
1401 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1402 			hdd_err("Get nom_msdu_size_ac_bk failed");
1403 			return;
1404 		}
1405 		tspec.nominal_msdu_size = nom_msdu_size_ac;
1406 
1407 		status = ucfg_mlme_get_wmm_sba_ac_bk(hdd_ctx->psoc, &sba_ac);
1408 		if (!QDF_IS_STATUS_SUCCESS(status)) {
1409 			hdd_err("Get sba_ac_bk failed");
1410 			return;
1411 		}
1412 		tspec.surplus_bw_allowance = sba_ac;
1413 
1414 		break;
1415 	}
1416 #ifdef FEATURE_WLAN_ESE
1417 	ucfg_mlme_get_inactivity_interval(hdd_ctx->psoc, &uapsd_value);
1418 	tspec.inactivity_interval = uapsd_value;
1419 #endif
1420 	ucfg_mlme_get_is_ts_burst_size_enable(hdd_ctx->psoc,
1421 					      &is_ts_burst_enable);
1422 	tspec.ts_info.burst_size_defn = is_ts_burst_enable;
1423 
1424 	ucfg_mlme_get_ts_info_ack_policy(hdd_ctx->psoc, &ack_policy);
1425 	switch (ack_policy) {
1426 	case TS_INFO_ACK_POLICY_NORMAL_ACK:
1427 		tspec.ts_info.ack_policy =
1428 			SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1429 		break;
1430 
1431 	case TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK:
1432 		tspec.ts_info.ack_policy =
1433 			SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
1434 		break;
1435 
1436 	default:
1437 		/* unknown */
1438 		tspec.ts_info.ack_policy =
1439 			SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1440 	}
1441 
1442 	if (tspec.ts_info.ack_policy ==
1443 	    SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) {
1444 		if (!sme_qos_is_ts_info_ack_policy_valid(
1445 					mac_handle, &tspec,
1446 					adapter->deflink->vdev_id)) {
1447 			tspec.ts_info.ack_policy =
1448 				SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1449 		}
1450 	}
1451 
1452 	mutex_lock(&adapter->hdd_wmm_status.mutex);
1453 	list_add(&qos_context->node, &adapter->hdd_wmm_status.context_list);
1454 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
1455 
1456 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
1457 	sme_status = sme_qos_setup_req(mac_handle,
1458 				       adapter->deflink->vdev_id,
1459 				       &tspec,
1460 				       hdd_wmm_sme_callback,
1461 				       qos_context,
1462 				       tspec.ts_info.up,
1463 				       &qos_context->flow_id);
1464 
1465 	hdd_debug("sme_qos_setup_req returned %d flowid %d",
1466 		  sme_status, qos_context->flow_id);
1467 
1468 	/* need to check the return values and act appropriately */
1469 	switch (sme_status) {
1470 	case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
1471 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
1472 		/* setup is pending, so no more work to do now.  all
1473 		 * further work will be done in hdd_wmm_sme_callback()
1474 		 */
1475 		hdd_debug("Setup is pending, no further work");
1476 
1477 		break;
1478 
1479 	case SME_QOS_STATUS_SETUP_FAILURE_RSP:
1480 		/* disable the inactivity timer */
1481 		hdd_wmm_disable_inactivity_timer(qos_context);
1482 
1483 		/* we can't tell the difference between when a request
1484 		 * fails because AP rejected it versus when SME
1485 		 * encountered an internal error.  in either case SME
1486 		 * won't ever reference this context so free the
1487 		 * record
1488 		 */
1489 		hdd_wmm_free_context(qos_context);
1490 		/* start packets flowing */
1491 		fallthrough;
1492 	case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
1493 		/* no ACM in effect, no need to setup U-APSD */
1494 	case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
1495 		/* no ACM in effect, U-APSD is desired but was already setup */
1496 
1497 		/* for these cases everything is already setup so we
1498 		 * can signal TL that it has work to do
1499 		 */
1500 		hdd_debug("Setup is complete, notify TL");
1501 
1502 		ac->is_access_allowed = true;
1503 		ac->was_access_granted = true;
1504 		ac->is_access_pending = false;
1505 
1506 		break;
1507 
1508 	default:
1509 		hdd_err("unexpected SME Status=%d", sme_status);
1510 		QDF_ASSERT(0);
1511 	}
1512 #endif
1513 
1514 }
1515 
1516 /**
1517  * hdd_wmm_do_implicit_qos() - SSR wrapper function for hdd_wmm_do_implicit_qos
1518  * @work: pointer to work_struct
1519  *
1520  * Return: none
1521  */
hdd_wmm_do_implicit_qos(struct work_struct * work)1522 static void hdd_wmm_do_implicit_qos(struct work_struct *work)
1523 {
1524 	struct hdd_wmm_qos_context *qos_ctx =
1525 		container_of(work, struct hdd_wmm_qos_context,
1526 			     implicit_qos_work);
1527 	struct osif_vdev_sync *vdev_sync;
1528 
1529 	if (qos_ctx->magic != HDD_WMM_CTX_MAGIC) {
1530 		hdd_err("Invalid QoS Context");
1531 		return;
1532 	}
1533 
1534 	if (osif_vdev_sync_op_start(qos_ctx->adapter->dev, &vdev_sync))
1535 		return;
1536 
1537 	__hdd_wmm_do_implicit_qos(qos_ctx);
1538 
1539 	osif_vdev_sync_op_stop(vdev_sync);
1540 }
1541 
hdd_send_dscp_up_map_to_fw(struct hdd_adapter * adapter)1542 QDF_STATUS hdd_send_dscp_up_map_to_fw(struct hdd_adapter *adapter)
1543 {
1544 	uint32_t *dscp_to_up_map = adapter->dscp_to_up_map;
1545 	struct wlan_objmgr_vdev *vdev;
1546 	int ret;
1547 
1548 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_FWOL_NB_ID);
1549 
1550 	if (vdev) {
1551 		/* Send DSCP to TID map table to FW */
1552 		ret = os_if_fwol_send_dscp_up_map_to_fw(vdev, dscp_to_up_map);
1553 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_FWOL_NB_ID);
1554 		if (ret && ret != -EOPNOTSUPP)
1555 			return QDF_STATUS_E_FAILURE;
1556 	}
1557 
1558 	return QDF_STATUS_SUCCESS;
1559 }
1560 
1561 /**
1562  * hdd_fill_dscp_to_up_map() - Fill up dscp_to_up_map table with default values
1563  * @dscp_to_up_map: Array of DSCP-to-UP map
1564  *
1565  * This function will fill up the DSCP-to-UP map table with default values.
1566  *
1567  * Return: QDF_STATUS enumeration
1568  */
hdd_fill_dscp_to_up_map(enum sme_qos_wmmuptype * dscp_to_up_map)1569 static inline void hdd_fill_dscp_to_up_map(
1570 		enum sme_qos_wmmuptype *dscp_to_up_map)
1571 {
1572 	uint8_t dscp;
1573 
1574 	/*
1575 	 * DSCP to User Priority Lookup Table
1576 	 * By default use the 3 Precedence bits of DSCP as the User Priority
1577 	 *
1578 	 * In case of changing the default map values, need to take care of
1579 	 * hdd_custom_dscp_up_map as well.
1580 	 */
1581 	for (dscp = 0; dscp <= WLAN_MAX_DSCP; dscp++)
1582 		dscp_to_up_map[dscp] = dscp >> 3;
1583 
1584 	/* Special case for Expedited Forwarding (DSCP 46) in default mapping */
1585 	dscp_to_up_map[DSCP(46)] = SME_QOS_WMM_UP_VO;
1586 }
1587 
1588 #ifdef WLAN_CUSTOM_DSCP_UP_MAP
1589 /**
1590  * hdd_custom_dscp_up_map() - Customize dscp_to_up_map based on RFC8325
1591  * @dscp_to_up_map: Array of DSCP-to-UP map
1592  *
1593  * This function will customize the DSCP-to-UP map table based on RFC8325..
1594  *
1595  * Return: QDF_STATUS enumeration
1596  */
hdd_custom_dscp_up_map(enum sme_qos_wmmuptype * dscp_to_up_map)1597 static inline QDF_STATUS hdd_custom_dscp_up_map(
1598 		enum sme_qos_wmmuptype *dscp_to_up_map)
1599 {
1600 	/*
1601 	 * Customizing few of DSCP to UP mapping based on RFC8325,
1602 	 * those are different from default hdd_fill_dscp_to_up_map values.
1603 	 * So, below changes are always relative to hdd_fill_dscp_to_up_map.
1604 	 */
1605 	dscp_to_up_map[DSCP(10)] = SME_QOS_WMM_UP_BE;
1606 	dscp_to_up_map[DSCP(12)] = SME_QOS_WMM_UP_BE;
1607 	dscp_to_up_map[DSCP(14)] = SME_QOS_WMM_UP_BE;
1608 	dscp_to_up_map[DSCP(16)] = SME_QOS_WMM_UP_BE;
1609 
1610 	dscp_to_up_map[DSCP(18)] = SME_QOS_WMM_UP_EE;
1611 	dscp_to_up_map[DSCP(20)] = SME_QOS_WMM_UP_EE;
1612 	dscp_to_up_map[DSCP(22)] = SME_QOS_WMM_UP_EE;
1613 
1614 	dscp_to_up_map[DSCP(24)] = SME_QOS_WMM_UP_CL;
1615 	dscp_to_up_map[DSCP(26)] = SME_QOS_WMM_UP_CL;
1616 	dscp_to_up_map[DSCP(28)] = SME_QOS_WMM_UP_CL;
1617 	dscp_to_up_map[DSCP(30)] = SME_QOS_WMM_UP_CL;
1618 
1619 	dscp_to_up_map[DSCP(44)] = SME_QOS_WMM_UP_VO;
1620 
1621 	dscp_to_up_map[DSCP(48)] = SME_QOS_WMM_UP_NC;
1622 
1623 	return QDF_STATUS_SUCCESS;
1624 }
1625 #else
hdd_custom_dscp_up_map(enum sme_qos_wmmuptype * dscp_to_up_map)1626 static inline QDF_STATUS hdd_custom_dscp_up_map(
1627 		enum sme_qos_wmmuptype *dscp_to_up_map)
1628 {
1629 	return QDF_STATUS_E_NOSUPPORT;
1630 }
1631 #endif /* WLAN_CUSTOM_DSCP_UP_MAP */
1632 
1633 /**
1634  * hdd_wmm_dscp_initial_state() - initialize the WMM DSCP configuration
1635  * @adapter : [in]  pointer to Adapter context
1636  *
1637  * This function will initialize the WMM DSCP configuration of an
1638  * adapter to an initial state.  The configuration can later be
1639  * overwritten via application APIs or via QoS Map sent OTA.
1640  *
1641  * Return: QDF_STATUS enumeration
1642  */
hdd_wmm_dscp_initial_state(struct hdd_adapter * adapter)1643 QDF_STATUS hdd_wmm_dscp_initial_state(struct hdd_adapter *adapter)
1644 {
1645 	enum sme_qos_wmmuptype *dscp_to_up_map = adapter->dscp_to_up_map;
1646 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
1647 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1648 
1649 	if (!psoc) {
1650 		hdd_err("Invalid psoc handle");
1651 		return QDF_STATUS_E_FAILURE;
1652 	}
1653 
1654 	hdd_fill_dscp_to_up_map(dscp_to_up_map);
1655 
1656 	if (hdd_custom_dscp_up_map(dscp_to_up_map) == QDF_STATUS_SUCCESS) {
1657 		/* Send DSCP to TID map table to FW */
1658 		status = hdd_send_dscp_up_map_to_fw(adapter);
1659 	}
1660 
1661 	return status;
1662 }
1663 
1664 /**
1665  * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter
1666  * @adapter: [in]  pointer to Adapter context
1667  *
1668  * This function will initialize the WMM configuration and status of an
1669  * adapter to an initial state.  The configuration can later be
1670  * overwritten via application APIs
1671  *
1672  * Return: QDF_STATUS enumeration
1673  */
hdd_wmm_adapter_init(struct hdd_adapter * adapter)1674 QDF_STATUS hdd_wmm_adapter_init(struct hdd_adapter *adapter)
1675 {
1676 	struct hdd_wmm_ac_status *ac_status;
1677 	sme_ac_enum_type ac_type;
1678 
1679 	hdd_enter();
1680 
1681 	hdd_wmm_dscp_initial_state(adapter);
1682 
1683 	adapter->hdd_wmm_status.qap = false;
1684 	INIT_LIST_HEAD(&adapter->hdd_wmm_status.context_list);
1685 	mutex_init(&adapter->hdd_wmm_status.mutex);
1686 
1687 	for (ac_type = 0; ac_type < WLAN_MAX_AC; ac_type++) {
1688 		ac_status = &adapter->hdd_wmm_status.ac_status[ac_type];
1689 		ac_status->is_access_required = false;
1690 		ac_status->is_access_needed = false;
1691 		ac_status->is_access_pending = false;
1692 		ac_status->has_access_failed = false;
1693 		ac_status->was_access_granted = false;
1694 		ac_status->is_access_allowed = false;
1695 		ac_status->is_tspec_valid = false;
1696 		ac_status->is_uapsd_info_valid = false;
1697 	}
1698 	/* Invalid value(0xff) to indicate psb not configured through
1699 	 * framework initially.
1700 	 */
1701 	adapter->configured_psb = HDD_PSB_CFG_INVALID;
1702 
1703 	return QDF_STATUS_SUCCESS;
1704 }
1705 
1706 /**
1707  * hdd_wmm_adapter_clear() - Function which will clear the WMM status
1708  * for all the ACs
1709  *
1710  * @adapter: [in]  pointer to Adapter context
1711  *
1712  * Return: QDF_STATUS enumeration
1713  */
hdd_wmm_adapter_clear(struct hdd_adapter * adapter)1714 QDF_STATUS hdd_wmm_adapter_clear(struct hdd_adapter *adapter)
1715 {
1716 	struct hdd_wmm_ac_status *ac_status;
1717 	sme_ac_enum_type ac_type;
1718 
1719 	hdd_enter();
1720 	for (ac_type = 0; ac_type < WLAN_MAX_AC; ac_type++) {
1721 		ac_status = &adapter->hdd_wmm_status.ac_status[ac_type];
1722 		ac_status->is_access_required = false;
1723 		ac_status->is_access_needed = false;
1724 		ac_status->is_access_pending = false;
1725 		ac_status->has_access_failed = false;
1726 		ac_status->was_access_granted = false;
1727 		ac_status->is_access_allowed = false;
1728 		ac_status->is_tspec_valid = false;
1729 		ac_status->is_uapsd_info_valid = false;
1730 	}
1731 	return QDF_STATUS_SUCCESS;
1732 }
1733 
1734 /**
1735  * hdd_wmm_adapter_close() - WMM close function
1736  * @adapter: [in]  pointer to adapter context
1737  *
1738  * Function which will perform any necessary work to to clean up the
1739  * WMM functionality prior to the kernel module unload.
1740  *
1741  * Return: QDF_STATUS enumeration
1742  */
hdd_wmm_adapter_close(struct hdd_adapter * adapter)1743 QDF_STATUS hdd_wmm_adapter_close(struct hdd_adapter *adapter)
1744 {
1745 	struct hdd_wmm_qos_context *qos_context;
1746 
1747 	hdd_enter();
1748 
1749 	/* free any context records that we still have linked */
1750 	while (!list_empty(&adapter->hdd_wmm_status.context_list)) {
1751 		qos_context =
1752 			list_first_entry(&adapter->hdd_wmm_status.context_list,
1753 					 struct hdd_wmm_qos_context, node);
1754 
1755 		hdd_wmm_disable_inactivity_timer(qos_context);
1756 
1757 		if (qos_context->handle == HDD_WMM_HANDLE_IMPLICIT
1758 			&& qos_context->magic == HDD_WMM_CTX_MAGIC)
1759 			cds_flush_work(&qos_context->implicit_qos_work);
1760 
1761 		hdd_wmm_free_context(qos_context);
1762 	}
1763 
1764 	return QDF_STATUS_SUCCESS;
1765 }
1766 
1767 /**
1768  * hdd_check_upgrade_vo_vi_qos() - Check and upgrade QOS for UDP packets
1769  *				   based on request type received
1770  * @adapter: [in] pointer to the adapter context (Should not be invalid)
1771  * @user_pri: [out] priority set for this packet
1772  *
1773  * This function checks for the request type and upgrade based on request type
1774  *
1775  * UDP_QOS_UPGRADE_ALL: Upgrade QoS of all UDP packets if the current set
1776  *	priority is below the pre-configured threshold for upgrade.
1777  *
1778  * UDP_QOS_UPGRADE_BK_BE: Upgrade QoS of all UDP packets if the current set
1779  *	priority is below the AC VI.
1780  */
1781 static inline void
hdd_check_upgrade_vo_vi_qos(struct hdd_adapter * adapter,enum sme_qos_wmmuptype * user_pri)1782 hdd_check_upgrade_vo_vi_qos(struct hdd_adapter *adapter,
1783 			    enum sme_qos_wmmuptype *user_pri)
1784 {
1785 	switch (adapter->udp_qos_upgrade_type) {
1786 	case UDP_QOS_UPGRADE_ALL:
1787 		if (*user_pri <
1788 		    qca_wlan_ac_to_sme_qos(adapter->upgrade_udp_qos_threshold))
1789 			*user_pri = qca_wlan_ac_to_sme_qos(
1790 					adapter->upgrade_udp_qos_threshold);
1791 		break;
1792 	case UDP_QOS_UPGRADE_BK_BE:
1793 		if (*user_pri < qca_wlan_ac_to_sme_qos(QCA_WLAN_AC_VI))
1794 			*user_pri = qca_wlan_ac_to_sme_qos(
1795 					adapter->upgrade_udp_qos_threshold);
1796 		break;
1797 	default:
1798 		break;
1799 	}
1800 }
1801 
1802 /**
1803  * hdd_check_and_upgrade_udp_qos() - Check and upgrade the qos for UDP packets
1804  *				     if the current set priority is below the
1805  *				     pre-configured threshold for upgrade.
1806  * @adapter: [in] pointer to the adapter context (Should not be invalid)
1807  * @skb: [in] pointer to the packet to be transmitted
1808  * @user_pri: [out] priority set for this packet
1809  *
1810  * This function checks if the packet is a UDP packet and upgrades its
1811  * priority if its below the pre-configured upgrade threshold.
1812  * The upgrade order is as below:
1813  * BK -> BE -> VI -> VO
1814  *
1815  * Return: none
1816  */
1817 static inline void
hdd_check_and_upgrade_udp_qos(struct hdd_adapter * adapter,qdf_nbuf_t skb,enum sme_qos_wmmuptype * user_pri)1818 hdd_check_and_upgrade_udp_qos(struct hdd_adapter *adapter,
1819 			      qdf_nbuf_t skb,
1820 			      enum sme_qos_wmmuptype *user_pri)
1821 {
1822 	/* Upgrade UDP pkt priority alone */
1823 	if (!(qdf_nbuf_is_ipv4_udp_pkt(skb) || qdf_nbuf_is_ipv6_udp_pkt(skb)))
1824 		return;
1825 
1826 	switch (adapter->upgrade_udp_qos_threshold) {
1827 	case QCA_WLAN_AC_BK:
1828 		break;
1829 	case QCA_WLAN_AC_BE:
1830 		if (*user_pri == qca_wlan_ac_to_sme_qos(QCA_WLAN_AC_BK))
1831 			*user_pri = qca_wlan_ac_to_sme_qos(QCA_WLAN_AC_BE);
1832 
1833 		break;
1834 	case QCA_WLAN_AC_VI:
1835 	case QCA_WLAN_AC_VO:
1836 		hdd_check_upgrade_vo_vi_qos(adapter, user_pri);
1837 		break;
1838 	default:
1839 		break;
1840 	}
1841 }
1842 
1843 /**
1844  * hdd_wmm_classify_critical_pkt() - Function checks and classifies critical skb
1845  * @skb: pointer to network buffer
1846  * @user_pri: user priority of the OS packet to be determined
1847  * @is_critical: pointer to be marked true for a critical packet
1848  *
1849  * Function checks if the packet is one of the critical packets and determines
1850  * 'user_pri' for it. EAPOL, ARP, DHCP(v4,v6), NS, NA are considered critical.
1851  *
1852  * Note that wlan_hdd_mark_critical_pkt is used to mark packet type in CB for
1853  * these critical packets. This is done as skb->cb amay be overwritten between
1854  * _select_queue and_hard_start_xmit functions. hdd_wmm_classify_critical_pkt
1855  * and wlan_hdd_mark_critical_pkt should be in sync w.r.t packet types.
1856  *
1857  * Return: None
1858  */
1859 static
hdd_wmm_classify_critical_pkt(struct sk_buff * skb,enum sme_qos_wmmuptype * user_pri,bool * is_critical)1860 void hdd_wmm_classify_critical_pkt(struct sk_buff *skb,
1861 				   enum sme_qos_wmmuptype *user_pri,
1862 				   bool *is_critical)
1863 {
1864 	enum qdf_proto_subtype proto_subtype;
1865 
1866 	 /* Send EAPOL on TID 6(VO). Rest are sent on TID 0(BE). */
1867 
1868 	if (qdf_nbuf_is_ipv4_eapol_pkt(skb)) {
1869 		*is_critical = true;
1870 		*user_pri = SME_QOS_WMM_UP_VO;
1871 	} else if (qdf_nbuf_is_ipv4_arp_pkt(skb)) {
1872 		*is_critical = true;
1873 		*user_pri = SME_QOS_WMM_UP_BE;
1874 	} else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb)) {
1875 		*is_critical = true;
1876 		*user_pri = SME_QOS_WMM_UP_BE;
1877 	} else if (qdf_nbuf_is_ipv6_dhcp_pkt(skb)) {
1878 		*is_critical = true;
1879 		*user_pri = SME_QOS_WMM_UP_BE;
1880 	} else if (qdf_nbuf_is_icmpv6_pkt(skb)) {
1881 		proto_subtype = qdf_nbuf_get_icmpv6_subtype(skb);
1882 		switch (proto_subtype) {
1883 		case QDF_PROTO_ICMPV6_NA:
1884 		case QDF_PROTO_ICMPV6_NS:
1885 			*is_critical = true;
1886 			*user_pri = SME_QOS_WMM_UP_BE;
1887 			break;
1888 		default:
1889 			break;
1890 		}
1891 	}
1892 }
1893 
1894 #ifdef DP_TRAFFIC_END_INDICATION
1895 /**
1896  * hdd_wmm_traffic_end_indication_is_enable() - Get feature enable/disable
1897  *                                              status
1898  * @adapter: hdd adapter handle
1899  *
1900  * Return: true if feature is enable else false
1901  */
1902 static inline bool
hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter * adapter)1903 hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter *adapter)
1904 {
1905 	return qdf_unlikely(adapter->traffic_end_ind_en);
1906 }
1907 #else
1908 static inline bool
hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter * adapter)1909 hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter *adapter)
1910 {
1911 	return false;
1912 }
1913 #endif
1914 
1915 static
hdd_wmm_get_user_priority_from_ip_tos(struct hdd_adapter * adapter,struct sk_buff * skb,enum sme_qos_wmmuptype * user_pri)1916 void hdd_wmm_get_user_priority_from_ip_tos(struct hdd_adapter *adapter,
1917 					   struct sk_buff *skb,
1918 					   enum sme_qos_wmmuptype *user_pri)
1919 
1920 {
1921 	unsigned char dscp;
1922 	unsigned char tos;
1923 	union generic_ethhdr *eth_hdr;
1924 	struct iphdr *ip_hdr;
1925 	struct ipv6hdr *ipv6hdr;
1926 	unsigned char *pkt;
1927 	struct wlan_objmgr_psoc *psoc;
1928 
1929 	/* this code is executed for every packet therefore
1930 	 * all debug code is kept conditional
1931 	 */
1932 
1933 #ifdef HDD_WMM_DEBUG
1934 	hdd_enter();
1935 #endif /* HDD_WMM_DEBUG */
1936 
1937 	pkt = skb->data;
1938 	eth_hdr = (union generic_ethhdr *)pkt;
1939 
1940 #ifdef HDD_WMM_DEBUG
1941 	hdd_debug("proto is 0x%04x", skb->protocol);
1942 #endif /* HDD_WMM_DEBUG */
1943 
1944 	if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) {
1945 		/* case 1: Ethernet II IP packet */
1946 		ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)];
1947 		tos = ip_hdr->tos;
1948 #ifdef HDD_WMM_DEBUG
1949 		hdd_debug("Ethernet II IP Packet, tos is %d", tos);
1950 #endif /* HDD_WMM_DEBUG */
1951 
1952 	} else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) {
1953 		ipv6hdr = ipv6_hdr(skb);
1954 		tos = ntohs(*(const __be16 *)ipv6hdr) >> 4;
1955 #ifdef HDD_WMM_DEBUG
1956 		hdd_debug("Ethernet II IPv6 Packet, tos is %d", tos);
1957 #endif /* HDD_WMM_DEBUG */
1958 	} else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) &&
1959 		  (eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) &&
1960 		  (eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) &&
1961 		  (eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) &&
1962 		  (eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) {
1963 		/* case 2: 802.3 LLC/SNAP IP packet */
1964 		ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)];
1965 		tos = ip_hdr->tos;
1966 #ifdef HDD_WMM_DEBUG
1967 		hdd_debug("802.3 LLC/SNAP IP Packet, tos is %d", tos);
1968 #endif /* HDD_WMM_DEBUG */
1969 	} else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) {
1970 		/* VLAN tagged */
1971 
1972 		if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto ==
1973 			htons(ETH_P_IP)) {
1974 			/* case 3: Ethernet II vlan-tagged IP packet */
1975 			ip_hdr =
1976 				(struct iphdr *)
1977 				&pkt[sizeof(eth_hdr->eth_IIv)];
1978 			tos = ip_hdr->tos;
1979 #ifdef HDD_WMM_DEBUG
1980 			hdd_debug("Ether II VLAN tagged IP Packet, tos is %d",
1981 				 tos);
1982 #endif /* HDD_WMM_DEBUG */
1983 		} else if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto)
1984 			< WLAN_MIN_PROTO) &&
1985 			(eth_hdr->eth_8023v.h_snap.dsap ==
1986 			WLAN_SNAP_DSAP)
1987 			&& (eth_hdr->eth_8023v.h_snap.ssap ==
1988 			WLAN_SNAP_SSAP)
1989 			&& (eth_hdr->eth_8023v.h_snap.ctrl ==
1990 			WLAN_SNAP_CTRL)
1991 			&& (eth_hdr->eth_8023v.h_proto ==
1992 			htons(ETH_P_IP))) {
1993 			/* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */
1994 			ip_hdr =
1995 				(struct iphdr *)
1996 				&pkt[sizeof(eth_hdr->eth_8023v)];
1997 			tos = ip_hdr->tos;
1998 #ifdef HDD_WMM_DEBUG
1999 			hdd_debug("802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
2000 				 tos);
2001 #endif /* HDD_WMM_DEBUG */
2002 		} else {
2003 			/* default */
2004 #ifdef HDD_WMM_DEBUG
2005 			hdd_warn("VLAN tagged Unhandled Protocol, using default tos");
2006 #endif /* HDD_WMM_DEBUG */
2007 			tos = 0;
2008 		}
2009 	} else {
2010 		/* default */
2011 #ifdef HDD_WMM_DEBUG
2012 		hdd_warn("Unhandled Protocol, using default tos");
2013 #endif /* HDD_WMM_DEBUG */
2014 		/* Give the highest priority to 802.1x packet */
2015 		if (eth_hdr->eth_II.h_proto ==
2016 			htons(HDD_ETHERTYPE_802_1_X)) {
2017 			tos = 0xC0;
2018 		} else
2019 			tos = 0;
2020 	}
2021 
2022 	dscp = (tos >> 2) & 0x3f;
2023 	if (hdd_wmm_traffic_end_indication_is_enable(adapter)) {
2024 		psoc = adapter->hdd_ctx->psoc;
2025 		ucfg_dp_traffic_end_indication_update_dscp(
2026 				psoc, adapter->deflink->vdev_id, &dscp);
2027 	}
2028 	*user_pri = adapter->dscp_to_up_map[dscp];
2029 
2030 #ifdef HDD_WMM_DEBUG
2031 	hdd_debug("tos is %d, dscp is %d, up is %d", tos, dscp, *user_pri);
2032 #endif /* HDD_WMM_DEBUG */
2033 }
2034 
2035 /**
2036  * hdd_wmm_classify_pkt() - Function to classify skb into WMM AC based on DSCP
2037  *
2038  * @adapter: adapter upon which the packet is being transmitted
2039  * @skb: pointer to network buffer
2040  * @user_pri: user priority of the OS packet
2041  * @is_critical: pointer to be marked true for a critical packet
2042  *
2043  * Function checks if the packet is one of the critical packets and determines
2044  * 'user_pri' for it. Else it uses IP TOS value to determine 'user_pri'.
2045  * It is the responsibility of caller to set the user_pri to skb->priority.
2046  * Return: None
2047  */
2048 static
hdd_wmm_classify_pkt(struct hdd_adapter * adapter,struct sk_buff * skb,enum sme_qos_wmmuptype * user_pri,bool * is_critical)2049 void hdd_wmm_classify_pkt(struct hdd_adapter *adapter,
2050 			  struct sk_buff *skb,
2051 			  enum sme_qos_wmmuptype *user_pri,
2052 			  bool *is_critical)
2053 {
2054 	hdd_wmm_classify_critical_pkt(skb, user_pri, is_critical);
2055 
2056 	if (false == *is_critical) {
2057 		hdd_wmm_get_user_priority_from_ip_tos(adapter, skb, user_pri);
2058 		hdd_check_and_upgrade_udp_qos(adapter, skb, user_pri);
2059 	}
2060 }
2061 
2062 #ifdef QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES
hdd_wmm_classify_pkt_cb(void * adapter,struct sk_buff * skb)2063 void hdd_wmm_classify_pkt_cb(void *adapter,
2064 			     struct sk_buff *skb)
2065 {
2066 	enum sme_qos_wmmuptype user_pri = SME_QOS_WMM_UP_BE;
2067 	bool is_critical = false;
2068 
2069 	hdd_wmm_classify_critical_pkt(skb, &user_pri, &is_critical);
2070 
2071 	if (is_critical) {
2072 		skb->priority = user_pri;
2073 		QDF_NBUF_CB_TX_EXTRA_IS_CRITICAL(skb) = true;
2074 	}
2075 }
2076 #endif
2077 
2078 #ifdef TX_MULTIQ_PER_AC
2079 /**
2080  * hdd_get_tx_queue_for_ac() - Get the netdev tx queue index
2081  *  based on access category
2082  * @adapter: adapter upon which the packet is being transmitted
2083  * @skb: pointer to network buffer
2084  * @ac: access category
2085  *
2086  * Return: tx queue index
2087  */
2088 static
hdd_get_tx_queue_for_ac(struct hdd_adapter * adapter,struct sk_buff * skb,uint16_t ac)2089 uint16_t hdd_get_tx_queue_for_ac(struct hdd_adapter *adapter,
2090 				 struct sk_buff *skb, uint16_t ac)
2091 {
2092 	struct sock *sk = skb->sk;
2093 	int new_index;
2094 	int cpu = qdf_get_smp_processor_id();
2095 	struct hdd_tx_rx_stats *stats =
2096 				&adapter->deflink->hdd_stats.tx_rx_stats;
2097 
2098 	if (qdf_unlikely(ac == HDD_LINUX_AC_HI_PRIO))
2099 		return TX_GET_QUEUE_IDX(HDD_LINUX_AC_HI_PRIO, 0);
2100 
2101 	if (!sk) {
2102 		/*
2103 		 * Neither valid socket nor skb_hash so default to the
2104 		 * first queue for the access category.
2105 		 */
2106 		if (qdf_unlikely(!skb->sw_hash && !skb->l4_hash)) {
2107 			++stats->per_cpu[cpu].inv_sk_and_skb_hash;
2108 
2109 			return TX_GET_QUEUE_IDX(ac, 0);
2110 		}
2111 		++stats->per_cpu[cpu].qselect_existing_skb_hash;
2112 
2113 		return TX_GET_QUEUE_IDX(ac,
2114 					reciprocal_scale(skb->hash,
2115 							 TX_QUEUES_PER_AC));
2116 	}
2117 
2118 	if (sk->sk_tx_queue_mapping != NO_QUEUE_MAPPING &&
2119 	    sk->sk_tx_queue_mapping < NUM_TX_QUEUES) {
2120 		++stats->per_cpu[cpu].qselect_sk_tx_map;
2121 		return sk->sk_tx_queue_mapping;
2122 	}
2123 
2124 	++stats->per_cpu[cpu].qselect_skb_hash_calc;
2125 	new_index = TX_GET_QUEUE_IDX(ac,
2126 				     reciprocal_scale(skb_get_hash(skb),
2127 						      TX_QUEUES_PER_AC));
2128 
2129 	if (sk_fullsock(sk) && rcu_access_pointer(sk->sk_dst_cache))
2130 		sk_tx_queue_set(sk, new_index);
2131 
2132 	return new_index;
2133 }
2134 #else
2135 static inline
hdd_get_tx_queue_for_ac(struct hdd_adapter * adapter,struct sk_buff * skb,uint16_t ac)2136 uint16_t hdd_get_tx_queue_for_ac(struct hdd_adapter *adapter,
2137 				 struct sk_buff *skb, uint16_t ac) {
2138 	return ac;
2139 }
2140 #endif
2141 
2142 /**
2143  * __hdd_get_queue_index() - get queue index
2144  * @up: user priority
2145  *
2146  * Return: queue_index
2147  */
__hdd_get_queue_index(uint16_t up)2148 static uint16_t __hdd_get_queue_index(uint16_t up)
2149 {
2150 	if (qdf_unlikely(up >= ARRAY_SIZE(hdd_linux_up_to_ac_map)))
2151 		return HDD_LINUX_AC_BE;
2152 	return hdd_linux_up_to_ac_map[up];
2153 }
2154 
2155 #if defined(QCA_LL_TX_FLOW_CONTROL_V2) || \
2156 	defined(QCA_HL_NETDEV_FLOW_CONTROL) || \
2157 	defined(QCA_LL_PDEV_TX_FLOW_CONTROL)
2158 /**
2159  * hdd_get_queue_index() - get queue index
2160  * @up: user priority
2161  * @is_critical: is_critical flag
2162  *
2163  * Return: queue_index
2164  */
2165 static
hdd_get_queue_index(uint16_t up,bool is_critical)2166 uint16_t hdd_get_queue_index(uint16_t up, bool is_critical)
2167 {
2168 	if (qdf_unlikely(is_critical))
2169 		return HDD_LINUX_AC_HI_PRIO;
2170 	return __hdd_get_queue_index(up);
2171 }
2172 #else
2173 static
hdd_get_queue_index(uint16_t up,bool is_critical)2174 uint16_t hdd_get_queue_index(uint16_t up, bool is_critical)
2175 {
2176 	return __hdd_get_queue_index(up);
2177 }
2178 #endif
2179 
2180 #ifdef DP_TX_PACKET_INSPECT_FOR_ILP
2181 /**
2182  * hdd_update_pkt_priority_with_inspection() - update TX packets priority
2183  * @skb: network buffer
2184  * @up: user priority
2185  *
2186  * Update TX packets priority, if some special TX packets like TCP ack,
2187  * reuse skb->priority upper 8 bits(bit24 ~ 31) to mark them.
2188  *
2189  * Return: None
2190  */
2191 static inline
hdd_update_pkt_priority_with_inspection(struct sk_buff * skb,enum sme_qos_wmmuptype up)2192 void hdd_update_pkt_priority_with_inspection(struct sk_buff *skb,
2193 					     enum sme_qos_wmmuptype up)
2194 {
2195 	skb->priority = up;
2196 
2197 	if (qdf_unlikely(qdf_nbuf_is_ipv4_v6_pure_tcp_ack(skb)))
2198 		qdf_nbuf_set_priority_pkt_type(
2199 				skb, QDF_NBUF_PRIORITY_PKT_TCP_ACK);
2200 }
2201 #else
2202 static inline
hdd_update_pkt_priority_with_inspection(struct sk_buff * skb,enum sme_qos_wmmuptype up)2203 void hdd_update_pkt_priority_with_inspection(struct sk_buff *skb,
2204 					     enum sme_qos_wmmuptype up)
2205 {
2206 	skb->priority = up;
2207 }
2208 #endif
2209 
__hdd_wmm_select_queue(struct net_device * dev,struct sk_buff * skb)2210 static uint16_t __hdd_wmm_select_queue(struct net_device *dev,
2211 				       struct sk_buff *skb)
2212 {
2213 	enum sme_qos_wmmuptype up = SME_QOS_WMM_UP_BE;
2214 	uint16_t index;
2215 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2216 	bool is_critical = false;
2217 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2218 
2219 	if (qdf_unlikely(!hdd_ctx || cds_is_driver_transitioning())) {
2220 		hdd_debug_rl("driver is transitioning! Using default(BE) queue.");
2221 		skb->priority = SME_QOS_WMM_UP_BE;
2222 		return TX_GET_QUEUE_IDX(HDD_LINUX_AC_BE, 0);
2223 	}
2224 
2225 	/* Get the user priority from IP header */
2226 	hdd_wmm_classify_pkt(adapter, skb, &up, &is_critical);
2227 
2228 	hdd_update_pkt_priority_with_inspection(skb, up);
2229 
2230 	index = hdd_get_queue_index(up, is_critical);
2231 
2232 	return hdd_get_tx_queue_for_ac(adapter, skb, index);
2233 }
2234 
hdd_wmm_select_queue(struct net_device * dev,struct sk_buff * skb)2235 uint16_t hdd_wmm_select_queue(struct net_device *dev,
2236 			      struct sk_buff *skb)
2237 {
2238 	uint16_t q_index;
2239 
2240 	q_index = __hdd_wmm_select_queue(dev, skb);
2241 
2242 	return q_index;
2243 }
2244 
2245 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
hdd_select_queue(struct net_device * dev,struct sk_buff * skb,struct net_device * sb_dev)2246 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
2247 			  struct net_device *sb_dev)
2248 {
2249 	return hdd_wmm_select_queue(dev, skb);
2250 }
2251 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
hdd_select_queue(struct net_device * dev,struct sk_buff * skb,struct net_device * sb_dev,select_queue_fallback_t fallback)2252 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
2253 			  struct net_device *sb_dev,
2254 			  select_queue_fallback_t fallback)
2255 {
2256 	return hdd_wmm_select_queue(dev, skb);
2257 }
2258 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
hdd_select_queue(struct net_device * dev,struct sk_buff * skb,void * accel_priv,select_queue_fallback_t fallback)2259 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
2260 			  void *accel_priv, select_queue_fallback_t fallback)
2261 {
2262 	return hdd_wmm_select_queue(dev, skb);
2263 }
2264 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
hdd_select_queue(struct net_device * dev,struct sk_buff * skb,void * accel_priv)2265 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
2266 			  void *accel_priv)
2267 {
2268 	return hdd_wmm_select_queue(dev, skb);
2269 }
2270 #else
hdd_select_queue(struct net_device * dev,struct sk_buff * skb)2271 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb)
2272 {
2273 	return hdd_wmm_select_queue(dev, skb);
2274 }
2275 #endif
2276 
2277 
2278 /**
2279  * hdd_wmm_acquire_access_required() - Function which will determine
2280  * acquire admittance for a WMM AC is required or not based on psb configuration
2281  * done in framework
2282  *
2283  * @adapter: [in] pointer to adapter structure
2284  * @ac_type: [in] WMM AC type of OS packet
2285  *
2286  * Return: void
2287  */
hdd_wmm_acquire_access_required(struct hdd_adapter * adapter,sme_ac_enum_type ac_type)2288 void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter,
2289 				     sme_ac_enum_type ac_type)
2290 {
2291 	/* Each bit in the LSB nibble indicates 1 AC.
2292 	 * Clearing the particular bit in LSB nibble to indicate
2293 	 * access required
2294 	 */
2295 	switch (ac_type) {
2296 	case SME_AC_BK:
2297 		/* clear first bit */
2298 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK;
2299 		break;
2300 	case SME_AC_BE:
2301 		/* clear second bit */
2302 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK;
2303 		break;
2304 	case SME_AC_VI:
2305 		/* clear third bit */
2306 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK;
2307 		break;
2308 	case SME_AC_VO:
2309 		/* clear fourth bit */
2310 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK;
2311 		break;
2312 	default:
2313 		hdd_err("Invalid AC Type");
2314 		break;
2315 	}
2316 }
2317 
2318 /**
2319  * hdd_wmm_acquire_access() - Function which will attempt to acquire
2320  * admittance for a WMM AC
2321  *
2322  * @adapter: [in]  pointer to adapter context
2323  * @ac_type: [in]  WMM AC type of OS packet
2324  * @granted: [out] pointer to bool flag when indicates if access
2325  *	      has been granted or not
2326  *
2327  * Return: QDF_STATUS enumeration
2328  */
hdd_wmm_acquire_access(struct hdd_adapter * adapter,sme_ac_enum_type ac_type,bool * granted)2329 QDF_STATUS hdd_wmm_acquire_access(struct hdd_adapter *adapter,
2330 				  sme_ac_enum_type ac_type, bool *granted)
2331 {
2332 	struct hdd_wmm_qos_context *qos_context;
2333 	struct hdd_context *hdd_ctx;
2334 	/* The ini ImplicitQosIsEnabled is deprecated. By default, the ini
2335 	 * value is disabled. So, setting the variable is_implicit_qos_enabled
2336 	 * value to false.
2337 	 */
2338 	bool is_implicit_qos_enabled = false;
2339 
2340 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2341 
2342 	QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
2343 		  "%s: Entered for AC %d", __func__, ac_type);
2344 
2345 	if (!hdd_wmm_is_active(adapter) || !(is_implicit_qos_enabled) ||
2346 	    !adapter->hdd_wmm_status.ac_status[ac_type].is_access_required) {
2347 		/* either we don't want QoS or the AP doesn't support
2348 		 * QoS or we don't want to do implicit QoS
2349 		 */
2350 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
2351 			  "%s: QoS not configured on both ends ", __func__);
2352 
2353 		*granted =
2354 			adapter->hdd_wmm_status.ac_status[ac_type].
2355 			is_access_allowed;
2356 
2357 		return QDF_STATUS_SUCCESS;
2358 	}
2359 	/* do we already have an implicit QoS request pending for this AC? */
2360 	if ((adapter->hdd_wmm_status.ac_status[ac_type].is_access_needed) ||
2361 	    (adapter->hdd_wmm_status.ac_status[ac_type].is_access_pending)) {
2362 		/* request already pending so we need to wait for that
2363 		 * response
2364 		 */
2365 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
2366 			  "%s: Implicit QoS for TL AC %d already scheduled",
2367 			  __func__, ac_type);
2368 
2369 		*granted = false;
2370 		return QDF_STATUS_SUCCESS;
2371 	}
2372 	/* did we already fail to establish implicit QoS for this AC?
2373 	 * (if so, access should have been granted when the failure
2374 	 * was handled)
2375 	 */
2376 	if (adapter->hdd_wmm_status.ac_status[ac_type].has_access_failed) {
2377 		/* request previously failed
2378 		 * allow access, but we'll be downgraded
2379 		 */
2380 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
2381 			  "%s: Implicit QoS for TL AC %d previously failed",
2382 			  __func__, ac_type);
2383 
2384 		if (!adapter->hdd_wmm_status.ac_status[ac_type].
2385 		    is_access_required) {
2386 			adapter->hdd_wmm_status.ac_status[ac_type].
2387 			is_access_allowed = true;
2388 			*granted = true;
2389 		} else {
2390 			adapter->hdd_wmm_status.ac_status[ac_type].
2391 			is_access_allowed = false;
2392 			*granted = false;
2393 		}
2394 
2395 		return QDF_STATUS_SUCCESS;
2396 	}
2397 	/* we need to establish implicit QoS */
2398 	QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
2399 		  "%s: Need to schedule implicit QoS for TL AC %d, adapter is %pK",
2400 		  __func__, ac_type, adapter);
2401 
2402 	adapter->hdd_wmm_status.ac_status[ac_type].is_access_needed = true;
2403 
2404 	qos_context = qdf_mem_malloc(sizeof(*qos_context));
2405 	if (!qos_context) {
2406 		/* no memory for QoS context.  Nothing we can do but
2407 		 * let data flow
2408 		 */
2409 		adapter->hdd_wmm_status.ac_status[ac_type].is_access_allowed =
2410 			true;
2411 		*granted = true;
2412 		return QDF_STATUS_SUCCESS;
2413 	}
2414 
2415 	qos_context->ac_type = ac_type;
2416 	qos_context->adapter = adapter;
2417 	qos_context->flow_id = 0;
2418 	qos_context->handle = HDD_WMM_HANDLE_IMPLICIT;
2419 	qos_context->magic = HDD_WMM_CTX_MAGIC;
2420 	qos_context->is_inactivity_timer_running = false;
2421 
2422 	INIT_WORK(&qos_context->implicit_qos_work, hdd_wmm_do_implicit_qos);
2423 
2424 	QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
2425 		  "%s: Scheduling work for AC %d, context %pK",
2426 		  __func__, ac_type, qos_context);
2427 
2428 	schedule_work(&qos_context->implicit_qos_work);
2429 
2430 	/* caller will need to wait until the work takes place and
2431 	 * TSPEC negotiation completes
2432 	 */
2433 	*granted = false;
2434 	return QDF_STATUS_SUCCESS;
2435 }
2436 
hdd_wmm_assoc(struct hdd_adapter * adapter,bool is_reassoc,uint8_t uapsd_mask)2437 QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter,
2438 			 bool is_reassoc, uint8_t uapsd_mask)
2439 {
2440 	QDF_STATUS status;
2441 	uint32_t srv_value = 0;
2442 	uint32_t sus_value = 0;
2443 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2444 	uint32_t delayed_trgr_frm_int;
2445 
2446 	/* when we associate we need to notify TL if it needs to
2447 	 * enable UAPSD for any access categories
2448 	 */
2449 
2450 	hdd_enter();
2451 
2452 	if (is_reassoc) {
2453 		/* when we reassociate we should continue to use
2454 		 * whatever parameters were previously established.
2455 		 * if we are reassociating due to a U-APSD change for
2456 		 * a particular Access Category, then the change will
2457 		 * be communicated to HDD via the QoS callback
2458 		 * associated with the given flow, and U-APSD
2459 		 * parameters will be updated there
2460 		 */
2461 
2462 		hdd_debug("Reassoc so no work, Exiting");
2463 
2464 		return QDF_STATUS_SUCCESS;
2465 	}
2466 
2467 	hdd_debug("U-APSD mask is 0x%02x", (int)uapsd_mask);
2468 
2469 	ucfg_mlme_get_tl_delayed_trgr_frm_int(hdd_ctx->psoc,
2470 					      &delayed_trgr_frm_int);
2471 
2472 	if (uapsd_mask & HDD_AC_VO) {
2473 		status = ucfg_mlme_get_wmm_uapsd_vo_srv_intv(hdd_ctx->psoc,
2474 							     &srv_value);
2475 		if (QDF_IS_STATUS_ERROR(status)) {
2476 			hdd_err("Get uapsd_srv_intv failed");
2477 			return QDF_STATUS_SUCCESS;
2478 		}
2479 		status = ucfg_mlme_get_wmm_uapsd_vo_sus_intv(hdd_ctx->psoc,
2480 							     &sus_value);
2481 		if (QDF_IS_STATUS_ERROR(status)) {
2482 			hdd_err("Get uapsd_vo_sus_intv failed");
2483 			return QDF_STATUS_SUCCESS;
2484 		}
2485 
2486 		status = sme_enable_uapsd_for_ac(
2487 				SME_AC_VO, 7, 7, srv_value, sus_value,
2488 				SME_QOS_WMM_TS_DIR_BOTH, 1,
2489 				adapter->deflink->vdev_id,
2490 				delayed_trgr_frm_int);
2491 
2492 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
2493 	}
2494 
2495 	if (uapsd_mask & HDD_AC_VI) {
2496 		status = ucfg_mlme_get_wmm_uapsd_vi_srv_intv(
2497 			hdd_ctx->psoc, &srv_value);
2498 		if (!QDF_IS_STATUS_SUCCESS(status)) {
2499 			hdd_err("Get uapsd_vi_srv_intv failed");
2500 			return QDF_STATUS_SUCCESS;
2501 		}
2502 		status = ucfg_mlme_get_wmm_uapsd_vi_sus_intv(
2503 			hdd_ctx->psoc, &sus_value);
2504 		if (!QDF_IS_STATUS_SUCCESS(status)) {
2505 			hdd_err("Get uapsd_vi_sus_intv failed");
2506 			return QDF_STATUS_SUCCESS;
2507 		}
2508 
2509 		status = sme_enable_uapsd_for_ac(
2510 				SME_AC_VI, 5, 5, srv_value, sus_value,
2511 				SME_QOS_WMM_TS_DIR_BOTH, 1,
2512 				adapter->deflink->vdev_id,
2513 				delayed_trgr_frm_int);
2514 
2515 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
2516 	}
2517 
2518 	if (uapsd_mask & HDD_AC_BK) {
2519 		status = ucfg_mlme_get_wmm_uapsd_bk_srv_intv(hdd_ctx->psoc,
2520 							     &srv_value);
2521 		if (!QDF_IS_STATUS_SUCCESS(status)) {
2522 			hdd_err("Get uapsd_bk_srv_intv failed");
2523 			return QDF_STATUS_SUCCESS;
2524 		}
2525 		status = ucfg_mlme_get_wmm_uapsd_bk_sus_intv(hdd_ctx->psoc,
2526 							     &sus_value);
2527 		if (!QDF_IS_STATUS_SUCCESS(status)) {
2528 			hdd_err("Get uapsd_bk_sus_intv failed");
2529 			return QDF_STATUS_SUCCESS;
2530 		}
2531 
2532 		status = sme_enable_uapsd_for_ac(
2533 				SME_AC_BK, 2, 2, srv_value, sus_value,
2534 				SME_QOS_WMM_TS_DIR_BOTH, 1,
2535 				adapter->deflink->vdev_id,
2536 				delayed_trgr_frm_int);
2537 
2538 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
2539 	}
2540 
2541 	if (uapsd_mask & HDD_AC_BE) {
2542 		status = ucfg_mlme_get_wmm_uapsd_be_srv_intv(hdd_ctx->psoc,
2543 							     &srv_value);
2544 		if (!QDF_IS_STATUS_SUCCESS(status)) {
2545 			hdd_err("Get uapsd_be_srv_intv failed");
2546 			return QDF_STATUS_SUCCESS;
2547 		}
2548 		status = ucfg_mlme_get_wmm_uapsd_be_sus_intv(hdd_ctx->psoc,
2549 							     &sus_value);
2550 		if (!QDF_IS_STATUS_SUCCESS(status)) {
2551 			hdd_err("Get uapsd_be_sus_intv failed");
2552 			return QDF_STATUS_SUCCESS;
2553 		}
2554 
2555 		status = sme_enable_uapsd_for_ac(
2556 				SME_AC_BE, 3, 3, srv_value, sus_value,
2557 				SME_QOS_WMM_TS_DIR_BOTH, 1,
2558 				adapter->deflink->vdev_id,
2559 				delayed_trgr_frm_int);
2560 
2561 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
2562 	}
2563 
2564 	status = sme_update_dsc_pto_up_mapping(hdd_ctx->mac_handle,
2565 					       adapter->dscp_to_up_map,
2566 					       adapter->deflink->vdev_id);
2567 
2568 	if (!QDF_IS_STATUS_SUCCESS(status))
2569 		hdd_wmm_dscp_initial_state(adapter);
2570 
2571 	hdd_exit();
2572 
2573 	return QDF_STATUS_SUCCESS;
2574 }
2575 
2576 /**
2577  * hdd_wmm_connect() - Function which will handle the housekeeping
2578  * required by WMM when a connection is established
2579  *
2580  * @adapter : [in]  pointer to adapter context
2581  * @roam_info: [in]  pointer to roam information
2582  * @bss_type : [in]  type of BSS
2583  *
2584  * Return: QDF_STATUS enumeration
2585  */
hdd_wmm_connect(struct hdd_adapter * adapter,struct csr_roam_info * roam_info,eCsrRoamBssType bss_type)2586 QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter,
2587 			   struct csr_roam_info *roam_info,
2588 			   eCsrRoamBssType bss_type)
2589 {
2590 	int ac;
2591 	bool qap = true;
2592 	bool qos_connection = true;
2593 	uint8_t acm_mask = 0x0;
2594 
2595 	hdd_debug("qap is %d, qos_connection is %d, acm_mask is 0x%x",
2596 		 qap, qos_connection, acm_mask);
2597 
2598 	adapter->hdd_wmm_status.qap = qap;
2599 	adapter->hdd_wmm_status.qos_connection = qos_connection;
2600 
2601 	for (ac = 0; ac < WLAN_MAX_AC; ac++) {
2602 		/* admission is not required so access is allowed */
2603 		adapter->hdd_wmm_status.ac_status[ac].is_access_required = false;
2604 		adapter->hdd_wmm_status.ac_status[ac].is_access_allowed = true;
2605 	}
2606 
2607 	return QDF_STATUS_SUCCESS;
2608 }
2609 
2610 /**
2611  * hdd_wmm_is_active() - Function which will determine if WMM is
2612  * active on the current connection
2613  *
2614  * @adapter: [in]  pointer to adapter context
2615  *
2616  * Return: true if WMM is enabled, false if WMM is not enabled
2617  */
hdd_wmm_is_active(struct hdd_adapter * adapter)2618 bool hdd_wmm_is_active(struct hdd_adapter *adapter)
2619 {
2620 	if ((!adapter->hdd_wmm_status.qos_connection) ||
2621 	    (!adapter->hdd_wmm_status.qap)) {
2622 		return false;
2623 	} else {
2624 		return true;
2625 	}
2626 }
2627 
hdd_wmm_is_acm_allowed(uint8_t vdev_id)2628 bool hdd_wmm_is_acm_allowed(uint8_t vdev_id)
2629 {
2630 	struct hdd_adapter *adapter;
2631 	struct hdd_wmm_ac_status *wmm_ac_status;
2632 	struct hdd_context *hdd_ctx;
2633 	struct wlan_hdd_link_info *link_info;
2634 
2635 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2636 	if (!hdd_ctx)
2637 		return false;
2638 
2639 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
2640 	if (!link_info || hdd_validate_adapter(link_info->adapter))
2641 		return false;
2642 
2643 	adapter = link_info->adapter;
2644 	wmm_ac_status = adapter->hdd_wmm_status.ac_status;
2645 
2646 	if (hdd_wmm_is_active(adapter) &&
2647 	    !(wmm_ac_status[QCA_WLAN_AC_VI].is_access_allowed))
2648 		return false;
2649 	return true;
2650 }
2651 
hdd_wmm_addts(struct hdd_adapter * adapter,uint32_t handle,struct sme_qos_wmmtspecinfo * tspec)2652 hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter,
2653 				    uint32_t handle,
2654 				    struct sme_qos_wmmtspecinfo *tspec)
2655 {
2656 	struct hdd_wmm_qos_context *qos_context = NULL;
2657 	struct hdd_wmm_qos_context *cur_entry;
2658 	hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2659 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2660 	enum sme_qos_statustype sme_status;
2661 #endif
2662 	mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
2663 
2664 	hdd_debug("Entered with handle 0x%x", handle);
2665 
2666 	/* see if a context already exists with the given handle */
2667 	mutex_lock(&adapter->hdd_wmm_status.mutex);
2668 	list_for_each_entry(cur_entry,
2669 			    &adapter->hdd_wmm_status.context_list, node) {
2670 		if (cur_entry->handle == handle) {
2671 			qos_context = cur_entry;
2672 			break;
2673 		}
2674 	}
2675 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
2676 	if (qos_context) {
2677 		/* record with that handle already exists */
2678 		hdd_err("Record already exists with handle 0x%x", handle);
2679 
2680 		/* Application is trying to modify some of the Tspec
2681 		 * params. Allow it
2682 		 */
2683 		sme_status = sme_qos_modify_req(mac_handle,
2684 						tspec, qos_context->flow_id);
2685 
2686 		/* need to check the return value and act appropriately */
2687 		switch (sme_status) {
2688 		case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
2689 			status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING;
2690 			break;
2691 		case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2692 			status =
2693 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
2694 			break;
2695 		case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
2696 			status =
2697 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
2698 			break;
2699 		case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
2700 			status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
2701 			break;
2702 		case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
2703 			status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2704 			break;
2705 		case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2706 			status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2707 			break;
2708 		default:
2709 			/* we didn't get back one of the
2710 			 * SME_QOS_STATUS_MODIFY_* status codes
2711 			 */
2712 			hdd_err("unexpected SME Status=%d",
2713 				  sme_status);
2714 			QDF_ASSERT(0);
2715 			return HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2716 		}
2717 
2718 		/* we were successful, save the status */
2719 		mutex_lock(&adapter->hdd_wmm_status.mutex);
2720 		if (qos_context->magic == HDD_WMM_CTX_MAGIC)
2721 			qos_context->status = status;
2722 		mutex_unlock(&adapter->hdd_wmm_status.mutex);
2723 
2724 		return status;
2725 	}
2726 
2727 	qos_context = qdf_mem_malloc(sizeof(*qos_context));
2728 	if (!qos_context) {
2729 		/* no memory for QoS context.  Nothing we can do */
2730 		return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE;
2731 	}
2732 	/* we assume the tspec has already been validated by the caller */
2733 
2734 	qos_context->handle = handle;
2735 	if (tspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE)
2736 		qos_context->ac_type = hdd_wmm_up_to_ac_map[tspec->ts_info.up];
2737 	else {
2738 		hdd_err("ts_info.up (%d) larger than max value (%d), use default ac_type (%d)",
2739 			tspec->ts_info.up,
2740 			HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]);
2741 		qos_context->ac_type = hdd_wmm_up_to_ac_map[0];
2742 	}
2743 	qos_context->adapter = adapter;
2744 	qos_context->flow_id = 0;
2745 	qos_context->ts_id = tspec->ts_info.tid;
2746 	qos_context->magic = HDD_WMM_CTX_MAGIC;
2747 	qos_context->is_inactivity_timer_running = false;
2748 
2749 	hdd_debug("Setting up QoS, context %pK", qos_context);
2750 
2751 	mutex_lock(&adapter->hdd_wmm_status.mutex);
2752 	list_add(&qos_context->node, &adapter->hdd_wmm_status.context_list);
2753 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
2754 
2755 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2756 	sme_status = sme_qos_setup_req(mac_handle,
2757 				       adapter->deflink->vdev_id,
2758 				       tspec,
2759 				       hdd_wmm_sme_callback,
2760 				       qos_context,
2761 				       tspec->ts_info.up,
2762 				       &qos_context->flow_id);
2763 
2764 	hdd_debug("sme_qos_setup_req returned %d flowid %d",
2765 		   sme_status, qos_context->flow_id);
2766 
2767 	/* need to check the return value and act appropriately */
2768 	switch (sme_status) {
2769 	case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
2770 		status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2771 		break;
2772 	case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2773 		status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
2774 		break;
2775 	case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
2776 		status =
2777 			HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
2778 		break;
2779 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
2780 		status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2781 		break;
2782 	case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
2783 		/* disable the inactivity timer */
2784 		hdd_wmm_disable_inactivity_timer(qos_context);
2785 		hdd_wmm_free_context(qos_context);
2786 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
2787 	case SME_QOS_STATUS_SETUP_FAILURE_RSP:
2788 		/* disable the inactivity timer */
2789 		hdd_wmm_disable_inactivity_timer(qos_context);
2790 		/* we can't tell the difference between when a request
2791 		 * fails because AP rejected it versus when SME
2792 		 * encountered an internal error
2793 		 */
2794 		hdd_wmm_free_context(qos_context);
2795 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2796 	case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2797 		/* disable the inactivity timer */
2798 		hdd_wmm_disable_inactivity_timer(qos_context);
2799 		hdd_wmm_free_context(qos_context);
2800 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2801 	default:
2802 		/* disable the inactivity timer */
2803 		hdd_wmm_disable_inactivity_timer(qos_context);
2804 		/* we didn't get back one of the
2805 		 * SME_QOS_STATUS_SETUP_* status codes
2806 		 */
2807 		hdd_wmm_free_context(qos_context);
2808 		hdd_err("unexpected SME Status=%d", sme_status);
2809 		QDF_ASSERT(0);
2810 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2811 	}
2812 #endif
2813 
2814 	/* we were successful, save the status */
2815 	mutex_lock(&adapter->hdd_wmm_status.mutex);
2816 	if (qos_context->magic == HDD_WMM_CTX_MAGIC)
2817 		qos_context->status = status;
2818 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
2819 
2820 	return status;
2821 }
2822 
2823 /**
2824  * hdd_wmm_delts() - Function which will delete a traffic spec at the
2825  * request of an application
2826  *
2827  * @adapter: [in]  pointer to adapter context
2828  * @handle: [in]  handle to uniquely identify a TS
2829  *
2830  * Return: HDD_WLAN_WMM_STATUS_*
2831  */
hdd_wmm_delts(struct hdd_adapter * adapter,uint32_t handle)2832 hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter,
2833 				    uint32_t handle)
2834 {
2835 	struct hdd_wmm_qos_context *qos_context = NULL;
2836 	struct hdd_wmm_qos_context *cur_entry;
2837 	sme_ac_enum_type ac_type = 0;
2838 	uint32_t flow_id = 0;
2839 	hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2840 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2841 	enum sme_qos_statustype sme_status;
2842 	mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
2843 #endif
2844 
2845 	hdd_debug("Entered with handle 0x%x", handle);
2846 
2847 	/* locate the context with the given handle */
2848 	mutex_lock(&adapter->hdd_wmm_status.mutex);
2849 	list_for_each_entry(cur_entry,
2850 			    &adapter->hdd_wmm_status.context_list, node) {
2851 		if (cur_entry->handle == handle) {
2852 			qos_context = cur_entry;
2853 			break;
2854 		}
2855 	}
2856 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
2857 
2858 	if (!qos_context) {
2859 		/* we didn't find the handle, tid is already freed */
2860 		hdd_info("tid already freed for handle 0x%x", handle);
2861 		return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
2862 	}
2863 
2864 	ac_type = qos_context->ac_type;
2865 	flow_id = qos_context->flow_id;
2866 
2867 	hdd_debug("found handle 0x%x, flow %d, AC %d",
2868 		 handle, flow_id, ac_type);
2869 
2870 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2871 	sme_status = sme_qos_release_req(mac_handle, adapter->deflink->vdev_id,
2872 					 flow_id);
2873 
2874 	hdd_debug("SME flow %d released, SME status %d", flow_id, sme_status);
2875 
2876 	switch (sme_status) {
2877 	case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
2878 		/* this flow is the only one on that AC, so go ahead
2879 		 * and update our TSPEC state for the AC
2880 		 */
2881 		adapter->hdd_wmm_status.ac_status[ac_type].is_tspec_valid =
2882 			false;
2883 		adapter->hdd_wmm_status.ac_status[ac_type].is_access_allowed =
2884 			false;
2885 
2886 		/* need to tell TL to stop trigger timer, etc */
2887 		hdd_wmm_disable_tl_uapsd(qos_context);
2888 
2889 		/* disable the inactivity timer */
2890 		hdd_wmm_disable_inactivity_timer(qos_context);
2891 
2892 		/* we are done with this context */
2893 		hdd_wmm_free_context(qos_context);
2894 
2895 		/* SME must not fire any more callbacks for this flow
2896 		 * since the context is no longer valid
2897 		 */
2898 
2899 		return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
2900 
2901 	case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
2902 		/* do nothing as we will get a response from SME */
2903 		status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING;
2904 		break;
2905 
2906 	case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
2907 		/* nothing we can do with the existing flow except leave it */
2908 		status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2909 		break;
2910 
2911 	case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
2912 		/* nothing we can do with the existing flow except leave it */
2913 		status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2914 		break;
2915 
2916 	default:
2917 		/* we didn't get back one of the
2918 		 * SME_QOS_STATUS_RELEASE_* status codes
2919 		 */
2920 		hdd_err("unexpected SME Status=%d", sme_status);
2921 		QDF_ASSERT(0);
2922 		status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2923 	}
2924 
2925 #endif
2926 	mutex_lock(&adapter->hdd_wmm_status.mutex);
2927 	if (qos_context->magic == HDD_WMM_CTX_MAGIC)
2928 		qos_context->status = status;
2929 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
2930 
2931 	return status;
2932 }
2933 
2934 /**
2935  * hdd_wmm_checkts() - Function which will return the status of a traffic
2936  * spec at the request of an application
2937  *
2938  * @adapter: [in]  pointer to adapter context
2939  * @handle: [in]  handle to uniquely identify a TS
2940  *
2941  * Return: HDD_WLAN_WMM_STATUS_*
2942  */
hdd_wmm_checkts(struct hdd_adapter * adapter,uint32_t handle)2943 hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter, uint32_t handle)
2944 {
2945 	struct hdd_wmm_qos_context *qos_context;
2946 	hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST;
2947 
2948 	hdd_debug("Entered with handle 0x%x", handle);
2949 
2950 	/* locate the context with the given handle */
2951 	mutex_lock(&adapter->hdd_wmm_status.mutex);
2952 	list_for_each_entry(qos_context,
2953 			    &adapter->hdd_wmm_status.context_list, node) {
2954 		if (qos_context->handle == handle) {
2955 			hdd_debug("found handle 0x%x, context %pK",
2956 				 handle, qos_context);
2957 
2958 			status = qos_context->status;
2959 			break;
2960 		}
2961 	}
2962 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
2963 	return status;
2964 }
2965 
2966 /**
2967  * hdd_get_handle_from_ts_id() - get handle from ts id
2968  * @adapter : hdd adapter
2969  * @ts_id: ts_id
2970  * @del_tspec_handle: handle to delete the request
2971  *
2972  * Return: None
2973  */
2974 static void
hdd_get_handle_from_ts_id(struct hdd_adapter * adapter,uint8_t ts_id,uint32_t * del_tspec_handle)2975 hdd_get_handle_from_ts_id(struct hdd_adapter *adapter, uint8_t ts_id,
2976 			  uint32_t *del_tspec_handle)
2977 {
2978 	struct hdd_wmm_qos_context *cur_entry;
2979 
2980 	hdd_debug("Entered with ts_id 0x%x", ts_id);
2981 
2982 	mutex_lock(&adapter->hdd_wmm_status.mutex);
2983 	list_for_each_entry(cur_entry,
2984 			    &adapter->hdd_wmm_status.context_list, node) {
2985 		if (cur_entry->ts_id == ts_id) {
2986 			*del_tspec_handle = cur_entry->handle;
2987 			break;
2988 		}
2989 	}
2990 	mutex_unlock(&adapter->hdd_wmm_status.mutex);
2991 }
2992 
2993 /**
2994  * __wlan_hdd_cfg80211_config_tspec() - config tspec
2995  * @wiphy: pointer to wireless wiphy structure.
2996  * @wdev: pointer to wireless_dev structure.
2997  * @data: pointer to config tspec command parameters.
2998  * @data_len: the length in byte of config tspec command parameters.
2999  *
3000  * Return: An error code or 0 on success.
3001  */
__wlan_hdd_cfg80211_config_tspec(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3002 static int __wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy,
3003 					    struct wireless_dev *wdev,
3004 					    const void *data,
3005 					    int data_len)
3006 {
3007 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
3008 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3009 	struct sme_qos_wmmtspecinfo tspec;
3010 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1];
3011 	uint8_t oper, ts_id;
3012 	static uint32_t add_tspec_handle = MIN_HANDLE_VALUE;
3013 	uint32_t del_tspec_handle = 0;
3014 	hdd_wlan_wmm_status_e status;
3015 	int ret;
3016 
3017 	hdd_enter_dev(wdev->netdev);
3018 
3019 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3020 		hdd_err("Command not allowed in FTM mode");
3021 		return -EPERM;
3022 	}
3023 
3024 	ret = wlan_hdd_validate_context(hdd_ctx);
3025 	if (ret != 0)
3026 		return ret;
3027 
3028 	ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX,
3029 				      data, data_len, config_tspec_policy);
3030 	if (ret) {
3031 		hdd_err_rl("Invalid ATTR");
3032 		return -EINVAL;
3033 	}
3034 
3035 	if (!tb[CONFIG_TSPEC_OPERATION] || !tb[CONFIG_TSPEC_TSID]) {
3036 		hdd_err_rl("Mandatory attributes are not present");
3037 		return -EINVAL;
3038 	}
3039 
3040 	memset(&tspec, 0, sizeof(tspec));
3041 
3042 	oper = nla_get_u8(tb[CONFIG_TSPEC_OPERATION]);
3043 	ts_id = nla_get_u8(tb[CONFIG_TSPEC_TSID]);
3044 
3045 	switch (oper) {
3046 	case QCA_WLAN_TSPEC_ADD:
3047 
3048 		tspec.ts_info.tid = ts_id;
3049 
3050 		/* Mandatory attributes */
3051 		if (tb[CONFIG_TSPEC_DIRECTION]) {
3052 			uint8_t direction = nla_get_u8(
3053 						    tb[CONFIG_TSPEC_DIRECTION]);
3054 
3055 			switch (direction) {
3056 			case QCA_WLAN_TSPEC_DIRECTION_UPLINK:
3057 				tspec.ts_info.direction =
3058 						SME_QOS_WMM_TS_DIR_UPLINK;
3059 				break;
3060 			case QCA_WLAN_TSPEC_DIRECTION_DOWNLINK:
3061 				tspec.ts_info.direction =
3062 						SME_QOS_WMM_TS_DIR_DOWNLINK;
3063 				break;
3064 			case QCA_WLAN_TSPEC_DIRECTION_BOTH:
3065 				tspec.ts_info.direction =
3066 						SME_QOS_WMM_TS_DIR_BOTH;
3067 				break;
3068 			default:
3069 				hdd_err_rl("Invalid direction %d", direction);
3070 				return -EINVAL;
3071 			}
3072 		} else {
3073 			hdd_err_rl("Direction is not present");
3074 			return -EINVAL;
3075 		}
3076 
3077 		if (tb[CONFIG_TSPEC_APSD])
3078 			tspec.ts_info.psb = 1;
3079 
3080 		if (tb[CONFIG_TSPEC_ACK_POLICY]) {
3081 			uint8_t ack_policy = nla_get_u8(
3082 						   tb[CONFIG_TSPEC_ACK_POLICY]);
3083 
3084 			switch (ack_policy) {
3085 			case QCA_WLAN_TSPEC_NORMAL_ACK:
3086 				tspec.ts_info.ack_policy =
3087 					SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
3088 				break;
3089 			case QCA_WLAN_TSPEC_BLOCK_ACK:
3090 				tspec.ts_info.ack_policy =
3091 			       SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
3092 				break;
3093 			default:
3094 				hdd_err_rl("Invalid ack policy %d", ack_policy);
3095 				return -EINVAL;
3096 			}
3097 		} else {
3098 			hdd_err_rl("ACK policy is not present");
3099 			return -EINVAL;
3100 		}
3101 
3102 		if (tb[CONFIG_TSPEC_NOMINAL_MSDU_SIZE]) {
3103 			tspec.nominal_msdu_size = nla_get_u16(
3104 					    tb[CONFIG_TSPEC_NOMINAL_MSDU_SIZE]);
3105 		} else {
3106 			hdd_err_rl("Nominal msdu size is not present");
3107 			return -EINVAL;
3108 		}
3109 
3110 		if (tb[CONFIG_TSPEC_MAXIMUM_MSDU_SIZE]) {
3111 			tspec.maximum_msdu_size = nla_get_u16(
3112 					    tb[CONFIG_TSPEC_MAXIMUM_MSDU_SIZE]);
3113 		} else {
3114 			hdd_err_rl("Maximum msdu size is not present");
3115 			return -EINVAL;
3116 		}
3117 
3118 		if (tb[CONFIG_TSPEC_MIN_SERVICE_INTERVAL]) {
3119 			tspec.min_service_interval = nla_get_u32(
3120 					 tb[CONFIG_TSPEC_MIN_SERVICE_INTERVAL]);
3121 		} else {
3122 			hdd_err_rl("Min service interval is not present");
3123 			return -EINVAL;
3124 		}
3125 
3126 		if (tb[CONFIG_TSPEC_MAX_SERVICE_INTERVAL]) {
3127 			tspec.max_service_interval = nla_get_u32(
3128 					 tb[CONFIG_TSPEC_MAX_SERVICE_INTERVAL]);
3129 		} else {
3130 			hdd_err_rl("Max service interval is not present");
3131 			return -EINVAL;
3132 		}
3133 
3134 		if (tb[CONFIG_TSPEC_INACTIVITY_INTERVAL]) {
3135 			tspec.inactivity_interval = nla_get_u32(
3136 					  tb[CONFIG_TSPEC_INACTIVITY_INTERVAL]);
3137 		} else {
3138 			hdd_err_rl("Inactivity interval is not present");
3139 			return -EINVAL;
3140 		}
3141 
3142 		if (tb[CONFIG_TSPEC_SUSPENSION_INTERVAL]) {
3143 			tspec.suspension_interval = nla_get_u32(
3144 					  tb[CONFIG_TSPEC_SUSPENSION_INTERVAL]);
3145 		} else {
3146 			hdd_err_rl("Suspension interval is not present");
3147 			return -EINVAL;
3148 		}
3149 
3150 		if (tb[CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE]) {
3151 			tspec.surplus_bw_allowance = nla_get_u16(
3152 				  tb[CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE]);
3153 		} else {
3154 			hdd_err_rl("Surplus bw allowance is not present");
3155 			return -EINVAL;
3156 		}
3157 
3158 		/* Optional attributes */
3159 		if (tb[CONFIG_TSPEC_USER_PRIORITY])
3160 			tspec.ts_info.up = nla_get_u8(
3161 						tb[CONFIG_TSPEC_USER_PRIORITY]);
3162 
3163 		if (tb[CONFIG_TSPEC_MINIMUM_DATA_RATE])
3164 			tspec.min_data_rate = nla_get_u32(
3165 					    tb[CONFIG_TSPEC_MINIMUM_DATA_RATE]);
3166 
3167 		if (tb[CONFIG_TSPEC_MEAN_DATA_RATE])
3168 			tspec.mean_data_rate = nla_get_u32(
3169 					       tb[CONFIG_TSPEC_MEAN_DATA_RATE]);
3170 
3171 		if (tb[CONFIG_TSPEC_PEAK_DATA_RATE])
3172 			tspec.peak_data_rate = nla_get_u32(
3173 					       tb[CONFIG_TSPEC_PEAK_DATA_RATE]);
3174 
3175 		if (tb[CONFIG_TSPEC_BURST_SIZE])
3176 			tspec.max_burst_size = nla_get_u32(
3177 						   tb[CONFIG_TSPEC_BURST_SIZE]);
3178 
3179 		if (tspec.max_burst_size)
3180 			tspec.ts_info.burst_size_defn = 1;
3181 
3182 		if (tb[CONFIG_TSPEC_MINIMUM_PHY_RATE])
3183 			tspec.min_phy_rate = nla_get_u32(
3184 					     tb[CONFIG_TSPEC_MINIMUM_PHY_RATE]);
3185 		/*
3186 		 * ts_id send by upper layer is always same as handle and host
3187 		 * doesn't add new TS entry for same handle. To avoid this
3188 		 * issue host modifies handle internally.
3189 		 */
3190 		status = hdd_wmm_addts(adapter, add_tspec_handle, &tspec);
3191 		if (status == HDD_WLAN_WMM_STATUS_SETUP_FAILED ||
3192 		    status == HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM ||
3193 		    status == HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM ||
3194 		    status == HDD_WLAN_WMM_STATUS_MODIFY_FAILED ||
3195 		    status == HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM ||
3196 		    status == HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED ||
3197 		    status == HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED ||
3198 		    status == HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE) {
3199 			hdd_err_rl("hdd_wmm_addts failed %d", status);
3200 			return -EINVAL;
3201 		}
3202 
3203 		add_tspec_handle++;
3204 		if (add_tspec_handle >= MAX_HANDLE_VALUE)
3205 			add_tspec_handle = MIN_HANDLE_VALUE;
3206 		break;
3207 
3208 	case QCA_WLAN_TSPEC_DEL:
3209 		/*
3210 		 * Host modifies handle internally. So, always
3211 		 * delete the entry for provided ts_id.
3212 		 */
3213 		hdd_get_handle_from_ts_id(adapter, ts_id, &del_tspec_handle);
3214 		if (!del_tspec_handle) {
3215 			hdd_err_rl("ts_id is already freed %d", ts_id);
3216 			break;
3217 		}
3218 		status = hdd_wmm_delts(adapter, del_tspec_handle);
3219 		if (status == HDD_WLAN_WMM_STATUS_RELEASE_FAILED ||
3220 		    status == HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM ||
3221 		    status == HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE) {
3222 			hdd_err_rl("hdd_wmm_delts failed %d", status);
3223 			return -EINVAL;
3224 		}
3225 		break;
3226 
3227 	case QCA_WLAN_TSPEC_GET:
3228 
3229 		status = hdd_wmm_checkts(adapter, ts_id);
3230 		if (status == HDD_WLAN_WMM_STATUS_LOST ||
3231 		    status == HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE) {
3232 			hdd_err_rl("hdd_wmm_checkts failed %d", status);
3233 			return -EINVAL;
3234 		}
3235 		break;
3236 
3237 	default:
3238 		hdd_err_rl("Invalid operation %d", oper);
3239 		return -EINVAL;
3240 	}
3241 
3242 	hdd_exit();
3243 
3244 	return 0;
3245 }
3246 
wlan_hdd_cfg80211_config_tspec(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3247 int wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy,
3248 				   struct wireless_dev *wdev,
3249 				   const void *data, int data_len)
3250 {
3251 	int errno;
3252 	struct osif_vdev_sync *vdev_sync;
3253 
3254 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3255 	if (errno)
3256 		return errno;
3257 
3258 	errno = __wlan_hdd_cfg80211_config_tspec(wiphy, wdev, data, data_len);
3259 
3260 	osif_vdev_sync_op_stop(vdev_sync);
3261 
3262 	return errno;
3263 }
3264