mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
fsl_usb2_udc: Fix oops on probe failure.
In some circumstances when fsl_udc_probe fails udc_controller is freed but the pointer remains non-NULL. fsl_udc_remove will then try and teardown the partly initialized and freed controller structure resulting in an oops. This patch ensures udc_controller is either NULL or fully initialized after fsl_udc_probe. Signed-off-by: Will Newton <will.newton@gmail.com> Acked-by: Li Yang <leoli@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
59097fb73c
commit
23d7cd040e
@ -2244,21 +2244,21 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
kfree(udc_controller);
|
ret = -ENXIO;
|
||||||
return -ENXIO;
|
goto err_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request_mem_region(res->start, res->end - res->start + 1,
|
if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||||
driver_name)) {
|
driver_name)) {
|
||||||
ERR("request mem region for %s failed\n", pdev->name);
|
ERR("request mem region for %s failed\n", pdev->name);
|
||||||
kfree(udc_controller);
|
ret = -EBUSY;
|
||||||
return -EBUSY;
|
goto err_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
dr_regs = ioremap(res->start, res->end - res->start + 1);
|
dr_regs = ioremap(res->start, res->end - res->start + 1);
|
||||||
if (!dr_regs) {
|
if (!dr_regs) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err1;
|
goto err_release_mem_region;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_sys_regs = (struct usb_sys_interface *)
|
usb_sys_regs = (struct usb_sys_interface *)
|
||||||
@ -2269,7 +2269,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||||||
if (!(dccparams & DCCPARAMS_DC)) {
|
if (!(dccparams & DCCPARAMS_DC)) {
|
||||||
ERR("This SOC doesn't support device role\n");
|
ERR("This SOC doesn't support device role\n");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err2;
|
goto err_iounmap;
|
||||||
}
|
}
|
||||||
/* Get max device endpoints */
|
/* Get max device endpoints */
|
||||||
/* DEN is bidirectional ep number, max_ep doubles the number */
|
/* DEN is bidirectional ep number, max_ep doubles the number */
|
||||||
@ -2278,7 +2278,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||||||
udc_controller->irq = platform_get_irq(pdev, 0);
|
udc_controller->irq = platform_get_irq(pdev, 0);
|
||||||
if (!udc_controller->irq) {
|
if (!udc_controller->irq) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err2;
|
goto err_iounmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
|
ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
|
||||||
@ -2286,14 +2286,14 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
ERR("cannot request irq %d err %d\n",
|
ERR("cannot request irq %d err %d\n",
|
||||||
udc_controller->irq, ret);
|
udc_controller->irq, ret);
|
||||||
goto err2;
|
goto err_iounmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the udc structure including QH member and other member */
|
/* Initialize the udc structure including QH member and other member */
|
||||||
if (struct_udc_setup(udc_controller, pdev)) {
|
if (struct_udc_setup(udc_controller, pdev)) {
|
||||||
ERR("Can't initialize udc data structure\n");
|
ERR("Can't initialize udc data structure\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err3;
|
goto err_free_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize usb hw reg except for regs for EP,
|
/* initialize usb hw reg except for regs for EP,
|
||||||
@ -2314,7 +2314,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||||||
udc_controller->gadget.dev.parent = &pdev->dev;
|
udc_controller->gadget.dev.parent = &pdev->dev;
|
||||||
ret = device_register(&udc_controller->gadget.dev);
|
ret = device_register(&udc_controller->gadget.dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err3;
|
goto err_free_irq;
|
||||||
|
|
||||||
/* setup QH and epctrl for ep0 */
|
/* setup QH and epctrl for ep0 */
|
||||||
ep0_setup(udc_controller);
|
ep0_setup(udc_controller);
|
||||||
@ -2344,20 +2344,22 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||||||
DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
|
DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
|
||||||
if (udc_controller->td_pool == NULL) {
|
if (udc_controller->td_pool == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err4;
|
goto err_unregister;
|
||||||
}
|
}
|
||||||
create_proc_file();
|
create_proc_file();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err4:
|
err_unregister:
|
||||||
device_unregister(&udc_controller->gadget.dev);
|
device_unregister(&udc_controller->gadget.dev);
|
||||||
err3:
|
err_free_irq:
|
||||||
free_irq(udc_controller->irq, udc_controller);
|
free_irq(udc_controller->irq, udc_controller);
|
||||||
err2:
|
err_iounmap:
|
||||||
iounmap(dr_regs);
|
iounmap(dr_regs);
|
||||||
err1:
|
err_release_mem_region:
|
||||||
release_mem_region(res->start, res->end - res->start + 1);
|
release_mem_region(res->start, res->end - res->start + 1);
|
||||||
|
err_kfree:
|
||||||
kfree(udc_controller);
|
kfree(udc_controller);
|
||||||
|
udc_controller = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user