diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-02-28 21:32:34 +0000 |
---|---|---|
committer | Chris Ball <chris@printf.net> | 2014-03-04 16:28:39 -0500 |
commit | fcdb7c8f5019f77b1f55739a1caf9168d3b455d4 (patch) | |
tree | 521af2903ea711ab26d85289d4a4efab48d427d4 | |
parent | 142dbab951fb9d2281e69f8d7522e6b7e0553ec0 (diff) |
mmc: sdhci-spear: fix platform_data usage
sdhci-spear is unsafe should a probe fail or defer, since it overwrites
the platform_data with its own driver-private data. It's trivial to
fix as SDHCI allows for driver-private data to be appended to its own
structure - we just need to arrange the code to allow this.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Chris Ball <chris@printf.net>
-rw-r--r-- | drivers/mmc/host/sdhci-spear.c | 43 |
1 files changed, 17 insertions, 26 deletions
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 394714f71b2f..d89267eb14b6 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -105,6 +105,7 @@ static int sdhci_probe(struct platform_device *pdev) struct sdhci_host *host; struct resource *iomem; struct spear_sdhci *sdhci; + struct device *dev; int ret; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -121,25 +122,28 @@ static int sdhci_probe(struct platform_device *pdev) goto err; } - sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL); - if (!sdhci) { - ret = -ENOMEM; + dev = pdev->dev.parent ? pdev->dev.parent : &pdev->dev; + host = sdhci_alloc_host(dev, sizeof(*sdhci)); + if (IS_ERR(host)) { + ret = PTR_ERR(host); dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); goto err; } + sdhci = sdhci_priv(host); + /* clk enable */ sdhci->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sdhci->clk)) { ret = PTR_ERR(sdhci->clk); dev_dbg(&pdev->dev, "Error getting clock\n"); - goto err; + goto err_host; } ret = clk_prepare_enable(sdhci->clk); if (ret) { dev_dbg(&pdev->dev, "Error enabling clock\n"); - goto err; + goto err_host; } ret = clk_set_rate(sdhci->clk, 50000000); @@ -157,19 +161,6 @@ static int sdhci_probe(struct platform_device *pdev) sdhci->data = dev_get_platdata(&pdev->dev); } - pdev->dev.platform_data = sdhci; - - if (pdev->dev.parent) - host = sdhci_alloc_host(pdev->dev.parent, 0); - else - host = sdhci_alloc_host(&pdev->dev, 0); - - if (IS_ERR(host)) { - ret = PTR_ERR(host); - dev_dbg(&pdev->dev, "error allocating host\n"); - goto disable_clk; - } - host->hw_name = "sdhci"; host->ops = &sdhci_pltfm_ops; host->irq = platform_get_irq(pdev, 0); @@ -180,13 +171,13 @@ static int sdhci_probe(struct platform_device *pdev) if (!host->ioaddr) { ret = -ENOMEM; dev_dbg(&pdev->dev, "failed to remap registers\n"); - goto free_host; + goto disable_clk; } ret = sdhci_add_host(host); if (ret) { dev_dbg(&pdev->dev, "error adding host\n"); - goto free_host; + goto disable_clk; } platform_set_drvdata(pdev, host); @@ -257,10 +248,10 @@ static int sdhci_probe(struct platform_device *pdev) set_drvdata: sdhci_remove_host(host, 1); -free_host: - sdhci_free_host(host); disable_clk: clk_disable_unprepare(sdhci->clk); +err_host: + sdhci_free_host(host); err: dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); return ret; @@ -269,7 +260,7 @@ err: static int sdhci_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); - struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); + struct spear_sdhci *sdhci = sdhci_priv(host); int dead = 0; u32 scratch; @@ -278,8 +269,8 @@ static int sdhci_remove(struct platform_device *pdev) dead = 1; sdhci_remove_host(host, dead); - sdhci_free_host(host); clk_disable_unprepare(sdhci->clk); + sdhci_free_host(host); return 0; } @@ -288,7 +279,7 @@ static int sdhci_remove(struct platform_device *pdev) static int sdhci_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); - struct spear_sdhci *sdhci = dev_get_platdata(dev); + struct spear_sdhci *sdhci = sdhci_priv(host); int ret; ret = sdhci_suspend_host(host); @@ -301,7 +292,7 @@ static int sdhci_suspend(struct device *dev) static int sdhci_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); - struct spear_sdhci *sdhci = dev_get_platdata(dev); + struct spear_sdhci *sdhci = sdhci_priv(host); int ret; ret = clk_enable(sdhci->clk); |