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