diff mbox series

[v2] ata: ahci_ceva: fix error handling for Xilinx GT PHY support

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

Commit Message

Pandey, Radhey Shyam Feb. 15, 2024, 6:01 p.m. UTC
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(-)

Comments

Damien Le Moal Feb. 15, 2024, 10:45 p.m. UTC | #1
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>
Niklas Cassel Feb. 16, 2024, 10:29 a.m. UTC | #2
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 mbox series

Patch

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;