2018-05-23 10:48:21

by Srinivas Kandagatla

[permalink] [raw]
Subject: [PATCH v2] PCI: qcom: add runtime pm support to pcie_port

This patch is required when the pcie controller sits on a bus with
its own power domain and clocks which are controlled via a bus driver
like simple pm bus. As these bus driver have runtime pm enabled, it makes
sense to update the usage counter so that the runtime pm does not suspend
the clks or power domain associated with the bus driver.

Signed-off-by: Srinivas Kandagatla <[email protected]>
Signed-off-by: Bjorn Andersson <[email protected]>
---
drivers/pci/dwc/pcie-qcom.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c
index 5897af7d3355..d6ed5aeeae9c 100644
--- a/drivers/pci/dwc/pcie-qcom.c
+++ b/drivers/pci/dwc/pcie-qcom.c
@@ -19,6 +19,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pci.h>
+#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/regulator/consumer.h>
@@ -1088,6 +1089,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
struct qcom_pcie *pcie = to_qcom_pcie(pci);
int ret;

+ pm_runtime_get_sync(pci->dev);
qcom_ep_reset_assert(pcie);

ret = pcie->ops->init(pcie);
@@ -1124,6 +1126,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
phy_power_off(pcie->phy);
err_deinit:
pcie->ops->deinit(pcie);
+ pm_runtime_put(pci->dev);

return ret;
}
@@ -1212,6 +1215,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
if (!pci)
return -ENOMEM;

+ pm_runtime_enable(dev);
pci->dev = dev;
pci->ops = &dw_pcie_ops;
pp = &pci->pp;
@@ -1257,14 +1261,17 @@ static int qcom_pcie_probe(struct platform_device *pdev)
}

ret = phy_init(pcie->phy);
- if (ret)
+ if (ret) {
+ pm_runtime_disable(&pdev->dev);
return ret;
+ }

platform_set_drvdata(pdev, pcie);

ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "cannot initialize host\n");
+ pm_runtime_disable(&pdev->dev);
return ret;
}

--
2.16.2



2018-05-23 13:38:31

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH v2] PCI: qcom: add runtime pm support to pcie_port

On 23-05-18, 11:44, Srinivas Kandagatla wrote:
> This patch is required when the pcie controller sits on a bus with
> its own power domain and clocks which are controlled via a bus driver
> like simple pm bus. As these bus driver have runtime pm enabled, it makes
> sense to update the usage counter so that the runtime pm does not suspend
> the clks or power domain associated with the bus driver.

FWIW:

Reviewed-by: Vinod Koul <[email protected]>

--
~Vinod

2018-05-23 13:55:07

by Stanimir Varbanov

[permalink] [raw]
Subject: Re: [PATCH v2] PCI: qcom: add runtime pm support to pcie_port

Hi Srini,

On 05/23/2018 01:44 PM, Srinivas Kandagatla wrote:
> This patch is required when the pcie controller sits on a bus with
> its own power domain and clocks which are controlled via a bus driver
> like simple pm bus. As these bus driver have runtime pm enabled, it makes
> sense to update the usage counter so that the runtime pm does not suspend
> the clks or power domain associated with the bus driver.
>
> Signed-off-by: Srinivas Kandagatla <[email protected]>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> drivers/pci/dwc/pcie-qcom.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)

Acked-by: Stanimir Varbanov <[email protected]>

--
regards,
Stan

2018-05-23 15:51:16

by Lorenzo Pieralisi

[permalink] [raw]
Subject: Re: [PATCH v2] PCI: qcom: add runtime pm support to pcie_port

On Wed, May 23, 2018 at 11:44:25AM +0100, Srinivas Kandagatla wrote:
> This patch is required when the pcie controller sits on a bus with
> its own power domain and clocks which are controlled via a bus driver
> like simple pm bus. As these bus driver have runtime pm enabled, it makes
> sense to update the usage counter so that the runtime pm does not suspend
> the clks or power domain associated with the bus driver.
>
> Signed-off-by: Srinivas Kandagatla <[email protected]>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> drivers/pci/dwc/pcie-qcom.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)

Applied to pci/dwc for v4.18, thanks.

Lorenzo

> diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c
> index 5897af7d3355..d6ed5aeeae9c 100644
> --- a/drivers/pci/dwc/pcie-qcom.c
> +++ b/drivers/pci/dwc/pcie-qcom.c
> @@ -19,6 +19,7 @@
> #include <linux/of_device.h>
> #include <linux/of_gpio.h>
> #include <linux/pci.h>
> +#include <linux/pm_runtime.h>
> #include <linux/platform_device.h>
> #include <linux/phy/phy.h>
> #include <linux/regulator/consumer.h>
> @@ -1088,6 +1089,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
> struct qcom_pcie *pcie = to_qcom_pcie(pci);
> int ret;
>
> + pm_runtime_get_sync(pci->dev);
> qcom_ep_reset_assert(pcie);
>
> ret = pcie->ops->init(pcie);
> @@ -1124,6 +1126,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
> phy_power_off(pcie->phy);
> err_deinit:
> pcie->ops->deinit(pcie);
> + pm_runtime_put(pci->dev);
>
> return ret;
> }
> @@ -1212,6 +1215,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> if (!pci)
> return -ENOMEM;
>
> + pm_runtime_enable(dev);
> pci->dev = dev;
> pci->ops = &dw_pcie_ops;
> pp = &pci->pp;
> @@ -1257,14 +1261,17 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> }
>
> ret = phy_init(pcie->phy);
> - if (ret)
> + if (ret) {
> + pm_runtime_disable(&pdev->dev);
> return ret;
> + }
>
> platform_set_drvdata(pdev, pcie);
>
> ret = dw_pcie_host_init(pp);
> if (ret) {
> dev_err(dev, "cannot initialize host\n");
> + pm_runtime_disable(&pdev->dev);
> return ret;
> }
>
> --
> 2.16.2
>

2018-05-25 19:10:19

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH] PCI: qcom: Fix error handling in pm_runtime support

The driver does not cope with the fact that probe can fail in a number
of cases after enabling pm_runtime on the device, this results in
warnings about "Unbalanced pm_runtime_enable". Further more if probe
fails after invoking host_init the power-domain will be left referenced.

As it's not possible for the error handling in qcom_pcie_host_init() to
handle errors happening after returning from that function the
pm_runtime_get_sync() is moved to probe() as well.

Signed-off-by: Bjorn Andersson <[email protected]>
---

I'm sorry for not spotting this last week when we discussed the previous patch.

drivers/pci/dwc/pcie-qcom.c | 65 ++++++++++++++++++++++++++-----------
1 file changed, 46 insertions(+), 19 deletions(-)

diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c
index 3f35098b71b1..f2453196278f 100644
--- a/drivers/pci/dwc/pcie-qcom.c
+++ b/drivers/pci/dwc/pcie-qcom.c
@@ -1088,8 +1088,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
struct qcom_pcie *pcie = to_qcom_pcie(pci);
int ret;

- pm_runtime_get_sync(pci->dev);
-
qcom_ep_reset_assert(pcie);

ret = pcie->ops->init(pcie);
@@ -1126,7 +1124,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
phy_power_off(pcie->phy);
err_deinit:
pcie->ops->deinit(pcie);
- pm_runtime_put_sync(pci->dev);

return ret;
}
@@ -1207,7 +1204,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
struct qcom_pcie *pcie;
int ret;

-
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
return -ENOMEM;
@@ -1217,6 +1213,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
return -ENOMEM;

pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);

pci->dev = dev;
pci->ops = &dw_pcie_ops;
@@ -1227,53 +1224,82 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pcie->ops = of_device_get_match_data(dev);

pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW);
- if (IS_ERR(pcie->reset))
- return PTR_ERR(pcie->reset);
+ if (IS_ERR(pcie->reset)) {
+ ret = PTR_ERR(pcie->reset);
+ goto err_pm_runtime_put;
+ }

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
pcie->parf = devm_ioremap_resource(dev, res);
- if (IS_ERR(pcie->parf))
- return PTR_ERR(pcie->parf);
+ if (IS_ERR(pcie->parf)) {
+ ret = PTR_ERR(pcie->parf);
+ goto err_pm_runtime_put;
+ }

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
- if (IS_ERR(pci->dbi_base))
- return PTR_ERR(pci->dbi_base);
+ if (IS_ERR(pci->dbi_base)) {
+ ret = PTR_ERR(pci->dbi_base);
+ goto err_pm_runtime_put;
+ }

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi");
pcie->elbi = devm_ioremap_resource(dev, res);
- if (IS_ERR(pcie->elbi))
- return PTR_ERR(pcie->elbi);
+ if (IS_ERR(pcie->elbi)) {
+ ret = PTR_ERR(pcie->elbi);
+ goto err_pm_runtime_put;
+ }

pcie->phy = devm_phy_optional_get(dev, "pciephy");
- if (IS_ERR(pcie->phy))
- return PTR_ERR(pcie->phy);
+ if (IS_ERR(pcie->phy)) {
+ ret = PTR_ERR(pcie->phy);
+ goto err_pm_runtime_put;
+ }

