drivers/irqchip/irq-ompic.c

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

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-ompic.c
Extension
.c
Size
5768 bytes
Lines
210
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

#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>

#include <linux/irqchip.h>

#define OMPIC_CPUBYTES		8
#define OMPIC_CTRL(cpu)		(0x0 + (cpu * OMPIC_CPUBYTES))
#define OMPIC_STAT(cpu)		(0x4 + (cpu * OMPIC_CPUBYTES))

#define OMPIC_CTRL_IRQ_ACK	(1 << 31)
#define OMPIC_CTRL_IRQ_GEN	(1 << 30)
#define OMPIC_CTRL_DST(cpu)	(((cpu) & 0x3fff) << 16)

#define OMPIC_STAT_IRQ_PENDING	(1 << 30)

#define OMPIC_DATA(x)		((x) & 0xffff)

DEFINE_PER_CPU(unsigned long, ops);

static void __iomem *ompic_base;

static DEFINE_PER_CPU_READ_MOSTLY(int, ipi_dummy_dev);

static inline u32 ompic_readreg(void __iomem *base, loff_t offset)
{
	return ioread32be(base + offset);
}

static void ompic_writereg(void __iomem *base, loff_t offset, u32 data)
{
	iowrite32be(data, base + offset);
}

static void ompic_raise_softirq(const struct cpumask *mask,
				unsigned int ipi_msg)
{
	unsigned int dst_cpu;
	unsigned int src_cpu = smp_processor_id();

	for_each_cpu(dst_cpu, mask) {
		set_bit(ipi_msg, &per_cpu(ops, dst_cpu));

		/*
		 * On OpenRISC the atomic set_bit() call implies a memory
		 * barrier.  Otherwise we would need: smp_wmb(); paired
		 * with the read in ompic_ipi_handler.
		 */

		ompic_writereg(ompic_base, OMPIC_CTRL(src_cpu),
			       OMPIC_CTRL_IRQ_GEN |
			       OMPIC_CTRL_DST(dst_cpu) |
			       OMPIC_DATA(1));
	}
}

static irqreturn_t ompic_ipi_handler(int irq, void *dev_id)
{
	unsigned int cpu = smp_processor_id();
	unsigned long *pending_ops = &per_cpu(ops, cpu);
	unsigned long ops;

	ompic_writereg(ompic_base, OMPIC_CTRL(cpu), OMPIC_CTRL_IRQ_ACK);
	while ((ops = xchg(pending_ops, 0)) != 0) {

		/*
		 * On OpenRISC the atomic xchg() call implies a memory
		 * barrier.  Otherwise we may need an smp_rmb(); paired
		 * with the write in ompic_raise_softirq.
		 */

		do {
			unsigned long ipi_msg;

			ipi_msg = __ffs(ops);
			ops &= ~(1UL << ipi_msg);

			handle_IPI(ipi_msg);
		} while (ops);
	}

	return IRQ_HANDLED;
}

static int __init ompic_of_init(struct device_node *node,
				struct device_node *parent)

Annotation

Implementation Notes