aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2013-11-25 08:06:26 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2013-11-27 09:45:33 -0500
commitab977bd04bd56edf473e0317eb2370abba04356c (patch)
tree024170cc7853daaa16fba7bca5d4f2a5f6349e6c
parent2685218b3f3dd2af1c9ac09d7b3800725bb34d9c (diff)
ath10k: re-add support for early fw indication
It's possible for FW to panic during early boot. The patch re-introduces support to detect and print those crashes. This introduces an additional irq handler that is set for the duration of early boot and shutdown. The handler is then overriden with regular handlers upon hif start(). 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.c106
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h1
2 files changed, 102 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 1d2939c35d9c..0a2d1c20e4df 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -248,6 +248,46 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
248 PCIE_INTR_ENABLE_ADDRESS); 248 PCIE_INTR_ENABLE_ADDRESS);
249} 249}
250 250
251static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
252{
253 struct ath10k *ar = arg;
254 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
255
256 if (ar_pci->num_msi_intrs == 0) {
257 if (!ath10k_pci_irq_pending(ar))
258 return IRQ_NONE;
259
260 ath10k_pci_disable_and_clear_legacy_irq(ar);
261 }
262
263 tasklet_schedule(&ar_pci->early_irq_tasklet);
264
265 return IRQ_HANDLED;
266}
267
268static int ath10k_pci_request_early_irq(struct ath10k *ar)
269{
270 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
271 int ret;
272
273 /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
274 * interrupt from irq vector is triggered in all cases for FW
275 * indication/errors */
276 ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
277 IRQF_SHARED, "ath10k_pci (early)", ar);
278 if (ret) {
279 ath10k_warn("failed to request early irq: %d\n", ret);
280 return ret;
281 }
282
283 return 0;
284}
285
286static void ath10k_pci_free_early_irq(struct ath10k *ar)
287{
288 free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
289}
290
251/* 291/*
252 * Diagnostic read/write access is provided for startup/config/debug usage. 292 * Diagnostic read/write access is provided for startup/config/debug usage.
253 * Caller must guarantee proper alignment, when applicable, and single user 293 * Caller must guarantee proper alignment, when applicable, and single user
@@ -937,6 +977,7 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
937 977
938 tasklet_kill(&ar_pci->intr_tq); 978 tasklet_kill(&ar_pci->intr_tq);
939 tasklet_kill(&ar_pci->msi_fw_err); 979 tasklet_kill(&ar_pci->msi_fw_err);
980 tasklet_kill(&ar_pci->early_irq_tasklet);
940 981
941 for (i = 0; i < CE_COUNT; i++) 982 for (i = 0; i < CE_COUNT; i++)
942 tasklet_kill(&ar_pci->pipe_info[i].intr); 983 tasklet_kill(&ar_pci->pipe_info[i].intr);
@@ -1249,12 +1290,15 @@ static int ath10k_pci_post_rx(struct ath10k *ar)
1249static int ath10k_pci_hif_start(struct ath10k *ar) 1290static int ath10k_pci_hif_start(struct ath10k *ar)
1250{ 1291{
1251 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 1292 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
1252 int ret; 1293 int ret, ret_early;
1294
1295 ath10k_pci_free_early_irq(ar);
1296 ath10k_pci_kill_tasklet(ar);
1253 1297
1254 ret = ath10k_pci_alloc_compl(ar); 1298 ret = ath10k_pci_alloc_compl(ar);
1255 if (ret) { 1299 if (ret) {
1256 ath10k_warn("failed to allocate CE completions: %d\n", ret); 1300 ath10k_warn("failed to allocate CE completions: %d\n", ret);
1257 return ret; 1301 goto err_early_irq;
1258 } 1302 }
1259 1303
1260 ret = ath10k_pci_request_irq(ar); 1304 ret = ath10k_pci_request_irq(ar);
@@ -1289,6 +1333,14 @@ err_stop:
1289 ath10k_pci_process_ce(ar); 1333 ath10k_pci_process_ce(ar);
1290err_free_compl: 1334err_free_compl:
1291 ath10k_pci_cleanup_ce(ar); 1335 ath10k_pci_cleanup_ce(ar);
1336err_early_irq:
1337 /* Though there should be no interrupts (device was reset)
1338 * power_down() expects the early IRQ to be installed as per the
1339 * driver lifecycle. */
1340 ret_early = ath10k_pci_request_early_irq(ar);
1341 if (ret_early)
1342 ath10k_warn("failed to re-enable early irq: %d\n", ret_early);
1343
1292 return ret; 1344 return ret;
1293} 1345}
1294 1346
@@ -1422,6 +1474,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
1422 ath10k_pci_kill_tasklet(ar); 1474 ath10k_pci_kill_tasklet(ar);
1423 ath10k_pci_stop_ce(ar); 1475 ath10k_pci_stop_ce(ar);
1424 1476
1477 ret = ath10k_pci_request_early_irq(ar);
1478 if (ret)
1479 ath10k_warn("failed to re-enable early irq: %d\n", ret);
1480
1425 /* At this point, asynchronous threads are stopped, the target should 1481 /* At this point, asynchronous threads are stopped, the target should
1426 * not DMA nor interrupt. We process the leftovers and then free 1482 * not DMA nor interrupt. We process the leftovers and then free
1427 * everything else up. */ 1483 * everything else up. */
@@ -1970,22 +2026,28 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
1970 goto err_ce; 2026 goto err_ce;
1971 } 2027 }
1972 2028
2029 ret = ath10k_pci_request_early_irq(ar);
2030 if (ret) {
2031 ath10k_err("failed to request early irq: %d\n", ret);
2032 goto err_deinit_irq;
2033 }
2034
1973 ret = ath10k_pci_wait_for_target_init(ar); 2035 ret = ath10k_pci_wait_for_target_init(ar);
1974 if (ret) { 2036 if (ret) {
1975 ath10k_err("failed to wait for target to init: %d\n", ret); 2037 ath10k_err("failed to wait for target to init: %d\n", ret);
1976 goto err_deinit_irq; 2038 goto err_free_early_irq;
1977 } 2039 }
1978 2040
1979 ret = ath10k_pci_init_config(ar); 2041 ret = ath10k_pci_init_config(ar);
1980 if (ret) { 2042 if (ret) {
1981 ath10k_err("failed to setup init config: %d\n", ret); 2043 ath10k_err("failed to setup init config: %d\n", ret);
1982 goto err_deinit_irq; 2044 goto err_free_early_irq;
1983 } 2045 }
1984 2046
1985 ret = ath10k_pci_wake_target_cpu(ar); 2047 ret = ath10k_pci_wake_target_cpu(ar);
1986 if (ret) { 2048 if (ret) {
1987 ath10k_err("could not wake up target CPU: %d\n", ret); 2049 ath10k_err("could not wake up target CPU: %d\n", ret);
1988 goto err_deinit_irq; 2050 goto err_free_early_irq;
1989 } 2051 }
1990 2052
1991 if (ar_pci->num_msi_intrs > 1) 2053 if (ar_pci->num_msi_intrs > 1)
@@ -2000,6 +2062,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
2000 2062
2001 return 0; 2063 return 0;
2002 2064
2065err_free_early_irq:
2066 ath10k_pci_free_early_irq(ar);
2003err_deinit_irq: 2067err_deinit_irq:
2004 ath10k_pci_deinit_irq(ar); 2068 ath10k_pci_deinit_irq(ar);
2005err_ce: 2069err_ce:
@@ -2016,6 +2080,8 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
2016{ 2080{
2017 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 2081 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2018 2082
2083 ath10k_pci_free_early_irq(ar);
2084 ath10k_pci_kill_tasklet(ar);
2019 ath10k_pci_deinit_irq(ar); 2085 ath10k_pci_deinit_irq(ar);
2020 ath10k_pci_device_reset(ar); 2086 ath10k_pci_device_reset(ar);
2021 2087
@@ -2164,6 +2230,34 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
2164 return IRQ_HANDLED; 2230 return IRQ_HANDLED;
2165} 2231}
2166 2232
2233static void ath10k_pci_early_irq_tasklet(unsigned long data)
2234{
2235 struct ath10k *ar = (struct ath10k *)data;
2236 struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
2237 u32 fw_ind;
2238 int ret;
2239
2240 ret = ath10k_pci_wake(ar);
2241 if (ret) {
2242 ath10k_warn("failed to wake target in early irq tasklet: %d\n",
2243 ret);
2244 return;
2245 }
2246
2247 fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address);
2248 if (fw_ind & FW_IND_EVENT_PENDING) {
2249 ath10k_pci_write32(ar, ar_pci->fw_indicator_address,
2250 fw_ind & ~FW_IND_EVENT_PENDING);
2251
2252 /* Some structures are unavailable during early boot or at
2253 * driver teardown so just print that the device has crashed. */
2254 ath10k_warn("device crashed - no diagnostics available\n");
2255 }
2256
2257 ath10k_pci_sleep(ar);
2258 ath10k_pci_enable_legacy_irq(ar);
2259}
2260
2167static void ath10k_pci_tasklet(unsigned long data) 2261static void ath10k_pci_tasklet(unsigned long data)
2168{ 2262{
2169 struct ath10k *ar = (struct ath10k *)data; 2263 struct ath10k *ar = (struct ath10k *)data;
@@ -2280,6 +2374,8 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
2280 tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); 2374 tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
2281 tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, 2375 tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
2282 (unsigned long)ar); 2376 (unsigned long)ar);
2377 tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
2378 (unsigned long)ar);
2283 2379
2284 for (i = 0; i < CE_COUNT; i++) { 2380 for (i = 0; i < CE_COUNT; i++) {
2285 ar_pci->pipe_info[i].ar_pci = ar_pci; 2381 ar_pci->pipe_info[i].ar_pci = ar_pci;
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 73a3d4ee6ebf..a4f32038c440 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -198,6 +198,7 @@ struct ath10k_pci {
198 198
199 struct tasklet_struct intr_tq; 199 struct tasklet_struct intr_tq;
200 struct tasklet_struct msi_fw_err; 200 struct tasklet_struct msi_fw_err;
201 struct tasklet_struct early_irq_tasklet;
201 202
202 int started; 203 int started;
203 204