drivers/pci/controller/pcie-iproc-msi.c

Source file repositories/reference/linux-study-clean/drivers/pci/controller/pcie-iproc-msi.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/controller/pcie-iproc-msi.c
Extension
.c
Size
17791 bytes
Lines
678
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: exported/initcall integration point
Status
integration 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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct iproc_msi_grp {
	struct iproc_msi *msi;
	int gic_irq;
	unsigned int eq;
};

/**
 * struct iproc_msi - iProc event queue based MSI
 *
 * Only meant to be used on platforms without MSI support integrated into the
 * GIC.
 *
 * @pcie: pointer to iProc PCIe data
 * @reg_offsets: MSI register offsets
 * @grps: MSI groups
 * @nr_irqs: number of total interrupts connected to GIC
 * @nr_cpus: number of toal CPUs
 * @has_inten_reg: indicates the MSI interrupt enable register needs to be
 * set explicitly (required for some legacy platforms)
 * @bitmap: MSI vector bitmap
 * @bitmap_lock: lock to protect access to the MSI bitmap
 * @nr_msi_vecs: total number of MSI vectors
 * @inner_domain: inner IRQ domain
 * @nr_eq_region: required number of 4K aligned memory region for MSI event
 * queues
 * @nr_msi_region: required number of 4K aligned address region for MSI posted
 * writes
 * @eq_cpu: pointer to allocated memory region for MSI event queues
 * @eq_dma: DMA address of MSI event queues
 * @msi_addr: MSI address
 */
struct iproc_msi {
	struct iproc_pcie *pcie;
	const u16 (*reg_offsets)[IPROC_MSI_REG_SIZE];
	struct iproc_msi_grp *grps;
	int nr_irqs;
	int nr_cpus;
	bool has_inten_reg;
	unsigned long *bitmap;
	struct mutex bitmap_lock;
	unsigned int nr_msi_vecs;
	struct irq_domain *inner_domain;
	unsigned int nr_eq_region;
	unsigned int nr_msi_region;
	void *eq_cpu;
	dma_addr_t eq_dma;
	phys_addr_t msi_addr;
};

static const u16 iproc_msi_reg_paxb[NR_HW_IRQS][IPROC_MSI_REG_SIZE] = {
	{ 0x200, 0x2c0, 0x204, 0x2c4, 0x210, 0x250, 0x254, 0x208 },
	{ 0x200, 0x2c0, 0x204, 0x2c4, 0x214, 0x258, 0x25c, 0x208 },
	{ 0x200, 0x2c0, 0x204, 0x2c4, 0x218, 0x260, 0x264, 0x208 },
	{ 0x200, 0x2c0, 0x204, 0x2c4, 0x21c, 0x268, 0x26c, 0x208 },
	{ 0x200, 0x2c0, 0x204, 0x2c4, 0x220, 0x270, 0x274, 0x208 },
	{ 0x200, 0x2c0, 0x204, 0x2c4, 0x224, 0x278, 0x27c, 0x208 },
};

static const u16 iproc_msi_reg_paxc[NR_HW_IRQS][IPROC_MSI_REG_SIZE] = {
	{ 0xc00, 0xc04, 0xc08, 0xc0c, 0xc40, 0xc50, 0xc60 },
	{ 0xc10, 0xc14, 0xc18, 0xc1c, 0xc44, 0xc54, 0xc64 },
	{ 0xc20, 0xc24, 0xc28, 0xc2c, 0xc48, 0xc58, 0xc68 },
	{ 0xc30, 0xc34, 0xc38, 0xc3c, 0xc4c, 0xc5c, 0xc6c },
};

static inline u32 iproc_msi_read_reg(struct iproc_msi *msi,
				     enum iproc_msi_reg reg,
				     unsigned int eq)
{
	struct iproc_pcie *pcie = msi->pcie;

	return readl_relaxed(pcie->base + msi->reg_offsets[eq][reg]);
}

static inline void iproc_msi_write_reg(struct iproc_msi *msi,
				       enum iproc_msi_reg reg,
				       int eq, u32 val)
{
	struct iproc_pcie *pcie = msi->pcie;

	writel_relaxed(val, pcie->base + msi->reg_offsets[eq][reg]);
}

static inline u32 hwirq_to_group(struct iproc_msi *msi, unsigned long hwirq)
{
	return (hwirq % msi->nr_irqs);
}

static inline unsigned int iproc_msi_addr_offset(struct iproc_msi *msi,
						 unsigned long hwirq)

Annotation

Implementation Notes