drivers/irqchip/irq-mvebu-sei.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-mvebu-sei.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-mvebu-sei.c
Extension
.c
Size
12850 bytes
Lines
489
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 mvebu_sei_interrupt_range {
	u32 first;
	u32 size;
};

struct mvebu_sei_caps {
	struct mvebu_sei_interrupt_range ap_range;
	struct mvebu_sei_interrupt_range cp_range;
};

struct mvebu_sei {
	struct device *dev;
	void __iomem *base;
	struct resource *res;
	struct irq_domain *sei_domain;
	struct irq_domain *ap_domain;
	struct irq_domain *cp_domain;
	const struct mvebu_sei_caps *caps;

	/* Lock on MSI allocations/releases */
	struct mutex cp_msi_lock;
	DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_COUNT);

	/* Lock on IRQ masking register */
	raw_spinlock_t mask_lock;
};

static void mvebu_sei_ack_irq(struct irq_data *d)
{
	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
	u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);

	writel_relaxed(BIT(SEI_IRQ_REG_BIT(d->hwirq)),
		       sei->base + GICP_SECR(reg_idx));
}

static void mvebu_sei_mask_irq(struct irq_data *d)
{
	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
	u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
	unsigned long flags;

	/* 1 disables the interrupt */
	raw_spin_lock_irqsave(&sei->mask_lock, flags);
	reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx));
	reg |= BIT(SEI_IRQ_REG_BIT(d->hwirq));
	writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx));
	raw_spin_unlock_irqrestore(&sei->mask_lock, flags);
}

static void mvebu_sei_unmask_irq(struct irq_data *d)
{
	struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
	u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
	unsigned long flags;

	/* 0 enables the interrupt */
	raw_spin_lock_irqsave(&sei->mask_lock, flags);
	reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx));
	reg &= ~BIT(SEI_IRQ_REG_BIT(d->hwirq));
	writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx));
	raw_spin_unlock_irqrestore(&sei->mask_lock, flags);
}

static int mvebu_sei_set_affinity(struct irq_data *d,
				  const struct cpumask *mask_val,
				  bool force)
{
	return -EINVAL;
}

static int mvebu_sei_set_irqchip_state(struct irq_data *d,
				       enum irqchip_irq_state which,
				       bool state)
{
	/* We can only clear the pending state by acking the interrupt */
	if (which != IRQCHIP_STATE_PENDING || state)
		return -EINVAL;

	mvebu_sei_ack_irq(d);
	return 0;
}

static struct irq_chip mvebu_sei_irq_chip = {
	.name			= "SEI",
	.irq_ack		= mvebu_sei_ack_irq,
	.irq_mask		= mvebu_sei_mask_irq,
	.irq_unmask		= mvebu_sei_unmask_irq,
	.irq_set_affinity       = mvebu_sei_set_affinity,
	.irq_set_irqchip_state	= mvebu_sei_set_irqchip_state,

Annotation

Implementation Notes