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