Commit ec5ba4d3 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: make sure to really disable irqs

This fixes two corner cases.

One is a race between disabling copy engine
interrupts and unhandled pending interrupts on the
host. This could end up with a runaway tasklet and
consequently memory leak of a few copy engine
rx buffers.

The other one is an unexpected (and non-maskable
via device CSR) MSI fw indication interrupt during
teardown. This could trigger the same problem as
the first corner case.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 145cc121
...@@ -1121,6 +1121,40 @@ static int ath10k_pci_post_rx(struct ath10k *ar) ...@@ -1121,6 +1121,40 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
return 0; return 0;
} }
static void ath10k_pci_irq_disable(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i;
ath10k_ce_disable_interrupts(ar);
/* Regardless how many interrupts were assigned for MSI the first one
* is always used for firmware indications (crashes). There's no way to
* mask the irq in the device so call disable_irq(). Legacy (shared)
* interrupts can be masked on the device though.
*/
if (ar_pci->num_msi_intrs > 0)
disable_irq(ar_pci->pdev->irq);
else
ath10k_pci_disable_and_clear_legacy_irq(ar);
for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
synchronize_irq(ar_pci->pdev->irq + i);
}
static void ath10k_pci_irq_enable(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
ath10k_ce_enable_interrupts(ar);
/* See comment in ath10k_pci_irq_disable() */
if (ar_pci->num_msi_intrs > 0)
enable_irq(ar_pci->pdev->irq);
else
ath10k_pci_enable_legacy_irq(ar);
}
static int ath10k_pci_hif_start(struct ath10k *ar) static int ath10k_pci_hif_start(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
...@@ -1138,7 +1172,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar) ...@@ -1138,7 +1172,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
goto err_early_irq; goto err_early_irq;
} }
ath10k_ce_enable_interrupts(ar); ath10k_pci_irq_enable(ar);
/* Post buffers once to start things off. */ /* Post buffers once to start things off. */
ret = ath10k_pci_post_rx(ar); ret = ath10k_pci_post_rx(ar);
...@@ -1152,7 +1186,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar) ...@@ -1152,7 +1186,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
return 0; return 0;
err_stop: err_stop:
ath10k_ce_disable_interrupts(ar); ath10k_pci_irq_disable(ar);
ath10k_pci_free_irq(ar); ath10k_pci_free_irq(ar);
ath10k_pci_kill_tasklet(ar); ath10k_pci_kill_tasklet(ar);
err_early_irq: err_early_irq:
...@@ -1275,10 +1309,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ...@@ -1275,10 +1309,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
if (WARN_ON(!ar_pci->started)) if (WARN_ON(!ar_pci->started))
return; return;
ret = ath10k_ce_disable_interrupts(ar); ath10k_pci_irq_disable(ar);
if (ret)
ath10k_warn("failed to disable CE interrupts: %d\n", ret);
ath10k_pci_free_irq(ar); ath10k_pci_free_irq(ar);
ath10k_pci_kill_tasklet(ar); ath10k_pci_kill_tasklet(ar);
......
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