1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * DHD debug ring API and structures - implementation
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2020, Broadcom.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Unless you and Broadcom execute a separate written software license
7*4882a593Smuzhiyun * agreement governing use of this software, this software is licensed to you
8*4882a593Smuzhiyun * under the terms of the GNU General Public License version 2 (the "GPL"),
9*4882a593Smuzhiyun * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10*4882a593Smuzhiyun * following added to such license:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * As a special exception, the copyright holders of this software give you
13*4882a593Smuzhiyun * permission to link this software with independent modules, and to copy and
14*4882a593Smuzhiyun * distribute the resulting executable under terms of your choice, provided that
15*4882a593Smuzhiyun * you also meet, for each linked independent module, the terms and conditions of
16*4882a593Smuzhiyun * the license of that module. An independent module is a module which is not
17*4882a593Smuzhiyun * derived from this software. The special exception does not apply to any
18*4882a593Smuzhiyun * modifications of the software.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * <<Broadcom-WL-IPTag/Open:>>
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * $Id$
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun #include <typedefs.h>
26*4882a593Smuzhiyun #include <osl.h>
27*4882a593Smuzhiyun #include <bcmutils.h>
28*4882a593Smuzhiyun #include <bcmendian.h>
29*4882a593Smuzhiyun #include <dngl_stats.h>
30*4882a593Smuzhiyun #include <dhd.h>
31*4882a593Smuzhiyun #include <dhd_dbg.h>
32*4882a593Smuzhiyun #include <dhd_dbg_ring.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun dhd_dbg_ring_t *
dhd_dbg_ring_alloc_init(dhd_pub_t * dhd,uint16 ring_id,char * ring_name,uint32 ring_sz,void * allocd_buf,bool pull_inactive)35*4882a593Smuzhiyun dhd_dbg_ring_alloc_init(dhd_pub_t *dhd, uint16 ring_id,
36*4882a593Smuzhiyun char *ring_name, uint32 ring_sz, void *allocd_buf,
37*4882a593Smuzhiyun bool pull_inactive)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun dhd_dbg_ring_t *ring = NULL;
40*4882a593Smuzhiyun int ret = 0;
41*4882a593Smuzhiyun unsigned long flags = 0;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun ring = MALLOCZ(dhd->osh, sizeof(dhd_dbg_ring_t));
44*4882a593Smuzhiyun if (!ring)
45*4882a593Smuzhiyun goto fail;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun ret = dhd_dbg_ring_init(dhd, ring, ring_id,
48*4882a593Smuzhiyun (uint8 *)ring_name, ring_sz,
49*4882a593Smuzhiyun allocd_buf, pull_inactive);
50*4882a593Smuzhiyun if (ret != BCME_OK) {
51*4882a593Smuzhiyun DHD_ERROR(("%s: unable to init ring %s!\n",
52*4882a593Smuzhiyun __FUNCTION__, ring_name));
53*4882a593Smuzhiyun goto fail;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun DHD_DBG_RING_LOCK(ring->lock, flags);
56*4882a593Smuzhiyun ring->state = RING_ACTIVE;
57*4882a593Smuzhiyun ring->threshold = 0;
58*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun return ring;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun fail:
63*4882a593Smuzhiyun if (ring) {
64*4882a593Smuzhiyun dhd_dbg_ring_deinit(dhd, ring);
65*4882a593Smuzhiyun ring->ring_buf = NULL;
66*4882a593Smuzhiyun ring->ring_size = 0;
67*4882a593Smuzhiyun MFREE(dhd->osh, ring, sizeof(dhd_dbg_ring_t));
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun return NULL;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun void
dhd_dbg_ring_dealloc_deinit(void ** ring_ptr,dhd_pub_t * dhd)73*4882a593Smuzhiyun dhd_dbg_ring_dealloc_deinit(void **ring_ptr, dhd_pub_t *dhd)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun dhd_dbg_ring_t *ring = NULL;
76*4882a593Smuzhiyun dhd_dbg_ring_t **dbgring = (dhd_dbg_ring_t **)ring_ptr;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (!dbgring)
79*4882a593Smuzhiyun return;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun ring = *dbgring;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (ring) {
84*4882a593Smuzhiyun dhd_dbg_ring_deinit(dhd, ring);
85*4882a593Smuzhiyun ring->ring_buf = NULL;
86*4882a593Smuzhiyun ring->ring_size = 0;
87*4882a593Smuzhiyun MFREE(dhd->osh, ring, sizeof(dhd_dbg_ring_t));
88*4882a593Smuzhiyun *dbgring = NULL;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun int
dhd_dbg_ring_init(dhd_pub_t * dhdp,dhd_dbg_ring_t * ring,uint16 id,uint8 * name,uint32 ring_sz,void * allocd_buf,bool pull_inactive)93*4882a593Smuzhiyun dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name,
94*4882a593Smuzhiyun uint32 ring_sz, void *allocd_buf, bool pull_inactive)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun void *buf;
97*4882a593Smuzhiyun unsigned long flags = 0;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (allocd_buf == NULL) {
100*4882a593Smuzhiyun return BCME_NOMEM;
101*4882a593Smuzhiyun } else {
102*4882a593Smuzhiyun buf = allocd_buf;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun ring->lock = DHD_DBG_RING_LOCK_INIT(dhdp->osh);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun DHD_DBG_RING_LOCK(ring->lock, flags);
108*4882a593Smuzhiyun ring->id = id;
109*4882a593Smuzhiyun strlcpy((char *)ring->name, (char *)name, sizeof(ring->name));
110*4882a593Smuzhiyun ring->ring_size = ring_sz;
111*4882a593Smuzhiyun ring->wp = ring->rp = 0;
112*4882a593Smuzhiyun ring->ring_buf = buf;
113*4882a593Smuzhiyun ring->threshold = DBGRING_FLUSH_THRESHOLD(ring);
114*4882a593Smuzhiyun ring->state = RING_SUSPEND;
115*4882a593Smuzhiyun ring->rem_len = 0;
116*4882a593Smuzhiyun ring->sched_pull = TRUE;
117*4882a593Smuzhiyun ring->pull_inactive = pull_inactive;
118*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return BCME_OK;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun void
dhd_dbg_ring_deinit(dhd_pub_t * dhdp,dhd_dbg_ring_t * ring)124*4882a593Smuzhiyun dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun unsigned long flags = 0;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun DHD_DBG_RING_LOCK(ring->lock, flags);
129*4882a593Smuzhiyun ring->id = 0;
130*4882a593Smuzhiyun ring->name[0] = 0;
131*4882a593Smuzhiyun ring->wp = ring->rp = 0;
132*4882a593Smuzhiyun memset(&ring->stat, 0, sizeof(ring->stat));
133*4882a593Smuzhiyun ring->threshold = 0;
134*4882a593Smuzhiyun ring->state = RING_STOP;
135*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun DHD_DBG_RING_LOCK_DEINIT(dhdp->osh, ring->lock);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun void
dhd_dbg_ring_sched_pull(dhd_dbg_ring_t * ring,uint32 pending_len,os_pullreq_t pull_fn,void * os_pvt,const int id)141*4882a593Smuzhiyun dhd_dbg_ring_sched_pull(dhd_dbg_ring_t *ring, uint32 pending_len,
142*4882a593Smuzhiyun os_pullreq_t pull_fn, void *os_pvt, const int id)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun unsigned long flags = 0;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun DHD_DBG_RING_LOCK(ring->lock, flags);
147*4882a593Smuzhiyun /* if the current pending size is bigger than threshold and
148*4882a593Smuzhiyun * threshold is set
149*4882a593Smuzhiyun */
150*4882a593Smuzhiyun if (ring->threshold > 0 &&
151*4882a593Smuzhiyun (pending_len >= ring->threshold) && ring->sched_pull) {
152*4882a593Smuzhiyun /*
153*4882a593Smuzhiyun * Update the state and release the lock before calling
154*4882a593Smuzhiyun * the pull_fn. Do not transfer control to other layers
155*4882a593Smuzhiyun * with locks held. If the call back again calls into
156*4882a593Smuzhiyun * the same layer fro this context, can lead to deadlock.
157*4882a593Smuzhiyun */
158*4882a593Smuzhiyun ring->sched_pull = FALSE;
159*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
160*4882a593Smuzhiyun pull_fn(os_pvt, id);
161*4882a593Smuzhiyun } else {
162*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun uint32
dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t * ring)167*4882a593Smuzhiyun dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun uint32 pending_len = 0;
170*4882a593Smuzhiyun unsigned long flags = 0;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun DHD_DBG_RING_LOCK(ring->lock, flags);
173*4882a593Smuzhiyun if (ring->stat.written_bytes > ring->stat.read_bytes) {
174*4882a593Smuzhiyun pending_len = ring->stat.written_bytes - ring->stat.read_bytes;
175*4882a593Smuzhiyun } else if (ring->stat.written_bytes < ring->stat.read_bytes) {
176*4882a593Smuzhiyun pending_len = PENDING_LEN_MAX - ring->stat.read_bytes + ring->stat.written_bytes;
177*4882a593Smuzhiyun } else {
178*4882a593Smuzhiyun pending_len = 0;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun return pending_len;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun int
dhd_dbg_ring_push(dhd_dbg_ring_t * ring,dhd_dbg_ring_entry_t * hdr,void * data)186*4882a593Smuzhiyun dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun unsigned long flags;
189*4882a593Smuzhiyun uint32 w_len;
190*4882a593Smuzhiyun uint32 avail_size;
191*4882a593Smuzhiyun dhd_dbg_ring_entry_t *w_entry, *r_entry;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (!ring || !hdr || !data) {
194*4882a593Smuzhiyun return BCME_BADARG;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun DHD_DBG_RING_LOCK(ring->lock, flags);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (ring->state != RING_ACTIVE) {
200*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
201*4882a593Smuzhiyun return BCME_OK;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun w_len = ENTRY_LENGTH(hdr);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun DHD_DBGIF(("%s: RING%d[%s] hdr->len=%u, w_len=%u, wp=%d, rp=%d, ring_start=0x%p;"
207*4882a593Smuzhiyun " ring_size=%u\n",
208*4882a593Smuzhiyun __FUNCTION__, ring->id, ring->name, hdr->len, w_len, ring->wp, ring->rp,
209*4882a593Smuzhiyun ring->ring_buf, ring->ring_size));
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (w_len > ring->ring_size) {
212*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
213*4882a593Smuzhiyun DHD_ERROR(("%s: RING%d[%s] w_len=%u, ring_size=%u,"
214*4882a593Smuzhiyun " write size exceeds ring size !\n",
215*4882a593Smuzhiyun __FUNCTION__, ring->id, ring->name, w_len, ring->ring_size));
216*4882a593Smuzhiyun return BCME_ERROR;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun /* Claim the space */
219*4882a593Smuzhiyun do {
220*4882a593Smuzhiyun avail_size = DBG_RING_CHECK_WRITE_SPACE(ring->rp, ring->wp, ring->ring_size);
221*4882a593Smuzhiyun if (avail_size <= w_len) {
222*4882a593Smuzhiyun /* Prepare the space */
223*4882a593Smuzhiyun if (ring->rp <= ring->wp) {
224*4882a593Smuzhiyun ring->tail_padded = TRUE;
225*4882a593Smuzhiyun ring->rem_len = ring->ring_size - ring->wp;
226*4882a593Smuzhiyun DHD_DBGIF(("%s: RING%d[%s] Insuffient tail space,"
227*4882a593Smuzhiyun " rp=%d, wp=%d, rem_len=%d, ring_size=%d,"
228*4882a593Smuzhiyun " avail_size=%d, w_len=%d\n", __FUNCTION__,
229*4882a593Smuzhiyun ring->id, ring->name, ring->rp, ring->wp,
230*4882a593Smuzhiyun ring->rem_len, ring->ring_size, avail_size,
231*4882a593Smuzhiyun w_len));
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /* 0 pad insufficient tail space */
234*4882a593Smuzhiyun memset((uint8 *)ring->ring_buf + ring->wp, 0, ring->rem_len);
235*4882a593Smuzhiyun /* If read pointer is still at the beginning, make some room */
236*4882a593Smuzhiyun if (ring->rp == 0) {
237*4882a593Smuzhiyun r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf +
238*4882a593Smuzhiyun ring->rp);
239*4882a593Smuzhiyun ring->rp += ENTRY_LENGTH(r_entry);
240*4882a593Smuzhiyun ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
241*4882a593Smuzhiyun DHD_DBGIF(("%s: rp at 0, move by one entry length"
242*4882a593Smuzhiyun " (%u bytes)\n",
243*4882a593Smuzhiyun __FUNCTION__, (uint32)ENTRY_LENGTH(r_entry)));
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun if (ring->rp == ring->wp) {
246*4882a593Smuzhiyun ring->rp = 0;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun ring->wp = 0;
249*4882a593Smuzhiyun DHD_DBGIF(("%s: new rp=%u, wp=%u\n",
250*4882a593Smuzhiyun __FUNCTION__, ring->rp, ring->wp));
251*4882a593Smuzhiyun } else {
252*4882a593Smuzhiyun /* Not enough space for new entry, free some up */
253*4882a593Smuzhiyun r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf +
254*4882a593Smuzhiyun ring->rp);
255*4882a593Smuzhiyun /* check bounds before incrementing read ptr */
256*4882a593Smuzhiyun if (ring->rp + ENTRY_LENGTH(r_entry) >= ring->ring_size) {
257*4882a593Smuzhiyun DHD_ERROR(("%s: RING%d[%s] rp points out of boundary,"
258*4882a593Smuzhiyun "ring->wp=%u, ring->rp=%u, ring->ring_size=%d\n",
259*4882a593Smuzhiyun __FUNCTION__, ring->id, ring->name, ring->wp,
260*4882a593Smuzhiyun ring->rp, ring->ring_size));
261*4882a593Smuzhiyun ASSERT(0);
262*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
263*4882a593Smuzhiyun return BCME_BUFTOOSHORT;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun ring->rp += ENTRY_LENGTH(r_entry);
266*4882a593Smuzhiyun /* skip padding if there is one */
267*4882a593Smuzhiyun if (ring->tail_padded &&
268*4882a593Smuzhiyun ((ring->rp + ring->rem_len) == ring->ring_size)) {
269*4882a593Smuzhiyun DHD_DBGIF(("%s: RING%d[%s] Found padding,"
270*4882a593Smuzhiyun " avail_size=%d, w_len=%d, set rp = 0\n",
271*4882a593Smuzhiyun __FUNCTION__,
272*4882a593Smuzhiyun ring->id, ring->name, avail_size, w_len));
273*4882a593Smuzhiyun ring->rp = 0;
274*4882a593Smuzhiyun ring->tail_padded = FALSE;
275*4882a593Smuzhiyun ring->rem_len = 0;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
278*4882a593Smuzhiyun DHD_DBGIF(("%s: RING%d[%s] read_bytes=%d, wp=%d, rp=%d\n",
279*4882a593Smuzhiyun __FUNCTION__, ring->id, ring->name, ring->stat.read_bytes,
280*4882a593Smuzhiyun ring->wp, ring->rp));
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun } else {
283*4882a593Smuzhiyun break;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun } while (TRUE);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun /* check before writing to the ring */
288*4882a593Smuzhiyun if (ring->wp + w_len >= ring->ring_size) {
289*4882a593Smuzhiyun DHD_ERROR(("%s: RING%d[%s] wp pointed out of ring boundary, "
290*4882a593Smuzhiyun "wp=%d, ring_size=%d, w_len=%u\n", __FUNCTION__, ring->id,
291*4882a593Smuzhiyun ring->name, ring->wp, ring->ring_size, w_len));
292*4882a593Smuzhiyun ASSERT(0);
293*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
294*4882a593Smuzhiyun return BCME_BUFTOOLONG;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun w_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->wp);
298*4882a593Smuzhiyun /* header */
299*4882a593Smuzhiyun memcpy(w_entry, hdr, DBG_RING_ENTRY_SIZE);
300*4882a593Smuzhiyun w_entry->len = hdr->len;
301*4882a593Smuzhiyun /* payload */
302*4882a593Smuzhiyun memcpy((char *)w_entry + DBG_RING_ENTRY_SIZE, data, w_entry->len);
303*4882a593Smuzhiyun /* update write pointer */
304*4882a593Smuzhiyun ring->wp += w_len;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /* update statistics */
307*4882a593Smuzhiyun ring->stat.written_records++;
308*4882a593Smuzhiyun ring->stat.written_bytes += w_len;
309*4882a593Smuzhiyun DHD_DBGIF(("%s : RING%d[%s] written_records %d, written_bytes %d, read_bytes=%d,"
310*4882a593Smuzhiyun " ring->threshold=%d, wp=%d, rp=%d\n", __FUNCTION__, ring->id, ring->name,
311*4882a593Smuzhiyun ring->stat.written_records, ring->stat.written_bytes, ring->stat.read_bytes,
312*4882a593Smuzhiyun ring->threshold, ring->wp, ring->rp));
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
315*4882a593Smuzhiyun return BCME_OK;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /*
319*4882a593Smuzhiyun * This function folds ring->lock, so callers of this function
320*4882a593Smuzhiyun * should not hold ring->lock.
321*4882a593Smuzhiyun */
322*4882a593Smuzhiyun int
dhd_dbg_ring_pull_single(dhd_dbg_ring_t * ring,void * data,uint32 buf_len,bool strip_header)323*4882a593Smuzhiyun dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_header)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun dhd_dbg_ring_entry_t *r_entry = NULL;
326*4882a593Smuzhiyun uint32 rlen = 0;
327*4882a593Smuzhiyun char *buf = NULL;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (!ring || !data || buf_len <= 0) {
330*4882a593Smuzhiyun return 0;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /* pull from ring is allowed for inactive (suspended) ring
334*4882a593Smuzhiyun * in case of ecounters only, this is because, for ecounters
335*4882a593Smuzhiyun * when a trap occurs the ring is suspended and data is then
336*4882a593Smuzhiyun * pulled to dump it to a file. For other rings if ring is
337*4882a593Smuzhiyun * not in active state return without processing (as before)
338*4882a593Smuzhiyun */
339*4882a593Smuzhiyun if (!ring->pull_inactive && (ring->state != RING_ACTIVE)) {
340*4882a593Smuzhiyun goto exit;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (ring->rp == ring->wp) {
344*4882a593Smuzhiyun goto exit;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun DHD_DBGIF(("%s: RING%d[%s] buf_len=%u, wp=%d, rp=%d, ring_start=0x%p; ring_size=%u\n",
348*4882a593Smuzhiyun __FUNCTION__, ring->id, ring->name, buf_len, ring->wp, ring->rp,
349*4882a593Smuzhiyun ring->ring_buf, ring->ring_size));
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->rp);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /* Boundary Check */
354*4882a593Smuzhiyun rlen = ENTRY_LENGTH(r_entry);
355*4882a593Smuzhiyun if ((ring->rp + rlen) > ring->ring_size) {
356*4882a593Smuzhiyun DHD_ERROR(("%s: entry len %d is out of boundary of ring size %d,"
357*4882a593Smuzhiyun " current ring %d[%s] - rp=%d\n", __FUNCTION__, rlen,
358*4882a593Smuzhiyun ring->ring_size, ring->id, ring->name, ring->rp));
359*4882a593Smuzhiyun rlen = 0;
360*4882a593Smuzhiyun goto exit;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (strip_header) {
364*4882a593Smuzhiyun rlen = r_entry->len;
365*4882a593Smuzhiyun buf = (char *)r_entry + DBG_RING_ENTRY_SIZE;
366*4882a593Smuzhiyun } else {
367*4882a593Smuzhiyun rlen = ENTRY_LENGTH(r_entry);
368*4882a593Smuzhiyun buf = (char *)r_entry;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun if (rlen > buf_len) {
371*4882a593Smuzhiyun DHD_ERROR(("%s: buf len %d is too small for entry len %d\n",
372*4882a593Smuzhiyun __FUNCTION__, buf_len, rlen));
373*4882a593Smuzhiyun DHD_ERROR(("%s: ring %d[%s] - ring size=%d, wp=%d, rp=%d\n",
374*4882a593Smuzhiyun __FUNCTION__, ring->id, ring->name, ring->ring_size,
375*4882a593Smuzhiyun ring->wp, ring->rp));
376*4882a593Smuzhiyun ASSERT(0);
377*4882a593Smuzhiyun rlen = 0;
378*4882a593Smuzhiyun goto exit;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun memcpy(data, buf, rlen);
382*4882a593Smuzhiyun /* update ring context */
383*4882a593Smuzhiyun ring->rp += ENTRY_LENGTH(r_entry);
384*4882a593Smuzhiyun /* don't pass wp but skip padding if there is one */
385*4882a593Smuzhiyun if (ring->rp != ring->wp &&
386*4882a593Smuzhiyun ring->tail_padded && ((ring->rp + ring->rem_len) >= ring->ring_size)) {
387*4882a593Smuzhiyun DHD_DBGIF(("%s: RING%d[%s] Found padding, rp=%d, wp=%d\n",
388*4882a593Smuzhiyun __FUNCTION__, ring->id, ring->name, ring->rp, ring->wp));
389*4882a593Smuzhiyun ring->rp = 0;
390*4882a593Smuzhiyun ring->tail_padded = FALSE;
391*4882a593Smuzhiyun ring->rem_len = 0;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun if (ring->rp >= ring->ring_size) {
394*4882a593Smuzhiyun DHD_ERROR(("%s: RING%d[%s] rp pointed out of ring boundary,"
395*4882a593Smuzhiyun " rp=%d, ring_size=%d\n", __FUNCTION__, ring->id,
396*4882a593Smuzhiyun ring->name, ring->rp, ring->ring_size));
397*4882a593Smuzhiyun ASSERT(0);
398*4882a593Smuzhiyun rlen = 0;
399*4882a593Smuzhiyun goto exit;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
402*4882a593Smuzhiyun DHD_DBGIF(("%s RING%d[%s]read_bytes %d, wp=%d, rp=%d\n", __FUNCTION__,
403*4882a593Smuzhiyun ring->id, ring->name, ring->stat.read_bytes, ring->wp, ring->rp));
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun exit:
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun return rlen;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun int
dhd_dbg_ring_pull(dhd_dbg_ring_t * ring,void * data,uint32 buf_len,bool strip_hdr)411*4882a593Smuzhiyun dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_hdr)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun int32 r_len, total_r_len = 0;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun if (!ring || !data)
416*4882a593Smuzhiyun return 0;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun if (!ring->pull_inactive && (ring->state != RING_ACTIVE)) {
419*4882a593Smuzhiyun return 0;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun while (buf_len > 0) {
423*4882a593Smuzhiyun r_len = dhd_dbg_ring_pull_single(ring, data, buf_len, strip_hdr);
424*4882a593Smuzhiyun if (r_len == 0)
425*4882a593Smuzhiyun break;
426*4882a593Smuzhiyun data = (uint8 *)data + r_len;
427*4882a593Smuzhiyun buf_len -= r_len;
428*4882a593Smuzhiyun total_r_len += r_len;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun return total_r_len;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun int
dhd_dbg_ring_config(dhd_dbg_ring_t * ring,int log_level,uint32 threshold)435*4882a593Smuzhiyun dhd_dbg_ring_config(dhd_dbg_ring_t *ring, int log_level, uint32 threshold)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun unsigned long flags = 0;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun if (!ring)
440*4882a593Smuzhiyun return BCME_BADADDR;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun if (ring->state == RING_STOP)
443*4882a593Smuzhiyun return BCME_UNSUPPORTED;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun DHD_DBG_RING_LOCK(ring->lock, flags);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun if (log_level == 0)
448*4882a593Smuzhiyun ring->state = RING_SUSPEND;
449*4882a593Smuzhiyun else
450*4882a593Smuzhiyun ring->state = RING_ACTIVE;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun ring->log_level = log_level;
453*4882a593Smuzhiyun ring->threshold = MIN(threshold, DBGRING_FLUSH_THRESHOLD(ring));
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun DHD_DBG_RING_UNLOCK(ring->lock, flags);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun return BCME_OK;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun void
dhd_dbg_ring_start(dhd_dbg_ring_t * ring)461*4882a593Smuzhiyun dhd_dbg_ring_start(dhd_dbg_ring_t *ring)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun if (!ring)
464*4882a593Smuzhiyun return;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /* Initialize the information for the ring */
467*4882a593Smuzhiyun ring->state = RING_SUSPEND;
468*4882a593Smuzhiyun ring->log_level = 0;
469*4882a593Smuzhiyun ring->rp = ring->wp = 0;
470*4882a593Smuzhiyun ring->threshold = 0;
471*4882a593Smuzhiyun memset(&ring->stat, 0, sizeof(struct ring_statistics));
472*4882a593Smuzhiyun memset(ring->ring_buf, 0, ring->ring_size);
473*4882a593Smuzhiyun }
474