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