drivers/irqchip/irq-gic-v5-iwb.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-gic-v5-iwb.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-gic-v5-iwb.c
Extension
.c
Size
7389 bytes
Lines
299
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 gicv5_iwb_chip_data {
	void __iomem	*iwb_base;
	u16		nr_regs;
};

static u32 iwb_readl_relaxed(struct gicv5_iwb_chip_data *iwb_node, const u32 reg_offset)
{
	return readl_relaxed(iwb_node->iwb_base + reg_offset);
}

static void iwb_writel_relaxed(struct gicv5_iwb_chip_data *iwb_node, const u32 val,
			       const u32 reg_offset)
{
	writel_relaxed(val, iwb_node->iwb_base + reg_offset);
}

static int gicv5_iwb_wait_for_wenabler(struct gicv5_iwb_chip_data *iwb_node)
{
	return gicv5_wait_for_op_atomic(iwb_node->iwb_base, GICV5_IWB_WENABLE_STATUSR,
					GICV5_IWB_WENABLE_STATUSR_IDLE, NULL);
}

static int __gicv5_iwb_set_wire_enable(struct gicv5_iwb_chip_data *iwb_node,
				       u32 iwb_wire, bool enable)
{
	u32 n = iwb_wire / 32;
	u8 i = iwb_wire % 32;
	u32 val;

	if (n >= iwb_node->nr_regs) {
		pr_err("IWB_WENABLER<n> is invalid for n=%u\n", n);
		return -EINVAL;
	}

	/*
	 * Enable IWB wire/pin at this point
	 * Note: This is not the same as enabling the interrupt
	 */
	val = iwb_readl_relaxed(iwb_node, GICV5_IWB_WENABLER + (4 * n));
	if (enable)
		val |= BIT(i);
	else
		val &= ~BIT(i);
	iwb_writel_relaxed(iwb_node, val, GICV5_IWB_WENABLER + (4 * n));

	return gicv5_iwb_wait_for_wenabler(iwb_node);
}

static int gicv5_iwb_enable_wire(struct gicv5_iwb_chip_data *iwb_node,
				 u32 iwb_wire)
{
	return __gicv5_iwb_set_wire_enable(iwb_node, iwb_wire, true);
}

static int gicv5_iwb_disable_wire(struct gicv5_iwb_chip_data *iwb_node,
				  u32 iwb_wire)
{
	return __gicv5_iwb_set_wire_enable(iwb_node, iwb_wire, false);
}

static void gicv5_iwb_irq_disable(struct irq_data *d)
{
	struct gicv5_iwb_chip_data *iwb_node = irq_data_get_irq_chip_data(d);

	gicv5_iwb_disable_wire(iwb_node, d->hwirq);
	irq_chip_disable_parent(d);
}

static void gicv5_iwb_irq_enable(struct irq_data *d)
{
	struct gicv5_iwb_chip_data *iwb_node = irq_data_get_irq_chip_data(d);

	gicv5_iwb_enable_wire(iwb_node, d->hwirq);
	irq_chip_enable_parent(d);
}

static int gicv5_iwb_set_type(struct irq_data *d, unsigned int type)
{
	struct gicv5_iwb_chip_data *iwb_node = irq_data_get_irq_chip_data(d);
	u32 iwb_wire, n, wtmr;
	u8 i;

	iwb_wire = d->hwirq;
	i = iwb_wire % 32;
	n = iwb_wire / 32;

	if (n >= iwb_node->nr_regs) {
		pr_err_once("reg %u out of range\n", n);
		return -EINVAL;
	}

Annotation

Implementation Notes