drivers/pci/controller/mobiveil/pcie-mobiveil-host.c

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

File Facts

System
Linux kernel
Corpus path
drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
Extension
.c
Size
16465 bytes
Lines
583
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

for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
				int ret;
				ret = generic_handle_domain_irq(rp->intx_domain,
								bit + 1);
				if (ret)
					dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
							    bit);

				/* clear interrupt handled */
				mobiveil_csr_writel(pcie,
						    1 << (PAB_INTX_START + bit),
						    PAB_INTP_AMBA_MISC_STAT);
			}

			shifted_status = mobiveil_csr_readl(pcie,
							    PAB_INTP_AMBA_MISC_STAT);
			shifted_status &= PAB_INTP_INTX_MASK;
			shifted_status >>= PAB_INTX_START;
		} while (shifted_status != 0);
	}

	/* read extra MSI status register */
	msi_status = readl_relaxed(pcie->apb_csr_base + MSI_STATUS_OFFSET);

	/* handle MSI interrupts */
	while (msi_status & 1) {
		msi_data = readl_relaxed(pcie->apb_csr_base + MSI_DATA_OFFSET);

		/*
		 * MSI_STATUS_OFFSET register gets updated to zero
		 * once we pop not only the MSI data but also address
		 * from MSI hardware FIFO. So keeping these following
		 * two dummy reads.
		 */
		msi_addr_lo = readl_relaxed(pcie->apb_csr_base +
					    MSI_ADDR_L_OFFSET);
		msi_addr_hi = readl_relaxed(pcie->apb_csr_base +
					    MSI_ADDR_H_OFFSET);
		dev_dbg(dev, "MSI registers, data: %08x, addr: %08x:%08x\n",
			msi_data, msi_addr_hi, msi_addr_lo);

		generic_handle_domain_irq(msi->dev_domain, msi_data);

		msi_status = readl_relaxed(pcie->apb_csr_base +
					   MSI_STATUS_OFFSET);
	}

	/* Clear the interrupt status */
	mobiveil_csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
	chained_irq_exit(chip, desc);
}

static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
{
	struct device *dev = &pcie->pdev->dev;
	struct platform_device *pdev = pcie->pdev;
	struct device_node *node = dev->of_node;
	struct mobiveil_root_port *rp = &pcie->rp;
	struct resource *res;

	/* map config resource */
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
					   "config_axi_slave");
	rp->config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
	if (IS_ERR(rp->config_axi_slave_base))
		return PTR_ERR(rp->config_axi_slave_base);
	rp->ob_io_res = res;

	/* map csr resource */
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
					   "csr_axi_slave");
	pcie->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
	if (IS_ERR(pcie->csr_axi_slave_base))
		return PTR_ERR(pcie->csr_axi_slave_base);
	pcie->pcie_reg_base = res->start;

	/* read the number of windows requested */
	if (of_property_read_u32(node, "apio-wins", &pcie->apio_wins))
		pcie->apio_wins = MAX_PIO_WINDOWS;

	if (of_property_read_u32(node, "ppio-wins", &pcie->ppio_wins))
		pcie->ppio_wins = MAX_PIO_WINDOWS;

	return 0;
}

static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
{
	phys_addr_t msg_addr = pcie->pcie_reg_base;
	struct mobiveil_msi *msi = &pcie->rp.msi;

Annotation

Implementation Notes