aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/host.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/host.c
parentmmc: core: Prevent processing SDIO IRQs when none is claimed (diff)
downloadlinux-stable-682696605c7093d2800c498c04166831e5aedf87.tar.xz
linux-stable-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/host.c')
-rw-r--r--drivers/mmc/core/host.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 3f8c85d5aa09..8823c97a7b38 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -30,6 +30,7 @@
#include "host.h"
#include "slot-gpio.h"
#include "pwrseq.h"
+#include "sdio_ops.h"
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
@@ -379,6 +380,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+ INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work);
setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
/*