|
@@ -59,26 +59,79 @@ int ath6kl_hif_rw_comp_handler(void *context, int status)
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+#define REG_DUMP_COUNT_AR6003 60
|
|
|
+#define REGISTER_DUMP_LEN_MAX 60
|
|
|
+
|
|
|
+static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
|
|
|
+{
|
|
|
+ __le32 regdump_val[REGISTER_DUMP_LEN_MAX];
|
|
|
+ u32 i, address, regdump_addr = 0;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (ar->target_type != TARGET_TYPE_AR6003)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* the reg dump pointer is copied to the host interest area */
|
|
|
+ address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
|
|
|
+ address = TARG_VTOP(ar->target_type, address);
|
|
|
+
|
|
|
+ /* read RAM location through diagnostic window */
|
|
|
+ ret = ath6kl_diag_read32(ar, address, ®dump_addr);
|
|
|
+
|
|
|
+ if (ret || !regdump_addr) {
|
|
|
+ ath6kl_warn("failed to get ptr to register dump area: %d\n",
|
|
|
+ ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n",
|
|
|
+ regdump_addr);
|
|
|
+ regdump_addr = TARG_VTOP(ar->target_type, regdump_addr);
|
|
|
+
|
|
|
+ /* fetch register dump data */
|
|
|
+ ret = ath6kl_diag_read(ar, regdump_addr, (u8 *)®dump_val[0],
|
|
|
+ REG_DUMP_COUNT_AR6003 * (sizeof(u32)));
|
|
|
+ if (ret) {
|
|
|
+ ath6kl_warn("failed to get register dump: %d\n", ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ath6kl_info("crash dump:\n");
|
|
|
+ ath6kl_info("hw 0x%x fw %s\n", ar->wiphy->hw_version,
|
|
|
+ ar->wiphy->fw_version);
|
|
|
+
|
|
|
+ BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4);
|
|
|
+
|
|
|
+ for (i = 0; i < REG_DUMP_COUNT_AR6003 / 4; i++) {
|
|
|
+ ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
|
|
|
+ 4 * i,
|
|
|
+ le32_to_cpu(regdump_val[i]),
|
|
|
+ le32_to_cpu(regdump_val[i + 1]),
|
|
|
+ le32_to_cpu(regdump_val[i + 2]),
|
|
|
+ le32_to_cpu(regdump_val[i + 3]));
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
|
|
|
static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
|
|
|
{
|
|
|
u32 dummy;
|
|
|
- int status;
|
|
|
+ int ret;
|
|
|
|
|
|
- ath6kl_err("target debug interrupt\n");
|
|
|
-
|
|
|
- ath6kl_target_failure(dev->ar);
|
|
|
+ ath6kl_warn("firmware crashed\n");
|
|
|
|
|
|
/*
|
|
|
* read counter to clear the interrupt, the debug error interrupt is
|
|
|
* counter 0.
|
|
|
*/
|
|
|
- status = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS,
|
|
|
+ ret = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS,
|
|
|
(u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC);
|
|
|
- if (status)
|
|
|
- WARN_ON(1);
|
|
|
+ if (ret)
|
|
|
+ ath6kl_warn("Failed to clear debug interrupt: %d\n", ret);
|
|
|
|
|
|
- return status;
|
|
|
+ ath6kl_hif_dump_fw_crash(dev->ar);
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* mailbox recv message polling */
|