diff options
-rw-r--r-- | drivers/mmc/host/sdhci.c | 62 | ||||
-rw-r--r-- | include/linux/mmc/sdhci.h | 2 |
2 files changed, 41 insertions, 23 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4b6cca2130bc..4a0622d52ae5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -2428,10 +2428,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
2428 | 2428 | ||
2429 | static irqreturn_t sdhci_irq(int irq, void *dev_id) | 2429 | static irqreturn_t sdhci_irq(int irq, void *dev_id) |
2430 | { | 2430 | { |
2431 | irqreturn_t result; | 2431 | irqreturn_t result = IRQ_NONE; |
2432 | struct sdhci_host *host = dev_id; | 2432 | struct sdhci_host *host = dev_id; |
2433 | u32 intmask, mask, unexpected = 0; | 2433 | u32 intmask, mask, unexpected = 0; |
2434 | int cardint = 0, max_loops = 16; | 2434 | int max_loops = 16; |
2435 | 2435 | ||
2436 | spin_lock(&host->lock); | 2436 | spin_lock(&host->lock); |
2437 | 2437 | ||
@@ -2490,8 +2490,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
2490 | pr_err("%s: Card is consuming too much power!\n", | 2490 | pr_err("%s: Card is consuming too much power!\n", |
2491 | mmc_hostname(host->mmc)); | 2491 | mmc_hostname(host->mmc)); |
2492 | 2492 | ||
2493 | if (intmask & SDHCI_INT_CARD_INT) | 2493 | if (intmask & SDHCI_INT_CARD_INT) { |
2494 | cardint = 1; | 2494 | sdhci_enable_sdio_irq_nolock(host, false); |
2495 | host->thread_isr |= SDHCI_INT_CARD_INT; | ||
2496 | result = IRQ_WAKE_THREAD; | ||
2497 | } | ||
2495 | 2498 | ||
2496 | intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | | 2499 | intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | |
2497 | SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | | 2500 | SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | |
@@ -2503,17 +2506,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
2503 | sdhci_writel(host, intmask, SDHCI_INT_STATUS); | 2506 | sdhci_writel(host, intmask, SDHCI_INT_STATUS); |
2504 | } | 2507 | } |
2505 | 2508 | ||
2506 | result = IRQ_HANDLED; | 2509 | if (result == IRQ_NONE) |
2510 | result = IRQ_HANDLED; | ||
2507 | 2511 | ||
2508 | intmask = sdhci_readl(host, SDHCI_INT_STATUS); | 2512 | intmask = sdhci_readl(host, SDHCI_INT_STATUS); |
2509 | |||
2510 | /* | ||
2511 | * If we know we'll call the driver to signal SDIO IRQ, | ||
2512 | * disregard further indications of Card Interrupt in | ||
2513 | * the status to avoid a needless loop. | ||
2514 | */ | ||
2515 | if (cardint) | ||
2516 | intmask &= ~SDHCI_INT_CARD_INT; | ||
2517 | } while (intmask && --max_loops); | 2513 | } while (intmask && --max_loops); |
2518 | out: | 2514 | out: |
2519 | spin_unlock(&host->lock); | 2515 | spin_unlock(&host->lock); |
@@ -2523,15 +2519,33 @@ out: | |||
2523 | mmc_hostname(host->mmc), unexpected); | 2519 | mmc_hostname(host->mmc), unexpected); |
2524 | sdhci_dumpregs(host); | 2520 | sdhci_dumpregs(host); |
2525 | } | 2521 | } |
2526 | /* | ||
2527 | * We have to delay this as it calls back into the driver. | ||
2528 | */ | ||
2529 | if (cardint) | ||
2530 | mmc_signal_sdio_irq(host->mmc); | ||
2531 | 2522 | ||
2532 | return result; | 2523 | return result; |
2533 | } | 2524 | } |
2534 | 2525 | ||
2526 | static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) | ||
2527 | { | ||
2528 | struct sdhci_host *host = dev_id; | ||
2529 | unsigned long flags; | ||
2530 | u32 isr; | ||
2531 | |||
2532 | spin_lock_irqsave(&host->lock, flags); | ||
2533 | isr = host->thread_isr; | ||
2534 | host->thread_isr = 0; | ||
2535 | spin_unlock_irqrestore(&host->lock, flags); | ||
2536 | |||
2537 | if (isr & SDHCI_INT_CARD_INT) { | ||
2538 | sdio_run_irqs(host->mmc); | ||
2539 | |||
2540 | spin_lock_irqsave(&host->lock, flags); | ||
2541 | if (host->flags & SDHCI_SDIO_IRQ_ENABLED) | ||
2542 | sdhci_enable_sdio_irq_nolock(host, true); | ||
2543 | spin_unlock_irqrestore(&host->lock, flags); | ||
2544 | } | ||
2545 | |||
2546 | return isr ? IRQ_HANDLED : IRQ_NONE; | ||
2547 | } | ||
2548 | |||
2535 | /*****************************************************************************\ | 2549 | /*****************************************************************************\ |
2536 | * * | 2550 | * * |
2537 | * Suspend/resume * | 2551 | * Suspend/resume * |
@@ -2601,8 +2615,9 @@ int sdhci_resume_host(struct sdhci_host *host) | |||
2601 | } | 2615 | } |
2602 | 2616 | ||
2603 | if (!device_may_wakeup(mmc_dev(host->mmc))) { | 2617 | if (!device_may_wakeup(mmc_dev(host->mmc))) { |
2604 | ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, | 2618 | ret = request_threaded_irq(host->irq, sdhci_irq, |
2605 | mmc_hostname(host->mmc), host); | 2619 | sdhci_thread_irq, IRQF_SHARED, |
2620 | mmc_hostname(host->mmc), host); | ||
2606 | if (ret) | 2621 | if (ret) |
2607 | return ret; | 2622 | return ret; |
2608 | } else { | 2623 | } else { |
@@ -2681,7 +2696,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) | |||
2681 | sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); | 2696 | sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); |
2682 | spin_unlock_irqrestore(&host->lock, flags); | 2697 | spin_unlock_irqrestore(&host->lock, flags); |
2683 | 2698 | ||
2684 | synchronize_irq(host->irq); | 2699 | synchronize_hardirq(host->irq); |
2685 | 2700 | ||
2686 | spin_lock_irqsave(&host->lock, flags); | 2701 | spin_lock_irqsave(&host->lock, flags); |
2687 | host->runtime_suspended = true; | 2702 | host->runtime_suspended = true; |
@@ -2937,6 +2952,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
2937 | mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; | 2952 | mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; |
2938 | 2953 | ||
2939 | mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; | 2954 | mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; |
2955 | mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; | ||
2940 | 2956 | ||
2941 | if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) | 2957 | if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) |
2942 | host->flags |= SDHCI_AUTO_CMD12; | 2958 | host->flags |= SDHCI_AUTO_CMD12; |
@@ -3226,8 +3242,8 @@ int sdhci_add_host(struct sdhci_host *host) | |||
3226 | 3242 | ||
3227 | sdhci_init(host, 0); | 3243 | sdhci_init(host, 0); |
3228 | 3244 | ||
3229 | ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, | 3245 | ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq, |
3230 | mmc_hostname(mmc), host); | 3246 | IRQF_SHARED, mmc_hostname(mmc), host); |
3231 | if (ret) { | 3247 | if (ret) { |
3232 | pr_err("%s: Failed to request IRQ %d: %d\n", | 3248 | pr_err("%s: Failed to request IRQ %d: %d\n", |
3233 | mmc_hostname(mmc), host->irq, ret); | 3249 | mmc_hostname(mmc), host->irq, ret); |
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 7be12b883485..d1aa97b77dd9 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h | |||
@@ -177,6 +177,8 @@ struct sdhci_host { | |||
177 | unsigned int ocr_avail_mmc; | 177 | unsigned int ocr_avail_mmc; |
178 | u32 ocr_mask; /* available voltages */ | 178 | u32 ocr_mask; /* available voltages */ |
179 | 179 | ||
180 | u32 thread_isr; | ||
181 | |||
180 | wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ | 182 | wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ |
181 | unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ | 183 | unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ |
182 | 184 | ||