summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYue Ma <yuem@qca.qualcomm.com>2014-02-10 17:55:22 -0800
committerAkash Patel <c_akashp@qca.qualcomm.com>2014-02-12 19:20:36 -0800
commit63d1786452bf80570b478a9b5ec276dc5064a48c (patch)
tree9490590a3319f994527353f0b5a83867b81c8c50
parenta06219fb808bca7976f3e2063ecd722d64a77170 (diff)
qcacld: Add SSR crash shutdown API
Add the SSR crash shutdown API in order to support collect target RAM dump when kernel panic happens or other subsystems crash. Change-Id: Ibe97baee5e1d782ecdc173a2f8d4dc9e841a2a37 CRs-Fixed: 609070
-rw-r--r--CORE/SERVICES/BMI/ol_fw.c69
-rw-r--r--CORE/SERVICES/BMI/ol_fw.h3
-rw-r--r--CORE/SERVICES/COMMON/ol_if_athvar.h2
-rw-r--r--CORE/SERVICES/HIF/PCIe/if_pci.c37
4 files changed, 89 insertions, 22 deletions
diff --git a/CORE/SERVICES/BMI/ol_fw.c b/CORE/SERVICES/BMI/ol_fw.c
index 4f5534af58b8..26e2ed4f154c 100644
--- a/CORE/SERVICES/BMI/ol_fw.c
+++ b/CORE/SERVICES/BMI/ol_fw.c
@@ -529,12 +529,35 @@ int dump_CE_register(struct ol_softc *scn)
#if defined(QCA_WIFI_2_0) && !defined(QCA_WIFI_ISOC) && defined(CONFIG_CNSS)
static struct ol_softc *ramdump_scn;
-static void ramdump_work_handler(struct work_struct *ramdump)
+int ol_copy_ramdump(struct ol_softc *scn)
{
void __iomem *ramdump_base;
unsigned long address;
unsigned long size;
int ret;
+
+ /* Get RAM dump memory address and size */
+ if (cnss_get_ramdump_mem(&address, &size)) {
+ printk("No RAM dump will be collected since failed to get "
+ "memory address or size!\n");
+ ret = -EACCES;
+ }
+
+ ramdump_base = ioremap(address, size);
+ if (!ramdump_base) {
+ printk("No RAM dump will be collected since ramdump_base is NULL!\n");
+ ret = -EACCES;
+ }
+
+ ret = ol_target_coredump(scn, ramdump_base, TOTAL_DUMP_SIZE);
+ iounmap(ramdump_base);
+
+ return ret;
+}
+
+static void ramdump_work_handler(struct work_struct *ramdump)
+{
+ int ret;
u_int32_t host_interest_address;
if (!ramdump_scn) {
@@ -542,6 +565,21 @@ static void ramdump_work_handler(struct work_struct *ramdump)
goto out_fail;
}
+ if (ramdump_scn->crash_shutdown) {
+ if (hif_pci_check_soc_status(ramdump_scn->hif_sc))
+ goto out;
+
+ if (ol_copy_ramdump(ramdump_scn))
+ goto out;
+
+ printk("%s: RAM dump collecting completed!\n", __func__);
+
+out:
+ ramdump_scn->crash_shutdown = false;
+ complete(&ramdump_scn->ramdump_event);
+ return;
+ }
+
#ifdef DEBUG
ret = hif_pci_check_soc_status(ramdump_scn->hif_sc);
if (ret)
@@ -566,32 +604,18 @@ static void ramdump_work_handler(struct work_struct *ramdump)
}
printk("Host interest item address: 0x%08x\n", host_interest_address);
- /* Get RAM dump memory address and size */
- if (cnss_get_ramdump_mem(&address, &size)) {
- printk("No RAM dump will be collected since failed to get "
- "memory address or size!\n");
- goto out_fail;
- }
-
- ramdump_base = ioremap(address, size);
- if (!ramdump_base) {
- printk("No RAM dump will be collected since ramdump_base is NULL!\n");
- goto out_fail;
- }
-
- ret = ol_target_coredump(ramdump_scn, ramdump_base, TOTAL_DUMP_SIZE);
- iounmap(ramdump_base);
- if (ret)
+ if (ol_copy_ramdump(ramdump_scn))
goto out_fail;
printk("%s: RAM dump collecting completed!\n", __func__);
msleep(250);
+
/* Notify SSR framework the target has crashed. */
cnss_device_crashed();
return;
out_fail:
- /* silent SSR on dump failure */
+ /* Silent SSR on dump failure */
#ifdef CNSS_SELF_RECOVERY
cnss_device_self_recovery();
#else
@@ -602,7 +626,7 @@ out_fail:
static DECLARE_WORK(ramdump_work, ramdump_work_handler);
-void schedule_ramdump_work(struct ol_softc *scn)
+void ol_schedule_ramdump_work(struct ol_softc *scn)
{
ramdump_scn = scn;
schedule_work(&ramdump_work);
@@ -633,7 +657,10 @@ void ol_target_failure(void *instance, A_STATUS status)
return;
}
- printk("XXX TARGET ASSERTED XXX\n");
+ if (scn->crash_shutdown)
+ printk("XXX TARGET ASSERTED because of Kernel Panic XXX\n");
+ else
+ printk("XXX TARGET ASSERTED XXX\n");
scn->target_status = OL_TRGET_STATUS_RESET;
#if defined(QCA_WIFI_2_0) && !defined(QCA_WIFI_ISOC)
@@ -719,7 +746,7 @@ void ol_target_failure(void *instance, A_STATUS status)
#if defined(QCA_WIFI_2_0) && !defined(QCA_WIFI_ISOC) && defined(CONFIG_CNSS)
/* Collect the RAM dump through a workqueue */
- schedule_ramdump_work(scn);
+ ol_schedule_ramdump_work(scn);
#endif
return;
diff --git a/CORE/SERVICES/BMI/ol_fw.h b/CORE/SERVICES/BMI/ol_fw.h
index 4b81a01005ab..bfd4b3e5ee5c 100644
--- a/CORE/SERVICES/BMI/ol_fw.h
+++ b/CORE/SERVICES/BMI/ol_fw.h
@@ -72,7 +72,8 @@ int ol_target_coredump(void *instance, void* memoryBlock,
u_int32_t blockLength);
int ol_diag_read(struct ol_softc *scn, u_int8_t* buffer,
u_int32_t pos, size_t count);
-void schedule_ramdump_work(struct ol_softc *scn);
+void ol_schedule_ramdump_work(struct ol_softc *scn);
+int ol_copy_ramdump(struct ol_softc *scn);
#endif
int ol_download_firmware(struct ol_softc *scn);
int ol_configure_target(struct ol_softc *scn);
diff --git a/CORE/SERVICES/COMMON/ol_if_athvar.h b/CORE/SERVICES/COMMON/ol_if_athvar.h
index 0b8d4c6d490c..a6495ea58b7b 100644
--- a/CORE/SERVICES/COMMON/ol_if_athvar.h
+++ b/CORE/SERVICES/COMMON/ol_if_athvar.h
@@ -206,6 +206,8 @@ struct ol_softc {
u_int32_t set_ht_vht_ies:1; /* true if vht ies are set on target */
bool scn_cwmenable; /*CWM enable/disable state*/
u_int8_t max_no_of_peers;
+ struct completion ramdump_event;
+ bool crash_shutdown;
};
#ifdef PERE_IP_HDR_ALIGNMENT_WAR
diff --git a/CORE/SERVICES/HIF/PCIe/if_pci.c b/CORE/SERVICES/HIF/PCIe/if_pci.c
index 90e1f71ed4fb..bbe206bd6c09 100644
--- a/CORE/SERVICES/HIF/PCIe/if_pci.c
+++ b/CORE/SERVICES/HIF/PCIe/if_pci.c
@@ -70,6 +70,7 @@
#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 */
+#define RAMDUMP_EVENT_TIMEOUT 2500
unsigned int msienable = 0;
module_param(msienable, int, 0644);
@@ -780,6 +781,7 @@ again:
adf_os_atomic_init(&sc->tasklet_from_intr);
init_waitqueue_head(&ol_sc->sc_osdev->event_queue);
+ init_completion(&ol_sc->ramdump_event);
ret = hdd_wlan_startup(&pdev->dev, ol_sc);
@@ -1078,7 +1080,9 @@ again:
ol_sc->enablesinglebinary = FALSE;
ol_sc->max_no_of_peers = 1;
+ adf_os_atomic_init(&sc->tasklet_from_intr);
init_waitqueue_head(&ol_sc->sc_osdev->event_queue);
+ init_completion(&ol_sc->ramdump_event);
if (VOS_STATUS_SUCCESS == hdd_wlan_re_init(ol_sc)) {
ret = 0;
@@ -1487,6 +1491,38 @@ void hif_pci_shutdown(struct pci_dev *pdev)
printk("%s: WLAN host driver shutting down completed!\n", __func__);
}
+
+void hif_pci_crash_shutdown(struct pci_dev *pdev)
+{
+ struct hif_pci_softc *sc;
+ struct ol_softc *scn;
+ int status;
+
+ sc = pci_get_drvdata(pdev);
+ if (!sc)
+ return;
+
+ scn = sc->ol_sc;
+ if (!scn)
+ return;
+
+ if (OL_TRGET_STATUS_RESET == scn->target_status) {
+ printk("%s: Target is already asserted, ignore!\n", __func__);
+ return;
+ }
+
+ scn->crash_shutdown = true;
+ process_wma_set_command(0,(int)GEN_PARAM_CRASH_INJECT,
+ 0, GEN_CMD);
+
+ status = wait_for_completion_interruptible_timeout(
+ &scn->ramdump_event,
+ msecs_to_jiffies(RAMDUMP_EVENT_TIMEOUT));
+ if (!status) {
+ printk("%s: RAM dump collecting timeout!\n", __func__);
+ return;
+ }
+}
#endif
#define OL_ATH_PCI_PM_CONTROL 0x44
@@ -1609,6 +1645,7 @@ struct cnss_wlan_driver cnss_wlan_drv_id = {
.remove = hif_pci_remove,
.reinit = hif_pci_reinit,
.shutdown = hif_pci_shutdown,
+ .crash_shutdown = hif_pci_crash_shutdown,
#ifdef ATH_BUS_PM
.suspend = hif_pci_suspend,
.resume = hif_pci_resume,