Skip to content

Commit 4581403

Browse files
Mani-Sadhasivamkwilczynski
authored andcommitted
PCI: qcom: Enumerate endpoints based on Link up event in 'global_irq' interrupt
Historically, Qcom PCIe RC controllers lacked standard hotplug support. So when an endpoint is attached to the SoC, users have to rescan the bus manually to enumerate the device. But this can be avoided by using the Link up event exposed by the Qcom specific 'global_irq' interrupt. Qcom PCIe RC controllers are capable of generating the 'global' SPI interrupt to the host CPUs. The device driver can use this interrupt to identify events such as PCIe link specific events, safety events etc... One such event is the PCIe Link up event generated when an endpoint is detected on the bus and the Link is 'up'. This event can be used to enumerate the PCIe endpoint devices without user intervention. So add support for capturing the PCIe Link up event using the 'global' interrupt in the driver. Once the Link up event is received, the bus underneath the host bridge is scanned to enumerate PCIe endpoint devices. All of the Qcom SoCs have only one Root Port per controller instance. So only a single 'Link up' event is generated for the PCIe controller. Link: https://lore.kernel.org/linux-pci/[email protected] Signed-off-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: Krzysztof Wilczyński <[email protected]> Reviewed-by: Konrad Dybcio <[email protected]>
1 parent 6efd853 commit 4581403

File tree

1 file changed

+54
-1
lines changed

1 file changed

+54
-1
lines changed

drivers/pci/controller/dwc/pcie-qcom.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
#define PARF_AXI_MSTR_WR_ADDR_HALT_V2 0x1a8
5151
#define PARF_Q2A_FLUSH 0x1ac
5252
#define PARF_LTSSM 0x1b0
53+
#define PARF_INT_ALL_STATUS 0x224
54+
#define PARF_INT_ALL_CLEAR 0x228
55+
#define PARF_INT_ALL_MASK 0x22c
5356
#define PARF_SID_OFFSET 0x234
5457
#define PARF_BDF_TRANSLATE_CFG 0x24c
5558
#define PARF_SLV_ADDR_SPACE_SIZE 0x358
@@ -121,6 +124,9 @@
121124
/* PARF_LTSSM register fields */
122125
#define LTSSM_EN BIT(8)
123126

127+
/* PARF_INT_ALL_{STATUS/CLEAR/MASK} register fields */
128+
#define PARF_INT_ALL_LINK_UP BIT(13)
129+
124130
/* PARF_NO_SNOOP_OVERIDE register fields */
125131
#define WR_NO_SNOOP_OVERIDE_EN BIT(1)
126132
#define RD_NO_SNOOP_OVERIDE_EN BIT(3)
@@ -1488,6 +1494,29 @@ static void qcom_pcie_init_debugfs(struct qcom_pcie *pcie)
14881494
qcom_pcie_link_transition_count);
14891495
}
14901496

1497+
static irqreturn_t qcom_pcie_global_irq_thread(int irq, void *data)
1498+
{
1499+
struct qcom_pcie *pcie = data;
1500+
struct dw_pcie_rp *pp = &pcie->pci->pp;
1501+
struct device *dev = pcie->pci->dev;
1502+
u32 status = readl_relaxed(pcie->parf + PARF_INT_ALL_STATUS);
1503+
1504+
writel_relaxed(status, pcie->parf + PARF_INT_ALL_CLEAR);
1505+
1506+
if (FIELD_GET(PARF_INT_ALL_LINK_UP, status)) {
1507+
dev_dbg(dev, "Received Link up event. Starting enumeration!\n");
1508+
/* Rescan the bus to enumerate endpoint devices */
1509+
pci_lock_rescan_remove();
1510+
pci_rescan_bus(pp->bridge->bus);
1511+
pci_unlock_rescan_remove();
1512+
} else {
1513+
dev_WARN_ONCE(dev, 1, "Received unknown event. INT_STATUS: 0x%08x\n",
1514+
status);
1515+
}
1516+
1517+
return IRQ_HANDLED;
1518+
}
1519+
14911520
static int qcom_pcie_probe(struct platform_device *pdev)
14921521
{
14931522
const struct qcom_pcie_cfg *pcie_cfg;
@@ -1498,7 +1527,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
14981527
struct dw_pcie_rp *pp;
14991528
struct resource *res;
15001529
struct dw_pcie *pci;
1501-
int ret;
1530+
int ret, irq;
1531+
char *name;
15021532

15031533
pcie_cfg = of_device_get_match_data(dev);
15041534
if (!pcie_cfg || !pcie_cfg->ops) {
@@ -1617,13 +1647,36 @@ static int qcom_pcie_probe(struct platform_device *pdev)
16171647
goto err_phy_exit;
16181648
}
16191649

1650+
name = devm_kasprintf(dev, GFP_KERNEL, "qcom_pcie_global_irq%d",
1651+
pci_domain_nr(pp->bridge->bus));
1652+
if (!name) {
1653+
ret = -ENOMEM;
1654+
goto err_host_deinit;
1655+
}
1656+
1657+
irq = platform_get_irq_byname_optional(pdev, "global");
1658+
if (irq > 0) {
1659+
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
1660+
qcom_pcie_global_irq_thread,
1661+
IRQF_ONESHOT, name, pcie);
1662+
if (ret) {
1663+
dev_err_probe(&pdev->dev, ret,
1664+
"Failed to request Global IRQ\n");
1665+
goto err_host_deinit;
1666+
}
1667+
1668+
writel_relaxed(PARF_INT_ALL_LINK_UP, pcie->parf + PARF_INT_ALL_MASK);
1669+
}
1670+
16201671
qcom_pcie_icc_opp_update(pcie);
16211672

16221673
if (pcie->mhi)
16231674
qcom_pcie_init_debugfs(pcie);
16241675

16251676
return 0;
16261677

1678+
err_host_deinit:
1679+
dw_pcie_host_deinit(pp);
16271680
err_phy_exit:
16281681
phy_exit(pcie->phy);
16291682
err_pm_runtime_put:

0 commit comments

Comments
 (0)