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