drivers/pci/controller/dwc/pcie-designware-host.c

Source file repositories/reference/linux-study-clean/drivers/pci/controller/dwc/pcie-designware-host.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/controller/dwc/pcie-designware-host.c
Extension
.c
Size
34839 bytes
Lines
1328
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

static void dw_irq_noop(struct irq_data *d) { }
#endif

static bool dw_pcie_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
				      struct irq_domain *real_parent, struct msi_domain_info *info)
{
	if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
		return false;

#ifdef CONFIG_SMP
	info->chip->irq_ack = dw_irq_noop;
	info->chip->irq_pre_redirect = irq_chip_pre_redirect_parent;
#else
	info->chip->irq_ack = irq_chip_ack_parent;
#endif
	return true;
}

#define DW_PCIE_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS		| \
				    MSI_FLAG_USE_DEF_CHIP_OPS		| \
				    MSI_FLAG_PCI_MSI_MASK_PARENT)
#define DW_PCIE_MSI_FLAGS_SUPPORTED (MSI_FLAG_MULTI_PCI_MSI		| \
				     MSI_FLAG_PCI_MSIX			| \
				     MSI_GENERIC_FLAGS_MASK)

#define IS_256MB_ALIGNED(x) IS_ALIGNED(x, SZ_256M)

static const struct msi_parent_ops dw_pcie_msi_parent_ops = {
	.required_flags		= DW_PCIE_MSI_FLAGS_REQUIRED,
	.supported_flags	= DW_PCIE_MSI_FLAGS_SUPPORTED,
	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
	.prefix			= "DW-",
	.init_dev_msi_info	= dw_pcie_init_dev_msi_info,
};

/* MSI int handler */
void dw_handle_msi_irq(struct dw_pcie_rp *pp)
{
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	unsigned int i, num_ctrls;

	num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;

	for (i = 0; i < num_ctrls; i++) {
		unsigned int reg_off = i * MSI_REG_CTRL_BLOCK_SIZE;
		unsigned int irq_off = i * MAX_MSI_IRQS_PER_CTRL;
		unsigned long status, pos;

		status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS + reg_off);
		if (!status)
			continue;

		for_each_set_bit(pos, &status, MAX_MSI_IRQS_PER_CTRL)
			generic_handle_demux_domain_irq(pp->irq_domain, irq_off + pos);
	}
}

/* Chained MSI interrupt service routine */
static void dw_chained_msi_isr(struct irq_desc *desc)
{
	struct irq_chip *chip = irq_desc_get_chip(desc);
	struct dw_pcie_rp *pp;

	chained_irq_enter(chip, desc);

	pp = irq_desc_get_handler_data(desc);
	dw_handle_msi_irq(pp);

	chained_irq_exit(chip, desc);
}

static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
	struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	u64 msi_target = (u64)pp->msi_data;

	msg->address_lo = lower_32_bits(msi_target);
	msg->address_hi = upper_32_bits(msi_target);
	msg->data = d->hwirq;

	dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
		(int)d->hwirq, msg->address_hi, msg->address_lo);
}

static void dw_pci_bottom_mask(struct irq_data *d)
{
	struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	unsigned int res, bit, ctrl;

Annotation

Implementation Notes