aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-04-25 07:55:30 -0400
committerChris Ball <chris@printf.net>2014-05-22 07:26:03 -0400
commitbf3b5ec66bd03d66e9ea729aaca013ea1047a797 (patch)
tree0aa1b43812cdde41d0a2de116951af61ee042fb7
parent197160d52e859575ff0ad1afd674ab2a825b9f83 (diff)
mmc: sdio_irq: rework sdio irq handling
Rather than the SDIO support spawning it's own thread for handling card interrupts, use the generic IRQ infrastructure for this, triggering it from the host interface's interrupt handling directly. This avoids a race between the parent thread waiting to receive an interrupt response from the card, and the slow startup from the sdio irq thread, which can occur as a result of high system load (eg, while udev is running.) Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Tested-by: Markus Pargmann <mpa@pengutronix.de> Tested-by: Stephen Warren <swarren@nvidia.com> [Ulf Hansson] Resolved conflict Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <chris@printf.net>
-rw-r--r--drivers/mmc/core/sdio_irq.c41
-rw-r--r--include/linux/mmc/host.h3
2 files changed, 34 insertions, 10 deletions
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index aaa90460ed23..5cc13c8d35bb 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -90,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
90 return ret; 90 return ret;
91} 91}
92 92
93void sdio_run_irqs(struct mmc_host *host)
94{
95 mmc_claim_host(host);
96 host->sdio_irq_pending = true;
97 process_sdio_pending_irqs(host);
98 mmc_release_host(host);
99}
100EXPORT_SYMBOL_GPL(sdio_run_irqs);
101
93static int sdio_irq_thread(void *_host) 102static int sdio_irq_thread(void *_host)
94{ 103{
95 struct mmc_host *host = _host; 104 struct mmc_host *host = _host;
@@ -189,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card)
189 WARN_ON(!host->claimed); 198 WARN_ON(!host->claimed);
190 199
191 if (!host->sdio_irqs++) { 200 if (!host->sdio_irqs++) {
192 atomic_set(&host->sdio_irq_thread_abort, 0); 201 if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
193 host->sdio_irq_thread = 202 atomic_set(&host->sdio_irq_thread_abort, 0);
194 kthread_run(sdio_irq_thread, host, "ksdioirqd/%s", 203 host->sdio_irq_thread =
195 mmc_hostname(host)); 204 kthread_run(sdio_irq_thread, host,
196 if (IS_ERR(host->sdio_irq_thread)) { 205 "ksdioirqd/%s", mmc_hostname(host));
197 int err = PTR_ERR(host->sdio_irq_thread); 206 if (IS_ERR(host->sdio_irq_thread)) {
198 host->sdio_irqs--; 207 int err = PTR_ERR(host->sdio_irq_thread);
199 return err; 208 host->sdio_irqs--;
209 return err;
210 }
211 } else {
212 mmc_host_clk_hold(host);
213 host->ops->enable_sdio_irq(host, 1);
214 mmc_host_clk_release(host);
200 } 215 }
201 } 216 }
202 217
@@ -211,8 +226,14 @@ static int sdio_card_irq_put(struct mmc_card *card)
211 BUG_ON(host->sdio_irqs < 1); 226 BUG_ON(host->sdio_irqs < 1);
212 227
213 if (!--host->sdio_irqs) { 228 if (!--host->sdio_irqs) {
214 atomic_set(&host->sdio_irq_thread_abort, 1); 229 if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
215 kthread_stop(host->sdio_irq_thread); 230 atomic_set(&host->sdio_irq_thread_abort, 1);
231 kthread_stop(host->sdio_irq_thread);
232 } else {
233 mmc_host_clk_hold(host);
234 host->ops->enable_sdio_irq(host, 0);
235 mmc_host_clk_release(host);
236 }
216 } 237 }
217 238
218 return 0; 239 return 0;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index cd595275e118..7960424d0bc0 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -282,6 +282,7 @@ struct mmc_host {
282#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */ 282#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */
283#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \ 283#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
284 MMC_CAP2_HS400_1_2V) 284 MMC_CAP2_HS400_1_2V)
285#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
285 286
286 mmc_pm_flag_t pm_caps; /* supported pm features */ 287 mmc_pm_flag_t pm_caps; /* supported pm features */
287 288
@@ -397,6 +398,8 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
397 wake_up_process(host->sdio_irq_thread); 398 wake_up_process(host->sdio_irq_thread);
398} 399}
399 400
401void sdio_run_irqs(struct mmc_host *host);
402
400#ifdef CONFIG_REGULATOR 403#ifdef CONFIG_REGULATOR
401int mmc_regulator_get_ocrmask(struct regulator *supply); 404int mmc_regulator_get_ocrmask(struct regulator *supply);
402int mmc_regulator_set_ocr(struct mmc_host *mmc, 405int mmc_regulator_set_ocr(struct mmc_host *mmc,