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