summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2012-04-02 10:27:13 -0700
committerOm Prakash Singh <omp@nvidia.com>2012-06-15 14:15:16 +0530
commit0b11bef2e7e660cc56d644f55b26843c66a9904b (patch)
treee6ba28b05abbe7ca315c924ae6cfce0e0889298a /drivers/net
parent76cc5ed02844a7ba70190e0d257ed6bb5637e1fc (diff)
net: wireless: bcmdhd: Move FW hang processign to work queue
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 80f53b346ced..6cd0d7002c19 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -130,6 +130,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 */
@@ -248,6 +251,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))
@@ -2752,6 +2756,8 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
}
dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
+ INIT_WORK(&dhd->work_hang, dhd_hang_process);
+
/*
* Save the dhd_info into the priv
*/
@@ -3634,6 +3640,8 @@ void dhd_detach(dhd_pub_t *dhdp)
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+ cancel_work_sync(&dhd->work_hang);
+
#if defined(CONFIG_BCMDHD_WEXT)
if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
/* Detatch and unlink in the iw */
@@ -4445,29 +4453,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(CONFIG_BCMDHD_WEXT)
- 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;