diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-08-22 08:23:34 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-08-25 04:29:49 -0400 |
commit | 5c771e7454d148af35e8b4297d00f880de79ea49 (patch) | |
tree | a08d6a80d2d6706217d79a0b5d76b3af721067d7 | |
parent | ec5ba4d3b6b60456b067e8c625e87e67cdde2d12 (diff) |
ath10k: remove early irq handling
It's not really necessary to have a dedicated irq
handler just for the sake of catching early fw
crashes anymore. It is now safe to use one handler
even during early stages of device boot up.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/pci.c | 172 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/pci.h | 1 |
2 files changed, 48 insertions, 125 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 6224952ba523..ffb980c5080d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c | |||
@@ -266,46 +266,6 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar) | |||
266 | PCIE_INTR_ENABLE_ADDRESS); | 266 | PCIE_INTR_ENABLE_ADDRESS); |
267 | } | 267 | } |
268 | 268 | ||
269 | static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg) | ||
270 | { | ||
271 | struct ath10k *ar = arg; | ||
272 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
273 | |||
274 | if (ar_pci->num_msi_intrs == 0) { | ||
275 | if (!ath10k_pci_irq_pending(ar)) | ||
276 | return IRQ_NONE; | ||
277 | |||
278 | ath10k_pci_disable_and_clear_legacy_irq(ar); | ||
279 | } | ||
280 | |||
281 | tasklet_schedule(&ar_pci->early_irq_tasklet); | ||
282 | |||
283 | return IRQ_HANDLED; | ||
284 | } | ||
285 | |||
286 | static int ath10k_pci_request_early_irq(struct ath10k *ar) | ||
287 | { | ||
288 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
289 | int ret; | ||
290 | |||
291 | /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first | ||
292 | * interrupt from irq vector is triggered in all cases for FW | ||
293 | * indication/errors */ | ||
294 | ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler, | ||
295 | IRQF_SHARED, "ath10k_pci (early)", ar); | ||
296 | if (ret) { | ||
297 | ath10k_warn("failed to request early irq: %d\n", ret); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static void ath10k_pci_free_early_irq(struct ath10k *ar) | ||
305 | { | ||
306 | free_irq(ath10k_pci_priv(ar)->pdev->irq, ar); | ||
307 | } | ||
308 | |||
309 | static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) | 269 | static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) |
310 | { | 270 | { |
311 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 271 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
@@ -948,7 +908,6 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) | |||
948 | 908 | ||
949 | tasklet_kill(&ar_pci->intr_tq); | 909 | tasklet_kill(&ar_pci->intr_tq); |
950 | tasklet_kill(&ar_pci->msi_fw_err); | 910 | tasklet_kill(&ar_pci->msi_fw_err); |
951 | tasklet_kill(&ar_pci->early_irq_tasklet); | ||
952 | 911 | ||
953 | for (i = 0; i < CE_COUNT; i++) | 912 | for (i = 0; i < CE_COUNT; i++) |
954 | tasklet_kill(&ar_pci->pipe_info[i].intr); | 913 | tasklet_kill(&ar_pci->pipe_info[i].intr); |
@@ -1158,20 +1117,10 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) | |||
1158 | static int ath10k_pci_hif_start(struct ath10k *ar) | 1117 | static int ath10k_pci_hif_start(struct ath10k *ar) |
1159 | { | 1118 | { |
1160 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 1119 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
1161 | int ret, ret_early; | 1120 | int ret; |
1162 | 1121 | ||
1163 | ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); | 1122 | ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); |
1164 | 1123 | ||
1165 | ath10k_pci_free_early_irq(ar); | ||
1166 | ath10k_pci_kill_tasklet(ar); | ||
1167 | |||
1168 | ret = ath10k_pci_request_irq(ar); | ||
1169 | if (ret) { | ||
1170 | ath10k_warn("failed to post RX buffers for all pipes: %d\n", | ||
1171 | ret); | ||
1172 | goto err_early_irq; | ||
1173 | } | ||
1174 | |||
1175 | ath10k_pci_irq_enable(ar); | 1124 | ath10k_pci_irq_enable(ar); |
1176 | 1125 | ||
1177 | /* Post buffers once to start things off. */ | 1126 | /* Post buffers once to start things off. */ |
@@ -1187,15 +1136,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar) | |||
1187 | 1136 | ||
1188 | err_stop: | 1137 | err_stop: |
1189 | ath10k_pci_irq_disable(ar); | 1138 | ath10k_pci_irq_disable(ar); |
1190 | ath10k_pci_free_irq(ar); | ||
1191 | ath10k_pci_kill_tasklet(ar); | 1139 | ath10k_pci_kill_tasklet(ar); |
1192 | err_early_irq: | ||
1193 | /* Though there should be no interrupts (device was reset) | ||
1194 | * power_down() expects the early IRQ to be installed as per the | ||
1195 | * driver lifecycle. */ | ||
1196 | ret_early = ath10k_pci_request_early_irq(ar); | ||
1197 | if (ret_early) | ||
1198 | ath10k_warn("failed to re-enable early irq: %d\n", ret_early); | ||
1199 | 1140 | ||
1200 | return ret; | 1141 | return ret; |
1201 | } | 1142 | } |
@@ -1302,7 +1243,6 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar) | |||
1302 | static void ath10k_pci_hif_stop(struct ath10k *ar) | 1243 | static void ath10k_pci_hif_stop(struct ath10k *ar) |
1303 | { | 1244 | { |
1304 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 1245 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
1305 | int ret; | ||
1306 | 1246 | ||
1307 | ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); | 1247 | ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); |
1308 | 1248 | ||
@@ -1310,17 +1250,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) | |||
1310 | return; | 1250 | return; |
1311 | 1251 | ||
1312 | ath10k_pci_irq_disable(ar); | 1252 | ath10k_pci_irq_disable(ar); |
1313 | ath10k_pci_free_irq(ar); | ||
1314 | ath10k_pci_kill_tasklet(ar); | 1253 | ath10k_pci_kill_tasklet(ar); |
1315 | |||
1316 | ret = ath10k_pci_request_early_irq(ar); | ||
1317 | if (ret) | ||
1318 | ath10k_warn("failed to re-enable early irq: %d\n", ret); | ||
1319 | |||
1320 | /* At this point, asynchronous threads are stopped, the target should | ||
1321 | * not DMA nor interrupt. We process the leftovers and then free | ||
1322 | * everything else up. */ | ||
1323 | |||
1324 | ath10k_pci_buffer_cleanup(ar); | 1254 | ath10k_pci_buffer_cleanup(ar); |
1325 | 1255 | ||
1326 | /* Make the sure the device won't access any structures on the host by | 1256 | /* Make the sure the device won't access any structures on the host by |
@@ -1806,28 +1736,19 @@ static int ath10k_pci_ce_init(struct ath10k *ar) | |||
1806 | return 0; | 1736 | return 0; |
1807 | } | 1737 | } |
1808 | 1738 | ||
1809 | static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) | 1739 | static bool ath10k_pci_has_fw_crashed(struct ath10k *ar) |
1810 | { | 1740 | { |
1811 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | 1741 | return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) & |
1812 | u32 fw_indicator; | 1742 | FW_IND_EVENT_PENDING; |
1813 | 1743 | } | |
1814 | fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); | ||
1815 | 1744 | ||
1816 | if (fw_indicator & FW_IND_EVENT_PENDING) { | 1745 | static void ath10k_pci_fw_crashed_clear(struct ath10k *ar) |
1817 | /* ACK: clear Target-side pending event */ | 1746 | { |
1818 | ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, | 1747 | u32 val; |
1819 | fw_indicator & ~FW_IND_EVENT_PENDING); | ||
1820 | 1748 | ||
1821 | if (ar_pci->started) { | 1749 | val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); |
1822 | ath10k_pci_fw_crashed_dump(ar); | 1750 | val &= ~FW_IND_EVENT_PENDING; |
1823 | } else { | 1751 | ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val); |
1824 | /* | ||
1825 | * Probable Target failure before we're prepared | ||
1826 | * to handle it. Generally unexpected. | ||
1827 | */ | ||
1828 | ath10k_warn("early firmware event indicated\n"); | ||
1829 | } | ||
1830 | } | ||
1831 | } | 1752 | } |
1832 | 1753 | ||
1833 | /* this function effectively clears target memory controller assert line */ | 1754 | /* this function effectively clears target memory controller assert line */ |
@@ -1960,34 +1881,26 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) | |||
1960 | goto err; | 1881 | goto err; |
1961 | } | 1882 | } |
1962 | 1883 | ||
1963 | ret = ath10k_pci_request_early_irq(ar); | ||
1964 | if (ret) { | ||
1965 | ath10k_err("failed to request early irq: %d\n", ret); | ||
1966 | goto err_ce; | ||
1967 | } | ||
1968 | |||
1969 | ret = ath10k_pci_wait_for_target_init(ar); | 1884 | ret = ath10k_pci_wait_for_target_init(ar); |
1970 | if (ret) { | 1885 | if (ret) { |
1971 | ath10k_err("failed to wait for target to init: %d\n", ret); | 1886 | ath10k_err("failed to wait for target to init: %d\n", ret); |
1972 | goto err_free_early_irq; | 1887 | goto err_ce; |
1973 | } | 1888 | } |
1974 | 1889 | ||
1975 | ret = ath10k_pci_init_config(ar); | 1890 | ret = ath10k_pci_init_config(ar); |
1976 | if (ret) { | 1891 | if (ret) { |
1977 | ath10k_err("failed to setup init config: %d\n", ret); | 1892 | ath10k_err("failed to setup init config: %d\n", ret); |
1978 | goto err_free_early_irq; | 1893 | goto err_ce; |
1979 | } | 1894 | } |
1980 | 1895 | ||
1981 | ret = ath10k_pci_wake_target_cpu(ar); | 1896 | ret = ath10k_pci_wake_target_cpu(ar); |
1982 | if (ret) { | 1897 | if (ret) { |
1983 | ath10k_err("could not wake up target CPU: %d\n", ret); | 1898 | ath10k_err("could not wake up target CPU: %d\n", ret); |
1984 | goto err_free_early_irq; | 1899 | goto err_ce; |
1985 | } | 1900 | } |
1986 | 1901 | ||
1987 | return 0; | 1902 | return 0; |
1988 | 1903 | ||
1989 | err_free_early_irq: | ||
1990 | ath10k_pci_free_early_irq(ar); | ||
1991 | err_ce: | 1904 | err_ce: |
1992 | ath10k_pci_ce_deinit(ar); | 1905 | ath10k_pci_ce_deinit(ar); |
1993 | ath10k_pci_warm_reset(ar); | 1906 | ath10k_pci_warm_reset(ar); |
@@ -2056,8 +1969,6 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) | |||
2056 | { | 1969 | { |
2057 | ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); | 1970 | ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); |
2058 | 1971 | ||
2059 | ath10k_pci_free_early_irq(ar); | ||
2060 | ath10k_pci_kill_tasklet(ar); | ||
2061 | ath10k_pci_warm_reset(ar); | 1972 | ath10k_pci_warm_reset(ar); |
2062 | } | 1973 | } |
2063 | 1974 | ||
@@ -2140,7 +2051,13 @@ static void ath10k_msi_err_tasklet(unsigned long data) | |||
2140 | { | 2051 | { |
2141 | struct ath10k *ar = (struct ath10k *)data; | 2052 | struct ath10k *ar = (struct ath10k *)data; |
2142 | 2053 | ||
2143 | ath10k_pci_fw_interrupt_handler(ar); | 2054 | if (!ath10k_pci_has_fw_crashed(ar)) { |
2055 | ath10k_warn("received unsolicited fw crash interrupt\n"); | ||
2056 | return; | ||
2057 | } | ||
2058 | |||
2059 | ath10k_pci_fw_crashed_clear(ar); | ||
2060 | ath10k_pci_fw_crashed_dump(ar); | ||
2144 | } | 2061 | } |
2145 | 2062 | ||
2146 | /* | 2063 | /* |
@@ -2201,27 +2118,17 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) | |||
2201 | return IRQ_HANDLED; | 2118 | return IRQ_HANDLED; |
2202 | } | 2119 | } |
2203 | 2120 | ||
2204 | static void ath10k_pci_early_irq_tasklet(unsigned long data) | 2121 | static void ath10k_pci_tasklet(unsigned long data) |
2205 | { | 2122 | { |
2206 | struct ath10k *ar = (struct ath10k *)data; | 2123 | struct ath10k *ar = (struct ath10k *)data; |
2207 | u32 fw_ind; | 2124 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
2208 | 2125 | ||
2209 | fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); | 2126 | if (ath10k_pci_has_fw_crashed(ar)) { |
2210 | if (fw_ind & FW_IND_EVENT_PENDING) { | 2127 | ath10k_pci_fw_crashed_clear(ar); |
2211 | ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, | ||
2212 | fw_ind & ~FW_IND_EVENT_PENDING); | ||
2213 | ath10k_pci_fw_crashed_dump(ar); | 2128 | ath10k_pci_fw_crashed_dump(ar); |
2129 | return; | ||
2214 | } | 2130 | } |
2215 | 2131 | ||
2216 | ath10k_pci_enable_legacy_irq(ar); | ||
2217 | } | ||
2218 | |||
2219 | static void ath10k_pci_tasklet(unsigned long data) | ||
2220 | { | ||
2221 | struct ath10k *ar = (struct ath10k *)data; | ||
2222 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||
2223 | |||
2224 | ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */ | ||
2225 | ath10k_ce_per_engine_service_any(ar); | 2132 | ath10k_ce_per_engine_service_any(ar); |
2226 | 2133 | ||
2227 | /* Re-enable legacy irq that was disabled in the irq handler */ | 2134 | /* Re-enable legacy irq that was disabled in the irq handler */ |
@@ -2332,8 +2239,6 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) | |||
2332 | tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); | 2239 | tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); |
2333 | tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, | 2240 | tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, |
2334 | (unsigned long)ar); | 2241 | (unsigned long)ar); |
2335 | tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet, | ||
2336 | (unsigned long)ar); | ||
2337 | 2242 | ||
2338 | for (i = 0; i < CE_COUNT; i++) { | 2243 | for (i = 0; i < CE_COUNT; i++) { |
2339 | ar_pci->pipe_info[i].ar_pci = ar_pci; | 2244 | ar_pci->pipe_info[i].ar_pci = ar_pci; |
@@ -2459,8 +2364,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) | |||
2459 | 2364 | ||
2460 | if (val & FW_IND_EVENT_PENDING) { | 2365 | if (val & FW_IND_EVENT_PENDING) { |
2461 | ath10k_warn("device has crashed during init\n"); | 2366 | ath10k_warn("device has crashed during init\n"); |
2462 | ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, | 2367 | ath10k_pci_fw_crashed_clear(ar); |
2463 | val & ~FW_IND_EVENT_PENDING); | ||
2464 | ath10k_pci_fw_crashed_dump(ar); | 2368 | ath10k_pci_fw_crashed_dump(ar); |
2465 | return -ECOMM; | 2369 | return -ECOMM; |
2466 | } | 2370 | } |
@@ -2643,6 +2547,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev, | |||
2643 | goto err_free_ce; | 2547 | goto err_free_ce; |
2644 | } | 2548 | } |
2645 | 2549 | ||
2550 | /* Workaround: There's no known way to mask all possible interrupts via | ||
2551 | * device CSR. The only way to make sure device doesn't assert | ||
2552 | * interrupts is to reset it. Interrupts are then disabled on host | ||
2553 | * after handlers are registered. | ||
2554 | */ | ||
2555 | ath10k_pci_warm_reset(ar); | ||
2556 | |||
2646 | ret = ath10k_pci_init_irq(ar); | 2557 | ret = ath10k_pci_init_irq(ar); |
2647 | if (ret) { | 2558 | if (ret) { |
2648 | ath10k_err("failed to init irqs: %d\n", ret); | 2559 | ath10k_err("failed to init irqs: %d\n", ret); |
@@ -2653,14 +2564,26 @@ static int ath10k_pci_probe(struct pci_dev *pdev, | |||
2653 | ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs, | 2564 | ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs, |
2654 | ath10k_pci_irq_mode, ath10k_pci_reset_mode); | 2565 | ath10k_pci_irq_mode, ath10k_pci_reset_mode); |
2655 | 2566 | ||
2567 | ret = ath10k_pci_request_irq(ar); | ||
2568 | if (ret) { | ||
2569 | ath10k_warn("failed to request irqs: %d\n", ret); | ||
2570 | goto err_deinit_irq; | ||
2571 | } | ||
2572 | |||
2573 | /* This shouldn't race as the device has been reset above. */ | ||
2574 | ath10k_pci_irq_disable(ar); | ||
2575 | |||
2656 | ret = ath10k_core_register(ar, chip_id); | 2576 | ret = ath10k_core_register(ar, chip_id); |
2657 | if (ret) { | 2577 | if (ret) { |
2658 | ath10k_err("failed to register driver core: %d\n", ret); | 2578 | ath10k_err("failed to register driver core: %d\n", ret); |
2659 | goto err_deinit_irq; | 2579 | goto err_free_irq; |
2660 | } | 2580 | } |
2661 | 2581 | ||
2662 | return 0; | 2582 | return 0; |
2663 | 2583 | ||
2584 | err_free_irq: | ||
2585 | ath10k_pci_free_irq(ar); | ||
2586 | |||
2664 | err_deinit_irq: | 2587 | err_deinit_irq: |
2665 | ath10k_pci_deinit_irq(ar); | 2588 | ath10k_pci_deinit_irq(ar); |
2666 | 2589 | ||
@@ -2695,6 +2618,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) | |||
2695 | return; | 2618 | return; |
2696 | 2619 | ||
2697 | ath10k_core_unregister(ar); | 2620 | ath10k_core_unregister(ar); |
2621 | ath10k_pci_free_irq(ar); | ||
2698 | ath10k_pci_deinit_irq(ar); | 2622 | ath10k_pci_deinit_irq(ar); |
2699 | ath10k_pci_ce_deinit(ar); | 2623 | ath10k_pci_ce_deinit(ar); |
2700 | ath10k_pci_free_ce(ar); | 2624 | ath10k_pci_free_ce(ar); |
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 294a72e01909..caed918c7102 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h | |||
@@ -166,7 +166,6 @@ struct ath10k_pci { | |||
166 | 166 | ||
167 | struct tasklet_struct intr_tq; | 167 | struct tasklet_struct intr_tq; |
168 | struct tasklet_struct msi_fw_err; | 168 | struct tasklet_struct msi_fw_err; |
169 | struct tasklet_struct early_irq_tasklet; | ||
170 | 169 | ||
171 | int started; | 170 | int started; |
172 | 171 | ||