summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYue Ma <yuem@qca.qualcomm.com>2014-01-28 14:56:08 -0800
committerPrakash Dhavali <pdhavali@qca.qualcomm.com>2014-01-31 20:36:00 -0800
commit8fe9f2ba3fe9c03f759091640b0ee43cef898685 (patch)
tree0e375261587c45b493d55673be9345664edac04b
parentd344033ef3c81acaf6ba0e1a8f81992a068adcf8 (diff)
qcacld: Add sanity checks before accessing target RAM
Sometimes when target assert happens, host driver fails to access target RAM memory space to copy the dump. Hence add sanity checks before copy the memory to help identify why it fails. Also disable dumping AXI registers to avoid potential watchdog bark. Change-Id: I903d4b2af1721328075fdb8d8fed8686e359ee8d CRs-Fixed: 604709
-rw-r--r--CORE/SERVICES/BMI/ol_fw.c36
-rw-r--r--CORE/SERVICES/BMI/ol_fw.h3
-rw-r--r--CORE/SERVICES/HIF/PCIe/if_pci.c50
-rw-r--r--CORE/SERVICES/HIF/PCIe/if_pci.h5
4 files changed, 90 insertions, 4 deletions
diff --git a/CORE/SERVICES/BMI/ol_fw.c b/CORE/SERVICES/BMI/ol_fw.c
index e632876fa4f3..c18fc831a0b2 100644
--- a/CORE/SERVICES/BMI/ol_fw.c
+++ b/CORE/SERVICES/BMI/ol_fw.c
@@ -34,6 +34,7 @@
#include "vos_api.h"
#include "wma_api.h"
#include "wma.h"
+#include "if_pci.h"
#define ATH_MODULE_NAME bmi
#include "a_debug.h"
@@ -490,6 +491,29 @@ u_int32_t host_interest_item_address(u_int32_t target_type, u_int32_t item_offse
}
}
+#if defined(QCA_WIFI_2_0) && !defined(QCA_WIFI_ISOC)
+void dump_CE_register(struct ol_softc *scn)
+{
+ A_UINT32 CE_reg_address = CE7_LOCATION;
+ A_UINT32 CE_reg_values[CE_USEFUL_SIZE>>2];
+ A_UINT32 CE_reg_word_size = CE_USEFUL_SIZE>>2;
+ A_UINT16 i;
+
+ if (HIFDiagReadMem(scn->hif_hdl, CE_reg_address,
+ (A_UCHAR*)&CE_reg_values[0],
+ CE_reg_word_size * sizeof(A_UINT32)) != A_OK)
+ {
+ printk(KERN_ERR "Dumping CE register failed!\n");
+ return;
+ }
+
+ printk("CE7 Register Dump:\n");
+ for (i = 0; i < CE_reg_word_size; i++) {
+ printk("[%02d] : 0x%08X\n", i, CE_reg_values[i]);
+ }
+}
+#endif
+
#if defined(QCA_WIFI_2_0) && !defined(QCA_WIFI_ISOC) && defined(CONFIG_CNSS)
static struct ol_softc *ramdump_scn;
@@ -505,11 +529,16 @@ static void ramdump_work_handler(struct work_struct *ramdump)
goto out;
}
+ hif_pci_check_soc_status(ramdump_scn->hif_sc);
+ dump_CE_register(ramdump_scn);
+
if (HIFDiagReadMem(ramdump_scn->hif_hdl,
host_interest_item_address(ramdump_scn->target_type,
offsetof(struct host_interest_s, hi_failure_state)),
(A_UCHAR*) &host_interest_address, sizeof(u_int32_t)) != A_OK) {
- printk("HifDiagReadiMem FW Dump Area Pointer failed!\n");
+ printk(KERN_ERR "HifDiagReadiMem FW Dump Area Pointer failed!\n");
+ dump_CE_register(ramdump_scn);
+
goto out;
}
printk("Host interest item address: 0x%08X\n", host_interest_address);
@@ -998,7 +1027,7 @@ void ol_target_coredump(void *inst, void *memoryBlock, u_int32_t blockLength)
* LENGTH = 0x00018000
*/
- while ((sectionCount < 3) && (amountRead < blockLength)) {
+ while ((sectionCount < 2) && (amountRead < blockLength)) {
switch (sectionCount) {
case 0:
/* DRAM SECTION */
@@ -1024,9 +1053,12 @@ void ol_target_coredump(void *inst, void *memoryBlock, u_int32_t blockLength)
bufferLoc += result;
sectionCount++;
} else {
+ printk(KERN_ERR "Could not read dump section!\n");
+ dump_CE_register(scn);
break; /* Could not read the section */
}
} else {
+ printk(KERN_ERR "Insufficient room in dump buffer!\n");
break; /* Insufficient room in buffer */
}
}
diff --git a/CORE/SERVICES/BMI/ol_fw.h b/CORE/SERVICES/BMI/ol_fw.h
index 18abf68cdb91..77c9bd19cdf1 100644
--- a/CORE/SERVICES/BMI/ol_fw.h
+++ b/CORE/SERVICES/BMI/ol_fw.h
@@ -62,6 +62,9 @@
#define AXI_LOCATION 0x000a0000
#define AXI_SIZE 0x00018000
+#define CE7_LOCATION 0x00036000
+#define CE_USEFUL_SIZE 0x00000058
+
#define TOTAL_DUMP_SIZE 0x00200000
#define PCIE_READ_LIMIT 0x00005000
diff --git a/CORE/SERVICES/HIF/PCIe/if_pci.c b/CORE/SERVICES/HIF/PCIe/if_pci.c
index 4be8c537dc6e..6de3a42c984c 100644
--- a/CORE/SERVICES/HIF/PCIe/if_pci.c
+++ b/CORE/SERVICES/HIF/PCIe/if_pci.c
@@ -64,6 +64,7 @@
#define AR6320_FW_2_0 (0x20)
#define MAX_NUM_OF_RECEIVES 1000 /* Maximum number of Rx buf to process before break out */
+#define PCIE_WAKE_TIMEOUT 1000 /* Maximum ms timeout for host to wake up target */
unsigned int msienable = 0;
module_param(msienable, int, 0644);
@@ -313,6 +314,55 @@ hif_pci_device_warm_reset(struct hif_pci_softc *sc)
}
+void
+hif_pci_check_soc_status(struct hif_pci_softc *sc)
+{
+ u_int16_t device_id;
+ u_int32_t val;
+ u_int16_t timeout_count = 0;
+
+ /* Check device ID from PCIe configuration space for link status */
+ pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &device_id);
+ if(device_id != sc->devid) {
+ printk(KERN_ERR "PCIe link is down!\n");
+ return;
+ }
+
+ /* Check PCIe local register for bar/memory access */
+ val = A_PCI_READ32(sc->mem + PCIE_LOCAL_BASE_ADDRESS +
+ RTC_STATE_ADDRESS);
+ printk("RTC_STATE_ADDRESS is %08x\n", val);
+
+ /* Try to wake up taget if it sleeps */
+ A_PCI_WRITE32(sc->mem + PCIE_LOCAL_BASE_ADDRESS +
+ PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK);
+ printk("PCIE_SOC_WAKE_ADDRESS is %08x\n",
+ A_PCI_READ32(sc->mem + PCIE_LOCAL_BASE_ADDRESS +
+ PCIE_SOC_WAKE_ADDRESS));
+
+ /* Check if taget can be woken up */
+ while(!hif_pci_targ_is_awake(sc, sc->mem)) {
+ if(timeout_count >= PCIE_WAKE_TIMEOUT) {
+ printk(KERN_ERR "Target cannot be woken up! "
+ "RTC_STATE_ADDRESS is %08x, PCIE_SOC_WAKE_ADDRESS is %08x\n",
+ A_PCI_READ32(sc->mem + PCIE_LOCAL_BASE_ADDRESS +
+ RTC_STATE_ADDRESS), A_PCI_READ32(sc->mem +
+ PCIE_LOCAL_BASE_ADDRESS + PCIE_SOC_WAKE_ADDRESS));
+ return;
+ }
+
+ A_PCI_WRITE32(sc->mem + PCIE_LOCAL_BASE_ADDRESS +
+ PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK);
+
+ A_MDELAY(100);
+ timeout_count += 100;
+ }
+
+ /* Check BAR + 0x10c register for SoC internal bus issues */
+ val = A_PCI_READ32(sc->mem + 0x10c);
+ printk("BAR + 0x10c is %08x\n", val);
+}
+
/*
* Handler for a per-engine interrupt on a PARTICULAR CE.
* This is used in cases where each CE has a private
diff --git a/CORE/SERVICES/HIF/PCIe/if_pci.h b/CORE/SERVICES/HIF/PCIe/if_pci.h
index 74f7130e04c7..65719c74b58f 100644
--- a/CORE/SERVICES/HIF/PCIe/if_pci.h
+++ b/CORE/SERVICES/HIF/PCIe/if_pci.h
@@ -1,9 +1,8 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
- *
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
@@ -120,6 +119,8 @@ extern int pktlogmod_init(void *context);
extern void pktlogmod_exit(void *context);
#endif
+void hif_pci_check_soc_status(struct hif_pci_softc *sc);
+
/*
* A firmware interrupt to the Host is indicated by the
* low bit of SCRATCH_3_ADDRESS being set.