对于不支持SDIO 中断的host,kerne会采用polling的方式来实现伪中断:不断的唤醒ksdioirqd来检查SDIO的CCCR的中断标志位。(支持SDIO中断的host,则直接在SDIO中断产生的时候由host的驱动来负责通知mmc子系统唤醒ksdioirqd来检查中断).
ksdioirqd的关键性代码如下。
do {
/*
* We claim the host here on drivers behalf for a couple
* reasons:
*
* 1) it is already needed to retrieve the CCCR_INTx;
* 2) we want the driver(s) to clear the IRQ condition ASAP;
* 3) we need to control the abort condition locally.
*
* Just like traditional hard IRQ handlers, we expect SDIO
* IRQ handlers to be quick and to the point, so that the
* holding of the host lock does not cover too much work
* that doesn't require that lock to be held.
*/
ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
if (ret)
break;
ret = process_sdio_pending_irqs(host->card); //检查是否有任何中断
mmc_release_host(host);
/*
* Give other threads a chance to run in the presence of
* errors.
*/
if (ret < 0) {
set_current_state(TASK_INTERRUPTIBLE);
if (!kthread_should_stop())
schedule_timeout(HZ);
set_current_state(TASK_RUNNING);
}
/*
* 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++; //这种方式很类似于高性能网卡驱动中使用的polling于int结合的方式。
if (period > idle_period) //在有中断产生的时候产生polling,一旦polling检查到没有中断就
period = idle_period;//改成中断模式(int)
}
}
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_current_state(TASK_RUNNING);
} while (!kthread_should_stop());