Commit 7c0f0e3c authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: mask/unmask msi fw irq

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: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent a428249d
...@@ -291,6 +291,7 @@ struct ath10k_pktlog_hdr { ...@@ -291,6 +291,7 @@ struct ath10k_pktlog_hdr {
#define SI_RX_DATA1_OFFSET 0x00000014 #define SI_RX_DATA1_OFFSET 0x00000014
#define CORE_CTRL_CPU_INTR_MASK 0x00002000 #define CORE_CTRL_CPU_INTR_MASK 0x00002000
#define CORE_CTRL_PCIE_REG_31_MASK 0x00000800
#define CORE_CTRL_ADDRESS 0x0000 #define CORE_CTRL_ADDRESS 0x0000
#define PCIE_INTR_ENABLE_ADDRESS 0x0008 #define PCIE_INTR_ENABLE_ADDRESS 0x0008
#define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CAUSE_ADDRESS 0x000c
......
...@@ -1143,14 +1143,37 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, ...@@ -1143,14 +1143,37 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
&dl_is_polled); &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); u32 val;
int i;
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_ce_disable_interrupts(ar);
ath10k_pci_disable_and_clear_legacy_irq(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++) for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
synchronize_irq(ar_pci->pdev->irq + i); synchronize_irq(ar_pci->pdev->irq + i);
...@@ -1160,7 +1183,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) ...@@ -1160,7 +1183,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
{ {
ath10k_ce_enable_interrupts(ar); ath10k_ce_enable_interrupts(ar);
ath10k_pci_enable_legacy_irq(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) static int ath10k_pci_hif_start(struct ath10k *ar)
...@@ -1288,6 +1311,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ...@@ -1288,6 +1311,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_warm_reset(ar); ath10k_pci_warm_reset(ar);
ath10k_pci_irq_disable(ar); ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar); ath10k_pci_flush(ar);
} }
...@@ -2285,6 +2309,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) ...@@ -2285,6 +2309,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
} while (time_before(jiffies, timeout)); } while (time_before(jiffies, timeout));
ath10k_pci_disable_and_clear_legacy_irq(ar); ath10k_pci_disable_and_clear_legacy_irq(ar);
ath10k_pci_irq_msi_fw_mask(ar);
if (val == 0xffffffff) { if (val == 0xffffffff) {
ath10k_err(ar, "failed to read device register, device is gone\n"); 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, ...@@ -2478,20 +2503,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
} }
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
ath10k_pci_irq_disable(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);
ret = ath10k_pci_init_irq(ar); ret = ath10k_pci_init_irq(ar);
if (ret) { if (ret) {
...@@ -2509,9 +2521,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -2509,9 +2521,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_deinit_irq; 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); ret = ath10k_core_register(ar, chip_id);
if (ret) { if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret); ath10k_err(ar, "failed to register driver core: %d\n", ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment