aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>2012-01-04 05:27:19 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2012-01-09 09:20:11 -0500
commit9d82682d45ef7407474e0ae043a587cb33a7fa26 (patch)
tree979005036a5315bcb99ea7b8ab92d9e7d46a8b56
parent982767b8c94482b4b7f694e2ab2074c95fbf3e0e (diff)
ath6kl: Use a mutex_lock to avoid race in diabling and handling irq
Currently this race is handled but in a messy way an atomic variable is being checked in a loop which sleeps upto ms in every iteration. Remove this logic and use a mutex to make sure irq is not disabled when irq handling is in progress. Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c19
1 files changed, 9 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 278a9f30795a..8b36904ec3ec 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -49,11 +49,13 @@ struct ath6kl_sdio {
49 /* scatter request list head */ 49 /* scatter request list head */
50 struct list_head scat_req; 50 struct list_head scat_req;
51 51
52 /* Avoids disabling irq while the interrupts being handled */
53 struct mutex mtx_irq;
54
52 spinlock_t scat_lock; 55 spinlock_t scat_lock;
53 bool scatter_enabled; 56 bool scatter_enabled;
54 57
55 bool is_disabled; 58 bool is_disabled;
56 atomic_t irq_handling;
57 const struct sdio_device_id *id; 59 const struct sdio_device_id *id;
58 struct work_struct wr_async_work; 60 struct work_struct wr_async_work;
59 struct list_head wr_asyncq; 61 struct list_head wr_asyncq;
@@ -460,8 +462,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
460 ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); 462 ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
461 463
462 ar_sdio = sdio_get_drvdata(func); 464 ar_sdio = sdio_get_drvdata(func);
463 atomic_set(&ar_sdio->irq_handling, 1); 465 mutex_lock(&ar_sdio->mtx_irq);
464
465 /* 466 /*
466 * Release the host during interrups so we can pick it back up when 467 * Release the host during interrups so we can pick it back up when
467 * we process commands. 468 * we process commands.
@@ -470,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
470 471
471 status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); 472 status = ath6kl_hif_intr_bh_handler(ar_sdio->ar);
472 sdio_claim_host(ar_sdio->func); 473 sdio_claim_host(ar_sdio->func);
473 atomic_set(&ar_sdio->irq_handling, 0); 474 mutex_unlock(&ar_sdio->mtx_irq);
474 WARN_ON(status && status != -ECANCELED); 475 WARN_ON(status && status != -ECANCELED);
475} 476}
476 477
@@ -578,17 +579,14 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
578 579
579 sdio_claim_host(ar_sdio->func); 580 sdio_claim_host(ar_sdio->func);
580 581
581 /* Mask our function IRQ */ 582 mutex_lock(&ar_sdio->mtx_irq);
582 while (atomic_read(&ar_sdio->irq_handling)) {
583 sdio_release_host(ar_sdio->func);
584 schedule_timeout(HZ / 10);
585 sdio_claim_host(ar_sdio->func);
586 }
587 583
588 ret = sdio_release_irq(ar_sdio->func); 584 ret = sdio_release_irq(ar_sdio->func);
589 if (ret) 585 if (ret)
590 ath6kl_err("Failed to release sdio irq: %d\n", ret); 586 ath6kl_err("Failed to release sdio irq: %d\n", ret);
591 587
588 mutex_unlock(&ar_sdio->mtx_irq);
589
592 sdio_release_host(ar_sdio->func); 590 sdio_release_host(ar_sdio->func);
593} 591}
594 592
@@ -1253,6 +1251,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
1253 spin_lock_init(&ar_sdio->scat_lock); 1251 spin_lock_init(&ar_sdio->scat_lock);
1254 spin_lock_init(&ar_sdio->wr_async_lock); 1252 spin_lock_init(&ar_sdio->wr_async_lock);
1255 mutex_init(&ar_sdio->dma_buffer_mutex); 1253 mutex_init(&ar_sdio->dma_buffer_mutex);
1254 mutex_init(&ar_sdio->mtx_irq);
1256 1255
1257 INIT_LIST_HEAD(&ar_sdio->scat_req); 1256 INIT_LIST_HEAD(&ar_sdio->scat_req);
1258 INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); 1257 INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);