1 /*
2  * Copyright (c) 2020-2021, 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 any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: This file has main dcs structures definition.
20  */
21 
22 #ifndef _WLAN_DCS_H_
23 #define _WLAN_DCS_H_
24 
25 #include <wmi_unified_param.h>
26 #include "wlan_dcs_tgt_api.h"
27 #include "wlan_dcs_ucfg_api.h"
28 
29 #define dcs_debug(args ...) \
30 		QDF_TRACE_DEBUG(QDF_MODULE_ID_DCS, ## args)
31 #define dcs_info(args ...) \
32 		QDF_TRACE_INFO(QDF_MODULE_ID_DCS, ## args)
33 #define dcs_err(args ...) \
34 		QDF_TRACE_ERROR(QDF_MODULE_ID_DCS, ## args)
35 
36 #define WLAN_DCS_MAX_PDEVS 3
37 
38 #define DCS_TX_MAX_CU  30
39 #define MAX_DCS_TIME_RECORD 10
40 #define DCS_FREQ_CONTROL_TIME (5 * 60 * 1000)
41 
42 /**
43  * enum wlan_dcs_debug_level - dcs debug trace level
44  * @DCS_DEBUG_DISABLE: disable debug trace
45  * @DCS_DEBUG_CRITICAL: critical debug trace level
46  * @DCS_DEBUG_VERBOSE:  verbose debug trace level
47  */
48 enum wlan_dcs_debug_level {
49 	DCS_DEBUG_DISABLE = 0,
50 	DCS_DEBUG_CRITICAL = 1,
51 	DCS_DEBUG_VERBOSE = 2
52 };
53 
54 /**
55  * struct pdev_dcs_im_stats - define dcs interference mitigation
56  *                            stats in pdev object
57  * @prev_dcs_im_stats: previous statistics at last time
58  * @user_dcs_im_stats: statistics requested from userspace
59  * @dcs_ch_util_im_stats: chan utilization statistics
60  * @im_intfr_cnt: number of times the interference is
61  *                detected within detection window
62  * @im_samp_cnt: sample counter
63  */
64 struct pdev_dcs_im_stats {
65 	struct wlan_host_dcs_im_tgt_stats prev_dcs_im_stats;
66 	struct wlan_host_dcs_im_user_stats user_dcs_im_stats;
67 	struct wlan_host_dcs_ch_util_stats dcs_ch_util_im_stats;
68 	uint8_t im_intfr_cnt;
69 	uint8_t im_samp_cnt;
70 };
71 
72 /**
73  * struct pdev_dcs_params - define dcs configuration parameter in pdev object
74  * @dcs_enable_cfg: dcs enable from ini config
75  * @dcs_enable: dcs enable from ucfg config
76  * @dcs_algorithm_process: do dcs algorithm process or not
77  * @force_disable_algorithm: disable dcs algorithm forcely
78  * @dcs_debug: dcs debug trace level
79  * @phy_err_penalty: phy error penalty
80  * @phy_err_threshold: phy error threshold
81  * @radar_err_threshold: radar error threshold
82  * @coch_intfr_threshold: co-channel interference threshold
83  * @user_max_cu: tx channel utilization due to AP's tx and rx
84  * @intfr_detection_threshold: interference detection threshold
85  * @intfr_detection_window: interference sampling window
86  * @tx_err_threshold: transmission failure rate threshold
87  * @user_request_count: counter of stats requested from userspace
88  * @notify_user: whether to notify userspace
89  */
90 struct pdev_dcs_params {
91 	uint8_t dcs_enable_cfg;
92 	uint8_t dcs_enable;
93 	bool dcs_algorithm_process;
94 	bool force_disable_algorithm;
95 	enum wlan_dcs_debug_level dcs_debug;
96 	uint32_t phy_err_penalty;
97 	uint32_t phy_err_threshold;
98 	uint32_t radar_err_threshold;
99 	uint32_t coch_intfr_threshold;
100 	uint32_t user_max_cu;
101 	uint32_t intfr_detection_threshold;
102 	uint32_t intfr_detection_window;
103 	uint32_t tx_err_threshold;
104 	uint32_t user_request_count;
105 	uint8_t notify_user;
106 };
107 
108 /**
109  * struct pdev_dcs_freq_ctrl_params - define dcs frequency control parameter
110  *                                    in pdebv object
111  * @disable_threshold_per_5mins: in five minutes, if dcs happen more than
112  *                               threshold, then disable dcs for some time
113  * @restart_delay: when dcs happen more than threshold in five minutes,
114  *                 then start to disable dcs for restart_delay minutes
115  * @timestamp: record dcs happened timestamp
116  * @dcs_happened_count: dcs happened count
117  * @disable_delay_process: in dcs disable delay process or not
118  */
119 struct pdev_dcs_freq_ctrl_params {
120 	uint8_t disable_threshold_per_5mins;
121 	uint32_t restart_delay;
122 	unsigned long timestamp[MAX_DCS_TIME_RECORD];
123 	unsigned long dcs_happened_count;
124 	bool disable_delay_process;
125 };
126 
127 /**
128  * struct pdev_dcs_timer_args - define pdev dcs timer args
129  * @psoc: psoc pointer
130  * @pdev_id: pdev id
131  */
132 struct pdev_dcs_timer_args {
133 	struct wlan_objmgr_psoc *psoc;
134 	uint32_t pdev_id;
135 };
136 
137 /**
138  * struct psoc_dcs_cbk - define dcs callback in psoc object
139  * @cbk: callback
140  * @arg: arguments
141  */
142 struct psoc_dcs_cbk {
143 	dcs_callback cbk;
144 	void *arg;
145 };
146 
147 #define WLAN_DCS_MAX_STA_NUM  1
148 #define WLAN_DCS_MAX_SAP_NUM  2
149 #define WLAN_DCS_AFC_PREFER_BW  CH_WIDTH_80MHZ
150 
151 /**
152  * struct connection_chan_info - define connection channel information
153  * @freq: channel frequency
154  * @bw: channel bandwidth
155  * @vdev_id: connection vdev id
156  */
157 struct connection_chan_info {
158 	qdf_freq_t freq;
159 	enum phy_ch_width bw;
160 	uint8_t vdev_id;
161 };
162 
163 /**
164  * struct wlan_dcs_conn_info - define arguments list for DCS when AFC updated
165  * @sta_cnt: station count
166  * @sap_5ghz_cnt: 5 GHz sap count
167  * @sap_6ghz_cnt: 6 GHz sap count
168  * @sta: connection info of station
169  * @sap_5ghz: connection info of 5 GHz sap
170  * @sap_6ghz: connection info of 6 GHz sap
171  * @exit_condition: flag to exit iteration immediately
172  */
173 struct wlan_dcs_conn_info {
174 	uint8_t sta_cnt;
175 	uint8_t sap_5ghz_cnt;
176 	uint8_t sap_6ghz_cnt;
177 	struct connection_chan_info sta[WLAN_DCS_MAX_STA_NUM];
178 	struct connection_chan_info sap_5ghz[WLAN_DCS_MAX_SAP_NUM];
179 	struct connection_chan_info sap_6ghz[WLAN_DCS_MAX_SAP_NUM];
180 	bool exit_condition;
181 };
182 
183 /**
184  * struct dcs_afc_select_chan_cbk - define sap afc select channel callback
185  * @cbk: callback
186  * @arg: argument supply by register
187  */
188 struct dcs_afc_select_chan_cbk {
189 	dcs_afc_select_chan_cb cbk;
190 	void *arg;
191 };
192 
193 /**
194  * struct dcs_pdev_priv_obj - define dcs pdev priv
195  * @dcs_host_params: dcs host configuration parameter
196  * @dcs_im_stats: dcs im statistics
197  * @dcs_freq_ctrl_params: dcs frequency control parameter
198  * @dcs_disable_timer: dcs disable timer
199  * @dcs_timer_args: dcs disable timer args
200  * @lock: lock to protect dcs pdev priv
201  * @requestor_vdev_id: user request vdev id
202  * @user_cb: user request callback
203  */
204 struct dcs_pdev_priv_obj {
205 	struct pdev_dcs_params dcs_host_params;
206 	struct pdev_dcs_im_stats dcs_im_stats;
207 	struct pdev_dcs_freq_ctrl_params dcs_freq_ctrl_params;
208 	qdf_timer_t dcs_disable_timer;
209 	struct pdev_dcs_timer_args dcs_timer_args;
210 	qdf_spinlock_t lock;
211 	uint8_t requestor_vdev_id;
212 	void (*user_cb)(uint8_t vdev_id,
213 			struct wlan_host_dcs_im_user_stats *stats,
214 			int status);
215 };
216 
217 /**
218  * enum wlan_dcs_chan_seg - Different segments in the channel band.
219  * @WLAN_DCS_SEG_INVALID: invalid segment
220  * @WLAN_DCS_SEG_PRI20: primary 20MHz
221  * @WLAN_DCS_SEG_SEC20: secondary 20MHz
222  * @WLAN_DCS_SEG_SEC40: secondary 40MHz
223  * @WLAN_DCS_SEG_SEC80: secondary 80MHz
224  * @WLAN_DCS_SEG_SEC160: secondary 160MHz
225  */
226 enum wlan_dcs_chan_seg {
227 	WLAN_DCS_SEG_INVALID,
228 	WLAN_DCS_SEG_PRI20,
229 	WLAN_DCS_SEG_SEC20,
230 	WLAN_DCS_SEG_SEC40,
231 	WLAN_DCS_SEG_SEC80,
232 	WLAN_DCS_SEG_SEC160,
233 };
234 
235 /* masks for segments */
236 #define WLAN_DCS_SEG_PRI20_MASK BIT(0)
237 #define WLAN_DCS_SEG_SEC20_MASK BIT(1)
238 #define WLAN_DCS_SEG_SEC40_MASK (BIT(2) | BIT(3))
239 #define WLAN_DCS_SEG_SEC80_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7))
240 #define WLAN_DCS_SEG_SEC160_MASK (BIT(8) | BIT(9) | BIT(10) | BIT(11) | \
241 				  BIT(12) | BIT(13) | BIT(14) | BIT(15))
242 
243 #define WLAN_DCS_CHAN_FREQ_OFFSET 5
244 #define WLAN_DCS_IS_FREQ_IN_WIDTH(__cfreq, __cfreq0, __cfreq1, __width, __freq)\
245 	((((__width) == CH_WIDTH_20MHZ) &&                                     \
246 	  ((__cfreq) == (__freq))) ||                                          \
247 	 (((__width) == CH_WIDTH_40MHZ) &&                                     \
248 	  (((__freq) >= ((__cfreq0) - (2 * WLAN_DCS_CHAN_FREQ_OFFSET))) &&     \
249 	   ((__freq) <= ((__cfreq0) + (2 * WLAN_DCS_CHAN_FREQ_OFFSET))))) ||   \
250 	 (((__width) == CH_WIDTH_80MHZ) &&                                     \
251 	  (((__freq) >= ((__cfreq0) - (6 * WLAN_DCS_CHAN_FREQ_OFFSET))) &&     \
252 	   ((__freq) <= ((__cfreq0) + (6 * WLAN_DCS_CHAN_FREQ_OFFSET))))) ||   \
253 	 (((__width) == CH_WIDTH_160MHZ) &&                                    \
254 	  (((__freq) >= ((__cfreq1) - (14 * WLAN_DCS_CHAN_FREQ_OFFSET))) &&    \
255 	   ((__freq) <= ((__cfreq1) + (14 * WLAN_DCS_CHAN_FREQ_OFFSET))))) ||  \
256 	 (((__width) == CH_WIDTH_80P80MHZ) &&                                  \
257 	  ((((__freq) >= ((__cfreq0) - (6 * WLAN_DCS_CHAN_FREQ_OFFSET))) &&    \
258 	   ((__freq) <= ((__cfreq0) + (6 * WLAN_DCS_CHAN_FREQ_OFFSET)))) ||    \
259 	   (((__freq) >= ((__cfreq1) - (6 * WLAN_DCS_CHAN_FREQ_OFFSET))) &&    \
260 	   ((__freq) <= ((__cfreq1) + (6 * WLAN_DCS_CHAN_FREQ_OFFSET)))))))
261 
262 /**
263  * struct dcs_psoc_priv_obj - define dcs psoc priv
264  * @dcs_pdev_priv: dcs pdev priv
265  * @dcs_cbk: dcs callback
266  * @switch_chan_cb: callback for switching channel
267  * @afc_sel_chan_cbk: callback for afc channel selection
268  */
269 struct dcs_psoc_priv_obj {
270 	struct dcs_pdev_priv_obj dcs_pdev_priv[WLAN_DCS_MAX_PDEVS];
271 	struct psoc_dcs_cbk dcs_cbk;
272 	dcs_switch_chan_cb switch_chan_cb;
273 	struct dcs_afc_select_chan_cbk afc_sel_chan_cbk;
274 };
275 
276 /**
277  * wlan_dcs_get_pdev_private_obj() - get dcs pdev private object
278  * @psoc: psoc pointer
279  * @pdev_id: pdev_id
280  *
281  * API to retrieve the pdev private object from the psoc context
282  *
283  * Return: pdev private object pointer on success, NULL on error
284  */
285 struct dcs_pdev_priv_obj *
286 wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id);
287 
288 /**
289  * wlan_dcs_attach() - Attach dcs handler
290  * @psoc: psoc pointer
291  *
292  * This function gets called to register dcs FW events handler
293  *
294  * Return: QDF_STATUS
295  */
296 QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc);
297 
298 /**
299  * wlan_dcs_detach() - Detach dcs handler
300  * @psoc: psoc pointer
301  *
302  * This function gets called to unregister dcs FW events handler
303  *
304  * Return: QDF_STATUS
305  */
306 QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc);
307 
308 /**
309  * wlan_dcs_cmd_send() - Send dcs command to target_if layer
310  * @psoc: psoc pointer
311  * @pdev_id: pdev_id
312  * @is_host_pdev_id: pdev_id is host id or not
313  *
314  * The function gets called to send dcs command to FW
315  *
316  * return: QDF_STATUS_SUCCESS for success or error code
317  */
318 QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc,
319 			     uint32_t pdev_id,
320 			     bool is_host_pdev_id);
321 
322 /**
323  * wlan_dcs_process() - dcs process main entry
324  * @psoc: psoc pointer
325  * @event: dcs event pointer
326  *
327  * This function is the main entry to do dcs related operation
328  * such as algorithm handling and dcs frequency control.
329  *
330  * Return: QDF_STATUS
331  */
332 QDF_STATUS wlan_dcs_process(struct wlan_objmgr_psoc *psoc,
333 			    struct wlan_host_dcs_event *event);
334 
335 /**
336  * wlan_dcs_disable_timer_fn() - dcs disable timer callback
337  * @dcs_timer_args: dcs timer argument pointer
338  *
339  * This function gets called when dcs disable timer timeout
340  *
341  * Return: None
342  */
343 void wlan_dcs_disable_timer_fn(void *dcs_timer_args);
344 
345 /**
346  * wlan_dcs_clear() - clear dcs information
347  * @psoc: psoc pointer
348  * @pdev_id: pdev_id
349  *
350  * The function gets called to clear dcs information such as dcs
351  * frequency control parameters and stop dcs disable timer
352  *
353  * Return: None
354  */
355 void wlan_dcs_clear(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id);
356 
357 /**
358  * wlan_dcs_set_algorithm_process() - config dcs event data to do algorithm
359  * process or not
360  * @psoc: psoc pointer
361  * @pdev_id: pdev_id
362  * @dcs_algorithm_process: dcs algorithm process
363  *
364  * The function gets called to config dcs event data to do algorithm
365  * process or not
366  *
367  * Return: None
368  */
369 void wlan_dcs_set_algorithm_process(struct wlan_objmgr_psoc *psoc,
370 				    uint32_t pdev_id,
371 				    bool dcs_algorithm_process);
372 
373 /**
374  * wlan_dcs_pdev_obj_lock() - private API to acquire spinlock at pdev
375  * @dcs_pdev: pointer to dcs pdev object
376  *
377  * Return: void
378  */
wlan_dcs_pdev_obj_lock(struct dcs_pdev_priv_obj * dcs_pdev)379 static inline void wlan_dcs_pdev_obj_lock(struct dcs_pdev_priv_obj *dcs_pdev)
380 {
381 	qdf_spin_lock_bh(&dcs_pdev->lock);
382 }
383 
384 /**
385  * wlan_dcs_pdev_obj_unlock() - private api to release spinlock at pdev
386  * @dcs_pdev: pointer to dcs pdev object
387  *
388  * Return: void
389  */
wlan_dcs_pdev_obj_unlock(struct dcs_pdev_priv_obj * dcs_pdev)390 static inline void wlan_dcs_pdev_obj_unlock(struct dcs_pdev_priv_obj *dcs_pdev)
391 {
392 	qdf_spin_unlock_bh(&dcs_pdev->lock);
393 }
394 
395 /**
396  * wlan_dcs_switch_chan() - switch channel for vdev
397  * @vdev: vdev ptr
398  * @tgt_freq: target frequency
399  * @tgt_width: target channel width
400  *
401  * Return: QDF_STATUS
402  */
403 QDF_STATUS
404 wlan_dcs_switch_chan(struct wlan_objmgr_vdev *vdev, qdf_freq_t tgt_freq,
405 		     enum phy_ch_width tgt_width);
406 #endif  /* _WLAN_DCS_H_ */
407