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])); } }
int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length) { u32 count, *buf = data; int ret; if (WARN_ON(length % 4)) return -EINVAL; for (count = 0; count < length / 4; count++, address += 4) { ret = ath6kl_diag_read32(ar, address, &buf[count]); if (ret) return ret; } return 0; }
static void ath6kl_hif_dump_fw_more(struct ath6kl *ar, u32 mask) { u32 fw_dump_addr, fw_dump_len; u32 address; int ret; if (ar->target_type != TARGET_TYPE_AR6003 ) { ath6kl_warn("not support dump stack for type: %x\n", ar->target_type); return; } if(mask & DUMP_MASK_FULL_STACK) { if(ar->wiphy->hw_version == AR6003_HW_2_1_1_VERSION) { fw_dump_addr = AR6003_HW211_KERNELSTACK_BASE - DUMP_STACK_OFFSET; fw_dump_len = AR6003_HW211_KERNELSTACK_SIZE + DUMP_STACK_OFFSET; ath6kl_warn("firmware stack:0x%x, len:0x%x\n", AR6003_HW211_KERNELSTACK_BASE, AR6003_HW211_KERNELSTACK_SIZE); ath6kl_hif_dump(ar, fw_dump_addr, fw_dump_len); } } if(mask & DUMP_MASK_DBGLOG) { if(ar->wiphy->hw_version == AR6003_HW_2_1_1_VERSION) { address = TARG_VTOP(ar->target_type, AR6003_HW211_DBGLOG_ADDR); ret = ath6kl_diag_read32(ar, address, &fw_dump_addr); if(!ret && fw_dump_addr) { fw_dump_len = AR6003_HW211_DBGLOG_SIZE; ath6kl_warn("fw dblog:0x%x, len:0x%x\n", fw_dump_addr, AR6003_HW211_DBGLOG_SIZE); ath6kl_hif_dump(ar, fw_dump_addr, fw_dump_len); } } } }
int ath6kl_read_fwlogs(struct ath6kl *ar) { struct ath6kl_dbglog_hdr debug_hdr; struct ath6kl_dbglog_buf debug_buf; u32 address, length, dropped, firstbuf, debug_hdr_addr; int ret = 0, loop; u8 *buf; buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; address = TARG_VTOP(ar->target_type, ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_dbglog_hdr))); ret = ath6kl_diag_read32(ar, address, &debug_hdr_addr); if (ret) goto out; /* Get the contents of the ring buffer */ if (debug_hdr_addr == 0) { ath6kl_warn("Invalid address for debug_hdr_addr\n"); ret = -EINVAL; goto out; } address = TARG_VTOP(ar->target_type, debug_hdr_addr); ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); address = TARG_VTOP(ar->target_type, le32_to_cpu(debug_hdr.dbuf_addr)); firstbuf = address; dropped = le32_to_cpu(debug_hdr.dropped); ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); loop = 100; do { address = TARG_VTOP(ar->target_type, le32_to_cpu(debug_buf.buffer_addr)); length = le32_to_cpu(debug_buf.length); if (length != 0 && (le32_to_cpu(debug_buf.length) <= le32_to_cpu(debug_buf.bufsize))) { length = ALIGN(length, 4); ret = ath6kl_diag_read(ar, address, buf, length); if (ret) goto out; ath6kl_debug_fwlog_event(ar, buf, length); } address = TARG_VTOP(ar->target_type, le32_to_cpu(debug_buf.next)); ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); if (ret) goto out; loop--; if (WARN_ON(loop == 0)) { ret = -ETIMEDOUT; goto out; } } while (address != firstbuf); out: kfree(buf); return ret; }