aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl/main.c
diff options
context:
space:
mode:
authorKalle Valo <kvalo@qca.qualcomm.com>2011-09-02 03:32:05 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2011-09-02 03:32:05 -0400
commitbc07ddb29a7b71ad009bcd84bee4c93908cf22b6 (patch)
tree4167151044211d1bea3e407ccd40b4e7a270f642 /drivers/net/wireless/ath/ath6kl/main.c
parentaddb44be036dd5fc814be770ec4b90f08c820e76 (diff)
ath6kl: read fwlog from firmware ring buffer
Firmare sends the logs only when it's internal ring buffer is full. But if firmware crashes we need to retrieve the latest logs through diagnose window. This is now done everytime the debugfs file is read. Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/main.c')
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index e346f835e779..937c7a238c12 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -309,6 +309,81 @@ int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length)
309 return 0; 309 return 0;
310} 310}
311 311
312int ath6kl_read_fwlogs(struct ath6kl *ar)
313{
314 struct ath6kl_dbglog_hdr debug_hdr;
315 struct ath6kl_dbglog_buf debug_buf;
316 u32 address, length, dropped, firstbuf, debug_hdr_addr;
317 int ret = 0, loop;
318 u8 *buf;
319
320 buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL);
321 if (!buf)
322 return -ENOMEM;
323
324 address = TARG_VTOP(ar->target_type,
325 ath6kl_get_hi_item_addr(ar,
326 HI_ITEM(hi_dbglog_hdr)));
327
328 ret = ath6kl_diag_read32(ar, address, &debug_hdr_addr);
329 if (ret)
330 goto out;
331
332 /* Get the contents of the ring buffer */
333 if (debug_hdr_addr == 0) {
334 ath6kl_warn("Invalid address for debug_hdr_addr\n");
335 ret = -EINVAL;
336 goto out;
337 }
338
339 address = TARG_VTOP(ar->target_type, debug_hdr_addr);
340 ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
341
342 address = TARG_VTOP(ar->target_type,
343 le32_to_cpu(debug_hdr.dbuf_addr));
344 firstbuf = address;
345 dropped = le32_to_cpu(debug_hdr.dropped);
346 ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
347
348 loop = 100;
349
350 do {
351 address = TARG_VTOP(ar->target_type,
352 le32_to_cpu(debug_buf.buffer_addr));
353 length = le32_to_cpu(debug_buf.length);
354
355 if (length != 0 && (le32_to_cpu(debug_buf.length) <=
356 le32_to_cpu(debug_buf.bufsize))) {
357 length = ALIGN(length, 4);
358
359 ret = ath6kl_diag_read(ar, address,
360 buf, length);
361 if (ret)
362 goto out;
363
364 ath6kl_debug_fwlog_event(ar, buf, length);
365 }
366
367 address = TARG_VTOP(ar->target_type,
368 le32_to_cpu(debug_buf.next));
369 ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
370 if (ret)
371 goto out;
372
373 loop--;
374
375 if (WARN_ON(loop == 0)) {
376 ret = -ETIMEDOUT;
377 goto out;
378 }
379 } while (address != firstbuf);
380
381out:
382 kfree(buf);
383
384 return ret;
385}
386
312/* FIXME: move to a better place, target.h? */ 387/* FIXME: move to a better place, target.h? */
313#define AR6003_RESET_CONTROL_ADDRESS 0x00004000 388#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
314#define AR6004_RESET_CONTROL_ADDRESS 0x00004000 389#define AR6004_RESET_CONTROL_ADDRESS 0x00004000