arm: tegra: xmm: device set to null in unregister
Vinayak Pane [Wed, 18 Jul 2012 02:06:54 +0000 (19:06 -0700)]
hsic_unregister is being called multiple times
during two step enumeration process of xmm.
In failure cases when enumeration does not
complete properly, kernel panic is seen because
of extra unregister-ehci device.

Bug 1016593

Change-Id: Ibaeb20ed0dab0e906741fdfad78f7d89a3672f60
Signed-off-by: Vinayak Pane <vpane@nvidia.com>
Reviewed-on: http://git-master/r/116626
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/baseband-xmm-power.c
arch/arm/mach-tegra/baseband-xmm-power.h
arch/arm/mach-tegra/baseband-xmm-power2.c
arch/arm/mach-tegra/board-enterprise.c
arch/arm/mach-tegra/include/mach/tegra-bb-power.h
drivers/misc/tegra-baseband/bb-m7400.c

index 3730231..f196aca 100644 (file)
@@ -66,7 +66,7 @@ static struct usb_device_id xmm_pm_ids[] = {
        .driver_info = 0 },
        {}
 };
-
+MODULE_DEVICE_TABLE(usb, xmm_pm_ids);
 
 static struct gpio tegra_baseband_gpios[] = {
        { -1, GPIOF_OUT_INIT_LOW,  "BB_RSTn" },
@@ -348,11 +348,10 @@ static int xmm_power_off(struct platform_device *device)
 
        /* unregister usb host controller */
        if (pdata->hsic_unregister)
-               pdata->hsic_unregister(data->hsic_device);
+               pdata->hsic_unregister(&data->hsic_device);
        else
                pr_err("%s: hsic_unregister is missing\n", __func__);
 
-
        /* set IPC_HSIC_ACTIVE low */
        gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
 
@@ -819,7 +818,7 @@ static void xmm_device_remove_handler(struct usb_device *udev)
        if (usbdev == udev) {
                pr_info("Remove device %d <%s %s>\n", udev->devnum,
                        udev->manufacturer, udev->product);
-               usbdev = 0;
+               usbdev = NULL;
        }
 
 }
@@ -1038,7 +1037,7 @@ static int xmm_power_driver_remove(struct platform_device *device)
 
        /* unregister usb host controller */
        if (pdata->hsic_unregister)
-               pdata->hsic_unregister(data->hsic_device);
+               pdata->hsic_unregister(&data->hsic_device);
        else
                pr_err("%s: hsic_unregister is missing\n", __func__);
 
index 0c8723f..55c8183 100644 (file)
@@ -41,7 +41,7 @@ enum baseband_type {
 struct baseband_power_platform_data {
        enum baseband_type baseband_type;
        struct platform_device* (*hsic_register)(void);
-       void (*hsic_unregister)(struct platform_device *);
+       void (*hsic_unregister)(struct platform_device **);
        union {
                struct {
                        int mdm_reset;
index 905759d..a79cd6f 100644 (file)
@@ -108,7 +108,7 @@ static void xmm_power2_step1(struct work_struct *work)
 
        /* unregister usb host controller */
        if (pdata->hsic_unregister)
-               pdata->hsic_unregister(data->hsic_device);
+               pdata->hsic_unregister(&data->hsic_device);
        else
                pr_err("%s: hsic_unregister is missing\n", __func__);
 
index 2aeb1a0..31292eb 100644 (file)
@@ -819,9 +819,15 @@ error:
        return NULL;
 }
 
-void tegra_usb_hsic_host_unregister(struct platform_device *pdev)
+void tegra_usb_hsic_host_unregister(struct platform_device **platdev)
 {
-       platform_device_unregister(pdev);
+       struct platform_device *pdev = *platdev;
+
+       if (pdev && &pdev->dev) {
+               platform_device_unregister(pdev);
+               *platdev = NULL;
+       } else
+               pr_err("%s: no platform device\n", __func__);
 }
 
 static void enterprise_usb_init(void)
index e0b7e3d..96e3611 100644 (file)
@@ -50,7 +50,7 @@ union tegra_bb_gpio_id {
 };
 
 typedef struct platform_device* (*ehci_register_cb)(void);
-typedef void (*ehci_unregister_cb)(struct platform_device *);
+typedef void (*ehci_unregister_cb)(struct platform_device **);
 
 struct tegra_bb_pdata {
        union tegra_bb_gpio_id *id;
index adabefd..edde7d1 100644 (file)
@@ -241,7 +241,7 @@ static int m7400_attrib_write(struct device *dev, int value)
        } else {
                /* Unregister ehci controller */
                if (ehci_device != NULL)
-                       pdata->ehci_unregister(ehci_device);
+                       pdata->ehci_unregister(&ehci_device);
 
                /* Signal AP going down */
                m7400_apdown_handshake();