ath10k: mask/unmask msi fw irq
authorMichal Kazior <michal.kazior@tieto.com>
Mon, 20 Oct 2014 12:14:38 +0000 (14:14 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 23 Oct 2014 13:40:38 +0000 (16:40 +0300)
This was the final missing bit to making sure the
device doesn't assert interrupts to host.

This should fix possible race when target crashes
during driver teardown.

This also removes an early warm reset workaround
during pci probing.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/pci.c

index ef09fe8cb4b2da7af66cd0787b5a1a55382f67ca..392c2501d0a1d9c75a24af5297f73780f6e10a28 100644 (file)
@@ -291,6 +291,7 @@ struct ath10k_pktlog_hdr {
 #define SI_RX_DATA1_OFFSET                     0x00000014
 
 #define CORE_CTRL_CPU_INTR_MASK                        0x00002000
+#define CORE_CTRL_PCIE_REG_31_MASK             0x00000800
 #define CORE_CTRL_ADDRESS                      0x0000
 #define PCIE_INTR_ENABLE_ADDRESS               0x0008
 #define PCIE_INTR_CAUSE_ADDRESS                        0x000c
index 9d700d1530d26bb0c1bb64c1f6c3a8cce2c0b13a..243099d62ee9273d390b36c853b9e05a6af99545 100644 (file)
@@ -1143,14 +1143,37 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
                                                 &dl_is_polled);
 }
 
-static void ath10k_pci_irq_disable(struct ath10k *ar)
+static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int i;
+       u32 val;
+
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
+       val &= ~CORE_CTRL_PCIE_REG_31_MASK;
+
+       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+}
+
+static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
+{
+       u32 val;
+
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
+       val |= CORE_CTRL_PCIE_REG_31_MASK;
+
+       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+}
 
+static void ath10k_pci_irq_disable(struct ath10k *ar)
+{
        ath10k_ce_disable_interrupts(ar);
        ath10k_pci_disable_and_clear_legacy_irq(ar);
-       /* FIXME: How to mask all MSI interrupts? */
+       ath10k_pci_irq_msi_fw_mask(ar);
+}
+
+static void ath10k_pci_irq_sync(struct ath10k *ar)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       int i;
 
        for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
                synchronize_irq(ar_pci->pdev->irq + i);
@@ -1160,7 +1183,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
 {
        ath10k_ce_enable_interrupts(ar);
        ath10k_pci_enable_legacy_irq(ar);
-       /* FIXME: How to unmask all MSI interrupts? */
+       ath10k_pci_irq_msi_fw_unmask(ar);
 }
 
 static int ath10k_pci_hif_start(struct ath10k *ar)
@@ -1288,6 +1311,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
        ath10k_pci_warm_reset(ar);
 
        ath10k_pci_irq_disable(ar);
+       ath10k_pci_irq_sync(ar);
        ath10k_pci_flush(ar);
 }
 
@@ -2285,6 +2309,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
        } while (time_before(jiffies, timeout));
 
        ath10k_pci_disable_and_clear_legacy_irq(ar);
+       ath10k_pci_irq_msi_fw_mask(ar);
 
        if (val == 0xffffffff) {
                ath10k_err(ar, "failed to read device register, device is gone\n");
@@ -2478,20 +2503,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        }
 
        ath10k_pci_ce_deinit(ar);
-
-       ret = ath10k_ce_disable_interrupts(ar);
-       if (ret) {
-               ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
-                          ret);
-               goto err_free_ce;
-       }
-
-       /* Workaround: There's no known way to mask all possible interrupts via
-        * device CSR. The only way to make sure device doesn't assert
-        * interrupts is to reset it. Interrupts are then disabled on host
-        * after handlers are registered.
-        */
-       ath10k_pci_warm_reset(ar);
+       ath10k_pci_irq_disable(ar);
 
        ret = ath10k_pci_init_irq(ar);
        if (ret) {
@@ -2509,9 +2521,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                goto err_deinit_irq;
        }
 
-       /* This shouldn't race as the device has been reset above. */
-       ath10k_pci_irq_disable(ar);
-
        ret = ath10k_core_register(ar, chip_id);
        if (ret) {
                ath10k_err(ar, "failed to register driver core: %d\n", ret);