[PATCH] libertas: push WEXT scan requests to a work queue
authorDan Williams <dcbw@redhat.com>
Thu, 2 Aug 2007 17:19:04 +0000 (13:19 -0400)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 10 Oct 2007 23:50:14 +0000 (16:50 -0700)
Push WEXT scan requests to a workqueue and have each partial scan queue
the next part, then only report results when the complete scan has finished.
Full scans don't go through the work queue.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/libertas/assoc.h
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/libertas/scan.h

index 5e9c31f0932b1d64377184c5fa038c16dbbdd19f..e09b7490abbdf18710cb1b112dab29d912efe8b9 100644 (file)
@@ -17,7 +17,7 @@ static inline void wlan_postpone_association_work(wlan_private *priv)
        if (priv->adapter->surpriseremoved)
                return;
        cancel_delayed_work(&priv->assoc_work);
-       queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+       queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY);
 }
 
 static inline void wlan_cancel_association_work(wlan_private *priv)
index 5697fec0cb1ddc1b665cd1eaea7447819699802e..762c4792774c0efb0f2ed052714bddaa41426228 100644 (file)
@@ -148,9 +148,10 @@ struct _wlan_private {
        /** thread to service interrupts */
        struct task_struct *main_thread;
        wait_queue_head_t waitq;
+       struct workqueue_struct *work_thread;
 
+       struct delayed_work scan_work;
        struct delayed_work assoc_work;
-       struct workqueue_struct *assoc_thread;
        struct work_struct sync_channel;
 
        /** Hardware access */
index 9a46339ce47e628bb2be1696586a0b10fd515072..bcd845060d4a5654a8201338ba3d5936ac733594 100644 (file)
@@ -1269,9 +1269,10 @@ int libertas_activate_card(wlan_private *priv)
                goto done;
        }
 
-       priv->assoc_thread =
-               create_singlethread_workqueue("libertas_assoc");
+       priv->work_thread = create_singlethread_workqueue("libertas_worker");
        INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+       INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
+
        INIT_WORK(&priv->sync_channel, libertas_sync_channel);
 
        /*
@@ -1305,7 +1306,7 @@ int libertas_activate_card(wlan_private *priv)
 err_init_fw:
        priv->hw_unregister_dev(priv);
 err_registerdev:
-       destroy_workqueue(priv->assoc_thread);
+       destroy_workqueue(priv->work_thread);
        /* Stop the thread servicing the interrupts */
        wake_up_interruptible(&priv->waitq);
        kthread_stop(priv->main_thread);
@@ -1426,8 +1427,9 @@ int libertas_remove_card(wlan_private *priv)
 
        unregister_netdev(dev);
 
+       cancel_delayed_work(&priv->scan_work);
        cancel_delayed_work(&priv->assoc_work);
-       destroy_workqueue(priv->assoc_thread);
+       destroy_workqueue(priv->work_thread);
 
        if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
                adapter->psmode = WLAN802_11POWERMODECAM;
index 8d4e1ee273959cb056d0a5a14dbe1e4058b80068..e2e9ebcd8340372e280de4d0d92632d1197dec4b 100644 (file)
@@ -314,6 +314,16 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
        }
 }
 
+
+/* Delayed partial scan worker */
+void libertas_scan_worker(struct work_struct *work)
+{
+       wlan_private *priv = container_of(work, wlan_private, scan_work.work);
+
+       wlan_scan_networks(priv, NULL, 0);
+}
+
+
 /**
  *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
  *
@@ -408,7 +418,6 @@ wlan_scan_setup_scan_config(wlan_private * priv,
        *pscancurrentonly = 0;
 
        if (puserscanin) {
-
                /* Set the bss type scan filter, use adapter setting if unset */
                pscancfgout->bsstype =
                    puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
