1 /*
2  * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 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 /**
21  * DOC: Driver State Management (DSC) APIs for *internal* use
22  */
23 
24 #ifndef ____WLAN_DSC_H
25 #define ____WLAN_DSC_H
26 
27 #include "qdf_event.h"
28 #include "qdf_list.h"
29 #include "qdf_threads.h"
30 #include "qdf_timer.h"
31 #include "qdf_trace.h"
32 #include "qdf_types.h"
33 #include "wlan_dsc.h"
34 
35 #define dsc_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_QDF, params)
36 #define dsc_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_QDF, params)
37 #ifdef WLAN_DSC_DEBUG
38 #define dsc_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_QDF, params)
39 #else
40 #define dsc_debug(params...) /* no-op */
41 #endif
42 
43 #define dsc_nofl_err(params...) \
44 	QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_QDF, params)
45 #define dsc_nofl_info(params...) \
46 	QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_QDF, params)
47 #define dsc_nofl_debug(params...) \
48 	QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_QDF, params)
49 
50 #define dsc_enter_exit dsc_debug
51 #define dsc_enter() dsc_enter_exit("enter")
52 #define dsc_enter_str(str) dsc_enter_exit("enter(\"%s\")", str)
53 #define dsc_exit() dsc_enter_exit("exit")
54 #define dsc_exit_status(status) dsc_enter_exit("exit(status:%u)", status)
55 
__dsc_assert(const bool cond,const char * cond_str,const char * func,const uint32_t line)56 static inline bool __dsc_assert(const bool cond, const char *cond_str,
57 				const char *func, const uint32_t line)
58 {
59 	if (cond)
60 		return true;
61 
62 	QDF_DEBUG_PANIC_FL(func, line, "Failed assertion '%s'!", cond_str);
63 
64 	return false;
65 }
66 
67 #define dsc_assert(cond) __dsc_assert(cond, #cond, __func__, __LINE__)
68 #define dsc_assert_success(status) dsc_assert(QDF_IS_STATUS_SUCCESS(status))
69 
70 #ifdef WLAN_DSC_DEBUG
71 #define DSC_OP_TIMEOUT_MS		(1 * 60 * 1000) /* 1 minute */
72 #define DSC_TRANS_TIMEOUT_MS		(1 * 60 * 1000) /* 1 minute */
73 #define DSC_TRANS_WAIT_TIMEOUT_MS	(2 * 60 * 1000) /* 2 minutes */
74 
75 /**
76  * struct dsc_op - list node for operation tracking information
77  * @node: list node
78  * @timeout_timer: a timer used to detect operation timeouts
79  * @thread: the thread which started the operation
80  * @func: name of the function the operation was started from
81  */
82 struct dsc_op {
83 	qdf_list_node_t node;
84 	qdf_timer_t timeout_timer;
85 	qdf_thread_t *thread;
86 	const char *func;
87 };
88 #endif /* WLAN_DSC_DEBUG */
89 
90 /**
91  * struct dsc_ops - operations in flight tracking container
92  * @list: list for tracking debug information
93  * @count: count of current operations in flight
94  * @event: event used to wait in *_wait_for_ops() APIs
95  */
96 struct dsc_ops {
97 #ifdef WLAN_DSC_DEBUG
98 	qdf_list_t list;
99 #endif
100 	uint32_t count;
101 	qdf_event_t event;
102 };
103 
104 /**
105  * struct dsc_tran - representation of a pending transition
106  * @abort: used to indicate if the transition stopped waiting due to an abort
107  * @desc: unique description of the transition
108  * @node: list node
109  * @event: event used to wait in *_start_trans_wait() APIs
110  * @timeout_timer: a timer used to detect transition wait timeouts
111  * @thread: the thread which started the transition wait
112  */
113 struct dsc_tran {
114 	bool abort;
115 	const char *desc;
116 	qdf_list_node_t node;
117 	qdf_event_t event;
118 #ifdef WLAN_DSC_DEBUG
119 	qdf_timer_t timeout_timer;
120 	qdf_thread_t *thread;
121 #endif
122 };
123 
124 /**
125  * struct dsc_trans - transition information container
126  * @active_desc: unique description of the current transition in progress
127  * @queue: queue of pending transitions
128  * @timeout_timer: a timer used to detect transition timeouts
129  * @thread: the thread which started the transition
130  */
131 struct dsc_trans {
132 	const char *active_desc;
133 	qdf_list_t queue;
134 #ifdef WLAN_DSC_DEBUG
135 	qdf_timer_t timeout_timer;
136 	qdf_thread_t *thread;
137 #endif
138 };
139 
140 /**
141  * struct dsc_driver - concrete dsc driver context
142  * @lock: lock under which all dsc APIs execute
143  * @psocs: list of children psoc contexts
144  * @trans: transition tracking container for this node
145  * @ops: operations in flight tracking container for this node
146  */
147 struct dsc_driver {
148 	struct qdf_spinlock lock;
149 	qdf_list_t psocs;
150 	struct dsc_trans trans;
151 	struct dsc_ops ops;
152 };
153 
154 /**
155  * struct dsc_psoc - concrete dsc psoc context
156  * @node: list node for membership in @driver->psocs
157  * @driver: parent driver context
158  * @vdevs: list of children vdevs contexts
159  * @trans: transition tracking container for this node
160  * @ops: operations in flight tracking container for this node
161  */
162 struct dsc_psoc {
163 	qdf_list_node_t node;
164 	struct dsc_driver *driver;
165 	qdf_list_t vdevs;
166 	struct dsc_trans trans;
167 	struct dsc_ops ops;
168 };
169 
170 /**
171  * struct dsc_vdev - concrete dsc vdev context
172  * @node: list node for membership in @psoc->vdevs
173  * @psoc: parent psoc context
174  * @trans: transition tracking container for this node
175  * @ops: operations in flight tracking container for this node
176  * @nb_cmd_during_ssr: north bound command id
177  */
178 struct dsc_vdev {
179 	qdf_list_node_t node;
180 	struct dsc_psoc *psoc;
181 	struct dsc_trans trans;
182 	struct dsc_ops ops;
183 	uint8_t nb_cmd_during_ssr;
184 };
185 
186 #define dsc_for_each_driver_psoc(driver_ptr, psoc_cursor) \
187 	qdf_list_for_each(&(driver_ptr)->psocs, psoc_cursor, node)
188 
189 #define dsc_for_each_psoc_vdev(psoc_ptr, vdev_cursor) \
190 	qdf_list_for_each(&(psoc_ptr)->vdevs, vdev_cursor, node)
191 
192 /**
193  * __dsc_lock() - grab the dsc driver lock
194  * @driver: the driver to lock
195  *
196  * Return: None
197  */
198 void __dsc_lock(struct dsc_driver *driver);
199 
200 /**
201  * __dsc_unlock() - release the dsc driver lock
202  * @driver: the driver to unlock
203  *
204  * Return: None
205  */
206 void __dsc_unlock(struct dsc_driver *driver);
207 
208 /**
209  * __dsc_ops_init() - initialize @ops
210  * @ops: the ops container to initialize
211  *
212  * Return: None
213  */
214 void __dsc_ops_init(struct dsc_ops *ops);
215 
216 /**
217  * __dsc_ops_deinit() - de-initialize @ops
218  * @ops: the ops container to de-initialize
219  *
220  * Return: None
221  */
222 void __dsc_ops_deinit(struct dsc_ops *ops);
223 
224 /**
225  * __dsc_ops_insert() - insert @func into the trakcing information in @ops
226  * @ops: the ops container to insert into
227  * @func: the debug information to insert
228  *
229  * Return: QDF_STATUS
230  */
231 QDF_STATUS __dsc_ops_insert(struct dsc_ops *ops, const char *func);
232 
233 /**
234  * __dsc_ops_remove() - remove @func from the tracking information in @ops
235  * @ops: the ops container to remove from
236  * @func: the debug information to remove
237  *
238  * Return: None
239  */
240 bool __dsc_ops_remove(struct dsc_ops *ops, const char *func);
241 
242 /**
243  * __dsc_trans_init() - initialize @trans
244  * @trans: the trans container to initialize
245  *
246  * Return: None
247  */
248 void __dsc_trans_init(struct dsc_trans *trans);
249 
250 /**
251  * __dsc_trans_deinit() - de-initialize @trans
252  * @trans: the trans container to de-initialize
253  *
254  * Return: None
255  */
256 void __dsc_trans_deinit(struct dsc_trans *trans);
257 
258 /**
259  * __dsc_trans_start() - set the active transition on @trans
260  * @trans: the transition container used to track the new active transition
261  * @desc: unique description of the transition being started
262  *
263  * Return: QDF_STATUS
264  */
265 QDF_STATUS __dsc_trans_start(struct dsc_trans *trans, const char *desc);
266 
267 /**
268  * __dsc_trans_stop() - unset the active transition on @trans
269  * @trans: the transition container currently tracking the active transition
270  *
271  * Return: None
272  */
273 void __dsc_trans_stop(struct dsc_trans *trans);
274 
275 /**
276  * __dsc_trans_queue() - queue @tran at the back of @trans
277  * @trans: the transitions container to enqueue to
278  * @tran: the transition to enqueue
279  * @desc: unique description of the transition being queued
280  *
281  * Return: QDF_STATUS
282  */
283 QDF_STATUS __dsc_trans_queue(struct dsc_trans *trans, struct dsc_tran *tran,
284 			     const char *desc);
285 
286 /**
287  * __dsc_tran_wait() - block until @tran completes
288  * @tran: the transition to wait on
289  *
290  * Return: QDF_STATUS
291  */
292 QDF_STATUS __dsc_tran_wait(struct dsc_tran *tran);
293 
294 /**
295  * __dsc_trans_abort() - abort the next queued transition from @trans
296  * @trans: the transitions container to abort from
297  *
298  * Return: true if a transition was aborted, false if @trans is empty
299  */
300 bool __dsc_trans_abort(struct dsc_trans *trans);
301 
302 /**
303  * __dsc_trans_trigger() - trigger the next queued trans in @trans
304  * @trans: the transitions container to trigger from
305  *
306  * Return: true if a transition was triggered
307  */
308 bool __dsc_trans_trigger(struct dsc_trans *trans);
309 
310 /**
311  * __dsc_trans_active() - check if a transition is active in @trans
312  * @trans: the transitions container to check
313  *
314  * Return: true if @trans has an active transition
315  */
316 bool __dsc_trans_active(struct dsc_trans *trans);
317 
318 /**
319  * __dsc_trans_queued() - check if a transition is queued in @trans
320  * @trans: the transitions container to check
321  *
322  * Return: true if @trans has a queued transition
323  */
324 bool __dsc_trans_queued(struct dsc_trans *trans);
325 
326 /**
327  * __dsc_trans_active_or_queued() - check if a transition is active or queued
328  *	in @trans
329  * @trans: the transitions container to check
330  *
331  * Return: true if @trans has an active or queued transition
332  */
333 bool __dsc_trans_active_or_queued(struct dsc_trans *trans);
334 
335 /**
336  * __dsc_driver_trans_trigger_checked() - trigger any next pending driver
337  *	transition, only after passing the "can trans" check
338  * @driver: driver context
339  *
340  * Return: true if the trigger was "handled." This indicates down-tree nodes
341  * should _not_ attempt to trigger a new transition.
342  */
343 bool __dsc_driver_trans_trigger_checked(struct dsc_driver *driver);
344 
345 /**
346  * __dsc_psoc_trans_trigger_checked() - trigger any next pending psoc
347  *	transition, only after passing the "can trans" check
348  * @psoc: psoc context
349  *
350  * Return: true if the trigger was "handled." This indicates down-tree nodes
351  * should _not_ attempt to trigger a new transition.
352  */
353 bool __dsc_psoc_trans_trigger_checked(struct dsc_psoc *psoc);
354 
355 #endif /* ____WLAN_DSC_H */
356