diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-02-28 16:32:34 -0500 |
---|---|---|
committer | Chris Ball <chris@printf.net> | 2014-03-04 16:28:39 -0500 |
commit | fcdb7c8f5019f77b1f55739a1caf9168d3b455d4 (patch) | |
tree | 521af2903ea711ab26d85289d4a4efab48d427d4 /drivers/mmc | |
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>
Diffstat (limited to 'drivers/mmc')
-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) | |||
105 | struct sdhci_host *host; | 105 | struct sdhci_host *host; |
106 | struct resource *iomem; | 106 | struct resource *iomem; |
107 | struct spear_sdhci *sdhci; | 107 | struct spear_sdhci *sdhci; |
108 | struct device *dev; | ||
108 | int ret; | 109 | int ret; |
109 | 110 | ||
110 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 111 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -121,25 +122,28 @@ static int sdhci_probe(struct platform_device *pdev) | |||
121 | goto err; | 122 | goto err; |
122 | } | 123 | } |
123 | 124 | ||
124 | sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL); | 125 | dev = pdev->dev.parent ? pdev->dev.parent : &pdev->dev; |
125 | if (!sdhci) { | 126 | host = sdhci_alloc_host(dev, sizeof(*sdhci)); |
126 | ret = -ENOMEM; | 127 | if (IS_ERR(host)) { |
128 | ret = PTR_ERR(host); | ||
127 | dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); | 129 | dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); |
128 | goto err; | 130 | goto err; |
129 | } | 131 | } |
130 | 132 | ||
133 | sdhci = sdhci_priv(host); | ||
134 | |||
131 | /* clk enable */ | 135 | /* clk enable */ |
132 | sdhci->clk = devm_clk_get(&pdev->dev, NULL); | 136 | sdhci->clk = devm_clk_get(&pdev->dev, NULL); |
133 | if (IS_ERR(sdhci->clk)) { | 137 | if (IS_ERR(sdhci->clk)) { |
134 | ret = PTR_ERR(sdhci->clk); | 138 | ret = PTR_ERR(sdhci->clk); |
135 | dev_dbg(&pdev->dev, "Error getting clock\n"); | 139 | dev_dbg(&pdev->dev, "Error getting clock\n"); |
136 | goto err; | 140 | goto err_host; |
137 | } | 141 | } |
138 | 142 | ||
139 | ret = clk_prepare_enable(sdhci->clk); | 143 | ret = clk_prepare_enable(sdhci->clk); |
140 | if (ret) { | 144 | if (ret) { |
141 | dev_dbg(&pdev->dev, "Error enabling clock\n"); | 145 | dev_dbg(&pdev->dev, "Error enabling clock\n"); |
142 | goto err; | 146 | goto err_host; |
143 | } | 147 | } |
144 | 148 | ||
145 | ret = clk_set_rate(sdhci->clk, 50000000); | 149 | ret = clk_set_rate(sdhci->clk, 50000000); |
@@ -157,19 +161,6 @@ static int sdhci_probe(struct platform_device *pdev) | |||
157 | sdhci->data = dev_get_platdata(&pdev->dev); | 161 | sdhci->data = dev_get_platdata(&pdev->dev); |
158 | } | 162 | } |
159 | 163 | ||
160 | pdev->dev.platform_data = sdhci; | ||
161 | |||
162 | if (pdev->dev.parent) | ||
163 | host = sdhci_alloc_host(pdev->dev.parent, 0); | ||
164 | else | ||
165 | host = sdhci_alloc_host(&pdev->dev, 0); | ||
166 | |||
167 | if (IS_ERR(host)) { | ||
168 | ret = PTR_ERR(host); | ||
169 | dev_dbg(&pdev->dev, "error allocating host\n"); | ||
170 | goto disable_clk; | ||
171 | } | ||
172 | |||
173 | host->hw_name = "sdhci"; | 164 | host->hw_name = "sdhci"; |
174 | host->ops = &sdhci_pltfm_ops; | 165 | host->ops = &sdhci_pltfm_ops; |
175 | host->irq = platform_get_irq(pdev, 0); | 166 | host->irq = platform_get_irq(pdev, 0); |
@@ -180,13 +171,13 @@ static int sdhci_probe(struct platform_device *pdev) | |||
180 | if (!host->ioaddr) { | 171 | if (!host->ioaddr) { |
181 | ret = -ENOMEM; | 172 | ret = -ENOMEM; |
182 | dev_dbg(&pdev->dev, "failed to remap registers\n"); | 173 | dev_dbg(&pdev->dev, "failed to remap registers\n"); |
183 | goto free_host; | 174 | goto disable_clk; |
184 | } | 175 | } |
185 | 176 | ||
186 | ret = sdhci_add_host(host); | 177 | ret = sdhci_add_host(host); |
187 | if (ret) { | 178 | if (ret) { |
188 | dev_dbg(&pdev->dev, "error adding host\n"); | 179 | dev_dbg(&pdev->dev, "error adding host\n"); |
189 | goto free_host; | 180 | goto disable_clk; |
190 | } | 181 | } |
191 | 182 | ||
192 | platform_set_drvdata(pdev, host); | 183 | platform_set_drvdata(pdev, host); |
@@ -257,10 +248,10 @@ static int sdhci_probe(struct platform_device *pdev) | |||
257 | 248 | ||
258 | set_drvdata: | 249 | set_drvdata: |
259 | sdhci_remove_host(host, 1); | 250 | sdhci_remove_host(host, 1); |
260 | free_host: | ||
261 | sdhci_free_host(host); | ||
262 | disable_clk: | 251 | disable_clk: |
263 | clk_disable_unprepare(sdhci->clk); | 252 | clk_disable_unprepare(sdhci->clk); |
253 | err_host: | ||
254 | sdhci_free_host(host); | ||
264 | err: | 255 | err: |
265 | dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); | 256 | dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); |
266 | return ret; | 257 | return ret; |
@@ -269,7 +260,7 @@ err: | |||
269 | static int sdhci_remove(struct platform_device *pdev) | 260 | static int sdhci_remove(struct platform_device *pdev) |
270 | { | 261 | { |
271 | struct sdhci_host *host = platform_get_drvdata(pdev); | 262 | struct sdhci_host *host = platform_get_drvdata(pdev); |
272 | struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); | 263 | struct spear_sdhci *sdhci = sdhci_priv(host); |
273 | int dead = 0; | 264 | int dead = 0; |
274 | u32 scratch; | 265 | u32 scratch; |
275 | 266 | ||
@@ -278,8 +269,8 @@ static int sdhci_remove(struct platform_device *pdev) | |||
278 | dead = 1; | 269 | dead = 1; |
279 | 270 | ||
280 | sdhci_remove_host(host, dead); | 271 | sdhci_remove_host(host, dead); |
281 | sdhci_free_host(host); | ||
282 | clk_disable_unprepare(sdhci->clk); | 272 | clk_disable_unprepare(sdhci->clk); |
273 | sdhci_free_host(host); | ||
283 | 274 | ||
284 | return 0; | 275 | return 0; |
285 | } | 276 | } |
@@ -288,7 +279,7 @@ static int sdhci_remove(struct platform_device *pdev) | |||
288 | static int sdhci_suspend(struct device *dev) | 279 | static int sdhci_suspend(struct device *dev) |
289 | { | 280 | { |
290 | struct sdhci_host *host = dev_get_drvdata(dev); | 281 | struct sdhci_host *host = dev_get_drvdata(dev); |
291 | struct spear_sdhci *sdhci = dev_get_platdata(dev); | 282 | struct spear_sdhci *sdhci = sdhci_priv(host); |
292 | int ret; | 283 | int ret; |
293 | 284 | ||
294 | ret = sdhci_suspend_host(host); | 285 | ret = sdhci_suspend_host(host); |
@@ -301,7 +292,7 @@ static int sdhci_suspend(struct device *dev) | |||
301 | static int sdhci_resume(struct device *dev) | 292 | static int sdhci_resume(struct device *dev) |
302 | { | 293 | { |
303 | struct sdhci_host *host = dev_get_drvdata(dev); | 294 | struct sdhci_host *host = dev_get_drvdata(dev); |
304 | struct spear_sdhci *sdhci = dev_get_platdata(dev); | 295 | struct spear_sdhci *sdhci = sdhci_priv(host); |
305 | int ret; | 296 | int ret; |
306 | 297 | ||
307 | ret = clk_enable(sdhci->clk); | 298 | ret = clk_enable(sdhci->clk); |