summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhang Qian <zhangq@codeaurora.org>2017-09-14 18:22:25 +0800
committersnandini <snandini@codeaurora.org>2017-09-20 03:44:07 -0700
commitd727ca2e0c254f94b892de5738c5e1b127744b44 (patch)
tree27c3efb5abba1d1b5ce34b27017ebd32475a10f4
parent39f5ef3bf21cb021ac50ba4d5fde32515017a001 (diff)
qcacld-2.0: Trigger SSR once CE hw_index is wrong
After PCIe resume, host would get invalid hw_index. The invalid hw_index will introduce infinite loop. SSR will be triggered for such a case. Change-Id: I81349098366689b329ae081b849dce8b022ae55c CRs-Fixed: 2089240
-rw-r--r--CORE/SERVICES/HIF/PCIe/copy_engine.c49
-rw-r--r--CORE/SERVICES/HIF/PCIe/copy_engine_api.h9
-rw-r--r--CORE/SERVICES/HIF/PCIe/hif_pci.c19
3 files changed, 69 insertions, 8 deletions
diff --git a/CORE/SERVICES/HIF/PCIe/copy_engine.c b/CORE/SERVICES/HIF/PCIe/copy_engine.c
index e7831136ffff..ebece13f3e05 100644
--- a/CORE/SERVICES/HIF/PCIe/copy_engine.c
+++ b/CORE/SERVICES/HIF/PCIe/copy_engine.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014,2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014,2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -68,6 +68,48 @@ enum hif_ce_event_type {
HIF_TX_DESC_COMPLETION,
};
+static struct hif_pci_softc *hif_sc = NULL;
+/**
+ * target_reset_work_handler() - Work queue handler to reset target
+ * @sc: work queue handle
+ */
+void target_reset_work_handler(struct work_struct *sc)
+{
+ if (hif_sc)
+ vos_device_crashed(hif_sc->dev);
+}
+
+static DECLARE_WORK(target_reset_work, target_reset_work_handler);
+
+/**
+ * ce_target_reset() - Trigger SSR
+ * @sc: hif layer handle
+ *
+ * Once hw error is hit, SSR would be triggered.
+ */
+void ce_target_reset(struct hif_pci_softc *sc)
+{
+ hif_sc = sc;
+ adf_os_warn(1);
+ adf_os_print("Trigger SSR.\n");
+ schedule_work(&target_reset_work);
+}
+
+/**
+ * ce_idx_invalid() - check whether a CE index is valid
+ * @ring: ring handle
+ * @idx: CE idx
+ */
+static bool ce_idx_invalid(struct CE_ring_state *ring, unsigned int idx)
+{
+ if (ring->nentries <= idx) {
+ adf_os_print("hw index %d is not correct.\n", idx);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
#ifdef CONFIG_SLUB_DEBUG_ON
/**
@@ -831,6 +873,9 @@ CE_completed_send_next_nolock(struct CE_state *CE_state,
A_TARGET_ACCESS_BEGIN_RET(targid);
src_ring->hw_index = CE_SRC_RING_READ_IDX_GET(targid, ctrl_addr);
A_TARGET_ACCESS_END_RET(targid);
+
+ if (ce_idx_invalid(src_ring, src_ring->hw_index))
+ return status;
}
read_index = src_ring->hw_index;
@@ -1060,7 +1105,7 @@ static inline bool ce_is_valid_entries(struct hif_pci_softc *sc,
} else {
adf_os_print("%s:Potential infinite loop detected during rx processing for CE%d\n",
__func__, ce_state->id);
- VOS_BUG(0);
+ ce_target_reset(sc);
status = false;
}
diff --git a/CORE/SERVICES/HIF/PCIe/copy_engine_api.h b/CORE/SERVICES/HIF/PCIe/copy_engine_api.h
index d69641540ab1..e48fd63bc11d 100644
--- a/CORE/SERVICES/HIF/PCIe/copy_engine_api.h
+++ b/CORE/SERVICES/HIF/PCIe/copy_engine_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -376,6 +376,13 @@ bool CE_get_rx_pending(struct hif_pci_softc *sc);
int get_next_record_index(atomic_t *table_index, int array_size);
+/**
+ * ce_target_reset() - Trigger SSR
+ * @sc: hif layer handle
+ *
+ * Once hw error is hit, SSR would be triggered.
+ */
+void ce_target_reset(struct hif_pci_softc *sc);
/* CE_attr.flags values */
#define CE_ATTR_NO_SNOOP 0x01 /* Use NonSnooping PCIe accesses? */
diff --git a/CORE/SERVICES/HIF/PCIe/hif_pci.c b/CORE/SERVICES/HIF/PCIe/hif_pci.c
index 3f1bee7ab62d..bfcb639e94ed 100644
--- a/CORE/SERVICES/HIF/PCIe/hif_pci.c
+++ b/CORE/SERVICES/HIF/PCIe/hif_pci.c
@@ -467,7 +467,7 @@ HIF_PCI_CE_send_done(struct CE_handle *copyeng, void *ce_context, void *transfer
"pipe_num:%d num_send_allowed:%d pipe_info:0x%p sw_index:%d hw_index:%d nbytes:%d\n",
pipe_info->pipe_num, pipe_info->num_sends_allowed,
pipe_info, sw_idx, hw_idx, nbytes));
- ASSERT(0);
+ ce_target_reset(hif_state->sc);
break;
}
pipe_info->completion_freeq_head = compl_state->next;
@@ -538,7 +538,10 @@ HIF_PCI_CE_recv_data(struct CE_handle *copyeng, void *ce_context, void *transfer
hif_pm_runtime_mark_last_busy(sc->dev);
adf_os_spin_lock(&pipe_info->completion_freeq_lock);
compl_state = pipe_info->completion_freeq_head;
- ASSERT(compl_state != NULL);
+
+ if (!compl_state)
+ ce_target_reset(sc);
+
pipe_info->completion_freeq_head = compl_state->next;
adf_os_spin_unlock(&pipe_info->completion_freeq_lock);
@@ -2862,9 +2865,15 @@ HIFTargetSleepStateAdjust(A_target_id_t targid,
hif_msm_pcie_debug_info(sc);
if (!sc->ol_sc->enable_self_recovery)
VOS_BUG(0);
- sc->recovery = true;
- vos_set_logp_in_progress(VOS_MODULE_ID_VOSS, TRUE);
- vos_wlan_pci_link_down();
+
+ if (!vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)) {
+ sc->recovery = true;
+ vos_set_logp_in_progress(VOS_MODULE_ID_VOSS, TRUE);
+ vos_wlan_pci_link_down();
+ } else {
+ adf_os_print("%s- %d: SSR is in progress!!!!\n",
+ __func__, __LINE__);
+ }
return -EACCES;
}