drivers/irqchip/irq-bcm6345-l1.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-bcm6345-l1.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-bcm6345-l1.c
Extension
.c
Size
9246 bytes
Lines
352
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 bcm6345_l1_chip {
	raw_spinlock_t		lock;
	unsigned int		n_words;
	struct irq_domain	*domain;
	struct cpumask		cpumask;
	struct bcm6345_l1_cpu	*cpus[NR_CPUS];
};

struct bcm6345_l1_cpu {
	struct bcm6345_l1_chip	*intc;
	void __iomem		*map_base;
	unsigned int		parent_irq;
	u32			enable_cache[];
};

static inline unsigned int reg_enable(struct bcm6345_l1_chip *intc,
					   unsigned int word)
{
#ifdef __BIG_ENDIAN
	return (1 * intc->n_words - word - 1) * sizeof(u32);
#else
	return (0 * intc->n_words + word) * sizeof(u32);
#endif
}

static inline unsigned int reg_status(struct bcm6345_l1_chip *intc,
				      unsigned int word)
{
#ifdef __BIG_ENDIAN
	return (2 * intc->n_words - word - 1) * sizeof(u32);
#else
	return (1 * intc->n_words + word) * sizeof(u32);
#endif
}

static inline unsigned int cpu_for_irq(struct bcm6345_l1_chip *intc,
					struct irq_data *d)
{
	return cpumask_first_and(&intc->cpumask, irq_data_get_affinity_mask(d));
}

static void bcm6345_l1_irq_handle(struct irq_desc *desc)
{
	struct bcm6345_l1_cpu *cpu = irq_desc_get_handler_data(desc);
	struct bcm6345_l1_chip *intc = cpu->intc;
	struct irq_chip *chip = irq_desc_get_chip(desc);
	unsigned int idx;

	chained_irq_enter(chip, desc);

	for (idx = 0; idx < intc->n_words; idx++) {
		int base = idx * IRQS_PER_WORD;
		unsigned long pending;
		irq_hw_number_t hwirq;

		pending = __raw_readl(cpu->map_base + reg_status(intc, idx));
		pending &= __raw_readl(cpu->map_base + reg_enable(intc, idx));

		for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
			if (generic_handle_domain_irq(intc->domain, base + hwirq))
				spurious_interrupt();
		}
	}

	chained_irq_exit(chip, desc);
}

static inline void __bcm6345_l1_unmask(struct irq_data *d)
{
	struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d);
	u32 word = d->hwirq / IRQS_PER_WORD;
	u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
	unsigned int cpu_idx = cpu_for_irq(intc, d);

	intc->cpus[cpu_idx]->enable_cache[word] |= mask;
	__raw_writel(intc->cpus[cpu_idx]->enable_cache[word],
		intc->cpus[cpu_idx]->map_base + reg_enable(intc, word));
}

static inline void __bcm6345_l1_mask(struct irq_data *d)
{
	struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d);
	u32 word = d->hwirq / IRQS_PER_WORD;
	u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
	unsigned int cpu_idx = cpu_for_irq(intc, d);

	intc->cpus[cpu_idx]->enable_cache[word] &= ~mask;
	__raw_writel(intc->cpus[cpu_idx]->enable_cache[word],
		intc->cpus[cpu_idx]->map_base + reg_enable(intc, word));
}

Annotation

Implementation Notes