xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_wdi_event.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 
20 #include "dp_internal.h"
21 #include "qdf_mem.h"   /* qdf_mem_malloc,free */
22 
23 #ifdef WDI_EVENT_ENABLE
24 void *dp_get_pldev(struct cdp_pdev *txrx_pdev)
25 {
26 	struct dp_pdev *pdev = (struct dp_pdev *)txrx_pdev;
27 	return pdev->pl_dev;
28 }
29 /*
30  * dp_wdi_event_next_sub() - Return handle for Next WDI event
31  * @wdi_sub: WDI Event handle
32  *
33  * Return handle for next WDI event in list
34  *
35  * Return: Next WDI event to be subscribe
36  */
37 static inline wdi_event_subscribe *
38 dp_wdi_event_next_sub(wdi_event_subscribe *wdi_sub)
39 {
40 	if (!wdi_sub) {
41 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
42 			"Invalid subscriber in %s", __func__);
43 		return NULL;
44 	}
45 	return wdi_sub->priv.next;
46 }
47 
48 
49 /*
50  * dp_wdi_event_del_subs() -Delete Event subscription
51  * @wdi_sub: WDI Event handle
52  * @event_index: Event index from list
53  *
54  * This API will delete subscribed event from list
55  * Return: None
56  */
57 static inline void
58 dp_wdi_event_del_subs(wdi_event_subscribe *wdi_sub, int event_index)
59 {
60 	/* Subscribers should take care of deletion */
61 }
62 
63 
64 /*
65  * dp_wdi_event_iter_sub() - Iterate through all WDI event in the list
66  * and pass WDI event to callback function
67  * @pdev: DP pdev handle
68  * @event_index: Event index in list
69  * @wdi_event: WDI event handle
70  * @data: pointer to data
71  * @peer_id: peer id number
72  * @status: HTT rx status
73  *
74  *
75  * Return: None
76  */
77 static inline void
78 dp_wdi_event_iter_sub(
79 	struct dp_pdev *pdev,
80 	uint32_t event_index,
81 	wdi_event_subscribe *wdi_sub,
82 	void *data,
83 	uint16_t peer_id,
84 	int status)
85 {
86 	enum WDI_EVENT event = event_index + WDI_EVENT_BASE;
87 
88 	if (wdi_sub) {
89 		do {
90 			wdi_sub->callback(wdi_sub->context, event, data,
91 					peer_id, status);
92 		} while ((wdi_sub = dp_wdi_event_next_sub(wdi_sub)));
93 	}
94 }
95 
96 
97 /*
98  * dp_wdi_event_handler() - Event handler for WDI event
99  * @event: wdi event number
100  * @soc: soc handle
101  * @data: pointer to data
102  * @peer_id: peer id number
103  * @status: HTT rx status
104  * @pdev_id: id of pdev
105  *
106  * It will be called to register WDI event
107  *
108  * Return: None
109  */
110 void
111 dp_wdi_event_handler(
112 	enum WDI_EVENT event,
113 	struct dp_soc *soc,
114 	void *data,
115 	uint16_t peer_id,
116 	int status, uint8_t pdev_id)
117 {
118 	uint32_t event_index;
119 	wdi_event_subscribe *wdi_sub;
120 	struct dp_pdev *txrx_pdev;
121 	struct dp_soc *soc_t = (struct dp_soc *)soc;
122 	txrx_pdev = dp_get_pdev_for_mac_id(soc_t, pdev_id);
123 
124 	if (!event) {
125 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
126 			"Invalid WDI event in %s", __func__);
127 		return;
128 	}
129 	if (!txrx_pdev || txrx_pdev->pdev_deinit) {
130 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
131 			"Invalid pdev in WDI event handler");
132 		return;
133 	}
134 
135 	/*
136 	 *  There can be NULL data, so no validation for the data
137 	 *  Subscribers must do the sanity based on the requirements
138 	 */
139 	event_index = event - WDI_EVENT_BASE;
140 
141 	DP_STATS_INC(txrx_pdev, wdi_event[event_index], 1);
142 	wdi_sub = txrx_pdev->wdi_event_list[event_index];
143 
144 	/* Find the subscriber */
145 	dp_wdi_event_iter_sub(txrx_pdev, event_index, wdi_sub, data,
146 			peer_id, status);
147 }
148 
149 
150 /*
151  * dp_wdi_event_sub() - Subscribe WDI event
152  * @txrx_pdev_handle: cdp_pdev handle
153  * @event_cb_sub_handle: subcribe evnet handle
154  * @event: Event to be subscribe
155  *
156  * Return: 0 for success. nonzero for failure.
157  */
158 int
159 dp_wdi_event_sub(
160 	struct cdp_pdev *txrx_pdev_handle,
161 	void *event_cb_sub_handle,
162 	uint32_t event)
163 {
164 	uint32_t event_index;
165 	wdi_event_subscribe *wdi_sub;
166 	struct dp_pdev *txrx_pdev = (struct dp_pdev *)txrx_pdev_handle;
167 	wdi_event_subscribe *event_cb_sub =
168 		(wdi_event_subscribe *) event_cb_sub_handle;
169 
170 	if (!txrx_pdev) {
171 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
172 			"Invalid txrx_pdev in %s", __func__);
173 		return -EINVAL;
174 	}
175 	if (!event_cb_sub) {
176 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
177 			"Invalid callback in %s", __func__);
178 		return -EINVAL;
179 	}
180 	if ((!event) || (event >= WDI_EVENT_LAST) || (event < WDI_EVENT_BASE)) {
181 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
182 			"Invalid event in %s", __func__);
183 		return -EINVAL;
184 	}
185 	dp_set_pktlog_wifi3(txrx_pdev, event, true);
186 	event_index = event - WDI_EVENT_BASE;
187 	wdi_sub = txrx_pdev->wdi_event_list[event_index];
188 
189 	/*
190 	 *  Check if it is the first subscriber of the event
191 	 */
192 	if (!wdi_sub) {
193 		wdi_sub = event_cb_sub;
194 		wdi_sub->priv.next = NULL;
195 		wdi_sub->priv.prev = NULL;
196 		txrx_pdev->wdi_event_list[event_index] = wdi_sub;
197 		return 0;
198 	}
199 	event_cb_sub->priv.next = wdi_sub;
200 	event_cb_sub->priv.prev = NULL;
201 	wdi_sub->priv.prev = event_cb_sub;
202 	txrx_pdev->wdi_event_list[event_index] = event_cb_sub;
203 	return 0;
204 
205 }
206 
207 /*
208  * dp_wdi_event_unsub() - WDI event unsubscribe
209  * @txrx_pdev_handle: cdp_pdev handle
210  * @event_cb_sub_handle: subscribed event handle
211  * @event: Event to be unsubscribe
212  *
213  *
214  * Return: 0 for success. nonzero for failure.
215  */
216 int
217 dp_wdi_event_unsub(
218 	struct cdp_pdev *txrx_pdev_handle,
219 	void *event_cb_sub_handle,
220 	uint32_t event)
221 {
222 	uint32_t event_index = event - WDI_EVENT_BASE;
223 	struct dp_pdev *txrx_pdev = (struct dp_pdev *)txrx_pdev_handle;
224 	wdi_event_subscribe *event_cb_sub =
225 		(wdi_event_subscribe *) event_cb_sub_handle;
226 
227 	if (!event_cb_sub) {
228 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
229 			"Invalid callback in %s", __func__);
230 		return -EINVAL;
231 	}
232 
233 	dp_set_pktlog_wifi3(txrx_pdev, event, false);
234 
235 	if (!event_cb_sub->priv.prev) {
236 		txrx_pdev->wdi_event_list[event_index] = event_cb_sub->priv.next;
237 	} else {
238 		event_cb_sub->priv.prev->priv.next = event_cb_sub->priv.next;
239 	}
240 	if (event_cb_sub->priv.next) {
241 		event_cb_sub->priv.next->priv.prev = event_cb_sub->priv.prev;
242 	}
243 
244 	return 0;
245 }
246 
247 
248 /*
249  * dp_wdi_event_attach() - Attach wdi event
250  * @txrx_pdev: DP pdev handle
251  *
252  * Return: 0 for success. nonzero for failure.
253  */
254 int
255 dp_wdi_event_attach(struct dp_pdev *txrx_pdev)
256 {
257 	if (!txrx_pdev) {
258 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
259 			"Invalid device in %s\nWDI event attach failed",
260 			__func__);
261 		return -EINVAL;
262 	}
263 	/* Separate subscriber list for each event */
264 	txrx_pdev->wdi_event_list = (wdi_event_subscribe **)
265 		qdf_mem_malloc(
266 			sizeof(wdi_event_subscribe *) * WDI_NUM_EVENTS);
267 	if (!txrx_pdev->wdi_event_list) {
268 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
269 			"Insufficient memory for the WDI event lists");
270 		return -EINVAL;
271 	}
272 	return 0;
273 }
274 
275 
276 /*
277  * dp_wdi_event_detach() - Detach WDI event
278  * @txrx_pdev: DP pdev handle
279  *
280  * Return: 0 for success. nonzero for failure.
281  */
282 int
283 dp_wdi_event_detach(struct dp_pdev *txrx_pdev)
284 {
285 	int i;
286 	wdi_event_subscribe *wdi_sub;
287 	if (!txrx_pdev) {
288 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
289 			"Invalid device in %s\nWDI attach failed", __func__);
290 		return -EINVAL;
291 	}
292 	if (!txrx_pdev->wdi_event_list) {
293 		return -EINVAL;
294 	}
295 	for (i = 0; i < WDI_NUM_EVENTS; i++) {
296 		wdi_sub = txrx_pdev->wdi_event_list[i];
297 		/* Delete all the subscribers */
298 		dp_wdi_event_del_subs(wdi_sub, i);
299 	}
300 	qdf_mem_free(txrx_pdev->wdi_event_list);
301 	return 0;
302 }
303 #endif /* CONFIG_WIN */
304