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