drivers/pci/controller/pci-xgene-msi.c
Source file repositories/reference/linux-study-clean/drivers/pci/controller/pci-xgene-msi.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pci/controller/pci-xgene-msi.c- Extension
.c- Size
- 11076 bytes
- Lines
- 400
- Domain
- Representative Device Path
- Bucket
- PCIe NVMe Storage Path
- Inferred role
- Representative Device Path: implementation source
- Status
- source implementation candidate
Why This File Exists
Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.
- Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- 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/cpu.hlinux/interrupt.hlinux/irqdomain.hlinux/module.hlinux/msi.hlinux/irqchip/chained_irq.hlinux/irqchip/irq-msi-lib.hlinux/pci.hlinux/platform_device.hlinux/of_pci.h
Detected Declarations
struct xgene_msifunction numberfunction xgene_msi_int_readfunction datafunction xgene_compose_msi_msgfunction xgene_msi_set_affinityfunction xgene_irq_domain_allocfunction xgene_irq_domain_freefunction xgene_allocate_domainsfunction xgene_msi_init_allocatorfunction xgene_msi_isrfunction for_each_set_bitfunction for_each_set_bitfunction xgene_msi_removefunction xgene_msi_handler_setupfunction xgene_msi_probe
Annotated Snippet
struct xgene_msi {
struct irq_domain *inner_domain;
u64 msi_addr;
void __iomem *msi_regs;
unsigned long *bitmap;
struct mutex bitmap_lock;
unsigned int gic_irq[NR_HW_IRQS];
};
/* Global data */
static struct xgene_msi *xgene_msi_ctrl;
/*
* X-Gene v1 has 16 frames of MSI termination registers MSInIRx, where n is
* frame number (0..15), x is index of registers in each frame (0..7). Each
* 32b register is at the beginning of a 64kB region, each frame occupying
* 512kB (and the whole thing 8MB of PA space).
*
* Each register supports 16 MSI vectors (0..15) to generate interrupts. A
* write to the MSInIRx from the PCI side generates an interrupt. A read
* from the MSInRx on the CPU side returns a bitmap of the pending MSIs in
* the lower 16 bits. A side effect of this read is that all pending
* interrupts are acknowledged and cleared).
*
* Additionally, each MSI termination frame has 1 MSIINTn register (n is
* 0..15) to indicate the MSI pending status caused by any of its 8
* termination registers, reported as a bitmap in the lower 8 bits. Each 32b
* register is at the beginning of a 64kB region (and overall occupying an
* extra 1MB).
*
* There is one GIC IRQ assigned for each MSI termination frame, 16 in
* total.
*
* The register layout is as follows:
* MSI0IR0 base_addr
* MSI0IR1 base_addr + 0x10000
* ... ...
* MSI0IR6 base_addr + 0x60000
* MSI0IR7 base_addr + 0x70000
* MSI1IR0 base_addr + 0x80000
* MSI1IR1 base_addr + 0x90000
* ... ...
* MSI1IR7 base_addr + 0xF0000
* MSI2IR0 base_addr + 0x100000
* ... ...
* MSIFIR0 base_addr + 0x780000
* MSIFIR1 base_addr + 0x790000
* ... ...
* MSIFIR7 base_addr + 0x7F0000
* MSIINT0 base_addr + 0x800000
* MSIINT1 base_addr + 0x810000
* ... ...
* MSIINTF base_addr + 0x8F0000
*/
/* MSInIRx read helper */
static u32 xgene_msi_ir_read(struct xgene_msi *msi, u32 msi_grp, u32 msir_idx)
{
return readl_relaxed(msi->msi_regs + MSI_IR0 +
(FIELD_PREP(MSI_GROUP_MASK, msi_grp) |
FIELD_PREP(MSI_INDEX_MASK, msir_idx)));
}
/* MSIINTn read helper */
static u32 xgene_msi_int_read(struct xgene_msi *msi, u32 msi_grp)
{
return readl_relaxed(msi->msi_regs + MSI_INT0 +
FIELD_PREP(MSI_INTR_MASK, msi_grp));
}
/*
* In order to allow an MSI to be moved from one CPU to another without
* having to repaint both the address and the data (which cannot be done
* atomically), we statically partitions the MSI frames between CPUs. Given
* that XGene-1 has 8 CPUs, each CPU gets two frames assigned to it
*
* We adopt the convention that when an MSI is moved, it is configured to
* target the same register number in the congruent frame assigned to the
* new target CPU. This reserves a given MSI across all CPUs, and reduces
* the MSI capacity from 2048 to 256.
*
* Effectively, this amounts to:
* - hwirq[7]::cpu[2:0] is the target frame number (n in MSInIRx)
* - hwirq[6:4] is the register index in any given frame (x in MSInIRx)
* - hwirq[3:0] is the MSI data
*/
static irq_hw_number_t compute_hwirq(u8 frame, u8 index, u8 data)
{
return (FIELD_PREP(BIT(7), FIELD_GET(BIT(3), frame)) |
FIELD_PREP(MSInRx_HWIRQ_MASK, index) |
Annotation
- Immediate include surface: `linux/bitfield.h`, `linux/cpu.h`, `linux/interrupt.h`, `linux/irqdomain.h`, `linux/module.h`, `linux/msi.h`, `linux/irqchip/chained_irq.h`, `linux/irqchip/irq-msi-lib.h`.
- Detected declarations: `struct xgene_msi`, `function number`, `function xgene_msi_int_read`, `function data`, `function xgene_compose_msi_msg`, `function xgene_msi_set_affinity`, `function xgene_irq_domain_alloc`, `function xgene_irq_domain_free`, `function xgene_allocate_domains`, `function xgene_msi_init_allocator`.
- Atlas domain: Representative Device Path / PCIe NVMe Storage Path.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
- 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.