wifi: update driver to 100.10.545.2 to support STA/AP concurrent [1/2]
[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 *
965f77c4 6 * Copyright (C) 1999-2019, Broadcom.
d2839953
RC
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 *
965f77c4 26 * $Id: dhd_dbg_ring.c 792099 2018-12-03 15:45:56Z $
d2839953
RC
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,
965f77c4 39 uint32 ring_sz, void *allocd_buf, bool pull_inactive)
d2839953
RC
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;
965f77c4 65 ring->pull_inactive = pull_inactive;
d2839953
RC
66 DHD_DBG_RING_UNLOCK(ring->lock, flags);
67
68 return BCME_OK;
69}
70
71void
72dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring)
73{
74 unsigned long flags = 0;
75 DHD_DBG_RING_LOCK(ring->lock, flags);
76 ring->id = 0;
77 ring->name[0] = 0;
78 ring->wp = ring->rp = 0;
79 memset(&ring->stat, 0, sizeof(ring->stat));
80 ring->threshold = 0;
81 ring->state = RING_STOP;
82 DHD_DBG_RING_UNLOCK(ring->lock, flags);
83
84 DHD_DBG_RING_LOCK_DEINIT(dhdp->osh, ring->lock);
85}
86
87void
88dhd_dbg_ring_sched_pull(dhd_dbg_ring_t *ring, uint32 pending_len,
89 os_pullreq_t pull_fn, void *os_pvt, const int id)
90{
91 unsigned long flags = 0;
92 DHD_DBG_RING_LOCK(ring->lock, flags);
93 /* if the current pending size is bigger than threshold and
94 * threshold is set
95 */
96 if (ring->threshold > 0 &&
97 (pending_len >= ring->threshold) && ring->sched_pull) {
98 /*
99 * Update the state and release the lock before calling
100 * the pull_fn. Do not transfer control to other layers
101 * with locks held. If the call back again calls into
102 * the same layer fro this context, can lead to deadlock.
103 */
104 ring->sched_pull = FALSE;
105 DHD_DBG_RING_UNLOCK(ring->lock, flags);
106 pull_fn(os_pvt, id);
107 } else {
108 DHD_DBG_RING_UNLOCK(ring->lock, flags);
109 }
110}
111
112uint32
113dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring)
114{
115 uint32 pending_len = 0;
116 unsigned long flags = 0;
117 DHD_DBG_RING_LOCK(ring->lock, flags);
118 if (ring->stat.written_bytes > ring->stat.read_bytes) {
119 pending_len = ring->stat.written_bytes - ring->stat.read_bytes;
120 } else if (ring->stat.written_bytes < ring->stat.read_bytes) {
121 pending_len = PENDING_LEN_MAX - ring->stat.read_bytes + ring->stat.written_bytes;
122 } else {
123 pending_len = 0;
124 }
125 DHD_DBG_RING_UNLOCK(ring->lock, flags);
126
127 return pending_len;
128}
129
130int
131dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
132{
133 unsigned long flags;
134 uint32 w_len;
135 uint32 avail_size;
136 dhd_dbg_ring_entry_t *w_entry, *r_entry;
137
138 if (!ring || !hdr || !data) {
139 return BCME_BADARG;
140 }
141
142 DHD_DBG_RING_LOCK(ring->lock, flags);
143
144 if (ring->state != RING_ACTIVE) {
145 DHD_DBG_RING_UNLOCK(ring->lock, flags);
146 return BCME_OK;
147 }
148
149 w_len = ENTRY_LENGTH(hdr);
150
151 DHD_DBGIF(("%s: RING%d[%s] hdr->len=%u, w_len=%u, wp=%d, rp=%d, ring_start=0x%p;"
152 " ring_size=%u\n",
153 __FUNCTION__, ring->id, ring->name, hdr->len, w_len, ring->wp, ring->rp,
154 ring->ring_buf, ring->ring_size));
155
156 if (w_len > ring->ring_size) {
157 DHD_DBG_RING_UNLOCK(ring->lock, flags);
158 DHD_ERROR(("%s: RING%d[%s] w_len=%u, ring_size=%u,"
159 " write size exceeds ring size !\n",
160 __FUNCTION__, ring->id, ring->name, w_len, ring->ring_size));
161 return BCME_BUFTOOLONG;
162 }
163 /* Claim the space */
164 do {
165 avail_size = DBG_RING_CHECK_WRITE_SPACE(ring->rp, ring->wp, ring->ring_size);
166 if (avail_size <= w_len) {
167 /* Prepare the space */
168 if (ring->rp <= ring->wp) {
169 ring->tail_padded = TRUE;
170 ring->rem_len = ring->ring_size - ring->wp;
171 DHD_DBGIF(("%s: RING%d[%s] Insuffient tail space,"
172 " rp=%d, wp=%d, rem_len=%d, ring_size=%d,"
173 " avail_size=%d, w_len=%d\n", __FUNCTION__,
174 ring->id, ring->name, ring->rp, ring->wp,
175 ring->rem_len, ring->ring_size, avail_size,
176 w_len));
177
178 /* 0 pad insufficient tail space */
179 memset((uint8 *)ring->ring_buf + ring->wp, 0, ring->rem_len);
180 /* If read pointer is still at the beginning, make some room */
181 if (ring->rp == 0) {
182 r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf +
183 ring->rp);
184 ring->rp += ENTRY_LENGTH(r_entry);
185 ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
186 DHD_DBGIF(("%s: rp at 0, move by one entry length"
187 " (%u bytes)\n",
188 __FUNCTION__, (uint32)ENTRY_LENGTH(r_entry)));
189 }
190 if (ring->rp == ring->wp) {
191 ring->rp = 0;
192 }
193 ring->wp = 0;
194 DHD_DBGIF(("%s: new rp=%u, wp=%u\n",
195 __FUNCTION__, ring->rp, ring->wp));
196 } else {
197 /* Not enough space for new entry, free some up */
198 r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf +
199 ring->rp);
200 /* check bounds before incrementing read ptr */
201 if (ring->rp + ENTRY_LENGTH(r_entry) >= ring->ring_size) {
965f77c4 202 DHD_ERROR(("%s: RING%d[%s] rp points out of boundary, "
d2839953
RC
203 "ring->wp=%u, ring->rp=%u, ring->ring_size=%d\n",
204 __FUNCTION__, ring->id, ring->name, ring->wp,
205 ring->rp, ring->ring_size));
206 ASSERT(0);
207 DHD_DBG_RING_UNLOCK(ring->lock, flags);
208 return BCME_BUFTOOSHORT;
209 }
210 ring->rp += ENTRY_LENGTH(r_entry);
211 /* skip padding if there is one */
212 if (ring->tail_padded &&
213 ((ring->rp + ring->rem_len) == ring->ring_size)) {
214 DHD_DBGIF(("%s: RING%d[%s] Found padding,"
215 " avail_size=%d, w_len=%d, set rp=0\n",
216 __FUNCTION__, ring->id, ring->name,
217 avail_size, w_len));
218 ring->rp = 0;
219 ring->tail_padded = FALSE;
220 ring->rem_len = 0;
221 }
222 ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
223 DHD_DBGIF(("%s: RING%d[%s] read_bytes=%d, wp=%d, rp=%d\n",
224 __FUNCTION__, ring->id, ring->name, ring->stat.read_bytes,
225 ring->wp, ring->rp));
226 }
227 } else {
228 break;
229 }
230 } while (TRUE);
231
232 /* check before writing to the ring */
233 if (ring->wp + w_len >= ring->ring_size) {
234 DHD_ERROR(("%s: RING%d[%s] wp pointed out of ring boundary, "
235 "wp=%d, ring_size=%d, w_len=%u\n", __FUNCTION__, ring->id,
236 ring->name, ring->wp, ring->ring_size, w_len));
237 ASSERT(0);
238 DHD_DBG_RING_UNLOCK(ring->lock, flags);
239 return BCME_BUFTOOLONG;
240 }
241
242 w_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->wp);
243 /* header */
244 memcpy(w_entry, hdr, DBG_RING_ENTRY_SIZE);
245 w_entry->len = hdr->len;
246 /* payload */
247 memcpy((char *)w_entry + DBG_RING_ENTRY_SIZE, data, w_entry->len);
248 /* update write pointer */
249 ring->wp += w_len;
250
251 /* update statistics */
252 ring->stat.written_records++;
253 ring->stat.written_bytes += w_len;
254 DHD_DBGIF(("%s : RING%d[%s] written_records %d, written_bytes %d, read_bytes=%d,"
255 " ring->threshold=%d, wp=%d, rp=%d\n", __FUNCTION__, ring->id, ring->name,
256 ring->stat.written_records, ring->stat.written_bytes, ring->stat.read_bytes,
257 ring->threshold, ring->wp, ring->rp));
258
259 DHD_DBG_RING_UNLOCK(ring->lock, flags);
260 return BCME_OK;
261}
262
965f77c4
RC
263/*
264 * This function folds ring->lock, so callers of this function
265 * should not hold ring->lock.
266 */
d2839953 267int
965f77c4 268dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_header)
d2839953
RC
269{
270 dhd_dbg_ring_entry_t *r_entry = NULL;
271 uint32 rlen = 0;
272 char *buf = NULL;
965f77c4 273 unsigned long flags;
d2839953
RC
274
275 if (!ring || !data || buf_len <= 0) {
276 return 0;
277 }
278
965f77c4
RC
279 DHD_DBG_RING_LOCK(ring->lock, flags);
280
d2839953
RC
281 /* pull from ring is allowed for inactive (suspended) ring
282 * in case of ecounters only, this is because, for ecounters
283 * when a trap occurs the ring is suspended and data is then
284 * pulled to dump it to a file. For other rings if ring is
285 * not in active state return without processing (as before)
286 */
965f77c4
RC
287 if (!ring->pull_inactive && (ring->state != RING_ACTIVE)) {
288 goto exit;
d2839953 289 }
d2839953
RC
290
291 if (ring->rp == ring->wp) {
965f77c4 292 goto exit;
d2839953
RC
293 }
294
295 DHD_DBGIF(("%s: RING%d[%s] buf_len=%u, wp=%d, rp=%d, ring_start=0x%p; ring_size=%u\n",
296 __FUNCTION__, ring->id, ring->name, buf_len, ring->wp, ring->rp,
297 ring->ring_buf, ring->ring_size));
298
299 r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->rp);
300
301 /* Boundary Check */
302 rlen = ENTRY_LENGTH(r_entry);
303 if ((ring->rp + rlen) > ring->ring_size) {
304 DHD_ERROR(("%s: entry len %d is out of boundary of ring size %d,"
305 " current ring %d[%s] - rp=%d\n", __FUNCTION__, rlen,
306 ring->ring_size, ring->id, ring->name, ring->rp));
965f77c4
RC
307 rlen = 0;
308 goto exit;
d2839953
RC
309 }
310
311 if (strip_header) {
312 rlen = r_entry->len;
313 buf = (char *)r_entry + DBG_RING_ENTRY_SIZE;
314 } else {
315 rlen = ENTRY_LENGTH(r_entry);
316 buf = (char *)r_entry;
317 }
318 if (rlen > buf_len) {
319 DHD_ERROR(("%s: buf len %d is too small for entry len %d\n",
320 __FUNCTION__, buf_len, rlen));
321 DHD_ERROR(("%s: ring %d[%s] - ring size=%d, wp=%d, rp=%d\n",
322 __FUNCTION__, ring->id, ring->name, ring->ring_size,
323 ring->wp, ring->rp));
324 ASSERT(0);
965f77c4
RC
325 rlen = 0;
326 goto exit;
d2839953
RC
327 }
328
329 memcpy(data, buf, rlen);
330 /* update ring context */
331 ring->rp += ENTRY_LENGTH(r_entry);
332 /* don't pass wp but skip padding if there is one */
333 if (ring->rp != ring->wp &&
965f77c4 334 ring->tail_padded && ((ring->rp + ring->rem_len) >= ring->ring_size)) {
d2839953
RC
335 DHD_DBGIF(("%s: RING%d[%s] Found padding, rp=%d, wp=%d\n",
336 __FUNCTION__, ring->id, ring->name, ring->rp, ring->wp));
337 ring->rp = 0;
338 ring->tail_padded = FALSE;
339 ring->rem_len = 0;
340 }
341 if (ring->rp >= ring->ring_size) {
342 DHD_ERROR(("%s: RING%d[%s] rp pointed out of ring boundary,"
343 " rp=%d, ring_size=%d\n", __FUNCTION__, ring->id,
344 ring->name, ring->rp, ring->ring_size));
345 ASSERT(0);
965f77c4
RC
346 rlen = 0;
347 goto exit;
d2839953
RC
348 }
349 ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
350 DHD_DBGIF(("%s RING%d[%s]read_bytes %d, wp=%d, rp=%d\n", __FUNCTION__,
351 ring->id, ring->name, ring->stat.read_bytes, ring->wp, ring->rp));
352
965f77c4
RC
353exit:
354 DHD_DBG_RING_UNLOCK(ring->lock, flags);
355
d2839953
RC
356 return rlen;
357}
358
359int
360dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_hdr)
361{
362 int32 r_len, total_r_len = 0;
965f77c4 363 unsigned long flags;
d2839953
RC
364
365 if (!ring || !data)
366 return 0;
367
965f77c4
RC
368 DHD_DBG_RING_LOCK(ring->lock, flags);
369 if (!ring->pull_inactive && (ring->state != RING_ACTIVE)) {
370 DHD_DBG_RING_UNLOCK(ring->lock, flags);
d2839953 371 return 0;
965f77c4
RC
372 }
373 DHD_DBG_RING_UNLOCK(ring->lock, flags);
d2839953
RC
374
375 while (buf_len > 0) {
376 r_len = dhd_dbg_ring_pull_single(ring, data, buf_len, strip_hdr);
377 if (r_len == 0)
378 break;
379 data = (uint8 *)data + r_len;
380 buf_len -= r_len;
381 total_r_len += r_len;
382 }
383
384 return total_r_len;
385}
386
387int
388dhd_dbg_ring_config(dhd_dbg_ring_t *ring, int log_level, uint32 threshold)
389{
390 unsigned long flags = 0;
391 if (!ring)
392 return BCME_BADADDR;
393
394 if (ring->state == RING_STOP)
395 return BCME_UNSUPPORTED;
396
397 DHD_DBG_RING_LOCK(ring->lock, flags);
398
399 if (log_level == 0)
400 ring->state = RING_SUSPEND;
401 else
402 ring->state = RING_ACTIVE;
403
404 ring->log_level = log_level;
405 ring->threshold = MIN(threshold, DBGRING_FLUSH_THRESHOLD(ring));
406
407 DHD_DBG_RING_UNLOCK(ring->lock, flags);
408
409 return BCME_OK;
410}
411
412void
413dhd_dbg_ring_start(dhd_dbg_ring_t *ring)
414{
415 if (!ring)
416 return;
417
418 /* Initialize the information for the ring */
419 ring->state = RING_SUSPEND;
420 ring->log_level = 0;
421 ring->rp = ring->wp = 0;
422 ring->threshold = 0;
423 memset(&ring->stat, 0, sizeof(struct ring_statistics));
424 memset(ring->ring_buf, 0, ring->ring_size);
425}