Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Russell King and committed by
Chris Ball
fcdb7c8f 142dbab9

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