drivers/irqchip/irq-bcm2712-mip.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-bcm2712-mip.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-bcm2712-mip.c
Extension
.c
Size
7251 bytes
Lines
289
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

struct mip_priv {
	spinlock_t		lock;
	void __iomem		*base;
	u64			msg_addr;
	u32			msi_base;
	u32			num_msis;
	u32			msi_offset;
	unsigned long		*bitmap;
	struct irq_domain	*parent;
	struct device		*dev;
};

static void mip_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
	struct mip_priv *mip = irq_data_get_irq_chip_data(d);

	msg->address_hi = upper_32_bits(mip->msg_addr);
	msg->address_lo = lower_32_bits(mip->msg_addr);
	msg->data = d->hwirq;
}

static struct irq_chip mip_middle_irq_chip = {
	.name			= "MIP",
	.irq_mask		= irq_chip_mask_parent,
	.irq_unmask		= irq_chip_unmask_parent,
	.irq_eoi		= irq_chip_eoi_parent,
	.irq_set_affinity	= irq_chip_set_affinity_parent,
	.irq_set_type		= irq_chip_set_type_parent,
	.irq_compose_msi_msg	= mip_compose_msi_msg,
};

static int mip_alloc_hwirq(struct mip_priv *mip, unsigned int nr_irqs)
{
	guard(spinlock)(&mip->lock);
	return bitmap_find_free_region(mip->bitmap, mip->num_msis, ilog2(nr_irqs));
}

static void mip_free_hwirq(struct mip_priv *mip, unsigned int hwirq,
			   unsigned int nr_irqs)
{
	guard(spinlock)(&mip->lock);
	bitmap_release_region(mip->bitmap, hwirq, ilog2(nr_irqs));
}

static int mip_middle_domain_alloc(struct irq_domain *domain, unsigned int virq,
				   unsigned int nr_irqs, void *arg)
{
	struct mip_priv *mip = domain->host_data;
	struct irq_fwspec fwspec = {0};
	unsigned int hwirq, i;
	struct irq_data *irqd;
	int irq, ret;

	irq = mip_alloc_hwirq(mip, nr_irqs);
	if (irq < 0)
		return irq;

	hwirq = irq + mip->msi_offset;

	fwspec.fwnode = domain->parent->fwnode;
	fwspec.param_count = 3;
	fwspec.param[0] = 0;
	fwspec.param[1] = hwirq + mip->msi_base;
	fwspec.param[2] = IRQ_TYPE_EDGE_RISING;

	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &fwspec);
	if (ret)
		goto err_free_hwirq;

	for (i = 0; i < nr_irqs; i++) {
		irqd = irq_domain_get_irq_data(domain->parent, virq + i);
		irqd->chip->irq_set_type(irqd, IRQ_TYPE_EDGE_RISING);

		ret = irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
						    &mip_middle_irq_chip, mip);
		if (ret)
			goto err_free;

		irqd = irq_get_irq_data(virq + i);
		irqd_set_single_target(irqd);
		irqd_set_affinity_on_activate(irqd);
	}

	return 0;

err_free:
	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
err_free_hwirq:
	mip_free_hwirq(mip, irq, nr_irqs);
	return ret;

Annotation

Implementation Notes