@@ -468,59 +477,57 @@ wlan_scan_setup_scan_config(wlan_private * priv,
         */
        *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
 
-       if (puserscanin && puserscanin->chanlist[0].channumber) {
+       if (!puserscanin || !puserscanin->chanlist[0].channumber) {
+               /* Create a default channel scan list */
+               lbs_deb_scan("Scan: Creating full region channel list\n");
+               wlan_scan_create_channel_list(priv, pscanchanlist,
+                                             *pfilteredscan);
+               goto out;
+       }
 
-               lbs_deb_scan("Scan: Using supplied channel list\n");
+       lbs_deb_scan("Scan: Using supplied channel list\n");
+       for (chanidx = 0;
+            chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+            && puserscanin->chanlist[chanidx].channumber; chanidx++) {
 
-               for (chanidx = 0;
-                    chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
-                    && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+               channel = puserscanin->chanlist[chanidx].channumber;
+               (pscanchanlist + chanidx)->channumber = channel;
 
-                       channel = puserscanin->chanlist[chanidx].channumber;
-                       (pscanchanlist + chanidx)->channumber = channel;
+               radiotype = puserscanin->chanlist[chanidx].radiotype;
+               (pscanchanlist + chanidx)->radiotype = radiotype;
 
-                       radiotype = puserscanin->chanlist[chanidx].radiotype;
-                       (pscanchanlist + chanidx)->radiotype = radiotype;
+               scantype = puserscanin->chanlist[chanidx].scantype;
 
-                       scantype = puserscanin->chanlist[chanidx].scantype;
+               if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+                       (pscanchanlist +
+                        chanidx)->chanscanmode.passivescan = 1;
+               } else {
+                       (pscanchanlist +
+                        chanidx)->chanscanmode.passivescan = 0;
+               }
 
+               if (puserscanin->chanlist[chanidx].scantime) {
+                       scandur = puserscanin->chanlist[chanidx].scantime;
+               } else {
                        if (scantype == CMD_SCAN_TYPE_PASSIVE) {
-                               (pscanchanlist +
-                                chanidx)->chanscanmode.passivescan = 1;
-                       } else {
-                               (pscanchanlist +
-                                chanidx)->chanscanmode.passivescan = 0;
-                       }
-
-                       if (puserscanin->chanlist[chanidx].scantime) {
-                               scandur =
-                                   puserscanin->chanlist[chanidx].scantime;
+                               scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
                        } else {
-                               if (scantype == CMD_SCAN_TYPE_PASSIVE) {
-                                       scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
-                               } else {
-                                       scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
-                               }
+                               scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
                        }
-
-                       (pscanchanlist + chanidx)->minscantime =
-                           cpu_to_le16(scandur);
-                       (pscanchanlist + chanidx)->maxscantime =
-                           cpu_to_le16(scandur);
                }
 
-               /* Check if we are only scanning the current channel */
-               if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
-                                      ==
-                                      priv->adapter->curbssparams.channel)) {
-                       *pscancurrentonly = 1;
-                       lbs_deb_scan("Scan: Scanning current channel only");
-               }
+               (pscanchanlist + chanidx)->minscantime =
+                   cpu_to_le16(scandur);
+               (pscanchanlist + chanidx)->maxscantime =
+                   cpu_to_le16(scandur);
+       }
 
