drivers/irqchip/irq-dw-apb-ictl.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-dw-apb-ictl.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-dw-apb-ictl.c
Extension
.c
Size
5906 bytes
Lines
218
Domain
Driver Families
Bucket
drivers/irqchip
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

while (stat) {
			u32 hwirq = ffs(stat) - 1;

			generic_handle_domain_irq(d, hwirq);
			stat &= ~BIT(hwirq);
		}
	}
}

static void dw_apb_ictl_handle_irq_cascaded(struct irq_desc *desc)
{
	struct irq_domain *d = irq_desc_get_handler_data(desc);
	struct irq_chip *chip = irq_desc_get_chip(desc);
	int n;

	chained_irq_enter(chip, desc);

	for (n = 0; n < d->revmap_size; n += 32) {
		struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, n);
		u32 stat = readl_relaxed(gc->reg_base + APB_INT_FINALSTATUS_L);

		while (stat) {
			u32 hwirq = ffs(stat) - 1;
			generic_handle_domain_irq(d, gc->irq_base + hwirq);

			stat &= ~BIT(hwirq);
		}
	}

	chained_irq_exit(chip, desc);
}

static int dw_apb_ictl_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
				unsigned int nr_irqs, void *arg)
{
	int i, ret;
	irq_hw_number_t hwirq;
	unsigned int type = IRQ_TYPE_NONE;
	struct irq_fwspec *fwspec = arg;

	ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
	if (ret)
		return ret;

	for (i = 0; i < nr_irqs; i++)
		irq_map_generic_chip(domain, virq + i, hwirq + i);

	return 0;
}

static const struct irq_domain_ops dw_apb_ictl_irq_domain_ops = {
	.translate = irq_domain_translate_onecell,
	.alloc = dw_apb_ictl_irq_domain_alloc,
	.free = irq_domain_free_irqs_top,
};

#ifdef CONFIG_PM
static void dw_apb_ictl_resume(struct irq_data *d)
{
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
	struct irq_chip_type *ct = irq_data_get_chip_type(d);

	guard(raw_spinlock)(&gc->lock);
	writel_relaxed(~0, gc->reg_base + ct->regs.enable);
	writel_relaxed(*ct->mask_cache, gc->reg_base + ct->regs.mask);
}
#else
#define dw_apb_ictl_resume	NULL
#endif /* CONFIG_PM */

static int __init dw_apb_ictl_init(struct device_node *np,
				   struct device_node *parent)
{
	const struct irq_domain_ops *domain_ops;
	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
	struct resource r;
	struct irq_domain *domain;
	struct irq_chip_generic *gc;
	void __iomem *iobase;
	int ret, nrirqs, parent_irq, i;
	u32 reg;

	if (!parent) {
		/* Used as the primary interrupt controller */
		parent_irq = 0;
		domain_ops = &dw_apb_ictl_irq_domain_ops;
	} else {
		/* Map the parent interrupt for the chained handler */
		parent_irq = irq_of_parse_and_map(np, 0);
		if (parent_irq <= 0) {

Annotation

Implementation Notes