drivers/irqchip/irq-brcmstb-l2.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-brcmstb-l2.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-brcmstb-l2.c
Extension
.c
Size
7611 bytes
Lines
277
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 brcmstb_intc_init_params {
	irq_flow_handler_t handler;
	int cpu_status;
	int cpu_clear;
	int cpu_mask_status;
	int cpu_mask_set;
	int cpu_mask_clear;
};

/* Register offsets in the L2 latched interrupt controller */
static const struct brcmstb_intc_init_params l2_edge_intc_init = {
	.handler		= handle_edge_irq,
	.cpu_status		= 0x00,
	.cpu_clear		= 0x08,
	.cpu_mask_status	= 0x0c,
	.cpu_mask_set		= 0x10,
	.cpu_mask_clear		= 0x14
};

/* Register offsets in the L2 level interrupt controller */
static const struct brcmstb_intc_init_params l2_lvl_intc_init = {
	.handler		= handle_level_irq,
	.cpu_status		= 0x00,
	.cpu_clear		= -1, /* Register not present */
	.cpu_mask_status	= 0x04,
	.cpu_mask_set		= 0x08,
	.cpu_mask_clear		= 0x0C
};

/* L2 intc private data structure */
struct brcmstb_l2_intc_data {
	struct irq_domain *domain;
	struct irq_chip_generic *gc;
	int status_offset;
	int mask_offset;
	bool can_wake;
	u32 saved_mask; /* for suspend/resume */
};

static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc)
{
	struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc);
	struct irq_chip *chip = irq_desc_get_chip(desc);
	unsigned int irq;
	u32 status;

	chained_irq_enter(chip, desc);

	status = irq_reg_readl(b->gc, b->status_offset) &
		~(irq_reg_readl(b->gc, b->mask_offset));

	if (status == 0) {
		raw_spin_lock(&desc->lock);
		handle_bad_irq(desc);
		raw_spin_unlock(&desc->lock);
		goto out;
	}

	do {
		irq = ffs(status) - 1;
		status &= ~(1 << irq);
		generic_handle_domain_irq(b->domain, irq);
	} while (status);
out:
	/* Don't ack parent before all device writes are done */
	wmb();

	chained_irq_exit(chip, desc);
}

static void __brcmstb_l2_intc_suspend(struct irq_data *d, bool save)
{
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
	struct irq_chip_type *ct = irq_data_get_chip_type(d);
	struct brcmstb_l2_intc_data *b = gc->private;

	guard(raw_spinlock_irqsave)(&gc->lock);
	/* Save the current mask */
	if (save)
		b->saved_mask = irq_reg_readl(gc, ct->regs.mask);

	if (b->can_wake) {
		/* Program the wakeup mask */
		irq_reg_writel(gc, ~gc->wake_active, ct->regs.disable);
		irq_reg_writel(gc, gc->wake_active, ct->regs.enable);
	}
}

static void brcmstb_l2_intc_shutdown(struct irq_data *d)
{

Annotation

Implementation Notes