aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/sdio_irq.c
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2017-04-13 16:48:11 +0200
committerUlf Hansson <ulf.hansson@linaro.org>2017-06-20 10:30:11 +0200
commit682696605c7093d2800c498c04166831e5aedf87 (patch)
tree97e6aad0dce5d5ba2356592b05587b5a99f18304 /drivers/mmc/core/sdio_irq.c
parentmmc: core: Prevent processing SDIO IRQs when none is claimed (diff)
downloadlinux-dev-682696605c7093d2800c498c04166831e5aedf87.tar.xz
linux-dev-682696605c7093d2800c498c04166831e5aedf87.zip
mmc: sdio: Add API to manage SDIO IRQs from a workqueue
For hosts not supporting MMC_CAP2_SDIO_IRQ_NOTHREAD but MMC_CAP_SDIO_IRQ, the SDIO IRQs are processed from a dedicated kernel thread. For these cases, the host calls mmc_signal_sdio_irq() from its ISR to signal a new SDIO IRQ. Signaling an SDIO IRQ makes the host's ->enable_sdio_irq() callback to be invoked to temporary disable the IRQs, before the kernel thread is woken up to process it. When processing of the IRQs are completed, they are re-enabled by the kernel thread, again via invoking the host's ->enable_sdio_irq(). The observation from this, is that the execution path is being unnecessary complex, as the host driver already knows that it needs to temporary disable the IRQs before signaling a new one. Moreover, replacing the kernel thread with a work/workqueue would not only greatly simplify the code, but also make it more robust. To address the above problems, let's continue to build upon the support for MMC_CAP2_SDIO_IRQ_NOTHREAD, as it already implements SDIO IRQs to be processed without using the clumsy kernel thread and without the ping-pong calls of the host's ->enable_sdio_irq() callback for each processed IRQ. Therefore, let's add new API sdio_signal_irq(), which enables hosts to signal/process SDIO IRQs by using a work/workqueue, rather than using the kernel thread. Add also a new host callback ->ack_sdio_irq(), which the work invokes when the SDIO IRQs have been processed. This informs the host about when it shall re-enable the SDIO IRQs. Potentially, we could re-use the existing ->enable_sdio_irq() callback instead of adding a new one, however it has turned out that it's more convenient for hosts to get this information via a separate callback. Hosts that wants to use this new method to signal/process SDIO IRQs, must enable MMC_CAP2_SDIO_IRQ_NOTHREAD and implement the ->ack_sdio_irq() callback. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Douglas Anderson <dianders@chromium.org> Reviewed-by: Douglas Anderson <dianders@chromium.org>
Diffstat (limited to 'drivers/mmc/core/sdio_irq.c')
-rw-r--r--drivers/mmc/core/sdio_irq.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 44d9c86bd2d4..c771843e4c15 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -98,11 +98,27 @@ void sdio_run_irqs(struct mmc_host *host)
if (host->sdio_irqs) {
host->sdio_irq_pending = true;
process_sdio_pending_irqs(host);
+ if (host->ops->ack_sdio_irq)
+ host->ops->ack_sdio_irq(host);
}
mmc_release_host(host);
}
EXPORT_SYMBOL_GPL(sdio_run_irqs);
+void sdio_irq_work(struct work_struct *work)
+{
+ struct mmc_host *host =
+ container_of(work, struct mmc_host, sdio_irq_work.work);
+
+ sdio_run_irqs(host);
+}
+
+void sdio_signal_irq(struct mmc_host *host)
+{
+ queue_delayed_work(system_wq, &host->sdio_irq_work, 0);
+}
+EXPORT_SYMBOL_GPL(sdio_signal_irq);
+
static int sdio_irq_thread(void *_host)
{
struct mmc_host *host = _host;