wcnss: Log WCNSS registers in reset & bite handler
Reset interrupt is sent to WCNSS when host drivers fail to
communicate with WCNSS over SMD. So log certain Pronto registers to
know the failure reason at Pronto. Similar debug mechanism is already
added for Riva. The same WCNSS registers are also logged in watchdog
bite handler.
Change-Id: I0ef4256b9702a61785e9ca2f0ccbf9f947d6dfa7
Signed-off-by: Sameer Thalappil <sameert@codeaurora.org>
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index b457599..cfcf5dc 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -329,6 +329,7 @@
disable_irq_nosync(drv->irq);
drv->restart_inprogress = true;
+ wcnss_pronto_log_debug_regs();
restart_wcnss(drv);
return IRQ_HANDLED;
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 96b9882..0f7bc6e 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -349,6 +349,7 @@
panic("Watchdog bite received from Riva");
drv->rst_in_progress = 1;
+ wcnss_riva_log_debug_regs();
subsystem_restart_dev(drv->subsys);
return IRQ_HANDLED;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 71a9860..457cbb3 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -26,6 +26,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
+#include <linux/ratelimit.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
@@ -61,6 +62,11 @@
#define CCU_LAST_ADDR1_OFFSET 0x108
#define CCU_LAST_ADDR2_OFFSET 0x10c
+#define MSM_PRONTO_A2XB_BASE 0xfb100400
+#define A2XB_CFG_OFFSET 0x00
+#define A2XB_INT_SRC_OFFSET 0x0c
+#define A2XB_ERR_INFO_OFFSET 0x1c
+
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE 500
#define WCNSS_VERSION_LEN 30
@@ -182,7 +188,7 @@
/* wcnss_reset_intr() is invoked when host drivers fails to
* communicate with WCNSS over SMD; so logging these registers
* helps to know WCNSS failure reason */
-static void wcnss_log_ccpu_regs(void)
+void wcnss_riva_log_debug_regs(void)
{
void __iomem *ccu_base;
void __iomem *ccu_reg;
@@ -196,31 +202,62 @@
ccu_reg = ccu_base + CCU_INVALID_ADDR_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+ pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
ccu_reg = ccu_base + CCU_LAST_ADDR0_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+ pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
ccu_reg = ccu_base + CCU_LAST_ADDR1_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+ pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
ccu_reg = ccu_base + CCU_LAST_ADDR2_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+ pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
iounmap(ccu_base);
}
+EXPORT_SYMBOL(wcnss_riva_log_debug_regs);
-/* interface to reset Riva by sending the reset interrupt */
+/* Log pronto debug registers before sending reset interrupt */
+void wcnss_pronto_log_debug_regs(void)
+{
+ void __iomem *a2xb_base;
+ void __iomem *reg_addr;
+ u32 reg = 0;
+
+ a2xb_base = ioremap(MSM_PRONTO_A2XB_BASE, SZ_512);
+ if (!a2xb_base) {
+ pr_err("%s: ioremap WCNSS A2XB reg failed\n", __func__);
+ return;
+ }
+
+ reg_addr = a2xb_base + A2XB_CFG_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: A2XB_CFG_OFFSET %08x\n", __func__, reg);
+
+ reg_addr = a2xb_base + A2XB_INT_SRC_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: A2XB_INT_SRC_OFFSET %08x\n", __func__, reg);
+
+ reg_addr = a2xb_base + A2XB_ERR_INFO_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: A2XB_ERR_INFO_OFFSET %08x\n", __func__, reg);
+
+ iounmap(a2xb_base);
+}
+EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
+
+/* interface to reset wcnss by sending the reset interrupt */
void wcnss_reset_intr(void)
{
- if (wcnss_hardware_type() != WCNSS_RIVA_HW) {
+ if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
+ wcnss_pronto_log_debug_regs();
pr_err("%s: reset interrupt not supported\n", __func__);
return;
}
- wcnss_log_ccpu_regs();
+ wcnss_riva_log_debug_regs();
wmb();
__raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8);
}
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 6d2eee4..f58c7a7 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -63,6 +63,8 @@
void wcnss_reset_intr(void);
void wcnss_suspend_notify(void);
void wcnss_resume_notify(void);
+void wcnss_riva_log_debug_regs(void);
+void wcnss_pronto_log_debug_regs(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))