drivers/mmc/core/sdio_irq.c

Source file repositories/reference/linux-study-clean/drivers/mmc/core/sdio_irq.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/core/sdio_irq.c
Extension
.c
Size
8824 bytes
Lines
376
Domain
Driver Families
Bucket
drivers/mmc
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (pending & (1 << i)) {
			func = card->sdio_func[i - 1];
			if (!func) {
				pr_warn("%s: pending IRQ for non-existent function\n",
					mmc_card_id(card));
				ret = -EINVAL;
			} else if (func->irq_handler) {
				func->irq_handler(func);
				count++;
			} else {
				pr_warn("%s: pending IRQ with no handler\n",
					sdio_func_id(func));
				ret = -EINVAL;
			}
		}
	}

	if (count)
		return count;

	return ret;
}

static void sdio_run_irqs(struct mmc_host *host)
{
	mmc_claim_host(host);
	if (host->sdio_irqs) {
		process_sdio_pending_irqs(host);
		if (!host->sdio_irq_pending)
			host->ops->ack_sdio_irq(host);
	}
	mmc_release_host(host);
}

void sdio_irq_work(struct work_struct *work)
{
	struct mmc_host *host =
		container_of(work, struct mmc_host, sdio_irq_work);

	sdio_run_irqs(host);
}

void sdio_signal_irq(struct mmc_host *host)
{
	host->sdio_irq_pending = true;
	schedule_work(&host->sdio_irq_work);
}
EXPORT_SYMBOL_GPL(sdio_signal_irq);

static int sdio_irq_thread(void *_host)
{
	struct mmc_host *host = _host;
	unsigned long period, idle_period;
	int ret;

	sched_set_fifo_low(current);

	/*
	 * We want to allow for SDIO cards to work even on non SDIO
	 * aware hosts.  One thing that non SDIO host cannot do is
	 * 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 : idle_period;

	pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
		 mmc_hostname(host), period);

	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, NULL,
				       &host->sdio_irq_thread_abort);
		if (ret)
			break;
		ret = process_sdio_pending_irqs(host);
		mmc_release_host(host);

Annotation

Implementation Notes