blob: 0a80a0ed4d31aea761e077a063646dca093d1b70 [file] [log] [blame]
Victor Hsue0cd0e72021-06-08 11:05:03 +08001/*
2 * DHD debugability Linux os layer
3 *
4 * Copyright (C) 2021, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Open:>>
22 *
23 * $Id$
24 */
25
26#include <typedefs.h>
27#include <osl.h>
28#include <bcmutils.h>
29#include <bcmendian.h>
30#include <dngl_stats.h>
31#include <dhd.h>
32#include <dhd_dbg.h>
33#include <dhd_debug.h>
34
35#include <net/cfg80211.h>
36#include <wl_cfgvendor.h>
37
38typedef void (*dbg_ring_send_sub_t)(void *ctx, const int ring_id, const void *data,
39 const uint32 len, const dhd_dbg_ring_status_t ring_status);
40typedef void (*dbg_urgent_noti_sub_t)(void *ctx, const void *data,
41 const uint32 len, const uint32 fw_len);
42
43static dbg_ring_send_sub_t ring_send_sub_cb[DEBUG_RING_ID_MAX];
44static dbg_urgent_noti_sub_t urgent_noti_sub_cb;
45typedef struct dhd_dbg_os_ring_info {
46 dhd_pub_t *dhdp;
47 int ring_id;
48 int log_level;
49 unsigned long interval;
50 struct delayed_work work;
51 uint64 tsoffset;
52} linux_dbgring_info_t;
53
54struct log_level_table dhd_event_map[] = {
55 {1, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, "DRIVER EAPOL TX REQ"},
56 {1, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, "DRIVER EAPOL RX"},
57 {2, WIFI_EVENT_DRIVER_SCAN_REQUESTED, "SCAN_REQUESTED"},
58 {2, WIFI_EVENT_DRIVER_SCAN_COMPLETE, "SCAN COMPELETE"},
59 {3, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND, "SCAN RESULT FOUND"},
60 {2, WIFI_EVENT_DRIVER_PNO_ADD, "PNO ADD"},
61 {2, WIFI_EVENT_DRIVER_PNO_REMOVE, "PNO REMOVE"},
62 {2, WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND, "PNO NETWORK FOUND"},
63 {2, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED, "PNO SCAN_REQUESTED"},
64 {1, WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND, "PNO SCAN RESULT FOUND"},
65 {1, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE, "PNO SCAN COMPELETE"}
66};
67
68static void
69debug_data_send(dhd_pub_t *dhdp, int ring_id, const void *data, const uint32 len,
70 const dhd_dbg_ring_status_t ring_status)
71{
72 struct net_device *ndev;
73 dbg_ring_send_sub_t ring_sub_send;
74 ndev = dhd_linux_get_primary_netdev(dhdp);
75 if (!ndev)
76 return;
77 if (!VALID_RING(ring_id))
78 return;
79 if (ring_send_sub_cb[ring_id]) {
80 ring_sub_send = ring_send_sub_cb[ring_id];
81 ring_sub_send(ndev, ring_id, data, len, ring_status);
82 }
83}
84
85static void
86dhd_os_dbg_urgent_notifier(dhd_pub_t *dhdp, const void *data, const uint32 len)
87{
88 struct net_device *ndev;
89 ndev = dhd_linux_get_primary_netdev(dhdp);
90 if (!ndev)
91 return;
92 if (urgent_noti_sub_cb) {
93 urgent_noti_sub_cb(ndev, data, len, dhdp->soc_ram_length);
94 }
95}
96
97static void
98dbg_ring_poll_worker(struct work_struct *work)
99{
100 struct delayed_work *d_work = to_delayed_work(work);
101 bool sched = TRUE;
102 dhd_dbg_ring_t *ring;
103 linux_dbgring_info_t *ring_info;
104 dhd_pub_t *dhdp;
105 int ringid;
106 dhd_dbg_ring_status_t ring_status;
107 void *buf;
108 dhd_dbg_ring_entry_t *hdr;
109 uint32 buflen, rlen;
110 unsigned long flags;
111
Terry Chendf920932023-05-02 20:44:35 +0800112 BCM_REFERENCE(hdr);
113
114 if (!CAN_SLEEP()) {
115 DHD_CONS_ONLY(("this context should be sleepable\n"));
116 sched = FALSE;
117 goto exit;
118 }
119
Victor Hsue0cd0e72021-06-08 11:05:03 +0800120 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
121 ring_info = container_of(d_work, linux_dbgring_info_t, work);
122 GCC_DIAGNOSTIC_POP();
123
124 dhdp = ring_info->dhdp;
125 ringid = ring_info->ring_id;
126
127 ring = &dhdp->dbg->dbg_rings[ringid];
128 DHD_DBG_RING_LOCK(ring->lock, flags);
129 dhd_dbg_get_ring_status(dhdp, ringid, &ring_status);
Terry Chenc027f9e2021-07-22 16:49:12 +0800130 DHD_DBG_RING_UNLOCK(ring->lock, flags);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800131
Terry Chenc027f9e2021-07-22 16:49:12 +0800132#ifdef DHD_PKT_LOGGING_DBGRING
133 if (ringid == PACKET_LOG_RING_ID) {
134 struct net_device *ndev;
135 ndev = dhd_linux_get_primary_netdev(dhdp);
136 buflen = DBG_RING_ENTRY_SIZE;
137 buflen += dhd_os_get_pktlog_dump_size(ndev);
138 DHD_DBGIF(("%s: buflen: %d\n", __FUNCTION__, buflen));
139 } else
140#endif /* DHD_PKT_LOGGING_DBGRING */
141 {
142 DHD_DBG_RING_LOCK(ring->lock, flags);
143 if (ring->wp > ring->rp) {
144 buflen = ring->wp - ring->rp;
145 } else if (ring->wp < ring->rp) {
146 buflen = ring->ring_size - ring->rp + ring->wp;
147 } else {
148 DHD_DBG_RING_UNLOCK(ring->lock, flags);
149 goto exit;
150 }
Victor Hsue0cd0e72021-06-08 11:05:03 +0800151
Terry Chenc027f9e2021-07-22 16:49:12 +0800152 if (buflen > ring->ring_size) {
153 DHD_DBG_RING_UNLOCK(ring->lock, flags);
154 goto exit;
155 }
156 DHD_DBG_RING_UNLOCK(ring->lock, flags);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800157 }
158
Terry Chen488d3172022-06-13 15:50:59 +0800159
Terry Chendf920932023-05-02 20:44:35 +0800160 buf = VMALLOCZ(dhdp->osh, buflen);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800161 if (!buf) {
Terry Chendf920932023-05-02 20:44:35 +0800162 DHD_CONS_ONLY(("%s failed to allocate read buf\n", __FUNCTION__));
Victor Hsue0cd0e72021-06-08 11:05:03 +0800163 sched = FALSE;
164 goto exit;
165 }
166
Terry Chenc027f9e2021-07-22 16:49:12 +0800167#ifdef DHD_PKT_LOGGING_DBGRING
168 if (ringid == PACKET_LOG_RING_ID) {
169 rlen = dhd_dbg_pull_from_pktlog(dhdp, ringid, buf, buflen);
170 DHD_DBGIF(("%s: rlen: %d\n", __FUNCTION__, rlen));
171 } else
172#endif /* DHD_PKT_LOGGING_DBGRING */
173 {
174 rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf, buflen);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800175 }
Victor Hsue0cd0e72021-06-08 11:05:03 +0800176 hdr = (dhd_dbg_ring_entry_t *)buf;
177 while (rlen > 0) {
Terry Chenc027f9e2021-07-22 16:49:12 +0800178 DHD_DBG_RING_LOCK(ring->lock, flags);
179#ifdef DHD_PKT_LOGGING_DBGRING
180 if (ringid == PACKET_LOG_RING_ID) {
181 ring_status.read_bytes += (rlen - DBG_RING_ENTRY_SIZE);
182 ring->stat.read_bytes += (rlen - DBG_RING_ENTRY_SIZE);
183 if (ring->stat.read_bytes > ring->stat.written_bytes) {
184 DHD_DBGIF(("%s READ/WRITE counter mismatched!\n", __FUNCTION__));
185 ring->stat.read_bytes = ring->stat.written_bytes;
186 }
187 DHD_DBGIF(("%s RING%d[%s]read_bytes %d, wp=%d, rp=%d\n", __FUNCTION__,
188 ring->id, ring->name, ring->stat.read_bytes, ring->wp, ring->rp));
189 } else
190#endif /* DHD_PKT_LOGGING_DBGRING */
191 {
192 ring_status.read_bytes += ENTRY_LENGTH(hdr);
193 }
194 DHD_DBG_RING_UNLOCK(ring->lock, flags);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800195 /* offset fw ts to host ts */
196 hdr->timestamp += ring_info->tsoffset;
197 debug_data_send(dhdp, ringid, hdr, ENTRY_LENGTH(hdr),
198 ring_status);
199 rlen -= ENTRY_LENGTH(hdr);
200 hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr));
201 }
Terry Chendf920932023-05-02 20:44:35 +0800202 VMFREE(dhdp->osh, buf, buflen);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800203
Terry Chenc027f9e2021-07-22 16:49:12 +0800204 DHD_DBG_RING_LOCK(ring->lock, flags);
205 if (!ring->sched_pull) {
206 ring->sched_pull = TRUE;
207 }
208 DHD_DBG_RING_UNLOCK(ring->lock, flags);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800209exit:
210 if (sched) {
211 /* retrigger the work at same interval */
212 if ((ring_status.written_bytes == ring_status.read_bytes) &&
213 (ring_info->interval)) {
214 schedule_delayed_work(d_work, ring_info->interval);
215 }
216 }
Victor Hsue0cd0e72021-06-08 11:05:03 +0800217 return;
218}
219
220int
221dhd_os_dbg_register_callback(int ring_id, dbg_ring_send_sub_t callback)
222{
223 if (!VALID_RING(ring_id))
224 return BCME_RANGE;
225
226 ring_send_sub_cb[ring_id] = callback;
227 return BCME_OK;
228}
229
230int
231dhd_os_dbg_register_urgent_notifier(dhd_pub_t *dhdp, dbg_urgent_noti_sub_t urgent_noti_sub)
232{
233 if (!dhdp || !urgent_noti_sub)
234 return BCME_BADARG;
235 urgent_noti_sub_cb = urgent_noti_sub;
236
237 return BCME_OK;
238}
239
240int
241dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level,
242 int flags, int time_intval, int threshold)
243{
244 int ret = BCME_OK;
245 int ring_id;
246 linux_dbgring_info_t *os_priv, *ring_info;
247
248 ring_id = dhd_dbg_find_ring_id(dhdp, ring_name);
249 if (!VALID_RING(ring_id))
250 return BCME_UNSUPPORTED;
251
252 DHD_INFO(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n",
253 __FUNCTION__, log_level, time_intval, threshold));
254
255 /* change the configuration */
256 ret = dhd_dbg_set_configuration(dhdp, ring_id, log_level, flags, threshold);
257 if (ret) {
258 DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret));
259 return ret;
260 }
261
262 os_priv = dhd_dbg_get_priv(dhdp);
263 if (!os_priv)
264 return BCME_ERROR;
265 ring_info = &os_priv[ring_id];
266 ring_info->log_level = log_level;
267 if (time_intval == 0 || log_level == 0) {
268 ring_info->interval = 0;
269 cancel_delayed_work_sync(&ring_info->work);
270 } else {
271 ring_info->interval = msecs_to_jiffies(time_intval * MSEC_PER_SEC);
272 cancel_delayed_work_sync(&ring_info->work);
273 schedule_delayed_work(&ring_info->work, ring_info->interval);
274 }
275
276 return ret;
277}
278
279int
280dhd_os_reset_logging(dhd_pub_t *dhdp)
281{
282 int ret = BCME_OK;
283 int ring_id;
284 linux_dbgring_info_t *os_priv, *ring_info;
285
286 os_priv = dhd_dbg_get_priv(dhdp);
287 if (!os_priv)
288 return BCME_ERROR;
289
290 /* Stop all rings */
291 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
292 DHD_INFO(("%s: Stop ring buffer %d\n", __FUNCTION__, ring_id));
293
294 ring_info = &os_priv[ring_id];
Victor Hsue0cd0e72021-06-08 11:05:03 +0800295 /* log level zero makes stop logging on that ring */
296 ring_info->log_level = 0;
297 ring_info->interval = 0;
298 /* change the configuration */
299 ret = dhd_dbg_set_configuration(dhdp, ring_id, 0, 0, 0);
300 if (ret) {
301 DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret));
302 return ret;
303 }
Terry Chendf920932023-05-02 20:44:35 +0800304 /* cancel any pending work */
305 cancel_delayed_work_sync(&ring_info->work);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800306 }
307 return ret;
308}
309
310#define SUPPRESS_LOG_LEVEL 1
311int
312dhd_os_suppress_logging(dhd_pub_t *dhdp, bool suppress)
313{
314 int ret = BCME_OK;
315 int max_log_level;
316 int enable = (suppress) ? 0 : 1;
317 linux_dbgring_info_t *os_priv;
318
319 os_priv = dhd_dbg_get_priv(dhdp);
320 if (!os_priv)
321 return BCME_ERROR;
322
323 max_log_level = os_priv[FW_VERBOSE_RING_ID].log_level;
324
325 if (max_log_level == SUPPRESS_LOG_LEVEL) {
326 /* suppress the logging in FW not to wake up host while device in suspend mode */
327 ret = dhd_iovar(dhdp, 0, "logtrace", (char *)&enable, sizeof(enable), NULL, 0,
328 TRUE);
329 if (ret < 0 && (ret != BCME_UNSUPPORTED)) {
330 DHD_ERROR(("logtrace is failed : %d\n", ret));
331 }
332 }
333
334 return ret;
335}
336
337int
338dhd_os_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status)
339{
340 return dhd_dbg_get_ring_status(dhdp, ring_id, dbg_ring_status);
341}
342
343int
344dhd_os_trigger_get_ring_data(dhd_pub_t *dhdp, char *ring_name)
345{
346 int ret = BCME_OK;
347 int ring_id;
348 linux_dbgring_info_t *os_priv, *ring_info;
349 ring_id = dhd_dbg_find_ring_id(dhdp, ring_name);
350 if (!VALID_RING(ring_id))
351 return BCME_UNSUPPORTED;
352 os_priv = dhd_dbg_get_priv(dhdp);
353 if (os_priv) {
354 ring_info = &os_priv[ring_id];
355 if (ring_info->interval) {
356 cancel_delayed_work_sync(&ring_info->work);
357 }
358 schedule_delayed_work(&ring_info->work, 0);
359 } else {
360 DHD_ERROR(("%s : os_priv is NULL\n", __FUNCTION__));
361 ret = BCME_ERROR;
362 }
363 return ret;
364}
365
366int
367dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_len)
368{
369 int ret = BCME_OK, i;
370 dhd_dbg_ring_entry_t msg_hdr;
371 log_conn_event_t *event_data = (log_conn_event_t *)data;
372 linux_dbgring_info_t *os_priv, *ring_info = NULL;
373
374 if (!VALID_RING(ring_id))
375 return BCME_UNSUPPORTED;
376 os_priv = dhd_dbg_get_priv(dhdp);
377
378 if (os_priv) {
379 ring_info = &os_priv[ring_id];
380 } else
381 return BCME_NORESOURCE;
382
383 memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t));
384
385 if (ring_id == DHD_EVENT_RING_ID) {
386 msg_hdr.type = DBG_RING_ENTRY_EVENT_TYPE;
387 msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP;
388 msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY;
389 msg_hdr.timestamp = local_clock();
390 /* convert to ms */
391 msg_hdr.timestamp = DIV_U64_BY_U32(msg_hdr.timestamp, NSEC_PER_MSEC);
392 msg_hdr.len = data_len;
393 /* filter the event for higher log level with current log level */
394 for (i = 0; i < ARRAYSIZE(dhd_event_map); i++) {
395 if ((dhd_event_map[i].tag == event_data->event) &&
396 dhd_event_map[i].log_level > ring_info->log_level) {
397 return ret;
398 }
399 }
400 }
401#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
402 else if (ring_id == FW_VERBOSE_RING_ID || ring_id == DRIVER_LOG_RING_ID ||
403 ring_id == ROAM_STATS_RING_ID) {
404 msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE;
405 msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP;
406 msg_hdr.timestamp = local_clock();
407 msg_hdr.timestamp = DIV_U64_BY_U32(msg_hdr.timestamp, NSEC_PER_MSEC);
408 msg_hdr.len = strlen(data);
409 }
410#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
411 ret = dhd_dbg_push_to_ring(dhdp, ring_id, &msg_hdr, event_data);
Terry Chenc027f9e2021-07-22 16:49:12 +0800412 if (ret && ret != BCME_BUSY) {
Victor Hsue0cd0e72021-06-08 11:05:03 +0800413 DHD_ERROR(("%s : failed to push data into the ring (%d) with ret(%d)\n",
414 __FUNCTION__, ring_id, ret));
415 }
416
417 return ret;
418}
419
420#ifdef DBG_PKT_MON
421int
422dhd_os_dbg_attach_pkt_monitor(dhd_pub_t *dhdp)
423{
424 return dhd_dbg_attach_pkt_monitor(dhdp, dhd_os_dbg_monitor_tx_pkts,
425 dhd_os_dbg_monitor_tx_status, dhd_os_dbg_monitor_rx_pkts);
426}
427
428int
429dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp)
430{
431 return dhd_dbg_start_pkt_monitor(dhdp);
432}
433
434int
Terry Chenc027f9e2021-07-22 16:49:12 +0800435dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
436 frame_type type, uint8 mgmt_acked)
Victor Hsue0cd0e72021-06-08 11:05:03 +0800437{
Terry Chenc027f9e2021-07-22 16:49:12 +0800438 return dhd_dbg_monitor_tx_pkts(dhdp, pkt, pktid, type, mgmt_acked);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800439}
440
441int
442dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
443 uint16 status)
444{
445 return dhd_dbg_monitor_tx_status(dhdp, pkt, pktid, status);
446}
447
448int
Terry Chenc027f9e2021-07-22 16:49:12 +0800449dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt, frame_type type)
Victor Hsue0cd0e72021-06-08 11:05:03 +0800450{
Terry Chenc027f9e2021-07-22 16:49:12 +0800451 return dhd_dbg_monitor_rx_pkts(dhdp, pkt, type);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800452}
453
454int
455dhd_os_dbg_stop_pkt_monitor(dhd_pub_t *dhdp)
456{
457 return dhd_dbg_stop_pkt_monitor(dhdp);
458}
459
460int
461dhd_os_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
462 uint16 req_count, uint16 *resp_count)
463{
464 return dhd_dbg_monitor_get_tx_pkts(dhdp, user_buf, req_count, resp_count);
465}
466
467int
468dhd_os_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
469 uint16 req_count, uint16 *resp_count)
470{
471 return dhd_dbg_monitor_get_rx_pkts(dhdp, user_buf, req_count, resp_count);
472}
473
474int
475dhd_os_dbg_detach_pkt_monitor(dhd_pub_t *dhdp)
476{
477 return dhd_dbg_detach_pkt_monitor(dhdp);
478}
479#endif /* DBG_PKT_MON */
480
481int
482dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features)
483{
484 int ret = BCME_OK;
485 /* XXX : we need to find a way to get the features for dbg */
486 *features = 0;
487#ifdef DEBUGABILITY
488#ifndef DEBUGABILITY_DISABLE_MEMDUMP
489 *features |= DBG_MEMORY_DUMP_SUPPORTED;
490#endif /* !DEBUGABILITY_DISABLE_MEMDUMP */
491 if (FW_SUPPORTED(dhdp, logtrace)) {
492 *features |= DBG_CONNECT_EVENT_SUPPORTED;
493 *features |= DBG_VERBOSE_LOG_SUPPORTED;
494 }
495 if (FW_SUPPORTED(dhdp, hchk)) {
496 *features |= DBG_HEALTH_CHECK_SUPPORTED;
497 }
498#ifdef DBG_PKT_MON
499 if (FW_SUPPORTED(dhdp, d11status)) {
500 *features |= DBG_PACKET_FATE_SUPPORTED;
501 }
502#endif /* DBG_PKT_MON */
503#endif /* DEBUGABILITY */
504 return ret;
505}
506
Terry Chenc027f9e2021-07-22 16:49:12 +0800507#ifdef DHD_PKT_LOGGING_DBGRING
508void
509dhd_os_dbg_urgent_pullreq(void *os_priv, int ring_id)
510{
511 linux_dbgring_info_t *ring_info;
512
513 ring_info = &((linux_dbgring_info_t *)os_priv)[ring_id];
514 cancel_delayed_work(&ring_info->work);
515 dbg_ring_poll_worker(&ring_info->work.work);
516 schedule_delayed_work(&ring_info->work, ring_info->interval);
517
518 return;
519}
520#endif /* DHD_PKT_LOGGING_DBGRING */
521
Victor Hsue0cd0e72021-06-08 11:05:03 +0800522static void
523dhd_os_dbg_pullreq(void *os_priv, int ring_id)
524{
525 linux_dbgring_info_t *ring_info;
526
527 ring_info = &((linux_dbgring_info_t *)os_priv)[ring_id];
528 cancel_delayed_work(&ring_info->work);
529 schedule_delayed_work(&ring_info->work, 0);
530}
531
532int
533dhd_os_dbg_attach(dhd_pub_t *dhdp)
534{
535 int ret = BCME_OK;
536 linux_dbgring_info_t *os_priv, *ring_info;
537 int ring_id;
538
539 /* os_dbg data */
Terry Chendf920932023-05-02 20:44:35 +0800540 os_priv = VMALLOCZ(dhdp->osh, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
Stephen Chua39257f2022-01-16 19:02:44 +0800541 if (!os_priv) {
Terry Chendf920932023-05-02 20:44:35 +0800542 DHD_ERROR(("%s:%d: VMALLOC failed for os_priv, size %d\n", __FUNCTION__,
Stephen Chua39257f2022-01-16 19:02:44 +0800543 __LINE__, (uint32)sizeof(*os_priv) * DEBUG_RING_ID_MAX));
Victor Hsue0cd0e72021-06-08 11:05:03 +0800544 return BCME_NOMEM;
Stephen Chua39257f2022-01-16 19:02:44 +0800545 }
Victor Hsue0cd0e72021-06-08 11:05:03 +0800546
547 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX;
548 ring_id++) {
549 ring_info = &os_priv[ring_id];
550 INIT_DELAYED_WORK(&ring_info->work, dbg_ring_poll_worker);
551 ring_info->dhdp = dhdp;
552 ring_info->ring_id = ring_id;
553 }
554
555 ret = dhd_dbg_attach(dhdp, dhd_os_dbg_pullreq, dhd_os_dbg_urgent_notifier, os_priv);
Stephen Chua39257f2022-01-16 19:02:44 +0800556 if (ret) {
Terry Chendf920932023-05-02 20:44:35 +0800557 VMFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
Stephen Chua39257f2022-01-16 19:02:44 +0800558 }
Victor Hsue0cd0e72021-06-08 11:05:03 +0800559
560 return ret;
561}
562
563void
564dhd_os_dbg_detach(dhd_pub_t *dhdp)
565{
566 linux_dbgring_info_t *os_priv, *ring_info;
567 int ring_id;
568 /* free os_dbg data */
569 os_priv = dhd_dbg_get_priv(dhdp);
570 if (!os_priv)
571 return;
572 /* abort pending any job */
573 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
574 ring_info = &os_priv[ring_id];
575 if (ring_info->interval) {
576 ring_info->interval = 0;
577 cancel_delayed_work_sync(&ring_info->work);
578 }
579 }
Terry Chendf920932023-05-02 20:44:35 +0800580 VMFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
Victor Hsue0cd0e72021-06-08 11:05:03 +0800581
582 return dhd_dbg_detach(dhdp);
583}