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