From: Dan Williams <dcbw@redhat.com>
Date: Thu, 2 Aug 2007 17:19:04 +0000 (-0400)
Subject: [PATCH] libertas: push WEXT scan requests to a work queue
X-Git-Tag: v2.6.24-rc1~1454^2~586
X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=2afc0c5d71a3dec6d35f3a234ed986d635ef41ad;p=linux-2.6-omap-h63xx.git

[PATCH] libertas: push WEXT scan requests to a work queue

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>
---

diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 5e9c31f0932..e09b7490abb 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -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)
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 5697fec0cb1..762c4792774 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -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 */
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 9a46339ce47..bcd845060d4 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -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;
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 8d4e1ee2739..e2e9ebcd834 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -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,
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index 9bb1a435c28..c29c031bef8 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -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 */