Message ID | 1708020060-1439879-1-git-send-email-radhey.shyam.pandey@amd.com |
---|---|
State | New |
Headers | show |
Series | [v2] ata: ahci_ceva: fix error handling for Xilinx GT PHY support | expand |
On 2/16/24 03:01, Radhey Shyam Pandey wrote: > Platform clock and phy error resources are not cleaned up in Xilinx GT PHY > error path. > > To fix it create a wrapper ceva_ahci_platform_enable_resources() API which create a wrapper ceva_ahci_platform_enable_resources() API -> introduce the function ceva_ahci_platform_enable_resources() > is a customized version of ahci_platform_enable_resources() and inline with > SATA IP programming sequence it does: > > - Assert SATA reset > - Program PS GTR phy > - Bring SATA by de-asserting the reset > - Wait for GT lane PLL to be locked > > It switches to ceva_ahci_platform_enable_resources() in resume path > as same SATA programming sequence (as in probe) should be followed. What is "It" ? > It also cleanup mix usage of ahci_platform_enable_resources() and custom > implementation in probe function as both are not required. Same here, but may be "It" == "this commit" ? If that is the case, then simply rewrite your sentences simply like: ceva_ahci_platform_enable_resources() is also used in the resume path as the same SATA programming sequence (as in probe) should be followed. Also cleanup the mixed usage of ahci_platform_enable_resources() and custom implementation in the probe function as both are not required. > Fixes: 9a9d3abe24bb ("ata: ahci: ceva: Update the driver to support xilinx GT phy") > Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> Other than these nits, this looks OK to me. Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Hello Radhey, On Thu, Feb 15, 2024 at 11:31:00PM +0530, Radhey Shyam Pandey wrote: > Platform clock and phy error resources are not cleaned up in Xilinx GT PHY > error path. > > To fix it create a wrapper ceva_ahci_platform_enable_resources() API which > is a customized version of ahci_platform_enable_resources() and inline with > SATA IP programming sequence it does: > > - Assert SATA reset > - Program PS GTR phy > - Bring SATA by de-asserting the reset > - Wait for GT lane PLL to be locked > > It switches to ceva_ahci_platform_enable_resources() in resume path > as same SATA programming sequence (as in probe) should be followed. > > It also cleanup mix usage of ahci_platform_enable_resources() and custom > implementation in probe function as both are not required. > > Fixes: 9a9d3abe24bb ("ata: ahci: ceva: Update the driver to support xilinx GT phy") > Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> > --- > Changes for v2: > > - Create wrapper ceva_ahci_platform_enable_resources() > - Remove legacy ahci_platform_enable_resources() and its related code. > - Modified commit description and merge 1/2 and 2/2 fix as it is > automatically done when reusing ahci_platform_enable_resources() > logic. > - Drop Reviewed-by: Damien Le Moal <dlemoal@kernel.org> tag. > --- > drivers/ata/ahci_ceva.c | 125 +++++++++++++++++++++++++--------------- > 1 file changed, 79 insertions(+), 46 deletions(-) > > diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c > index 64f7f7d6ba84..c04f5033f981 100644 > --- a/drivers/ata/ahci_ceva.c > +++ b/drivers/ata/ahci_ceva.c > @@ -88,7 +88,6 @@ struct ceva_ahci_priv { > u32 axicc; > bool is_cci_enabled; > int flags; > - struct reset_control *rst; > }; > > static unsigned int ceva_ahci_read_id(struct ata_device *dev, > @@ -189,6 +188,60 @@ static const struct scsi_host_template ahci_platform_sht = { > AHCI_SHT(DRV_NAME), > }; > > +static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv) > +{ > + int rc, i; > + > + rc = ahci_platform_enable_regulators(hpriv); > + if (rc) > + return rc; > + > + rc = ahci_platform_enable_clks(hpriv); > + if (rc) > + goto disable_regulator; > + > + /* Assert the controller reset */ > + rc = ahci_platform_assert_rsts(hpriv); > + if (rc) > + goto disable_clks; > + > + for (i = 0; i < hpriv->nports; i++) { > + rc = phy_init(hpriv->phys[i]); > + if (rc) > + goto disable_rsts; > + } > + > + /* De-assert the controller reset */ > + ahci_platform_deassert_rsts(hpriv); > + > + for (i = 0; i < hpriv->nports; i++) { > + rc = phy_power_on(hpriv->phys[i]); > + if (rc) { > + phy_exit(hpriv->phys[i]); > + goto disable_phys; > + } > + } > + > + return 0; > + > +disable_rsts: > + ahci_platform_deassert_rsts(hpriv); > + > +disable_phys: > + while (--i >= 0) { > + phy_power_off(hpriv->phys[i]); > + phy_exit(hpriv->phys[i]); > + } > + > +disable_clks: > + ahci_platform_disable_clks(hpriv); > + > +disable_regulator: > + ahci_platform_disable_regulators(hpriv); > + > + return rc; > +} > + > static int ceva_ahci_probe(struct platform_device *pdev) > { > struct device_node *np = pdev->dev.of_node; > @@ -203,47 +256,19 @@ static int ceva_ahci_probe(struct platform_device *pdev) > return -ENOMEM; > > cevapriv->ahci_pdev = pdev; > - > - cevapriv->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, > - NULL); > - if (IS_ERR(cevapriv->rst)) > - dev_err_probe(&pdev->dev, PTR_ERR(cevapriv->rst), > - "failed to get reset\n"); > - > hpriv = ahci_platform_get_resources(pdev, 0); > if (IS_ERR(hpriv)) > return PTR_ERR(hpriv); > > - if (!cevapriv->rst) { > - rc = ahci_platform_enable_resources(hpriv); > - if (rc) > - return rc; > - } else { > - int i; > - > - rc = ahci_platform_enable_clks(hpriv); > - if (rc) > - return rc; > - /* Assert the controller reset */ > - reset_control_assert(cevapriv->rst); > - > - for (i = 0; i < hpriv->nports; i++) { > - rc = phy_init(hpriv->phys[i]); > - if (rc) > - return rc; > - } > - > - /* De-assert the controller reset */ > - reset_control_deassert(cevapriv->rst); > + hpriv->rsts = devm_reset_control_get_optional_exclusive(&pdev->dev, > + NULL); > + if (IS_ERR(hpriv->rsts)) > + dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts), > + "failed to get reset\n"); > Here you just continue on even though there was an error. You should return the error here. It can be done in one statement: return dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts), "failed to get reset\n"); Otherwise, this looks good. Kind regards, Niklas > - for (i = 0; i < hpriv->nports; i++) { > - rc = phy_power_on(hpriv->phys[i]); > - if (rc) { > - phy_exit(hpriv->phys[i]); > - return rc; > - } > - } > - } > + rc = ceva_ahci_platform_enable_resources(hpriv); > + if (rc) > + return rc; > > if (of_property_read_bool(np, "ceva,broken-gen2")) > cevapriv->flags = CEVA_FLAG_BROKEN_GEN2; > @@ -252,52 +277,60 @@ static int ceva_ahci_probe(struct platform_device *pdev) > if (of_property_read_u8_array(np, "ceva,p0-cominit-params", > (u8 *)&cevapriv->pp2c[0], 4) < 0) { > dev_warn(dev, "ceva,p0-cominit-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > if (of_property_read_u8_array(np, "ceva,p1-cominit-params", > (u8 *)&cevapriv->pp2c[1], 4) < 0) { > dev_warn(dev, "ceva,p1-cominit-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > /* Read OOB timing value for COMWAKE from device-tree*/ > if (of_property_read_u8_array(np, "ceva,p0-comwake-params", > (u8 *)&cevapriv->pp3c[0], 4) < 0) { > dev_warn(dev, "ceva,p0-comwake-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > if (of_property_read_u8_array(np, "ceva,p1-comwake-params", > (u8 *)&cevapriv->pp3c[1], 4) < 0) { > dev_warn(dev, "ceva,p1-comwake-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > /* Read phy BURST timing value from device-tree */ > if (of_property_read_u8_array(np, "ceva,p0-burst-params", > (u8 *)&cevapriv->pp4c[0], 4) < 0) { > dev_warn(dev, "ceva,p0-burst-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > if (of_property_read_u8_array(np, "ceva,p1-burst-params", > (u8 *)&cevapriv->pp4c[1], 4) < 0) { > dev_warn(dev, "ceva,p1-burst-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > /* Read phy RETRY interval timing value from device-tree */ > if (of_property_read_u16_array(np, "ceva,p0-retry-params", > (u16 *)&cevapriv->pp5c[0], 2) < 0) { > dev_warn(dev, "ceva,p0-retry-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > if (of_property_read_u16_array(np, "ceva,p1-retry-params", > (u16 *)&cevapriv->pp5c[1], 2) < 0) { > dev_warn(dev, "ceva,p1-retry-params property not defined\n"); > - return -EINVAL; > + rc = -EINVAL; > + goto disable_resources; > } > > /* > @@ -335,7 +368,7 @@ static int __maybe_unused ceva_ahci_resume(struct device *dev) > struct ahci_host_priv *hpriv = host->private_data; > int rc; > > - rc = ahci_platform_enable_resources(hpriv); > + rc = ceva_ahci_platform_enable_resources(hpriv); > if (rc) > return rc; > > -- > 2.34.1 >
diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c index 64f7f7d6ba84..c04f5033f981 100644 --- a/drivers/ata/ahci_ceva.c +++ b/drivers/ata/ahci_ceva.c @@ -88,7 +88,6 @@ struct ceva_ahci_priv { u32 axicc; bool is_cci_enabled; int flags; - struct reset_control *rst; }; static unsigned int ceva_ahci_read_id(struct ata_device *dev, @@ -189,6 +188,60 @@ static const struct scsi_host_template ahci_platform_sht = { AHCI_SHT(DRV_NAME), }; +static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv) +{ + int rc, i; + + rc = ahci_platform_enable_regulators(hpriv); + if (rc) + return rc; + + rc = ahci_platform_enable_clks(hpriv); + if (rc) + goto disable_regulator; + + /* Assert the controller reset */ + rc = ahci_platform_assert_rsts(hpriv); + if (rc) + goto disable_clks; + + for (i = 0; i < hpriv->nports; i++) { + rc = phy_init(hpriv->phys[i]); + if (rc) + goto disable_rsts; + } + + /* De-assert the controller reset */ + ahci_platform_deassert_rsts(hpriv); + + for (i = 0; i < hpriv->nports; i++) { + rc = phy_power_on(hpriv->phys[i]); + if (rc) { + phy_exit(hpriv->phys[i]); + goto disable_phys; + } + } + + return 0; + +disable_rsts: + ahci_platform_deassert_rsts(hpriv); + +disable_phys: + while (--i >= 0) { + phy_power_off(hpriv->phys[i]); + phy_exit(hpriv->phys[i]); + } + +disable_clks: + ahci_platform_disable_clks(hpriv); + +disable_regulator: + ahci_platform_disable_regulators(hpriv); + + return rc; +} + static int ceva_ahci_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -203,47 +256,19 @@ static int ceva_ahci_probe(struct platform_device *pdev) return -ENOMEM; cevapriv->ahci_pdev = pdev; - - cevapriv->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, - NULL); - if (IS_ERR(cevapriv->rst)) - dev_err_probe(&pdev->dev, PTR_ERR(cevapriv->rst), - "failed to get reset\n"); - hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); - if (!cevapriv->rst) { - rc = ahci_platform_enable_resources(hpriv); - if (rc) - return rc; - } else { - int i; - - rc = ahci_platform_enable_clks(hpriv); - if (rc) - return rc; - /* Assert the controller reset */ - reset_control_assert(cevapriv->rst); - - for (i = 0; i < hpriv->nports; i++) { - rc = phy_init(hpriv->phys[i]); - if (rc) - return rc; - } - - /* De-assert the controller reset */ - reset_control_deassert(cevapriv->rst); + hpriv->rsts = devm_reset_control_get_optional_exclusive(&pdev->dev, + NULL); + if (IS_ERR(hpriv->rsts)) + dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts), + "failed to get reset\n"); - for (i = 0; i < hpriv->nports; i++) { - rc = phy_power_on(hpriv->phys[i]); - if (rc) { - phy_exit(hpriv->phys[i]); - return rc; - } - } - } + rc = ceva_ahci_platform_enable_resources(hpriv); + if (rc) + return rc; if (of_property_read_bool(np, "ceva,broken-gen2")) cevapriv->flags = CEVA_FLAG_BROKEN_GEN2; @@ -252,52 +277,60 @@ static int ceva_ahci_probe(struct platform_device *pdev) if (of_property_read_u8_array(np, "ceva,p0-cominit-params", (u8 *)&cevapriv->pp2c[0], 4) < 0) { dev_warn(dev, "ceva,p0-cominit-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } if (of_property_read_u8_array(np, "ceva,p1-cominit-params", (u8 *)&cevapriv->pp2c[1], 4) < 0) { dev_warn(dev, "ceva,p1-cominit-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } /* Read OOB timing value for COMWAKE from device-tree*/ if (of_property_read_u8_array(np, "ceva,p0-comwake-params", (u8 *)&cevapriv->pp3c[0], 4) < 0) { dev_warn(dev, "ceva,p0-comwake-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } if (of_property_read_u8_array(np, "ceva,p1-comwake-params", (u8 *)&cevapriv->pp3c[1], 4) < 0) { dev_warn(dev, "ceva,p1-comwake-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } /* Read phy BURST timing value from device-tree */ if (of_property_read_u8_array(np, "ceva,p0-burst-params", (u8 *)&cevapriv->pp4c[0], 4) < 0) { dev_warn(dev, "ceva,p0-burst-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } if (of_property_read_u8_array(np, "ceva,p1-burst-params", (u8 *)&cevapriv->pp4c[1], 4) < 0) { dev_warn(dev, "ceva,p1-burst-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } /* Read phy RETRY interval timing value from device-tree */ if (of_property_read_u16_array(np, "ceva,p0-retry-params", (u16 *)&cevapriv->pp5c[0], 2) < 0) { dev_warn(dev, "ceva,p0-retry-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } if (of_property_read_u16_array(np, "ceva,p1-retry-params", (u16 *)&cevapriv->pp5c[1], 2) < 0) { dev_warn(dev, "ceva,p1-retry-params property not defined\n"); - return -EINVAL; + rc = -EINVAL; + goto disable_resources; } /* @@ -335,7 +368,7 @@ static int __maybe_unused ceva_ahci_resume(struct device *dev) struct ahci_host_priv *hpriv = host->private_data; int rc; - rc = ahci_platform_enable_resources(hpriv); + rc = ceva_ahci_platform_enable_resources(hpriv); if (rc) return rc;
Platform clock and phy error resources are not cleaned up in Xilinx GT PHY error path. To fix it create a wrapper ceva_ahci_platform_enable_resources() API which is a customized version of ahci_platform_enable_resources() and inline with SATA IP programming sequence it does: - Assert SATA reset - Program PS GTR phy - Bring SATA by de-asserting the reset - Wait for GT lane PLL to be locked It switches to ceva_ahci_platform_enable_resources() in resume path as same SATA programming sequence (as in probe) should be followed. It also cleanup mix usage of ahci_platform_enable_resources() and custom implementation in probe function as both are not required. Fixes: 9a9d3abe24bb ("ata: ahci: ceva: Update the driver to support xilinx GT phy") Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com> --- Changes for v2: - Create wrapper ceva_ahci_platform_enable_resources() - Remove legacy ahci_platform_enable_resources() and its related code. - Modified commit description and merge 1/2 and 2/2 fix as it is automatically done when reusing ahci_platform_enable_resources() logic. - Drop Reviewed-by: Damien Le Moal <dlemoal@kernel.org> tag. --- drivers/ata/ahci_ceva.c | 125 +++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 46 deletions(-)