drivers/pci/controller/dwc/pci-layerscape-ep.c

Source file repositories/reference/linux-study-clean/drivers/pci/controller/dwc/pci-layerscape-ep.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/controller/dwc/pci-layerscape-ep.c
Extension
.c
Size
7690 bytes
Lines
296
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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ls_pcie_ep_drvdata {
	u32				func_offset;
	const struct dw_pcie_ep_ops	*ops;
	const struct dw_pcie_ops	*dw_pcie_ops;
};

struct ls_pcie_ep {
	struct dw_pcie			*pci;
	struct pci_epc_features		*ls_epc;
	const struct ls_pcie_ep_drvdata *drvdata;
	int				irq;
	u32				lnkcap;
	bool				big_endian;
};

static u32 ls_pcie_pf_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
{
	struct dw_pcie *pci = pcie->pci;

	if (pcie->big_endian)
		return ioread32be(pci->dbi_base + offset);
	else
		return ioread32(pci->dbi_base + offset);
}

static void ls_pcie_pf_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
{
	struct dw_pcie *pci = pcie->pci;

	if (pcie->big_endian)
		iowrite32be(value, pci->dbi_base + offset);
	else
		iowrite32(value, pci->dbi_base + offset);
}

static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
{
	struct ls_pcie_ep *pcie = dev_id;
	struct dw_pcie *pci = pcie->pci;
	u32 val, cfg;
	u8 offset;

	val = ls_pcie_pf_lut_readl(pcie, PEX_PF0_PME_MES_DR);
	ls_pcie_pf_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);

	if (!val)
		return IRQ_NONE;

	if (val & PEX_PF0_PME_MES_DR_LUD) {

		offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);

		/*
		 * The values of the Maximum Link Width and Supported Link
		 * Speed from the Link Capabilities Register will be lost
		 * during link down or hot reset. Restore initial value
		 * that configured by the Reset Configuration Word (RCW).
		 */
		dw_pcie_dbi_ro_wr_en(pci);
		dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, pcie->lnkcap);
		dw_pcie_dbi_ro_wr_dis(pci);

		cfg = ls_pcie_pf_lut_readl(pcie, PEX_PF0_CONFIG);
		cfg |= PEX_PF0_CFG_READY;
		ls_pcie_pf_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
		dw_pcie_ep_linkup(&pci->ep);

		dev_dbg(pci->dev, "Link up\n");
	} else if (val & PEX_PF0_PME_MES_DR_LDD) {
		dev_dbg(pci->dev, "Link down\n");
		dw_pcie_ep_linkdown(&pci->ep);
	} else if (val & PEX_PF0_PME_MES_DR_HRD) {
		dev_dbg(pci->dev, "Hot reset\n");
	}

	return IRQ_HANDLED;
}

static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
				     struct platform_device *pdev)
{
	u32 val;
	int ret;

	pcie->irq = platform_get_irq_byname(pdev, "pme");
	if (pcie->irq < 0)
		return pcie->irq;

	ret = devm_request_irq(&pdev->dev, pcie->irq, ls_pcie_ep_event_handler,
			       IRQF_SHARED, pdev->name, pcie);

Annotation

Implementation Notes