ret = pcie->ops->get_resources(pcie);
if (ret)
- return ret;
+ goto err_pm_runtime_put;

pp->root_bus_nr = -1;
pp->ops = &qcom_pcie_dw_ops;

if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
- if (pp->msi_irq < 0)
- return pp->msi_irq;
+ if (pp->msi_irq < 0) {
+ ret = pp->msi_irq;
+ goto err_pm_runtime_put;
+ }
}

ret = phy_init(pcie->phy);
if (ret)
- return ret;
+ goto err_pm_runtime_put;

platform_set_drvdata(pdev, pcie);

ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "cannot initialize host\n");
- return ret;
+ goto err_pm_runtime_put;
}

+ return 0;
+
+err_pm_runtime_put:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int qcom_pcie_remove(struct platform_device *pdev)
+{
+ struct qcom_pcie *pcie = platform_get_drvdata(pdev);
+ struct device *dev = pcie->pci->dev;
+
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
return 0;
}

@@ -1289,6 +1315,7 @@ static const struct of_device_id qcom_pcie_match[] = {

static struct platform_driver qcom_pcie_driver = {
.probe = qcom_pcie_probe,
+ .remove = qcom_pcie_remove,
.driver = {
.name = "qcom-pcie",
.suppress_bind_attrs = true,
--
2.17.0


2018-06-29 11:17:22

by Lorenzo Pieralisi

[permalink] [raw]
Subject: Re: [PATCH] PCI: qcom: Fix error handling in pm_runtime support

On Fri, May 25, 2018 at 12:09:34PM -0700, Bjorn Andersson wrote:
> The driver does not cope with the fact that probe can fail in a number
> of cases after enabling pm_runtime on the device, this results in
> warnings about "Unbalanced pm_runtime_enable". Further more if probe
> fails after invoking host_init the power-domain will be left referenced.
>
> As it's not possible for the error handling in qcom_pcie_host_init() to
> handle errors happening after returning from that function the
> pm_runtime_get_sync() is moved to probe() as well.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
>
> I'm sorry for not spotting this last week when we discussed the previous patch.

I need Stanimir's ACK to merge it, thanks.

Lorenzo

> drivers/pci/dwc/pcie-qcom.c | 65 ++++++++++++++++++++++++++-----------
> 1 file changed, 46 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c
> index 3f35098b71b1..f2453196278f 100644
> --- a/drivers/pci/dwc/pcie-qcom.c
> +++ b/drivers/pci/dwc/pcie-qcom.c
> @@ -1088,8 +1088,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
> struct qcom_pcie *pcie = to_qcom_pcie(pci);
> int ret;
>
> - pm_runtime_get_sync(pci->dev);
> -
> qcom_ep_reset_assert(pcie);
>
> ret = pcie->ops->init(pcie);
> @@ -1126,7 +1124,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
> phy_power_off(pcie->phy);
> err_deinit:
> pcie->ops->deinit(pcie);
> - pm_runtime_put_sync(pci->dev);
>
> return ret;
> }
> @@ -1207,7 +1204,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> struct qcom_pcie *pcie;
> int ret;
>
> -
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> return -ENOMEM;
> @@ -1217,6 +1213,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> return -ENOMEM;
>
> pm_runtime_enable(dev);
> + pm_runtime_get_sync(dev);
>
> pci->dev = dev;
> pci->ops = &dw_pcie_ops;
> @@ -1227,53 +1224,82 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> pcie->ops = of_device_get_match_data(dev);
>
> pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW);
> - if (IS_ERR(pcie->reset))
> - return PTR_ERR(pcie->reset);
> + if (IS_ERR(pcie->reset)) {
> + ret = PTR_ERR(pcie->reset);
> + goto err_pm_runtime_put;
> + }
>
> res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
> pcie->parf = devm_ioremap_resource(dev, res);
> - if (IS_ERR(pcie->parf))
> - return PTR_ERR(pcie->parf);
> + if (IS_ERR(pcie->parf)) {
> + ret = PTR_ERR(pcie->parf);
> + goto err_pm_runtime_put;
> + }
>
> res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
> pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
> - if (IS_ERR(pci->dbi_base))
> - return PTR_ERR(pci->dbi_base);
> + if (IS_ERR(pci->dbi_base)) {
> + ret = PTR_ERR(pci->dbi_base);
> + goto err_pm_runtime_put;
> + }
>
> res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi");
> pcie->elbi = devm_ioremap_resource(dev, res);
> - if (IS_ERR(pcie->elbi))
> - return PTR_ERR(pcie->elbi);
> + if (IS_ERR(pcie->elbi)) {
> + ret = PTR_ERR(pcie->elbi);
> + goto err_pm_runtime_put;
> + }
>
> pcie->phy = devm_phy_optional_get(dev, "pciephy");
> - if (IS_ERR(pcie->phy))
> - return PTR_ERR(pcie->phy);
> + if (IS_ERR(pcie->phy)) {
> + ret = PTR_ERR(pcie->phy);
> + goto err_pm_runtime_put;
> + }
>
> ret = pcie->ops->get_resources(pcie);
> if (ret)
> - return ret;
> + goto err_pm_runtime_put;
>
> pp->root_bus_nr = -1;
> pp->ops = &qcom_pcie_dw_ops;
>
> if (IS_ENABLED(CONFIG_PCI_MSI)) {
> pp->msi_irq = platform_get_irq_byname(pdev, "msi");
> - if (pp->msi_irq < 0)
> - return pp->msi_irq;
> + if (pp->msi_irq < 0) {
> + ret = pp->msi_irq;
> + goto err_pm_runtime_put;
> + }
> }
>
> ret = phy_init(pcie->phy);
> if (ret)
> - return ret;
> + goto err_pm_runtime_put;
>
> platform_set_drvdata(pdev, pcie);
>
> ret = dw_pcie_host_init(pp);
> if (ret) {
> dev_err(dev, "cannot initialize host\n");
> - return ret;
> + goto err_pm_runtime_put;
> }
>
> + return 0;
> +
> +err_pm_runtime_put:
> + pm_runtime_put(dev);
> + pm_runtime_disable(dev);
> +
> + return ret;
> +}
> +
> +static int qcom_pcie_remove(struct platform_device *pdev)
> +{
> + struct qcom_pcie *pcie = platform_get_drvdata(pdev);
> + struct device *dev = pcie->pci->dev;
> +
> + pm_runtime_put(dev);
> + pm_runtime_disable(dev);
> +
> return 0;
> }
>
> @@ -1289,6 +1315,7 @@ static const struct of_device_id qcom_pcie_match[] = {
>
> static struct platform_driver qcom_pcie_driver = {
> .probe = qcom_pcie_probe,
> + .remove = qcom_pcie_remove,
> .driver = {
> .name = "qcom-pcie",
> .suppress_bind_attrs = true,
> --
> 2.17.0
>

2018-06-29 11:34:32

by Stanimir Varbanov

[permalink] [raw]
Subject: Re: [PATCH] PCI: qcom: Fix error handling in pm_runtime support

Hi Bjorn,

On 05/25/2018 10:09 PM, Bjorn Andersson wrote:
> The driver does not cope with the fact that probe can fail in a number
> of cases after enabling pm_runtime on the device, this results in
> warnings about "Unbalanced pm_runtime_enable". Further more if probe
> fails after invoking host_init the power-domain will be left referenced.
>
> As it's not possible for the error handling in qcom_pcie_host_init() to
> handle errors happening after returning from that function the
> pm_runtime_get_sync() is moved to probe() as well.
>
> Signed-off-by: Bjorn Andersson <[email protected]>

Please add:

Fixes: 854b69efbdd2903991506ac5d5624d2cfb5b4e2f PCI: qcom: add runtime
pm support to pcie_port

> ---
>
> I'm sorry for not spotting this last week when we discussed the previous patch.
>
> drivers/pci/dwc/pcie-qcom.c | 65 ++++++++++++++++++++++++++-----------

the path has been changed to drivers/pci/controller/dwc/pcie-qcom.c

> 1 file changed, 46 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c
> index 3f35098b71b1..f2453196278f 100644
> --- a/drivers/pci/dwc/pcie-qcom.c
> +++ b/drivers/pci/dwc/pcie-qcom.c
> @@ -1088,8 +1088,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
> struct qcom_pcie *pcie = to_qcom_pcie(pci);
> int ret;
>
> - pm_runtime_get_sync(pci->dev);
> -
> qcom_ep_reset_assert(pcie);
>
> ret = pcie->ops->init(pcie);
> @@ -1126,7 +1124,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
> phy_power_off(pcie->phy);
> err_deinit:
> pcie->ops->deinit(pcie);
> - pm_runtime_put_sync(pci->dev);
>
> return ret;
> }
> @@ -1207,7 +1204,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> struct qcom_pcie *pcie;
> int ret;
>
> -
> pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> if (!pcie)
> return -ENOMEM;
> @@ -1217,6 +1213,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> return -ENOMEM;
>
> pm_runtime_enable(dev);
> + pm_runtime_get_sync(dev);

pm_runtime_get_sync could fail, please check for errors.

With those changes addressed:

Acked-by: Stanimir Varbanov <[email protected]>

--
regards,
Stan