| From f405387435a85a440d1ce16f3ca36e042281643a Mon Sep 17 00:00:00 2001 |
| From: Sergei Shtylyov <sshtylyov@ru.mvista.com> |
| Date: Wed, 29 Sep 2010 09:54:29 +0300 |
| Subject: USB: MUSB: fix kernel WARNING/oops when unloading module in OTG mode |
| |
| From: Sergei Shtylyov <sshtylyov@ru.mvista.com> |
| |
| commit f405387435a85a440d1ce16f3ca36e042281643a upstream. |
| |
| Since commit 461972d8a4c94bc44f11a13046041c78a7cf18dd (musb_core: don't call |
| musb_platform_exit() twice), unloading the driver module results in a WARNING |
| "kobject: '(null)' (c73de788): is not initialized, yet kobject_put() is being |
| called." (or even kernel oops) on e.g. DaVincis, though only in the OTG mode. |
| There exists dubious and unbalanced put_device() call in musb_free() which |
| takes place only in the OTG mode. As this commit caused musb_platform_exit() |
| to be called (and so unregister the NOP transceiver) before this put_device() |
| call, this function references already freed memory. |
| |
| On the other hand, all the glue layers miss the otg_put_transceiver() call, |
| complementary to the otg_get_transceiver() call that they do. So, I think |
| the solution is to get rid of the strange put_device() call, and instead |
| call otg_put_transceiver() in the glue layers... |
| |
| Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> |
| Signed-off-by: Felipe Balbi <balbi@ti.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/usb/musb/blackfin.c | 1 + |
| drivers/usb/musb/davinci.c | 2 ++ |
| drivers/usb/musb/musb_core.c | 4 ---- |
| drivers/usb/musb/omap2430.c | 1 + |
| drivers/usb/musb/tusb6010.c | 4 ++++ |
| 5 files changed, 8 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/usb/musb/blackfin.c |
| +++ b/drivers/usb/musb/blackfin.c |
| @@ -397,5 +397,6 @@ int musb_platform_exit(struct musb *musb |
| |
| gpio_free(musb->config->gpio_vrsel); |
| |
| + otg_put_transceiver(musb->xceiv); |
| return 0; |
| } |
| --- a/drivers/usb/musb/davinci.c |
| +++ b/drivers/usb/musb/davinci.c |
| @@ -446,6 +446,7 @@ int __init musb_platform_init(struct mus |
| fail: |
| clk_disable(musb->clock); |
| |
| + otg_put_transceiver(musb->xceiv); |
| usb_nop_xceiv_unregister(); |
| return -ENODEV; |
| } |
| @@ -496,6 +497,7 @@ int musb_platform_exit(struct musb *musb |
| |
| clk_disable(musb->clock); |
| |
| + otg_put_transceiver(musb->xceiv); |
| usb_nop_xceiv_unregister(); |
| |
| return 0; |
| --- a/drivers/usb/musb/musb_core.c |
| +++ b/drivers/usb/musb/musb_core.c |
| @@ -1921,10 +1921,6 @@ static void musb_free(struct musb *musb) |
| dma_controller_destroy(c); |
| } |
| |
| -#ifdef CONFIG_USB_MUSB_OTG |
| - put_device(musb->xceiv->dev); |
| -#endif |
| - |
| #ifdef CONFIG_USB_MUSB_HDRC_HCD |
| usb_put_hcd(musb_to_hcd(musb)); |
| #else |
| --- a/drivers/usb/musb/omap2430.c |
| +++ b/drivers/usb/musb/omap2430.c |
| @@ -320,5 +320,6 @@ int musb_platform_exit(struct musb *musb |
| |
| musb_platform_suspend(musb); |
| |
| + otg_put_transceiver(musb->xceiv); |
| return 0; |
| } |
| --- a/drivers/usb/musb/tusb6010.c |
| +++ b/drivers/usb/musb/tusb6010.c |
| @@ -1152,6 +1152,8 @@ done: |
| if (ret < 0) { |
| if (sync) |
| iounmap(sync); |
| + |
| + otg_put_transceiver(musb->xceiv); |
| usb_nop_xceiv_unregister(); |
| } |
| return ret; |
| @@ -1166,6 +1168,8 @@ int musb_platform_exit(struct musb *musb |
| musb->board_set_power(0); |
| |
| iounmap(musb->sync_va); |
| + |
| + otg_put_transceiver(musb->xceiv); |
| usb_nop_xceiv_unregister(); |
| return 0; |
| } |