aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2013-08-02 03:15:47 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2013-08-05 12:22:16 -0400
commit32270b61b3fcdce3495c7b746576d49f70587150 (patch)
tree642f7f8a9c80fa121cfd5a6c27fd60f65a1d8cc2 /drivers/net/wireless/ath/ath10k
parent591ecdb8f276925251bb5f5fad7eb064979ecee1 (diff)
ath10k: fix device teardown
This fixes interrupt-related issue when no interfaces were running thus the device was considered powered down. The power_down() function isn't really powering down the device. It simply assumed it won't interrupt. This wasn't true in some cases and could lead to paging failures upon FW indication interrupt (i.e. FW crash) because some structures aren't allocated in that device state. One reason for that was that ar_pci->started wasn't reset. The other is interrupts should've been masked when teardown starts. The patch reorganized interrupt setup and makes sure ar_pci->started is reset accordingly. Reported-by: Ben Greear <greearb@candelatech.com> Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k')
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c41
1 files changed, 30 insertions, 11 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index d95439b8dd33..503e380e4cc0 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -56,6 +56,8 @@ static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info);
56static void ath10k_pci_stop_ce(struct ath10k *ar); 56static void ath10k_pci_stop_ce(struct ath10k *ar);
57static void ath10k_pci_device_reset(struct ath10k *ar); 57static void ath10k_pci_device_reset(struct ath10k *ar);
58static int ath10k_pci_reset_target(struct ath10k *ar); 58static int ath10k_pci_reset_target(struct ath10k *ar);
59static int ath10k_pci_start_intr(struct ath10k *ar);
60static void ath10k_pci_stop_intr(struct ath10k *ar);
59 61
60static const struct ce_attr host_ce_config_wlan[] = { 62static const struct ce_attr host_ce_config_wlan[] = {
61 /* host->target HTC control and raw streams */ 63 /* host->target HTC control and raw streams */
@@ -1254,10 +1256,25 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
1254 } 1256 }
1255} 1257}
1256 1258
1259static void ath10k_pci_disable_irqs(struct ath10k *ar)
1260{
1261 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
1262 int i;
1263
1264 for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
1265 disable_irq(ar_pci->pdev->irq + i);
1266}
1267
1257static void ath10k_pci_hif_stop(struct ath10k *ar) 1268static void ath10k_pci_hif_stop(struct ath10k *ar)
1258{ 1269{
1270 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
1271
1259 ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); 1272 ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
1260 1273
1274 /* Irqs are never explicitly re-enabled. They are implicitly re-enabled
1275 * by ath10k_pci_start_intr(). */
1276 ath10k_pci_disable_irqs(ar);
1277
1261 ath10k_pci_stop_ce(ar); 1278 ath10k_pci_stop_ce(ar);
1262 1279
1263 /* At this point, asynchronous threads are stopped, the target should 1280 /* At this point, asynchronous threads are stopped, the target should
@@ -1267,6 +1284,8 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
1267 ath10k_pci_process_ce(ar); 1284 ath10k_pci_process_ce(ar);
1268 ath10k_pci_cleanup_ce(ar); 1285 ath10k_pci_cleanup_ce(ar);
1269 ath10k_pci_buffer_cleanup(ar); 1286 ath10k_pci_buffer_cleanup(ar);
1287
1288 ar_pci->started = 0;
1270} 1289}
1271 1290
1272static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, 1291static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@@ -1742,6 +1761,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
1742{ 1761{
1743 int ret; 1762 int ret;
1744 1763
1764 ret = ath10k_pci_start_intr(ar);
1765 if (ret) {
1766 ath10k_err("could not start interrupt handling (%d)\n", ret);
1767 goto err;
1768 }
1769
1745 /* 1770 /*
1746 * Bring the target up cleanly. 1771 * Bring the target up cleanly.
1747 * 1772 *
@@ -1756,7 +1781,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
1756 1781
1757 ret = ath10k_pci_reset_target(ar); 1782 ret = ath10k_pci_reset_target(ar);
1758 if (ret) 1783 if (ret)
1759 goto err; 1784 goto err_irq;
1760 1785
1761 if (ath10k_target_ps) { 1786 if (ath10k_target_ps) {
1762 ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n"); 1787 ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n");
@@ -1787,12 +1812,15 @@ err_ce:
1787err_ps: 1812err_ps:
1788 if (!ath10k_target_ps) 1813 if (!ath10k_target_ps)
1789 ath10k_do_pci_sleep(ar); 1814 ath10k_do_pci_sleep(ar);
1815err_irq:
1816 ath10k_pci_stop_intr(ar);
1790err: 1817err:
1791 return ret; 1818 return ret;
1792} 1819}
1793 1820
1794static void ath10k_pci_hif_power_down(struct ath10k *ar) 1821static void ath10k_pci_hif_power_down(struct ath10k *ar)
1795{ 1822{
1823 ath10k_pci_stop_intr(ar);
1796 ath10k_pci_ce_deinit(ar); 1824 ath10k_pci_ce_deinit(ar);
1797 if (!ath10k_target_ps) 1825 if (!ath10k_target_ps)
1798 ath10k_do_pci_sleep(ar); 1826 ath10k_do_pci_sleep(ar);
@@ -2363,22 +2391,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
2363 2391
2364 ar_pci->cacheline_sz = dma_get_cache_alignment(); 2392 ar_pci->cacheline_sz = dma_get_cache_alignment();
2365 2393
2366 ret = ath10k_pci_start_intr(ar);
2367 if (ret) {
2368 ath10k_err("could not start interrupt handling (%d)\n", ret);
2369 goto err_iomap;
2370 }
2371
2372 ret = ath10k_core_register(ar); 2394 ret = ath10k_core_register(ar);
2373 if (ret) { 2395 if (ret) {
2374 ath10k_err("could not register driver core (%d)\n", ret); 2396 ath10k_err("could not register driver core (%d)\n", ret);
2375 goto err_intr; 2397 goto err_iomap;
2376 } 2398 }
2377 2399
2378 return 0; 2400 return 0;
2379 2401
2380err_intr:
2381 ath10k_pci_stop_intr(ar);
2382err_iomap: 2402err_iomap:
2383 pci_iounmap(pdev, mem); 2403 pci_iounmap(pdev, mem);
2384err_master: 2404err_master:
@@ -2415,7 +2435,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
2415 tasklet_kill(&ar_pci->msi_fw_err); 2435 tasklet_kill(&ar_pci->msi_fw_err);
2416 2436
2417 ath10k_core_unregister(ar); 2437 ath10k_core_unregister(ar);
2418 ath10k_pci_stop_intr(ar);
2419 2438
2420 pci_set_drvdata(pdev, NULL); 2439 pci_set_drvdata(pdev, NULL);
2421 pci_iounmap(pdev, ar_pci->mem); 2440 pci_iounmap(pdev, ar_pci->mem);