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

usb: ehci-orion: fix clock reference leaking

In order to disable the clock in the ->remove() function, a call to
devm_clk_get() is being made, which further increases the reference
count of the clock.

In order to clean this up, a private structure holding a pointer to
the clock is added using the override mechanism provided by the ehci
framework. This makes the driver clock handling much more logical.

The bug was introduced in v3.6, however the ehci framework allowing to
use the override mechanism has only been introduced in v3.8, so this
patch won't apply before it.

[Thomas: reword commit log, fix goto label names.]

Fixes: 8c869edaee07c623066266827371235fb9c12e01 ('ARM: Orion: EHCI: Add support for enabling clocks')
Cc: <stable@vger.kernel.org> # v3.8+
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Gregory CLEMENT and committed by
Greg Kroah-Hartman
ac069662 d8ea69e2

+29 -16
+29 -16
drivers/usb/host/ehci-orion.c
··· 42 42 43 43 #define DRIVER_DESC "EHCI orion driver" 44 44 45 + #define hcd_to_orion_priv(h) ((struct orion_ehci_hcd *)hcd_to_ehci(h)->priv) 46 + 47 + struct orion_ehci_hcd { 48 + struct clk *clk; 49 + }; 50 + 45 51 static const char hcd_name[] = "ehci-orion"; 46 52 47 53 static struct hc_driver __read_mostly ehci_orion_hc_driver; ··· 143 137 } 144 138 } 145 139 140 + static const struct ehci_driver_overrides orion_overrides __initconst = { 141 + .extra_priv_size = sizeof(struct orion_ehci_hcd), 142 + }; 143 + 146 144 static int ehci_orion_drv_probe(struct platform_device *pdev) 147 145 { 148 146 struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev); ··· 154 144 struct resource *res; 155 145 struct usb_hcd *hcd; 156 146 struct ehci_hcd *ehci; 157 - struct clk *clk; 158 147 void __iomem *regs; 159 148 int irq, err; 160 149 enum orion_ehci_phy_ver phy_version; 150 + struct orion_ehci_hcd *priv; 161 151 162 152 if (usb_disabled()) 163 153 return -ENODEV; ··· 197 187 goto err; 198 188 } 199 189 200 - /* Not all platforms can gate the clock, so it is not 201 - an error if the clock does not exists. */ 202 - clk = devm_clk_get(&pdev->dev, NULL); 203 - if (!IS_ERR(clk)) 204 - clk_prepare_enable(clk); 205 - 206 190 hcd = usb_create_hcd(&ehci_orion_hc_driver, 207 191 &pdev->dev, dev_name(&pdev->dev)); 208 192 if (!hcd) { 209 193 err = -ENOMEM; 210 - goto err_create_hcd; 194 + goto err; 211 195 } 212 196 213 197 hcd->rsrc_start = res->start; ··· 211 207 ehci = hcd_to_ehci(hcd); 212 208 ehci->caps = hcd->regs + 0x100; 213 209 hcd->has_tt = 1; 210 + 211 + priv = hcd_to_orion_priv(hcd); 212 + /* 213 + * Not all platforms can gate the clock, so it is not an error if 214 + * the clock does not exists. 215 + */ 216 + priv->clk = devm_clk_get(&pdev->dev, NULL); 217 + if (!IS_ERR(priv->clk)) 218 + clk_prepare_enable(priv->clk); 214 219 215 220 /* 216 221 * (Re-)program MBUS remapping windows if we are asked to. ··· 256 243 return 0; 257 244 258 245 err_add_hcd: 246 + if (!IS_ERR(priv->clk)) 247 + clk_disable_unprepare(priv->clk); 259 248 usb_put_hcd(hcd); 260 - err_create_hcd: 261 - if (!IS_ERR(clk)) 262 - clk_disable_unprepare(clk); 263 249 err: 264 250 dev_err(&pdev->dev, "init %s fail, %d\n", 265 251 dev_name(&pdev->dev), err); ··· 269 257 static int ehci_orion_drv_remove(struct platform_device *pdev) 270 258 { 271 259 struct usb_hcd *hcd = platform_get_drvdata(pdev); 272 - struct clk *clk; 260 + struct orion_ehci_hcd *priv = hcd_to_orion_priv(hcd); 273 261 274 262 usb_remove_hcd(hcd); 263 + 264 + if (!IS_ERR(priv->clk)) 265 + clk_disable_unprepare(priv->clk); 266 + 275 267 usb_put_hcd(hcd); 276 268 277 - clk = devm_clk_get(&pdev->dev, NULL); 278 - if (!IS_ERR(clk)) 279 - clk_disable_unprepare(clk); 280 269 return 0; 281 270 } 282 271 ··· 305 292 306 293 pr_info("%s: " DRIVER_DESC "\n", hcd_name); 307 294 308 - ehci_init_driver(&ehci_orion_hc_driver, NULL); 295 + ehci_init_driver(&ehci_orion_hc_driver, &orion_overrides); 309 296 return platform_driver_register(&ehci_orion_driver); 310 297 } 311 298 module_init(ehci_orion_init);