Skip to content

Commit 2fd60a2

Browse files
Mani-Sadhasivambjorn-helgaas
authored andcommitted
PCI: qcom: Parse PERST# from all PCIe bridge nodes
Devicetree schema allows the PERST# GPIO to be present in all PCIe bridge nodes, not just in Root Port node. But the current logic parses PERST# only from the Root Port nodes. Though it is not causing any issue on the current platforms, the upcoming platforms will have PERST# in PCIe switch downstream ports also. So this requires parsing all the PCIe bridge nodes for the PERST# GPIO. Hence, rework the parsing logic to extend to all PCIe bridge nodes starting from the Root Port node. If the 'reset-gpios' property is found for a PCI bridge node, the GPIO descriptor will be stored in qcom_pcie_perst::desc and added to the qcom_pcie_port::perst list. It should be noted that if more than one bridge node has the same GPIO for PERST# (shared PERST#), the driver will error out. This is due to the limitation in the GPIOLIB subsystem that allows only exclusive (non-shared) access to GPIOs from consumers. But this is soon going to get fixed. Once that happens, it will get incorporated in this driver. So for now, PERST# sharing is not supported. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://patch.msgid.link/20251216-pci-pwrctrl-rework-v2-1-745a563b9be6@oss.qualcomm.com
1 parent 8f0b4cc commit 2fd60a2

1 file changed

Lines changed: 85 additions & 17 deletions

File tree

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

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,15 @@ struct qcom_pcie_cfg {
267267
bool no_l0s;
268268
};
269269

270+
struct qcom_pcie_perst {
271+
struct list_head list;
272+
struct gpio_desc *desc;
273+
};
274+
270275
struct qcom_pcie_port {
271276
struct list_head list;
272-
struct gpio_desc *reset;
273277
struct phy *phy;
278+
struct list_head perst;
274279
};
275280

276281
struct qcom_pcie {
@@ -291,11 +296,14 @@ struct qcom_pcie {
291296

292297
static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert)
293298
{
299+
struct qcom_pcie_perst *perst;
294300
struct qcom_pcie_port *port;
295301
int val = assert ? 1 : 0;
296302

297-
list_for_each_entry(port, &pcie->ports, list)
298-
gpiod_set_value_cansleep(port->reset, val);
303+
list_for_each_entry(port, &pcie->ports, list) {
304+
list_for_each_entry(perst, &port->perst, list)
305+
gpiod_set_value_cansleep(perst->desc, val);
306+
}
299307

300308
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
301309
}
@@ -1702,18 +1710,58 @@ static const struct pci_ecam_ops pci_qcom_ecam_ops = {
17021710
}
17031711
};
17041712

