summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHouston Hoffman <hhoffman@qca.qualcomm.com>2015-08-13 13:44:28 -0700
committerAkash Patel <akashp@codeaurora.org>2015-08-14 17:20:23 -0700
commitfa3f17ead99d23e953da134fe3cc630062abbc30 (patch)
treeade27f7d5ffb7c6992262143524b84f56b5fe87c
parente4a734388b6239e50d8b09f9111def4cbcc460b6 (diff)
qcacld-2.0: protect hif_state in wlan_tasklet
If hif init is not done the suspend lock isn't guaranteed to be valid. Change-Id: I330968e11f5e82a06ca7c35c7704fb71c5775fc7 CRs-Fixed: 890229
-rw-r--r--CORE/SERVICES/HIF/PCIe/if_pci.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/CORE/SERVICES/HIF/PCIe/if_pci.c b/CORE/SERVICES/HIF/PCIe/if_pci.c
index f6f3b701164d..4b95803c2fbb 100644
--- a/CORE/SERVICES/HIF/PCIe/if_pci.c
+++ b/CORE/SERVICES/HIF/PCIe/if_pci.c
@@ -695,8 +695,9 @@ wlan_tasklet(unsigned long data)
struct hif_pci_softc *sc = (struct hif_pci_softc *) data;
struct HIF_CE_state *hif_state = (struct HIF_CE_state *)sc->hif_device;
volatile int tmp;
+ bool hif_init_done = sc->hif_init_done;
- if (sc->hif_init_done == FALSE) {
+ if (hif_init_done == FALSE) {
goto irq_handled;
}
@@ -726,12 +727,18 @@ wlan_tasklet(unsigned long data)
return;
}
irq_handled:
- adf_os_spin_lock_irqsave(&hif_state->suspend_lock);
+ /* use cached value for hif_init_done to prevent
+ * unlocking an unlocked spinlock if hif init finishes
+ * while this tasklet is running
+ */
+ if (hif_init_done == TRUE)
+ adf_os_spin_lock_irqsave(&hif_state->suspend_lock);
+
if (LEGACY_INTERRUPTS(sc) && (sc->ol_sc->target_status !=
OL_TRGET_STATUS_RESET) &&
(!adf_os_atomic_read(&sc->pci_link_suspended))) {
- if (sc->hif_init_done == TRUE) {
+ if (hif_init_done == TRUE) {
if(HIFTargetSleepStateAdjust(hif_state->targid, FALSE, TRUE) < 0) {
adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
return;
@@ -744,14 +751,17 @@ irq_handled:
/* IMPORTANT: this extra read transaction is required to flush the posted write buffer */
tmp = A_PCI_READ32(sc->mem+(SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS));
- if (sc->hif_init_done == TRUE) {
+ if (hif_init_done == TRUE) {
if(HIFTargetSleepStateAdjust(hif_state->targid, TRUE, FALSE) < 0) {
adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
return;
}
}
}
- adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+
+ if (hif_init_done == TRUE)
+ adf_os_spin_unlock_irqrestore(&hif_state->suspend_lock);
+
adf_os_atomic_set(&sc->ce_suspend, 1);
}