drivers/irqchip/irq-al-fic.c
Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-al-fic.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/irqchip/irq-al-fic.c- Extension
.c- Size
- 7064 bytes
- Lines
- 279
- 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.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- 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/bitfield.hlinux/irq.hlinux/irqchip.hlinux/irqchip/chained_irq.hlinux/irqdomain.hlinux/module.hlinux/of.hlinux/of_address.hlinux/of_irq.h
Detected Declarations
struct al_ficenum al_fic_statefunction al_fic_set_triggerfunction al_fic_irq_set_typefunction al_fic_irq_handlerfunction al_fic_irq_retriggerfunction al_fic_registerfunction al_fic_wire_initfunction al_fic_init_dt
Annotated Snippet
struct al_fic {
void __iomem *base;
struct irq_domain *domain;
const char *name;
unsigned int parent_irq;
enum al_fic_state state;
};
static void al_fic_set_trigger(struct al_fic *fic,
struct irq_chip_generic *gc,
enum al_fic_state new_state)
{
irq_flow_handler_t handler;
u32 control = readl_relaxed(fic->base + AL_FIC_CONTROL);
if (new_state == AL_FIC_CONFIGURED_LEVEL) {
handler = handle_level_irq;
control &= ~CONTROL_TRIGGER_RISING;
} else {
handler = handle_edge_irq;
control |= CONTROL_TRIGGER_RISING;
}
gc->chip_types->handler = handler;
fic->state = new_state;
writel_relaxed(control, fic->base + AL_FIC_CONTROL);
}
static int al_fic_irq_set_type(struct irq_data *data, unsigned int flow_type)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
struct al_fic *fic = gc->private;
enum al_fic_state new_state;
guard(raw_spinlock)(&gc->lock);
if (((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) &&
((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)) {
pr_debug("fic doesn't support flow type %d\n", flow_type);
return -EINVAL;
}
new_state = (flow_type & IRQ_TYPE_LEVEL_HIGH) ?
AL_FIC_CONFIGURED_LEVEL : AL_FIC_CONFIGURED_RISING_EDGE;
/*
* A given FIC instance can be either all level or all edge triggered.
* This is generally fixed depending on what pieces of HW it's wired up
* to.
*
* We configure it based on the sensitivity of the first source
* being setup, and reject any subsequent attempt at configuring it in a
* different way.
*/
if (fic->state == AL_FIC_UNCONFIGURED) {
al_fic_set_trigger(fic, gc, new_state);
} else if (fic->state != new_state) {
pr_debug("fic %s state already configured to %d\n", fic->name, fic->state);
return -EINVAL;
}
return 0;
}
static void al_fic_irq_handler(struct irq_desc *desc)
{
struct al_fic *fic = irq_desc_get_handler_data(desc);
struct irq_domain *domain = fic->domain;
struct irq_chip *irqchip = irq_desc_get_chip(desc);
struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
unsigned long pending;
u32 hwirq;
chained_irq_enter(irqchip, desc);
pending = readl_relaxed(fic->base + AL_FIC_CAUSE);
pending &= ~gc->mask_cache;
for_each_set_bit(hwirq, &pending, NR_FIC_IRQS)
generic_handle_domain_irq(domain, hwirq);
chained_irq_exit(irqchip, desc);
}
static int al_fic_irq_retrigger(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
struct al_fic *fic = gc->private;
writel_relaxed(BIT(data->hwirq), fic->base + AL_FIC_SET_CAUSE);
return 1;
Annotation
- Immediate include surface: `linux/bitfield.h`, `linux/irq.h`, `linux/irqchip.h`, `linux/irqchip/chained_irq.h`, `linux/irqdomain.h`, `linux/module.h`, `linux/of.h`, `linux/of_address.h`.
- Detected declarations: `struct al_fic`, `enum al_fic_state`, `function al_fic_set_trigger`, `function al_fic_irq_set_type`, `function al_fic_irq_handler`, `function al_fic_irq_retrigger`, `function al_fic_register`, `function al_fic_wire_init`, `function al_fic_init_dt`.
- Atlas domain: Driver Families / drivers/irqchip.
- Implementation status: source implementation candidate.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
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.