net: wireless: bcmdhd: do not allow race condition
Mursalin Akon [Thu, 6 Dec 2012 23:40:59 +0000 (15:40 -0800)]
Module "init" turns off wifi chip after registering
the network interface. The chip is turned on at "open".
As "open" is allowed as soon as registration is
complete, the chip turning on and off becomaes a race
condition. We need to enforce a strict ordering between
these two operations.

Bug 1192094

Change-Id: I17e7da0252e1dd5c335722f98e9b54b0585b9690
Signed-off-by: Mursalin Akon <makon@nvidia.com>
Reviewed-on: http://git-master/r/172442
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

drivers/net/wireless/bcmdhd/dhd_linux.c

index 0338ee1..5c6ca07 100644 (file)
@@ -347,6 +347,10 @@ module_param(op_mode, int, 0644);
 extern int wl_control_wl_start(struct net_device *dev);
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
 struct semaphore dhd_registration_sem;
+#if defined(WL_CFG80211)
+struct semaphore dhd_init_sem;
+bool init_power_off = TRUE;
+#endif
 struct semaphore dhd_chipup_sem;
 int dhd_registration_check = FALSE;
 
@@ -2653,6 +2657,15 @@ dhd_open(struct net_device *net)
                atomic_set(&dhd->pend_8021x_cnt, 0);
 #if defined(WL_CFG80211)
                DHD_ERROR(("\n%s\n", dhd_version));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+               /*
+                * if we are here before powering off the chip
+                * in init, put a request of not powering off
+                */
+               down(&dhd_init_sem);
+               init_power_off = FALSE;
+               up(&dhd_init_sem);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
                if (!dhd_download_fw_on_driverload) {
                        ret = wl_android_wifi_on(net);
                        if (ret != 0) {
@@ -4245,6 +4258,9 @@ dhd_module_init(void)
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
        sema_init(&dhd_registration_sem, 0);
+#if defined(WL_CFG80211)
+       sema_init(&dhd_init_sem, 1);
+#endif
 #endif
 
 
@@ -4272,7 +4288,15 @@ dhd_module_init(void)
        }
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
 #if defined(WL_CFG80211)
-       wl_android_post_init();
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+       down(&dhd_init_sem);
+       if (init_power_off)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+               wl_android_post_init();
+       /* init is done, allow open to continue */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+       up(&dhd_init_sem);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
 #endif /* defined(WL_CFG80211) */
 
        return error;