-       } else {
-               lbs_deb_scan("Scan: Creating full region channel list\n");
-               wlan_scan_create_channel_list(priv, pscanchanlist,
-                                             *pfilteredscan);
+       /* Check if we are only scanning the current channel */
+       if ((chanidx == 1) &&
+           (puserscanin->chanlist[0].channumber ==
+                              priv->adapter->curbssparams.channel)) {
+               *pscancurrentonly = 1;
+               lbs_deb_scan("Scan: Scanning current channel only");
        }
 
 out:
@@ -604,12 +611,12 @@ static int wlan_scan_channel_list(wlan_private * priv,
                while (tlvidx < maxchanperscan && ptmpchan->channumber
                       && !doneearly && scanned < 2) {
 
-            lbs_deb_scan(
-                    "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
-                ptmpchan->channumber, ptmpchan->radiotype,
-                ptmpchan->chanscanmode.passivescan,
-                ptmpchan->chanscanmode.disablechanfilt,
-                ptmpchan->maxscantime);
+                       lbs_deb_scan("Scan: Chan(%3d), Radio(%d), mode(%d,%d), "
+                                    "Dur(%d)\n",
+                                    ptmpchan->channumber, ptmpchan->radiotype,
+                                    ptmpchan->chanscanmode.passivescan,
+                                    ptmpchan->chanscanmode.disablechanfilt,
+                                    ptmpchan->maxscantime);
 
                        /* Copy the current channel TLV to the command being prepared */
                        memcpy(pchantlvout->chanscanparam + tlvidx,
@@ -678,9 +685,18 @@ static int wlan_scan_channel_list(wlan_private * priv,
 done:
        priv->adapter->last_scanned_channel = ptmpchan->channumber;
 
-       /* Tell userspace the scan table has been updated */
-       memset(&wrqu, 0, sizeof(union iwreq_data));
-       wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+       if (priv->adapter->last_scanned_channel) {
+               /* Schedule the next part of the partial scan */
+               if (!full_scan && !priv->adapter->surpriseremoved) {
+                       cancel_delayed_work(&priv->scan_work);
+                       queue_delayed_work(priv->work_thread, &priv->scan_work,
+                                          msecs_to_jiffies(300));
+               }
+       } else {
+               /* All done, tell userspace the scan table has been updated */
+               memset(&wrqu, 0, sizeof(union iwreq_data));
+               wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+       }
 
        lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
        return ret;
@@ -747,8 +763,8 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
  *  @return              0 or < 0 if error
  */
 int wlan_scan_networks(wlan_private * priv,
-                             const struct wlan_ioctl_user_scan_cfg * puserscanin,
-                             int full_scan)
+                       const struct wlan_ioctl_user_scan_cfg * puserscanin,
+                       int full_scan)
 {
        wlan_adapter * adapter = priv->adapter;
        struct mrvlietypes_chanlistparamset *pchantlvout;
@@ -763,7 +779,13 @@ int wlan_scan_networks(wlan_private * priv,
        int i = 0;
 #endif
 
-       lbs_deb_enter(LBS_DEB_ASSOC);
+       lbs_deb_enter(LBS_DEB_SCAN);
+
+       /* Cancel any partial outstanding partial scans if this scan
+        * is a full scan.
+        */
+       if (full_scan && delayed_work_pending(&priv->scan_work))
+               cancel_delayed_work(&priv->scan_work);
 
        scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
                                WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
@@ -1289,7 +1311,10 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
 
        lbs_deb_enter(LBS_DEB_SCAN);
 
-       wlan_scan_networks(priv, NULL, 0);
+       if (!delayed_work_pending(&priv->scan_work)) {
+               queue_delayed_work(priv->work_thread, &priv->scan_work,
+                                  msecs_to_jiffies(50));
+       }
 
        if (adapter->surpriseremoved)
                return -1;
@@ -1508,10 +1533,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
 
        lbs_deb_enter(LBS_DEB_ASSOC);
 
-       /* If we've got an uncompleted scan, schedule the next part */
-       if (!adapter->nr_cmd_pending && adapter->last_scanned_channel)
-               wlan_scan_networks(priv, NULL, 0);
-
        /* Update RSSI if current BSS is a locally created ad-hoc BSS */
        if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
                libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
index 9bb1a435c28aaa626f8e5d4711d9626891c5b041..c29c031bef8cf8a9798ee9bf31e9314e0acc0676 100644 (file)
@@ -210,4 +210,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
 int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
                         struct iw_param *vwrq, char *extra);
 
+void libertas_scan_worker(struct work_struct *work);
+
 #endif                         /* _WLAN_SCAN_H */