Remove finish_tasklet. Requests that require DMA-unmapping or sdhci_reset are completed either in the IRQ thread or a workqueue if the completion is not initiated by the IRQ. Signed-off-by: Adrian Hunter <adrian.hunter@xxxxxxxxx> --- drivers/mmc/host/sdhci.c | 37 +++++++++++++++++++++---------------- drivers/mmc/host/sdhci.h | 3 ++- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3317c6a2f0f9..5c82387d53e2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1281,7 +1281,7 @@ static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) { __sdhci_finish_mrq(host, mrq); - tasklet_schedule(&host->finish_tasklet); + queue_work(host->complete_wq, &host->complete_work); } static void sdhci_finish_data(struct sdhci_host *host) @@ -2599,7 +2599,7 @@ static const struct mmc_host_ops sdhci_ops = { /*****************************************************************************\ * * - * Tasklets * + * Request done * * * \*****************************************************************************/ @@ -2713,9 +2713,10 @@ static bool sdhci_request_done(struct sdhci_host *host) return false; } -static void sdhci_tasklet_finish(unsigned long param) +static void sdhci_complete_work(struct work_struct *work) { - struct sdhci_host *host = (struct sdhci_host *)param; + struct sdhci_host *host = container_of(work, struct sdhci_host, + complete_work); while (!sdhci_request_done(host)) ; @@ -2761,7 +2762,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) if (host->data) { host->data->error = -ETIMEDOUT; sdhci_finish_data(host); - tasklet_schedule(&host->finish_tasklet); + queue_work(host->complete_wq, &host->complete_work); } else if (host->data_cmd) { host->data_cmd->error = -ETIMEDOUT; sdhci_finish_mrq(host, host->data_cmd->mrq); @@ -3122,7 +3123,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) continue; if (sdhci_defer_done(host, mrq)) { - tasklet_schedule(&host->finish_tasklet); + result = IRQ_WAKE_THREAD; } else { mrqs_done[i] = mrq; host->mrqs_done[i] = NULL; @@ -3152,6 +3153,9 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) unsigned long flags; u32 isr; + while (!sdhci_request_done(host)) + ; + spin_lock_irqsave(&host->lock, flags); isr = host->thread_isr; host->thread_isr = 0; @@ -3173,7 +3177,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) spin_unlock_irqrestore(&host->lock, flags); } - return isr ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } /*****************************************************************************\ @@ -4259,14 +4263,15 @@ EXPORT_SYMBOL_GPL(sdhci_cleanup_host); int __sdhci_add_host(struct sdhci_host *host) { + unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI; struct mmc_host *mmc = host->mmc; int ret; - /* - * Init tasklets. - */ - tasklet_init(&host->finish_tasklet, - sdhci_tasklet_finish, (unsigned long)host); + host->complete_wq = alloc_workqueue("sdhci", flags, 0); + if (!host->complete_wq) + return -ENOMEM; + + INIT_WORK(&host->complete_work, sdhci_complete_work); timer_setup(&host->timer, sdhci_timeout_timer, 0); timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0); @@ -4280,7 +4285,7 @@ int __sdhci_add_host(struct sdhci_host *host) if (ret) { pr_err("%s: Failed to request IRQ %d: %d\n", mmc_hostname(mmc), host->irq, ret); - goto untasklet; + goto unwq; } ret = sdhci_led_register(host); @@ -4313,8 +4318,8 @@ int __sdhci_add_host(struct sdhci_host *host) sdhci_writel(host, 0, SDHCI_INT_ENABLE); sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); free_irq(host->irq, host); -untasklet: - tasklet_kill(&host->finish_tasklet); +unwq: + destroy_workqueue(host->complete_wq); return ret; } @@ -4376,7 +4381,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) del_timer_sync(&host->timer); del_timer_sync(&host->data_timer); - tasklet_kill(&host->finish_tasklet); + destroy_workqueue(host->complete_wq); if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 57bb3e3dca89..d6bcc584c92b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -560,7 +560,8 @@ struct sdhci_host { unsigned int desc_sz; /* ADMA descriptor size */ - struct tasklet_struct finish_tasklet; /* Tasklet structures */ + struct workqueue_struct *complete_wq; /* Request completion wq */ + struct work_struct complete_work; /* Request completion work */ struct timer_list timer; /* Timer for timeouts */ struct timer_list data_timer; /* Timer for data timeouts */ -- 2.17.1