X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fmmc%2Fcore%2Fsdio_irq.c;h=c292e124107ac13ec36be751024ad3728cafaa40;hb=e9f76354ce83a20c7768ad37caa033f6506b4f96;hp=01daee934d16c270887bdbb097d8911b17ae832d;hpb=17b759aff916b4d02721e75ce5ed82b1903e5bd6;p=linux-2.6 diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 01daee934d..c292e12410 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -27,7 +27,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) { - int i, ret; + int i, ret, count; unsigned char pending; ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); @@ -37,29 +37,37 @@ static int process_sdio_pending_irqs(struct mmc_card *card) return ret; } + count = 0; for (i = 1; i <= 7; i++) { if (pending & (1 << i)) { struct sdio_func *func = card->sdio_func[i - 1]; if (!func) { printk(KERN_WARNING "%s: pending IRQ for " "non-existant function\n", - sdio_func_id(func)); + mmc_card_id(card)); + ret = -EINVAL; } else if (func->irq_handler) { func->irq_handler(func); - } else + count++; + } else { printk(KERN_WARNING "%s: pending IRQ with no handler\n", sdio_func_id(func)); + ret = -EINVAL; + } } } - return 0; + if (count) + return count; + + return ret; } static int sdio_irq_thread(void *_host) { struct mmc_host *host = _host; struct sched_param param = { .sched_priority = 1 }; - unsigned long period; + unsigned long period, idle_period; int ret; sched_setscheduler(current, SCHED_FIFO, ¶m); @@ -70,8 +78,9 @@ static int sdio_irq_thread(void *_host) * asynchronous notification of pending SDIO card interrupts * hence we poll for them in that case. */ + idle_period = msecs_to_jiffies(10); period = (host->caps & MMC_CAP_SDIO_IRQ) ? - MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(10); + MAX_SCHEDULE_TIMEOUT : idle_period; pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", mmc_hostname(host), period); @@ -101,15 +110,30 @@ static int sdio_irq_thread(void *_host) * errors. FIXME: determine if due to card removal and * possibly exit this thread if so. */ - if (ret) + if (ret < 0) ssleep(1); - set_task_state(current, TASK_INTERRUPTIBLE); + /* + * Adaptive polling frequency based on the assumption + * that an interrupt will be closely followed by more. + * This has a substantial benefit for network devices. + */ + if (!(host->caps & MMC_CAP_SDIO_IRQ)) { + if (ret > 0) + period /= 2; + else { + period++; + if (period > idle_period) + period = idle_period; + } + } + + set_current_state(TASK_INTERRUPTIBLE); if (host->caps & MMC_CAP_SDIO_IRQ) host->ops->enable_sdio_irq(host, 1); if (!kthread_should_stop()) schedule_timeout(period); - set_task_state(current, TASK_RUNNING); + set_current_state(TASK_RUNNING); } while (!kthread_should_stop()); if (host->caps & MMC_CAP_SDIO_IRQ) @@ -125,7 +149,7 @@ static int sdio_card_irq_get(struct mmc_card *card) { struct mmc_host *host = card->host; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); if (!host->sdio_irqs++) { atomic_set(&host->sdio_irq_thread_abort, 0); @@ -145,7 +169,7 @@ static int sdio_card_irq_put(struct mmc_card *card) { struct mmc_host *host = card->host; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); BUG_ON(host->sdio_irqs < 1); if (!--host->sdio_irqs) {