2015-04-20 13:41:13

by Peter Griffin

[permalink] [raw]
Subject: [PATCH v2] ata: ahci_st: fixup layering violations / drvdata errors

Hi Tejun / Brian,

I tested the initial version of this patch (see http://patchwork.ozlabs.org/patch/459422/)
on stih410 hardware, however it introduced a NULL ptr dereference, as plat_data
isn't set until ahci_platform_init_host() but plat_data was being used before
this in the st_ahci_probe_resets and st_ahci_deassert_resets() functions.

Also the original patch had a conflict with a patch which Tejun has already
taken of mine
(see here http://lists.infradead.org/pipermail/linux-arm-kernel/2015-March/326900.html).

So this V2 fixes the conflict, and re-works st_ahci_probe_resets and
st_ahci_deassert_resets functions to take struct ahci_host_priv *hpriv as
a parameter.

Brian - I'm not sure of the correct patch etiquette here. Currently I have
taken authorship of the patch and added a "Suggested-by" tag on the V2.
Maybe I should have also kept your "Signed-off-by" or done something else?
Please let me know if this is OK or if you would like something changed.

regards,

Peter.

Changes since v1:
- Rework st_ahci_deassert_resets and st_ahci_probe_resets
- Fix conflict with "st_configure_oob must be called after IP is clocked." patch

Peter Griffin (1):
ata: ahci_st: fixup layering violations / drvdata errors

drivers/ata/ahci_st.c | 49 ++++++++++++++++++++++++-------------------------
1 file changed, 24 insertions(+), 25 deletions(-)

--
1.9.1


2015-04-20 13:41:19

by Peter Griffin

[permalink] [raw]
Subject: [PATCH v2] ata: ahci_st: fixup layering violations / drvdata errors

Brian noticed while working on another SATA driver that uses libahci_platform,
an error in this driver; it tries to the the driver data for its
device, while libata also thinks it can set the driver data. See:

ahci_platform_init_host()
-> ata_host_alloc_pinfo()
-> ata_host_alloc()
-> dev_set_drvdata()

So instead of sticking the IP-specific platform data into drvdata, let's
use the plat_data variable that is reserved for this use.

Addtionally plat_data isn't set until ahci_platform_init_host() has been
called further down in probe(). So re-work the st_ahci_probe_resets and
st_ahci_deassert_resets functions to take ahci_host_priv *hpriv as a
parameter.

Signed-off-by: Peter Griffin <[email protected]>
Suggested-by: Brian Norris <[email protected]>
Cc: Srinivas Kandagatla <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Patrice Chotard <[email protected]>
---
drivers/ata/ahci_st.c | 49 ++++++++++++++++++++++++-------------------------
1 file changed, 24 insertions(+), 25 deletions(-)

diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
index ea0ff00..8ff428f 100644
--- a/drivers/ata/ahci_st.c
+++ b/drivers/ata/ahci_st.c
@@ -37,7 +37,6 @@ struct st_ahci_drv_data {
struct reset_control *pwr;
struct reset_control *sw_rst;
struct reset_control *pwr_rst;
- struct ahci_host_priv *hpriv;
};

static void st_ahci_configure_oob(void __iomem *mmio)
@@ -55,9 +54,10 @@ static void st_ahci_configure_oob(void __iomem *mmio)
writel(new_val, mmio + ST_AHCI_OOBR);
}

-static int st_ahci_deassert_resets(struct device *dev)
+static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv,
+ struct device *dev)
{
- struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ struct st_ahci_drv_data *drv_data = hpriv->plat_data;
int err;

if (drv_data->pwr) {
@@ -90,8 +90,8 @@ static int st_ahci_deassert_resets(struct device *dev)
static void st_ahci_host_stop(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
+ struct st_ahci_drv_data *drv_data = hpriv->plat_data;
struct device *dev = host->dev;
- struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
int err;

if (drv_data->pwr) {
@@ -103,29 +103,30 @@ static void st_ahci_host_stop(struct ata_host *host)
ahci_platform_disable_resources(hpriv);
}

-static int st_ahci_probe_resets(struct platform_device *pdev)
+static int st_ahci_probe_resets(struct ahci_host_priv *hpriv,
+ struct device *dev)
{
- struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev);
+ struct st_ahci_drv_data *drv_data = hpriv->plat_data;

- drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn");
+ drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn");
if (IS_ERR(drv_data->pwr)) {
- dev_info(&pdev->dev, "power reset control not defined\n");
+ dev_info(dev, "power reset control not defined\n");
drv_data->pwr = NULL;
}

- drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst");
+ drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst");
if (IS_ERR(drv_data->sw_rst)) {
- dev_info(&pdev->dev, "soft reset control not defined\n");
+ dev_info(dev, "soft reset control not defined\n");
drv_data->sw_rst = NULL;
}

- drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst");
+ drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst");
if (IS_ERR(drv_data->pwr_rst)) {
- dev_dbg(&pdev->dev, "power soft reset control not defined\n");
+ dev_dbg(dev, "power soft reset control not defined\n");
drv_data->pwr_rst = NULL;
}

- return st_ahci_deassert_resets(&pdev->dev);
+ return st_ahci_deassert_resets(hpriv, dev);
}

static struct ata_port_operations st_ahci_port_ops = {
@@ -154,15 +155,12 @@ static int st_ahci_probe(struct platform_device *pdev)
if (!drv_data)
return -ENOMEM;

- platform_set_drvdata(pdev, drv_data);
-
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
+ hpriv->plat_data = drv_data;

- drv_data->hpriv = hpriv;
-
- err = st_ahci_probe_resets(pdev);
+ err = st_ahci_probe_resets(hpriv, &pdev->dev);
if (err)
return err;

@@ -170,7 +168,7 @@ static int st_ahci_probe(struct platform_device *pdev)
if (err)
return err;

- st_ahci_configure_oob(drv_data->hpriv->mmio);
+ st_ahci_configure_oob(hpriv->mmio);

err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
&ahci_platform_sht);
@@ -185,8 +183,9 @@ static int st_ahci_probe(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int st_ahci_suspend(struct device *dev)
{
- struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = drv_data->hpriv;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct st_ahci_drv_data *drv_data = hpriv->plat_data;
int err;

err = ahci_platform_suspend_host(dev);
@@ -208,21 +207,21 @@ static int st_ahci_suspend(struct device *dev)

static int st_ahci_resume(struct device *dev)
{
- struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = drv_data->hpriv;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
int err;

err = ahci_platform_enable_resources(hpriv);
if (err)
return err;

- err = st_ahci_deassert_resets(dev);
+ err = st_ahci_deassert_resets(hpriv, dev);
if (err) {
ahci_platform_disable_resources(hpriv);
return err;
}

- st_ahci_configure_oob(drv_data->hpriv->mmio);
+ st_ahci_configure_oob(hpriv->mmio);

return ahci_platform_resume_host(dev);
}
--
1.9.1

2015-04-23 01:18:18

by Brian Norris

[permalink] [raw]
Subject: Re: [PATCH v2] ata: ahci_st: fixup layering violations / drvdata errors

On Mon, Apr 20, 2015 at 02:41:04PM +0100, Peter Griffin wrote:
> Brian - I'm not sure of the correct patch etiquette here. Currently I have
> taken authorship of the patch and added a "Suggested-by" tag on the V2.
> Maybe I should have also kept your "Signed-off-by" or done something else?
> Please let me know if this is OK or if you would like something changed.

No problem. 'Suggested-by' seems appropriate to me.

For the patch:

Acked-by: Brian Norris <[email protected]>

2015-04-29 14:31:33

by Maxime Coquelin

[permalink] [raw]
Subject: Re: [PATCH v2] ata: ahci_st: fixup layering violations / drvdata errors

Hi Peter,

On 04/20/2015 03:41 PM, Peter Griffin wrote:
> Brian noticed while working on another SATA driver that uses libahci_platform,
> an error in this driver; it tries to the the driver data for its
> device, while libata also thinks it can set the driver data. See:
>
> ahci_platform_init_host()
> -> ata_host_alloc_pinfo()
> -> ata_host_alloc()
> -> dev_set_drvdata()
>
> So instead of sticking the IP-specific platform data into drvdata, let's
> use the plat_data variable that is reserved for this use.
>
> Addtionally plat_data isn't set until ahci_platform_init_host() has been
> called further down in probe(). So re-work the st_ahci_probe_resets and
> st_ahci_deassert_resets functions to take ahci_host_priv *hpriv as a
> parameter.
>
> Signed-off-by: Peter Griffin <[email protected]>
> Suggested-by: Brian Norris <[email protected]>
> Cc: Srinivas Kandagatla <[email protected]>
> Cc: Maxime Coquelin <[email protected]>
> Cc: Patrice Chotard <[email protected]>
> ---
>

You can add my:
Acked-by: Maxime Coquelin <[email protected]>

Thanks!
Maxime