diff mbox series

[v2,14/26,SRU,U/OEM-5.10] UBUNTU: SAUCE: ath11k: fix pcie link unstable issue

Message ID 20201204152521.197069-15-vicamo.yang@canonical.com
State New
Headers show
Series Support Killer 500s (QCA6390) WLAN/BT | expand

Commit Message

You-Sheng Yang Dec. 4, 2020, 3:25 p.m. UTC
From: Carl Huang <cjhuang@codeaurora.org>

BugLink: https://bugs.launchpad.net/bugs/1879633

For QCA6390, host needs to reset some registers before power up MHI.

1. fix PCI link unstable issue if hot reset happened.
2. clear all pending interrupts in power up

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
(cherry picked from commit a82a3aee7cde95d533c28cad3749e3c354011896
https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git)
Signed-off-by: You-Sheng Yang <vicamo.yang@canonical.com>
---
 drivers/net/wireless/ath/ath11k/pci.c | 54 +++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath11k/pci.h | 10 +++++
 2 files changed, 61 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 044b09463873..cc515792e00c 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -241,6 +241,49 @@  static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
 }
 
+static void ath11k_pci_enable_LTSSM(struct ath11k_base *ab)
+{
+	u32 val;
+	int count = 5;
+
+	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
+
+	/* PCIE link seems very unstable after the Hot Reset*/
+	while (val != PARM_LTSSM_VALUE && count--) {
+		if (val == 0xffffffff)
+			mdelay(5);
+		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
+
+		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
+	}
+
+	ath11k_dbg(ab, ATH11K_DBG_PCI, "%s read parf_ltssm:0x%x\n",
+		   __func__, val);
+
+	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
+
+	val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10;
+
+	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
+
+	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
+
+	ath11k_dbg(ab, ATH11K_DBG_PCI,
+		   "after set, read GCC_GCC_PCIE_HOT_RST 0x%x\n", val);
+
+	mdelay(5);
+}
+
+static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
+{
+	/* This is a WAR for PCIE Hotreset.
+	 * When target receive Hotreset, but will set the interrupt.
+	 * So when download SBL again, SBL will open Interrupt and
+	 * receive it, and crash immediately.
+	 */
+	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
+}
+
 static void ath11k_pci_force_wake(struct ath11k_base *ab)
 {
 	int val;
@@ -252,8 +295,13 @@  static void ath11k_pci_force_wake(struct ath11k_base *ab)
 	ath11k_dbg(ab, ATH11K_DBG_PCI, "forcw_wake scratch 0: 0x%x\n", val);
 }
 
-static void ath11k_pci_sw_reset(struct ath11k_base *ab)
+static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
 {
+	if (power_on) {
+		ath11k_pci_enable_LTSSM(ab);
+		ath11k_pci_clear_all_intrs(ab);
+	}
+
 	ath11k_mhi_clear_vector(ab);
 	ath11k_pci_soc_global_reset(ab);
 	ath11k_mhi_set_mhictrl_reset(ab);
@@ -874,7 +922,7 @@  static int ath11k_pci_power_up(struct ath11k_base *ab)
 
 	ab_pci->register_window = 0;
 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
-	ath11k_pci_sw_reset(ab_pci->ab);
+	ath11k_pci_sw_reset(ab_pci->ab, true);
 
 	ret = ath11k_mhi_start(ab_pci);
 	if (ret) {
@@ -892,7 +940,7 @@  static void ath11k_pci_power_down(struct ath11k_base *ab)
 	ath11k_pci_force_wake(ab_pci->ab);
 	ath11k_mhi_stop(ab_pci);
 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
-	ath11k_pci_sw_reset(ab_pci->ab);
+	ath11k_pci_sw_reset(ab_pci->ab, false);
 }
 
 static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h
index bdce32bd0136..27124ac92cf7 100644
--- a/drivers/net/wireless/ath/ath11k/pci.h
+++ b/drivers/net/wireless/ath/ath11k/pci.h
@@ -24,6 +24,16 @@ 
 /* register used for handshake mechanism to validate UMAC is awake */
 #define PCIE_SOC_WAKE_PCIE_LOCAL_REG		0x3004
 
+#define PCIE_PCIE_PARF_LTSSM              0X1E081B0
+#define PARM_LTSSM_VALUE                  0x111
+
+#define GCC_GCC_PCIE_HOT_RST              0X1E402BC
+#define GCC_GCC_PCIE_HOT_RST_VAL          0x10
+
+#define PCIE_PCIE_INT_ALL_CLEAR           0X1E08228
+#define PCIE_SMLH_REQ_RST_LINK_DOWN       0x2
+#define PCIE_INT_CLEAR_ALL                0xFFFFFFFF
+
 struct ath11k_msi_user {
 	char *name;
 	int num_vectors;