drivers/irqchip/irq-armada-370-xp.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-armada-370-xp.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-armada-370-xp.c
Extension
.c
Size
25031 bytes
Lines
918
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 mpic {
	void __iomem *base;
	void __iomem *per_cpu;
	int parent_irq;
	struct irq_domain *domain;
#ifdef CONFIG_SMP
	struct irq_domain *ipi_domain;
#endif
#ifdef CONFIG_PCI_MSI
	struct irq_domain *msi_inner_domain;
	DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR);
	struct mutex msi_lock;
	phys_addr_t msi_doorbell_addr;
	u32 msi_doorbell_mask;
	unsigned int msi_doorbell_start, msi_doorbell_size;
#endif
	u32 doorbell_mask;
};

static struct mpic *mpic_data __ro_after_init;

static inline bool mpic_is_ipi_available(struct mpic *mpic)
{
	/*
	 * We distinguish IPI availability in the IC by the IC not having a
	 * parent irq defined. If a parent irq is defined, there is a parent
	 * interrupt controller (e.g. GIC) that takes care of inter-processor
	 * interrupts.
	 */
	return mpic->parent_irq <= 0;
}

static inline bool mpic_is_percpu_irq(irq_hw_number_t hwirq)
{
	return hwirq < MPIC_PER_CPU_IRQS_NR;
}

/*
 * In SMP mode:
 * For shared global interrupts, mask/unmask global enable bit
 * For CPU interrupts, mask/unmask the calling CPU's bit
 */
static void mpic_irq_mask(struct irq_data *d)
{
	struct mpic *mpic = irq_data_get_irq_chip_data(d);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);

	if (!mpic_is_percpu_irq(hwirq))
		writel(hwirq, mpic->base + MPIC_INT_CLEAR_ENABLE);
	else
		writel(hwirq, mpic->per_cpu + MPIC_INT_SET_MASK);
}

static void mpic_irq_unmask(struct irq_data *d)
{
	struct mpic *mpic = irq_data_get_irq_chip_data(d);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);

	if (!mpic_is_percpu_irq(hwirq))
		writel(hwirq, mpic->base + MPIC_INT_SET_ENABLE);
	else
		writel(hwirq, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
}

#ifdef CONFIG_PCI_MSI

static void mpic_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
	unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
	struct mpic *mpic = irq_data_get_irq_chip_data(d);

	msg->address_lo = lower_32_bits(mpic->msi_doorbell_addr);
	msg->address_hi = upper_32_bits(mpic->msi_doorbell_addr);
	msg->data = BIT(cpu + 8) | (d->hwirq + mpic->msi_doorbell_start);
}

static int mpic_msi_set_affinity(struct irq_data *d, const struct cpumask *mask, bool force)
{
	unsigned int cpu;

	if (!force)
		cpu = cpumask_any_and(mask, cpu_online_mask);
	else
		cpu = cpumask_first(mask);

	if (cpu >= nr_cpu_ids)
		return -EINVAL;

	irq_data_update_effective_affinity(d, cpumask_of(cpu));

Annotation

Implementation Notes