drivers/net/ipa/ipa_interrupt.c

Source file repositories/reference/linux-study-clean/drivers/net/ipa/ipa_interrupt.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ipa/ipa_interrupt.c
Extension
.c
Size
9018 bytes
Lines
345
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

struct ipa_interrupt {
	struct ipa *ipa;
	u32 irq;
	u32 enabled;
	unsigned long *suspend_enabled;
};

/* Clear the suspend interrupt for all endpoints that signaled it */
static void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt)
{
	struct ipa *ipa = interrupt->ipa;
	u32 unit_count;
	u32 unit;

	unit_count = DIV_ROUND_UP(ipa->endpoint_count, 32);
	for (unit = 0; unit < unit_count; unit++) {
		const struct reg *reg;
		u32 val;

		reg = ipa_reg(ipa, IRQ_SUSPEND_INFO);
		val = ioread32(ipa->reg_virt + reg_n_offset(reg, unit));

		/* SUSPEND interrupt status isn't cleared on IPA version 3.0 */
		if (!val || ipa->version == IPA_VERSION_3_0)
			continue;

		reg = ipa_reg(ipa, IRQ_SUSPEND_CLR);
		iowrite32(val, ipa->reg_virt + reg_n_offset(reg, unit));
	}
}

/* Process a particular interrupt type that has been received */
static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id)
{
	struct ipa *ipa = interrupt->ipa;
	const struct reg *reg;
	u32 mask = BIT(irq_id);
	u32 offset;

	reg = ipa_reg(ipa, IPA_IRQ_CLR);
	offset = reg_offset(reg);

	switch (irq_id) {
	case IPA_IRQ_UC_0:
	case IPA_IRQ_UC_1:
		/* For microcontroller interrupts, clear the interrupt right
		 * away, "to avoid clearing unhandled interrupts."
		 */
		iowrite32(mask, ipa->reg_virt + offset);
		ipa_uc_interrupt_handler(ipa, irq_id);
		break;

	case IPA_IRQ_TX_SUSPEND:
		/* Clearing the SUSPEND_TX interrupt also clears the
		 * register that tells us which suspended endpoint(s)
		 * caused the interrupt, so defer clearing until after
		 * the handler has been called.
		 */
		ipa_interrupt_suspend_clear_all(interrupt);
		fallthrough;

	default:	/* Silently ignore (and clear) any other condition */
		iowrite32(mask, ipa->reg_virt + offset);
		break;
	}
}

/* IPA IRQ handler is threaded */
static irqreturn_t ipa_isr_thread(int irq, void *dev_id)
{
	struct ipa_interrupt *interrupt = dev_id;
	struct ipa *ipa = interrupt->ipa;
	u32 enabled = interrupt->enabled;
	struct device *dev = ipa->dev;
	const struct reg *reg;
	u32 pending;
	u32 offset;
	u32 mask;
	int ret;

	ret = pm_runtime_get_sync(dev);
	if (WARN_ON(ret < 0))
		goto out_power_put;

	/* The status register indicates which conditions are present,
	 * including conditions whose interrupt is not enabled.  Handle
	 * only the enabled ones.
	 */
	reg = ipa_reg(ipa, IPA_IRQ_STTS);
	offset = reg_offset(reg);

Annotation

Implementation Notes