drivers/irqchip/irq-sifive-plic.c
Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-sifive-plic.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/irqchip/irq-sifive-plic.c- Extension
.c- Size
- 22313 bytes
- Lines
- 849
- 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.
- 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.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/acpi.hlinux/cpu.hlinux/interrupt.hlinux/io.hlinux/irq.hlinux/irqchip.hlinux/irqchip/chained_irq.hlinux/irqdomain.hlinux/module.hlinux/of.hlinux/of_address.hlinux/of_irq.hlinux/platform_device.hlinux/spinlock.hlinux/syscore_ops.hasm/smp.h
Detected Declarations
struct plic_privstruct plic_handlerfunction __plic_togglefunction plic_togglefunction plic_irq_togglefunction for_each_cpufunction plic_irq_unmaskfunction plic_irq_maskfunction plic_irq_enablefunction plic_irq_disablefunction plic_irq_eoifunction plic_set_affinityfunction plic_irq_set_typefunction plic_irq_suspendfunction for_each_device_irqfunction plic_irq_resumefunction for_each_device_irqfunction for_each_present_cpufunction plic_irqdomain_mapfunction plic_irq_domain_translatefunction plic_irq_domain_allocfunction plic_handle_irqfunction cp100_isolate_pending_irqfunction cp100_get_hwirqfunction plic_handle_irq_cp100function plic_set_thresholdfunction plic_dying_cpufunction plic_starting_cpufunction plic_parse_nr_irqs_and_contextsfunction plic_parse_context_parentfunction plic_probefunction for_each_device_irqfunction for_each_online_cpufunction plic_platform_probefunction plic_early_probe
Annotated Snippet
struct plic_priv {
struct fwnode_handle *fwnode;
struct cpumask lmask;
struct irq_domain *irqdomain;
void __iomem *regs;
unsigned long plic_quirks;
/* device interrupts + 1 to compensate for the reserved hwirq 0 */
unsigned int __private total_irqs;
unsigned int irq_groups;
unsigned long *prio_save;
u32 gsi_base;
int acpi_plic_id;
};
struct plic_handler {
bool present;
void __iomem *hart_base;
/*
* Protect mask operations on the registers given that we can't
* assume atomic memory operations work on them.
*/
raw_spinlock_t enable_lock;
void __iomem *enable_base;
u32 *enable_save;
struct plic_priv *priv;
};
/*
* Macro to deal with the insanity of hardware interrupt 0 being reserved */
#define for_each_device_irq(iter, priv) \
for (unsigned int iter = 1; iter < ACCESS_PRIVATE(priv, total_irqs); iter++)
static int plic_parent_irq __ro_after_init;
static bool plic_global_setup_done __ro_after_init;
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
static int plic_irq_set_type(struct irq_data *d, unsigned int type);
static void __plic_toggle(struct plic_handler *handler, int hwirq, int enable)
{
u32 __iomem *base = handler->enable_base;
u32 hwirq_mask = 1 << (hwirq % 32);
int group = hwirq / 32;
u32 value;
value = readl(base + group);
if (enable)
value |= hwirq_mask;
else
value &= ~hwirq_mask;
handler->enable_save[group] = value;
writel(value, base + group);
}
static void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
{
unsigned long flags;
raw_spin_lock_irqsave(&handler->enable_lock, flags);
__plic_toggle(handler, hwirq, enable);
raw_spin_unlock_irqrestore(&handler->enable_lock, flags);
}
static inline void plic_irq_toggle(const struct cpumask *mask,
struct irq_data *d, int enable)
{
int cpu;
for_each_cpu(cpu, mask) {
struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
plic_toggle(handler, d->hwirq, enable);
}
}
static void plic_irq_unmask(struct irq_data *d)
{
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
}
static void plic_irq_mask(struct irq_data *d)
{
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
writel(0, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
}
Annotation
- Immediate include surface: `linux/acpi.h`, `linux/cpu.h`, `linux/interrupt.h`, `linux/io.h`, `linux/irq.h`, `linux/irqchip.h`, `linux/irqchip/chained_irq.h`, `linux/irqdomain.h`.
- Detected declarations: `struct plic_priv`, `struct plic_handler`, `function __plic_toggle`, `function plic_toggle`, `function plic_irq_toggle`, `function for_each_cpu`, `function plic_irq_unmask`, `function plic_irq_mask`, `function plic_irq_enable`, `function plic_irq_disable`.
- Atlas domain: Driver Families / drivers/irqchip.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.