1705-
static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node)
1713+
/* Parse PERST# from all nodes in depth first manner starting from @np */
1714+
static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
1715+
struct qcom_pcie_port *port,
1716+
struct device_node *np)
17061717
{
17071718
struct device *dev = pcie->pci->dev;
1708-
struct qcom_pcie_port *port;
1719+
struct qcom_pcie_perst *perst;
17091720
struct gpio_desc *reset;
1710-
struct phy *phy;
17111721
int ret;
17121722

1713-
reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node),
1714-
"reset", GPIOD_OUT_HIGH, "PERST#");
1715-
if (IS_ERR(reset))
1723+
if (!of_find_property(np, "reset-gpios", NULL))
1724+
goto parse_child_node;
1725+
1726+
reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(np), "reset",
1727+
GPIOD_OUT_HIGH, "PERST#");
1728+
if (IS_ERR(reset)) {
1729+
/*
1730+
* FIXME: GPIOLIB currently supports exclusive GPIO access only.
1731+
* Non exclusive access is broken. But shared PERST# requires
1732+
* non-exclusive access. So once GPIOLIB properly supports it,
1733+
* implement it here.
1734+
*/
1735+
if (PTR_ERR(reset) == -EBUSY)
1736+
dev_err(dev, "Shared PERST# is not supported\n");
1737+
17161738
return PTR_ERR(reset);
1739+
}
1740+
1741+
perst = devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL);
1742+
if (!perst)
1743+
return -ENOMEM;
1744+
1745+
INIT_LIST_HEAD(&perst->list);
1746+
perst->desc = reset;
1747+
list_add_tail(&perst->list, &port->perst);
1748+
1749+
parse_child_node:
1750+
for_each_available_child_of_node_scoped(np, child) {
1751+
ret = qcom_pcie_parse_perst(pcie, port, child);
1752+
if (ret)
1753+
return ret;
1754+
}
1755+
1756+
return 0;
1757+
}
1758+
1759+
static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node)
1760+
{
1761+
struct device *dev = pcie->pci->dev;
1762+
struct qcom_pcie_port *port;
1763+
struct phy *phy;
1764+
int ret;
17171765

17181766
phy = devm_of_phy_get(dev, node, NULL);
17191767
if (IS_ERR(phy))
@@ -1727,7 +1775,12 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node
17271775
if (ret)
17281776
return ret;
17291777

1730-
port->reset = reset;
1778+
INIT_LIST_HEAD(&port->perst);
1779+
1780+
ret = qcom_pcie_parse_perst(pcie, port, node);
1781+
if (ret)
1782+
return ret;
1783+
17311784
port->phy = phy;
17321785
INIT_LIST_HEAD(&port->list);
17331786
list_add_tail(&port->list, &pcie->ports);
@@ -1737,9 +1790,10 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node
17371790

17381791
static int qcom_pcie_parse_ports(struct qcom_pcie *pcie)
17391792
{
1793+
struct qcom_pcie_perst *perst, *tmp_perst;
1794+
struct qcom_pcie_port *port, *tmp_port;
17401795
struct device *dev = pcie->pci->dev;
1741-
struct qcom_pcie_port *port, *tmp;
1742-
int ret = -ENOENT;
1796+
int ret = -ENODEV;
17431797

17441798
for_each_available_child_of_node_scoped(dev->of_node, of_port) {
17451799
if (!of_node_is_type(of_port, "pci"))
@@ -1752,7 +1806,9 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pcie)
17521806
return ret;
17531807

17541808
err_port_del:
1755-
list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
1809+
list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) {
1810+
list_for_each_entry_safe(perst, tmp_perst, &port->perst, list)
1811+
list_del(&perst->list);
17561812
phy_exit(port->phy);
17571813
list_del(&port->list);
17581814
}
@@ -1763,6 +1819,7 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pcie)
17631819
static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie)
17641820
{
17651821
struct device *dev = pcie->pci->dev;
1822+
struct qcom_pcie_perst *perst;
17661823
struct qcom_pcie_port *port;
17671824
struct gpio_desc *reset;
17681825
struct phy *phy;
@@ -1784,19 +1841,28 @@ static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie)
17841841
if (!port)
17851842
return -ENOMEM;
17861843

1787-
port->reset = reset;
1844+
perst = devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL);
1845+
if (!perst)
1846+
return -ENOMEM;
1847+
17881848
port->phy = phy;
17891849
INIT_LIST_HEAD(&port->list);
17901850
list_add_tail(&port->list, &pcie->ports);
17911851

1852+
perst->desc = reset;
1853+
INIT_LIST_HEAD(&port->perst);
1854+
INIT_LIST_HEAD(&perst->list);
1855+
list_add_tail(&perst->list, &port->perst);
1856+
17921857
return 0;
17931858
}
17941859

17951860
static int qcom_pcie_probe(struct platform_device *pdev)
17961861
{
1862+
struct qcom_pcie_perst *perst, *tmp_perst;
1863+
struct qcom_pcie_port *port, *tmp_port;
17971864
const struct qcom_pcie_cfg *pcie_cfg;
17981865
unsigned long max_freq = ULONG_MAX;
1799-
struct qcom_pcie_port *port, *tmp;
18001866
struct device *dev = &pdev->dev;
18011867
struct dev_pm_opp *opp;
18021868
struct qcom_pcie *pcie;
@@ -1937,7 +2003,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
19372003

19382004
ret = qcom_pcie_parse_ports(pcie);
19392005
if (ret) {
1940-
if (ret != -ENOENT) {
2006+
if (ret != -ENODEV) {
19412007
dev_err_probe(pci->dev, ret,
19422008
"Failed to parse Root Port: %d\n", ret);
19432009
goto err_pm_runtime_put;
@@ -1996,7 +2062,9 @@ static int qcom_pcie_probe(struct platform_device *pdev)
19962062
err_host_deinit:
19972063
dw_pcie_host_deinit(pp);
19982064
err_phy_exit:
1999-
list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
2065+
list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) {
2066+
list_for_each_entry_safe(perst, tmp_perst, &port->perst, list)
2067+
list_del(&perst->list);
20002068
phy_exit(port->phy);
20012069
list_del(&port->list);
20022070
}

0 commit comments

Comments
 (0)