xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_wdi_event.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2017-2018 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\n", __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 	void *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\n", __func__);
127 		return;
128 	}
129 	if (!txrx_pdev) {
130 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
131 			"Invalid pdev in WDI event handler\n");
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 	if (!(txrx_pdev->wdi_event_list[event_index]) &&
141 		(event == WDI_EVENT_RX_DESC)) {
142 		/* WDI_EVEN_RX_DESC is indicated for RX_LITE also */
143 		event_index = WDI_EVENT_LITE_RX - WDI_EVENT_BASE;
144 	}
145 	wdi_sub = txrx_pdev->wdi_event_list[event_index];
146 
147 	/* Find the subscriber */
148 	dp_wdi_event_iter_sub(txrx_pdev, event_index, wdi_sub, data,
149 			peer_id, status);
150 }
151 
152 
153 /*
154  * dp_wdi_event_sub() - Subscribe WDI event
155  * @txrx_pdev_handle: cdp_pdev handle
156  * @event_cb_sub_handle: subcribe evnet handle
157  * @event: Event to be subscribe
158  *
159  * Return: 0 for success. nonzero for failure.
160  */
161 int
162 dp_wdi_event_sub(
163 	struct cdp_pdev *txrx_pdev_handle,
164 	void *event_cb_sub_handle,
165 	uint32_t event)
166 {
167 	uint32_t event_index;
168 	wdi_event_subscribe *wdi_sub;
169 	struct dp_pdev *txrx_pdev = (struct dp_pdev *)txrx_pdev_handle;
170 	wdi_event_subscribe *event_cb_sub =
171 		(wdi_event_subscribe *) event_cb_sub_handle;
172 
173 	if (!txrx_pdev) {
174 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
175 			"Invalid txrx_pdev in %s", __func__);
176 		return -EINVAL;
177 	}
178 	if (!event_cb_sub) {
179 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
180 			"Invalid callback in %s", __func__);
181 		return -EINVAL;
182 	}
183 	if ((!event) || (event >= WDI_EVENT_LAST) || (event < WDI_EVENT_BASE)) {
184 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
185 			"Invalid event in %s", __func__);
186 		return -EINVAL;
187 	}
188 	dp_set_pktlog_wifi3(txrx_pdev, event, true);
189 	event_index = event - WDI_EVENT_BASE;
190 	wdi_sub = txrx_pdev->wdi_event_list[event_index];
191 
192 	/*
193 	 *  Check if it is the first subscriber of the event
194 	 */
195 	if (!wdi_sub) {
196 		wdi_sub = event_cb_sub;
197 		wdi_sub->priv.next = NULL;
198 		wdi_sub->priv.prev = NULL;
199 		txrx_pdev->wdi_event_list[event_index] = wdi_sub;
200 		return 0;
201 	}
202 	event_cb_sub->priv.next = wdi_sub;
203 	event_cb_sub->priv.prev = NULL;
204 	wdi_sub->priv.prev = event_cb_sub;
205 	txrx_pdev->wdi_event_list[event_index] = event_cb_sub;
206 	return 0;
207 
208 }
209 
210 /*
211  * dp_wdi_event_unsub() - WDI event unsubscribe
212  * @txrx_pdev_handle: cdp_pdev handle
213  * @event_cb_sub_handle: subscribed event handle
214  * @event: Event to be unsubscribe
215  *
216  *
217  * Return: 0 for success. nonzero for failure.
218  */
219 int
220 dp_wdi_event_unsub(
221 	struct cdp_pdev *txrx_pdev_handle,
222 	void *event_cb_sub_handle,
223 	uint32_t event)
224 {
225 	uint32_t event_index = event - WDI_EVENT_BASE;
226 	struct dp_pdev *txrx_pdev = (struct dp_pdev *)txrx_pdev_handle;
227 	wdi_event_subscribe *event_cb_sub =
228 		(wdi_event_subscribe *) event_cb_sub_handle;
229 
230 	if (!event_cb_sub) {
231 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
232 			"Invalid callback in %s", __func__);
233 		return -EINVAL;
234 	}
235 
236 	dp_set_pktlog_wifi3(txrx_pdev, event, false);
237 
238 	if (!event_cb_sub->priv.prev) {
239 		txrx_pdev->wdi_event_list[event_index] = event_cb_sub->priv.next;
240 	} else {
241 		event_cb_sub->priv.prev->priv.next = event_cb_sub->priv.next;
242 	}
243 	if (event_cb_sub->priv.next) {
244 		event_cb_sub->priv.next->priv.prev = event_cb_sub->priv.prev;
245 	}
246 
247 	return 0;
248 }
249 
250 
251 /*
252  * dp_wdi_event_attach() - Attach wdi event
253  * @txrx_pdev: DP pdev handle
254  *
255  * Return: 0 for success. nonzero for failure.
256  */
257 int
258 dp_wdi_event_attach(struct dp_pdev *txrx_pdev)
259 {
260 	if (!txrx_pdev) {
261 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
262 			"Invalid device in %s\nWDI event attach failed\n",
263 			__func__);
264 		return -EINVAL;
265 	}
266 	/* Separate subscriber list for each event */
267 	txrx_pdev->wdi_event_list = (wdi_event_subscribe **)
268 		qdf_mem_malloc(
269 			sizeof(wdi_event_subscribe *) * WDI_NUM_EVENTS);
270 	if (!txrx_pdev->wdi_event_list) {
271 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
272 			"Insufficient memory for the WDI event lists\n");
273 		return -EINVAL;
274 	}
275 	return 0;
276 }
277 
278 
279 /*
280  * dp_wdi_event_detach() - Detach WDI event
281  * @txrx_pdev: DP pdev handle
282  *
283  * Return: 0 for success. nonzero for failure.
284  */
285 int
286 dp_wdi_event_detach(struct dp_pdev *txrx_pdev)
287 {
288 	int i;
289 	wdi_event_subscribe *wdi_sub;
290 	if (!txrx_pdev) {
291 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
292 			"Invalid device in %s\nWDI attach failed", __func__);
293 		return -EINVAL;
294 	}
295 	if (!txrx_pdev->wdi_event_list) {
296 		return -EINVAL;
297 	}
298 	for (i = 0; i < WDI_NUM_EVENTS; i++) {
299 		wdi_sub = txrx_pdev->wdi_event_list[i];
300 		/* Delete all the subscribers */
301 		dp_wdi_event_del_subs(wdi_sub, i);
302 	}
303 	if (txrx_pdev->wdi_event_list) {
304 		qdf_mem_free(txrx_pdev->wdi_event_list);
305 	}
306 	return 0;
307 }
308 #endif /* CONFIG_WIN */
309