1 /*
2 * Copyright (c) 2011-2012,2016-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #ifndef _WLAN_HDD_WMM_H
21 #define _WLAN_HDD_WMM_H
22
23 /**
24 * DOC: HDD WMM
25 *
26 * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation)
27 * houses all the logic for WMM in HDD.
28 *
29 * On the control path, it has the logic to setup QoS, modify QoS and delete
30 * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an
31 * explicit application invoked and an internal HDD invoked. The implicit QoS
32 * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but
33 * which DO mark their traffic for priortization. It also has logic to start,
34 * update and stop the U-APSD trigger frame generation. It also has logic to
35 * read WMM related config parameters from the registry.
36 *
37 * On the data path, it has the logic to figure out the WMM AC of an egress
38 * packet and when to signal TL to serve a particular AC queue. It also has the
39 * logic to retrieve a packet based on WMM priority in response to a fetch from
40 * TL.
41 *
42 * The remaining functions are utility functions for information hiding.
43 */
44
45 /* Include files */
46 #include <linux/workqueue.h>
47 #include <linux/list.h>
48 #include <wlan_hdd_main.h>
49 #include <wlan_hdd_wext.h>
50 #include <sme_qos_api.h>
51 #include <qca_vendor.h>
52
53 /*Maximum number of ACs */
54 #define WLAN_MAX_AC 4
55
56
57 /* Preprocessor Definitions and Constants */
58
59 /* #define HDD_WMM_DEBUG 1 */
60
61 #define HDD_WMM_CTX_MAGIC 0x574d4d58 /* "WMMX" */
62
63 #define HDD_WMM_HANDLE_IMPLICIT 0xFFFFFFFF
64
65 #define HDD_WLAN_INVALID_STA_ID 0xFF
66
67 /* Type Declarations */
68
69 /**
70 * enum hdd_wmm_user_mode - WMM modes of operation
71 *
72 * @HDD_WMM_USER_MODE_AUTO: STA can associate with any AP, & HDD looks at
73 * the SME notification after association to find out if associated
74 * with QAP and acts accordingly
75 * @HDD_WMM_USER_MODE_QBSS_ONLY: SME will add the extra logic to make sure
76 * STA associates with a QAP only
77 * @HDD_WMM_USER_MODE_NO_QOS: Join any AP, but uapsd is disabled
78 */
79 enum hdd_wmm_user_mode {
80 HDD_WMM_USER_MODE_AUTO = 0,
81 HDD_WMM_USER_MODE_QBSS_ONLY = 1,
82 HDD_WMM_USER_MODE_NO_QOS = 2,
83 };
84
85 /* UAPSD Mask bits */
86 /* (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) */
87 #define HDD_AC_VO 0x1
88 #define HDD_AC_VI 0x2
89 #define HDD_AC_BK 0x4
90 #define HDD_AC_BE 0x8
91
92 /**
93 * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to
94 * operate on different traffic.
95 * @HDD_LINUX_AC_VO: voice priority
96 * @HDD_LINUX_AC_VI: video priority
97 * @HDD_LINUX_AC_BE: best effort priority
98 * @HDD_LINUX_AC_BK: background priority
99 * @HDD_LINUX_AC_HI_PRIO: unclassified high priority
100 */
101 enum hdd_wmm_linuxac {
102 HDD_LINUX_AC_VO = 0,
103 HDD_LINUX_AC_VI = 1,
104 HDD_LINUX_AC_BE = 2,
105 HDD_LINUX_AC_BK = 3,
106 HDD_LINUX_AC_HI_PRIO = 4,
107 };
108
109 /**
110 * struct hdd_wmm_qos_context - HDD WMM QoS Context
111 *
112 * This structure holds the context for a single flow which has either
113 * been configured explicitly from userspace or implicitly via the
114 * Implicit QoS feature.
115 *
116 * @node: list node which can be used to put the context into a list
117 * of contexts
118 * @handle: identifier which uniquely identifies this context to userspace
119 * @flow_id: identifier which uniquely identifies this flow to SME
120 * @adapter: adapter upon which this flow was configured
121 * @ac_type: access category for this flow
122 * @status: the status of the last operation performed on this flow by SME
123 * @implicit_qos_work: work structure used for deferring implicit QoS work
124 * from softirq context to thread context
125 * @magic: magic number used to verify that this is a valid context when
126 * referenced anonymously
127 * @is_inactivity_timer_running: true if inactivity timer is running
128 * @ts_id: identifier which gets used at time of DEL request
129 */
130 struct hdd_wmm_qos_context {
131 struct list_head node;
132 uint32_t handle;
133 uint32_t flow_id;
134 struct hdd_adapter *adapter;
135 sme_ac_enum_type ac_type;
136 hdd_wlan_wmm_status_e status;
137 struct work_struct implicit_qos_work;
138 uint32_t magic;
139 bool is_inactivity_timer_running;
140 uint8_t ts_id;
141 };
142
143 /**
144 * struct hdd_wmm_ac_status - WMM related per-AC state & status info
145 * @is_access_required: does the AP require access to this AC?
146 * @is_access_needed: does the worker thread need to acquire access to
147 * this AC?
148 * @is_access_pending: is implicit QoS negotiation currently taking place?
149 * @has_access_failed: has implicit QoS negotiation already failed?
150 * @was_access_granted: has implicit QoS negotiation already succeeded?
151 * @is_access_allowed: is access to this AC allowed, either because we
152 * are not doing WMM, we are not doing implicit QoS, implicit QoS has
153 * completed, or explicit QoS has completed?
154 * @is_tspec_valid: is the tspec valid?
155 * @is_uapsd_info_valid: are the UAPSD-related fields valid?
156 * @tspec: current (possibly aggregate) Tspec for this AC
157 * @is_uapsd_enabled: is UAPSD enabled on this AC?
158 * @uapsd_service_interval: service interval for this AC
159 * @uapsd_suspension_interval: suspension interval for this AC
160 * @uapsd_direction: direction for this AC
161 * @inactivity_time: inactivity time for this AC
162 * @last_traffic_count: TX counter used for inactivity detection
163 * @inactivity_timer: timer used for inactivity detection
164 */
165 struct hdd_wmm_ac_status {
166 bool is_access_required;
167 bool is_access_needed;
168 bool is_access_pending;
169 bool has_access_failed;
170 bool was_access_granted;
171 bool is_access_allowed;
172 bool is_tspec_valid;
173 bool is_uapsd_info_valid;
174 struct sme_qos_wmmtspecinfo tspec;
175 bool is_uapsd_enabled;
176 uint32_t uapsd_service_interval;
177 uint32_t uapsd_suspension_interval;
178 enum sme_qos_wmm_dir_type uapsd_direction;
179
180 #ifdef FEATURE_WLAN_ESE
181 uint32_t inactivity_time;
182 uint32_t last_traffic_count;
183 qdf_mc_timer_t inactivity_timer;
184 #endif
185 };
186
187 /**
188 * struct hdd_wmm_status - WMM status maintained per-adapter
189 * @context_list: list of WMM contexts active on the adapter
190 * @mutex: mutex used for exclusive access to this adapter's WMM status
191 * @ac_status: per-AC WMM status
192 * @qap: is this connected to a QoS-enabled AP?
193 * @qos_connection: is this a QoS connection?
194 */
195 struct hdd_wmm_status {
196 struct list_head context_list;
197 struct mutex mutex;
198 struct hdd_wmm_ac_status ac_status[WLAN_MAX_AC];
199 bool qap;
200 bool qos_connection;
201 };
202
203 extern const uint8_t hdd_qdisc_ac_to_tl_ac[];
204 extern const uint8_t hdd_wmm_up_to_ac_map[];
205 extern const uint8_t hdd_linux_up_to_ac_map[];
206
207 /**
208 * hdd_wmmps_helper() - Function to set uapsd psb dynamically
209 *
210 * @adapter: [in] pointer to adapter structure
211 * @ptr: [in] pointer to command buffer
212 *
213 * Return: Zero on success, appropriate error on failure.
214 */
215 int hdd_wmmps_helper(struct hdd_adapter *adapter, uint8_t *ptr);
216
217 /**
218 * hdd_send_dscp_up_map_to_fw() - send dscp to up map to FW
219 * @adapter : [in] pointer to Adapter context
220 *
221 * This function will send the WMM DSCP configuration of an
222 * adapter to FW.
223 *
224 * Return: QDF_STATUS enumeration
225 */
226 QDF_STATUS hdd_send_dscp_up_map_to_fw(struct hdd_adapter *adapter);
227
228 /**
229 * hdd_wmm_dscp_initial_state() - initialize the WMM DSCP configuration
230 * @adapter : [in] pointer to Adapter context
231 *
232 * This function will initialize the WMM DSCP configuration of an
233 * adapter to an initial state. The configuration can later be
234 * overwritten via application APIs or via QoS Map sent OTA.
235 *
236 * Return: QDF_STATUS enumeration
237 */
238 QDF_STATUS hdd_wmm_dscp_initial_state(struct hdd_adapter *adapter);
239
240 /**
241 * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter
242 * @adapter: [in] pointer to Adapter context
243 *
244 * This function will initialize the WMM configuration and status of an
245 * adapter to an initial state. The configuration can later be
246 * overwritten via application APIs
247 *
248 * Return: QDF_STATUS enumeration
249 */
250 QDF_STATUS hdd_wmm_adapter_init(struct hdd_adapter *adapter);
251
252 /**
253 * hdd_wmm_adapter_close() - WMM close function
254 * @adapter: [in] pointer to adapter context
255 *
256 * Function which will perform any necessary work to to clean up the
257 * WMM functionality prior to the kernel module unload.
258 *
259 * Return: QDF_STATUS enumeration
260 */
261 QDF_STATUS hdd_wmm_adapter_close(struct hdd_adapter *adapter);
262
263 /**
264 * hdd_select_queue() - Return queue to be used.
265 * @dev: Pointer to the WLAN device.
266 * @skb: Pointer to OS packet (sk_buff).
267 * @sb_dev: Pointer to subordinate device (unused)
268 *
269 * This function is registered with the Linux OS for network
270 * core to decide which queue to use for the skb.
271 *
272 * Return: Qdisc queue index.
273 */
274 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
275 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
276 struct net_device *sb_dev);
277 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
278 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
279 struct net_device *sb_dev,
280 select_queue_fallback_t fallback);
281 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
282 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
283 void *accel_priv, select_queue_fallback_t fallback);
284 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
285 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
286 void *accel_priv);
287 #else
288 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb);
289 #endif
290
291 /**
292 * hdd_wmm_select_queue() - Function which will classify the packet
293 * according to linux qdisc expectation.
294 *
295 * @dev: [in] pointer to net_device structure
296 * @skb: [in] pointer to os packet
297 *
298 * Return: Qdisc queue index
299 */
300 uint16_t hdd_wmm_select_queue(struct net_device *dev,
301 struct sk_buff *skb);
302
303 /**
304 * hdd_wmm_acquire_access_required() - Function which will determine
305 * acquire admittance for a WMM AC is required or not based on psb configuration
306 * done in framework
307 *
308 * @adapter: [in] pointer to adapter structure
309 * @ac_type: [in] WMM AC type of OS packet
310 *
311 * Return: void
312 */
313 void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter,
314 sme_ac_enum_type ac_type);
315
316 /**
317 * hdd_wmm_acquire_access() - Function which will attempt to acquire
318 * admittance for a WMM AC
319 *
320 * @adapter: [in] pointer to adapter context
321 * @ac_type: [in] WMM AC type of OS packet
322 * @granted: [out] pointer to bool flag when indicates if access
323 * has been granted or not
324 *
325 * Return: QDF_STATUS enumeration
326 */
327 QDF_STATUS hdd_wmm_acquire_access(struct hdd_adapter *adapter,
328 sme_ac_enum_type ac_type, bool *granted);
329
330 /**
331 * hdd_wmm_assoc() - Function which will handle the housekeeping
332 * required by WMM when association takes place
333 *
334 * @adapter: pointer to adapter context
335 * @is_reassoc: is this reassoc scenario
336 * @uapsd_mask : Negotiated uapsd msk
337 *
338 * Return: QDF_STATUS enumeration
339 */
340 QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter,
341 bool is_reassoc, uint8_t uapsd_mask);
342
343 /**
344 * hdd_wmm_connect() - Function which will handle the housekeeping
345 * required by WMM when a connection is established
346 *
347 * @adapter : [in] pointer to adapter context
348 * @roam_info: [in] pointer to roam information
349 * @bss_type : [in] type of BSS
350 *
351 * Return: QDF_STATUS enumeration
352 */
353 QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter,
354 struct csr_roam_info *roam_info,
355 eCsrRoamBssType bss_type);
356
357 /**
358 * hdd_wmm_is_active() - Function which will determine if WMM is
359 * active on the current connection
360 *
361 * @adapter: [in] pointer to adapter context
362 *
363 * Return: true if WMM is enabled, false if WMM is not enabled
364 */
365 bool hdd_wmm_is_active(struct hdd_adapter *adapter);
366
367 /**
368 * hdd_wmm_is_acm_allowed() - Function which will determine if WMM is
369 * active on the current connection
370 *
371 * @vdev_id: vdev id
372 *
373 * Return: true if WMM is enabled, false if WMM is not enabled
374 */
375 bool hdd_wmm_is_acm_allowed(uint8_t vdev_id);
376
377
378 /**
379 * hdd_wmm_addts() - Function which will add a traffic spec at the
380 * request of an application
381 *
382 * @adapter : [in] pointer to adapter context
383 * @handle : [in] handle to uniquely identify a TS
384 * @tspec : [in] pointer to the traffic spec
385 *
386 * Return: HDD_WLAN_WMM_STATUS_*
387 */
388 hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter,
389 uint32_t handle,
390 struct sme_qos_wmmtspecinfo *tspec);
391
392 /**
393 * hdd_wmm_delts() - Function which will delete a traffic spec at the
394 * request of an application
395 *
396 * @adapter: [in] pointer to adapter context
397 * @handle: [in] handle to uniquely identify a TS
398 *
399 * Return: HDD_WLAN_WMM_STATUS_*
400 */
401 hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter,
402 uint32_t handle);
403
404 /**
405 * hdd_wmm_checkts() - Function which will return the status of a traffic
406 * spec at the request of an application
407 *
408 * @adapter: [in] pointer to adapter context
409 * @handle: [in] handle to uniquely identify a TS
410 *
411 * Return: HDD_WLAN_WMM_STATUS_*
412 */
413 hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter,
414 uint32_t handle);
415 /**
416 * hdd_wmm_adapter_clear() - Function which will clear the WMM status
417 * for all the ACs
418 *
419 * @adapter: [in] pointer to Adapter context
420 *
421 * Return: QDF_STATUS enumeration
422 */
423 QDF_STATUS hdd_wmm_adapter_clear(struct hdd_adapter *adapter);
424
425 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter);
426
427 extern const struct nla_policy
428 config_tspec_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1];
429
430 /**
431 * wlan_hdd_cfg80211_config_tspec() - config tpsec
432 * @wiphy: pointer to wireless wiphy structure.
433 * @wdev: pointer to wireless_dev structure.
434 * @data: pointer to config tspec command parameters.
435 * @data_len: the length in byte of config tspec command parameters.
436 *
437 * Return: An error code or 0 on success.
438 */
439 int wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy,
440 struct wireless_dev *wdev,
441 const void *data, int data_len);
442 #ifdef QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES
443 /**
444 * hdd_wmm_classify_pkt_cb() - Call back to identify critical packets
445 * @adapter: adapter for which callback is called
446 * @nbuf: skb for which callback is called
447 *
448 * Callback used by intrabss forwarding path to identify critical packets.
449 * QDF_NBUF_CB_TX_EXTRA_IS_CRITICAL is marked 1 for such packets.
450 * The function also populates sb->priority for these packets.
451 * skb->priority is used as TID for these frames during TX.
452 *
453 * Return: None
454 */
455 void hdd_wmm_classify_pkt_cb(void *adapter,
456 qdf_nbuf_t nbuf);
457 #else
458 static inline
hdd_wmm_classify_pkt_cb(void * adapter,qdf_nbuf_t nbuf)459 void hdd_wmm_classify_pkt_cb(void *adapter,
460 qdf_nbuf_t nbuf)
461 {
462 }
463 #endif
464
465 #define FEATURE_WMM_COMMANDS \
466 { \
467 .info.vendor_id = QCA_NL80211_VENDOR_ID, \
468 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC, \
469 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
470 WIPHY_VENDOR_CMD_NEED_NETDEV | \
471 WIPHY_VENDOR_CMD_NEED_RUNNING, \
472 .doit = wlan_hdd_cfg80211_config_tspec, \
473 vendor_command_policy(config_tspec_policy, \
474 QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX) \
475 },
476
477 #endif /* #ifndef _WLAN_HDD_WMM_H */
478