OSDN Git Service

net: wireless: bcmdhd: Move FW hang processign to work queue
authorDmitry Shmidt <dimitrysh@google.com>
Mon, 2 Apr 2012 17:27:13 +0000 (10:27 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Mon, 2 Apr 2012 23:01:59 +0000 (16:01 -0700)
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
drivers/net/wireless/bcmdhd/dhd_linux.c

index 0205e7c..1e28fb8 100644 (file)
@@ -129,6 +129,9 @@ DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
 #if defined(OOB_INTR_ONLY)
 extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
 #endif /* defined(OOB_INTR_ONLY) */
+
+static void dhd_hang_process(struct work_struct *work);
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
 MODULE_LICENSE("GPL v2");
 #endif /* LinuxVer */
@@ -247,6 +250,7 @@ typedef struct dhd_info {
        bool dhd_tasklet_create;
 #endif /* DHDTHREAD */
        tsk_ctl_t       thr_sysioc_ctl;
+       struct work_struct work_hang;
 
        /* Wakelocks */
 #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -2750,6 +2754,8 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        }
        dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
 
+       INIT_WORK(&dhd->work_hang, dhd_hang_process);
+
        /*
         * Save the dhd_info into the priv
         */
@@ -3632,6 +3638,8 @@ void dhd_detach(dhd_pub_t *dhdp)
        }
 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
 
+       cancel_work_sync(&dhd->work_hang);
+
 #if defined(WL_WIRELESS_EXT)
        if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
                /* Detatch and unlink in the iw */
@@ -4443,29 +4451,37 @@ dhd_dev_get_pno_status(struct net_device *dev)
 
 #endif /* PNO_SUPPORT */
 
+static void dhd_hang_process(struct work_struct *work)
+{
+       dhd_info_t *dhd;
+       struct net_device *dev;
+
+       dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang);
+       dev = dhd->iflist[0]->net;
+
+       if (dev) {
+               rtnl_lock();
+               dev_close(dev);
+               rtnl_unlock();
+#if defined(WL_WIRELESS_EXT)
+               wl_iw_send_priv_event(dev, "HANG");
+#endif
+#if defined(WL_CFG80211)
+               wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
+       }
+}
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
 int net_os_send_hang_message(struct net_device *dev)
 {
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
        int ret = 0;
-       int need_unlock = 0;
 
        if (dhd) {
                if (!dhd->pub.hang_was_sent) {
                        dhd->pub.hang_was_sent = 1;
-                       if (!rtnl_is_locked()) {
-                               need_unlock = 1;
-                               rtnl_lock();
-                       }
-                       dev_close(dev);
-                       if (need_unlock)
-                               rtnl_unlock();
-#if defined(WL_WIRELESS_EXT)
-                       ret = wl_iw_send_priv_event(dev, "HANG");
-#endif
-#if defined(WL_CFG80211)
-                       ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
-#endif
+                       schedule_work(&dhd->work_hang);
                }
        }
        return ret;