ath10k: re-enable interrupts properly in hw recovery

Recent changes done to start/restart sequences
broke hw recovery in some hw configurations. The
pci transport was stopped twice however due to a
workaround in the pci disabling code the
disable/enable for first msi interrupt was not
balanced. This ended up with irqs not being
properly re-enabled and the following print out
during recovery:

 ath10k: failed to receive control response completion, polling..
 ath10k: Service connect timeout: -110
 ath10k: Could not init core: -110

Legacy interrupt mode was unaffected while msi
ranged mode would be partially crippled (it would
miss fw indication interrupts but otherwise it
worked fine).

This fixes completely broken fw recovery for a
single msi interrupt mode and fixes subsequent fw
crash reports for msi range interrupt mode.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
Michal Kazior 2014-08-28 22:14:16 +03:00 committed by Kalle Valo
parent 6a5d088a92
commit e75db4e368

View File

@ -1172,16 +1172,8 @@ static void ath10k_pci_irq_disable(struct ath10k *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);
ath10k_pci_disable_and_clear_legacy_irq(ar);
/* FIXME: How to mask all MSI interrupts? */
for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
synchronize_irq(ar_pci->pdev->irq + i);
@ -1189,15 +1181,9 @@ static void ath10k_pci_irq_disable(struct ath10k *ar)
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);
ath10k_pci_enable_legacy_irq(ar);
/* FIXME: How to unmask all MSI interrupts? */
}
static int ath10k_pci_hif_start(struct ath10k *ar)
@ -1311,14 +1297,21 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
{
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
ath10k_pci_irq_disable(ar);
ath10k_pci_flush(ar);
/* Most likely the device has HTT Rx ring configured. The only way to
* prevent the device from accessing (and possible corrupting) host
* memory is to reset the chip now.
*
* There's also no known way of masking MSI interrupts on the device.
* For ranged MSI the CE-related interrupts can be masked. However
* regardless how many MSI interrupts are assigned the first one
* is always used for firmware indications (crashes) and cannot be
* masked. To prevent the device from asserting the interrupt reset it
* before proceeding with cleanup.
*/
ath10k_pci_warm_reset(ar);
ath10k_pci_irq_disable(ar);
ath10k_pci_flush(ar);
}
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,