aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h15
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c13
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c75
-rw-r--r--drivers/net/wireless/ath/ath6kl/target.h14
5 files changed, 107 insertions, 13 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index c5213d509093..65d0d84b4767 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -26,6 +26,7 @@
26#include "htc.h" 26#include "htc.h"
27#include "wmi.h" 27#include "wmi.h"
28#include "bmi.h" 28#include "bmi.h"
29#include "target.h"
29 30
30#define MAX_ATH6KL 1 31#define MAX_ATH6KL 1
31#define ATH6KL_MAX_RX_BUFFERS 16 32#define ATH6KL_MAX_RX_BUFFERS 16
@@ -494,6 +495,19 @@ static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info
494 cred_info->cur_free_credits -= credits; 495 cred_info->cur_free_credits -= credits;
495} 496}
496 497
498static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar,
499 u32 item_offset)
500{
501 u32 addr = 0;
502
503 if (ar->target_type == TARGET_TYPE_AR6003)
504 addr = ATH6KL_AR6003_HI_START_ADDR + item_offset;
505 else if (ar->target_type == TARGET_TYPE_AR6004)
506 addr = ATH6KL_AR6004_HI_START_ADDR + item_offset;
507
508 return addr;
509}
510
497void ath6kl_destroy(struct net_device *dev, unsigned int unregister); 511void ath6kl_destroy(struct net_device *dev, unsigned int unregister);
498int ath6kl_configure_target(struct ath6kl *ar); 512int ath6kl_configure_target(struct ath6kl *ar);
499void ath6kl_detect_error(unsigned long ptr); 513void ath6kl_detect_error(unsigned long ptr);
@@ -510,6 +524,7 @@ void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar);
510int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length); 524int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length);
511int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value); 525int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value);
512int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length); 526int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length);
527int ath6kl_read_fwlogs(struct ath6kl *ar);
513void ath6kl_init_profile_info(struct ath6kl *ar); 528void ath6kl_init_profile_info(struct ath6kl *ar);
514void ath6kl_tx_data_cleanup(struct ath6kl *ar); 529void ath6kl_tx_data_cleanup(struct ath6kl *ar);
515void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, 530void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 239c092d3e11..87de44d0ee33 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -247,6 +247,9 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
247 if (!buf) 247 if (!buf)
248 return -ENOMEM; 248 return -ENOMEM;
249 249
250 /* read undelivered logs from firmware */
251 ath6kl_read_fwlogs(ar);
252
250 spin_lock_bh(&ar->debug.fwlog_lock); 253 spin_lock_bh(&ar->debug.fwlog_lock);
251 254
252 while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { 255 while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) {
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 60baf448f548..d234dc22e709 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -110,19 +110,6 @@ static u8 ath6kl_get_fw_iftype(struct ath6kl *ar)
110 } 110 }
111} 111}
112 112
113static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar,
114 u32 item_offset)
115{
116 u32 addr = 0;
117
118 if (ar->target_type == TARGET_TYPE_AR6003)
119 addr = ATH6KL_AR6003_HI_START_ADDR + item_offset;
120 else if (ar->target_type == TARGET_TYPE_AR6004)
121 addr = ATH6KL_AR6004_HI_START_ADDR + item_offset;
122
123 return addr;
124}
125
126static int ath6kl_set_host_app_area(struct ath6kl *ar) 113static int ath6kl_set_host_app_area(struct ath6kl *ar)
127{ 114{
128 u32 address, data; 115 u32 address, data;
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
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h
index 6c66a08e1793..dd8b953cbfc0 100644
--- a/drivers/net/wireless/ath/ath6kl/target.h
+++ b/drivers/net/wireless/ath/ath6kl/target.h
@@ -343,4 +343,18 @@ struct host_interest {
343 343
344#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 344#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500
345 345
346struct ath6kl_dbglog_buf {
347 __le32 next;
348 __le32 buffer_addr;
349 __le32 bufsize;
350 __le32 length;
351 __le32 count;
352 __le32 free;
353} __packed;
354
355struct ath6kl_dbglog_hdr {
356 __le32 dbuf_addr;
357 __le32 dropped;
358} __packed;
359
346#endif 360#endif