libertas: do not sleep during SIOCSIWSCAN

Marcelo Tosatti mtosatti at redhat.unroutablecom
Mon Dec 11 15:18:31 EST 2006


Commit:     7a61fcc9f6c78aba9d7d32b10baf5bc55f0b63c2
Parent:     f3df41dde8e5532cc626500fb1792cf14616a143
commit 7a61fcc9f6c78aba9d7d32b10baf5bc55f0b63c2
Author:     Marcelo Tosatti <mtosatti at redhat.com>
AuthorDate: Fri Dec 8 17:23:55 2006 -0200
Commit:     Marcelo Tosatti <mtosatti at redhat.com>
CommitDate: Fri Dec 8 17:23:55 2006 -0200

    libertas: do not sleep during SIOCSIWSCAN
    
    Network device ioctl's hold the rtnl_lock, which is required for
    certain workqueue instances.
    
    That in turn might block keventd for the period we're doing the
    scan, which will halt processing of important events in the system.
    
    Fix that by making SIOCSIWSCAN not block but simply queue the scan
    commands, and have SIOCGIWSCAN return -EAGAIN until they have
    been processed.
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
---
 drivers/net/wireless/libertas/wlan_cmd.c     |    1 +
 drivers/net/wireless/libertas/wlan_debugfs.c |    2 ++
 drivers/net/wireless/libertas/wlan_dev.h     |    3 +++
 drivers/net/wireless/libertas/wlan_main.c    |   10 ++++++++++
 drivers/net/wireless/libertas/wlan_scan.c    |   14 ++++++++++++--
 5 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/libertas/wlan_cmd.c b/drivers/net/wireless/libertas/wlan_cmd.c
index bf6426f..f556b58 100644
--- a/drivers/net/wireless/libertas/wlan_cmd.c
+++ b/drivers/net/wireless/libertas/wlan_cmd.c
@@ -1768,6 +1768,7 @@ #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS
 		Adapter->CurCmdRetCode = 0;
 		ret = WLAN_STATUS_FAILURE;
 	}
+	Adapter->is_cmd_pending = 1;
 	spin_unlock_irqrestore(&Adapter->driver_lock, flags);
 
 done:
diff --git a/drivers/net/wireless/libertas/wlan_debugfs.c b/drivers/net/wireless/libertas/wlan_debugfs.c
index 23f307d..47f2a82 100644
--- a/drivers/net/wireless/libertas/wlan_debugfs.c
+++ b/drivers/net/wireless/libertas/wlan_debugfs.c
@@ -398,6 +398,8 @@ static ssize_t libertas_setuserscan(stru
 	libertas_parse_type(buf, count, scan_cfg);
 
 	wlan_scan_networks(priv, scan_cfg);
+	wait_event_interruptible(priv->adapter->cmd_pending, 
+			   	 !priv->adapter->is_cmd_pending);
 
 	memset(&wrqu, 0x00, sizeof(union iwreq_data));
 	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
diff --git a/drivers/net/wireless/libertas/wlan_dev.h b/drivers/net/wireless/libertas/wlan_dev.h
index 8a39a34..467a0f5 100644
--- a/drivers/net/wireless/libertas/wlan_dev.h
+++ b/drivers/net/wireless/libertas/wlan_dev.h
@@ -291,6 +291,9 @@ struct _wlan_adapter {
 	struct list_head CmdFreeQ;
 	/** Pending command buffers */
 	struct list_head CmdPendingQ;
+
+	wait_queue_head_t cmd_pending;
+	u8 is_cmd_pending;
 	/* command related variables protected by adapter->driver_lock */
 
 	/** Async and Sync Event variables */
diff --git a/drivers/net/wireless/libertas/wlan_main.c b/drivers/net/wireless/libertas/wlan_main.c
index db12cc1..ef297c6 100644
--- a/drivers/net/wireless/libertas/wlan_main.c
+++ b/drivers/net/wireless/libertas/wlan_main.c
@@ -878,6 +878,14 @@ static int wlan_service_main_thread(void
 		if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd)
 			libertas_execute_next_command(priv);
 
+		/* Wake-up command waiters which can't sleep in 
+		 * libertas_prepare_and_send_command
+		 */
+		if (!Adapter->CurCmd && list_empty(&Adapter->CmdPendingQ)) {
+			Adapter->is_cmd_pending = 0;
+			wake_up_all(&Adapter->cmd_pending);
+		}
+
 		libertas_tx_runqueue(priv);
 	}
 
@@ -980,6 +988,8 @@ #define NETIF_F_DYNALLOC 16
 	INIT_LIST_HEAD(&priv->adapter->CmdPendingQ);
 
 	spin_lock_init(&priv->adapter->driver_lock);
+	init_waitqueue_head(&priv->adapter->cmd_pending);
+	priv->adapter->is_cmd_pending = 0;
 
 	dprintk(1, "Starting kthread...\n");
 	priv->MainThread.priv = priv;
diff --git a/drivers/net/wireless/libertas/wlan_scan.c b/drivers/net/wireless/libertas/wlan_scan.c
index 20e4059..d8bb118 100644
--- a/drivers/net/wireless/libertas/wlan_scan.c
+++ b/drivers/net/wireless/libertas/wlan_scan.c
@@ -769,8 +769,7 @@ static int wlan_scan_channel_list(wlan_p
 
 		/* Send the scan command to the firmware with the specified cfg */
 		ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SCAN, 0,
-					    HostCmd_OPTION_WAITFORRSP, 0,
-					    pScanCfgOut);
+					    0, 0, pScanCfgOut);
 	}
 
 	LEAVE();
@@ -1432,6 +1431,7 @@ int libertas_find_best_network_SSID(wlan
 	memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
 
 	wlan_scan_networks(priv, NULL);
+	wait_event_interruptible(Adapter->cmd_pending, !Adapter->is_cmd_pending);
 
 	i = libertas_find_best_SSID_in_list(Adapter, preferred_mode);
 	if (i < 0) {
@@ -1524,6 +1524,7 @@ int libertas_send_specific_SSID_scan(wla
 	scanCfg.keepPreviousScan = keepPreviousScan;
 
 	wlan_scan_networks(priv, &scanCfg);
+	wait_event_interruptible(Adapter->cmd_pending, !Adapter->is_cmd_pending);
 
 	if (Adapter->SurpriseRemoved)
 		return WLAN_STATUS_FAILURE;
@@ -1556,6 +1557,8 @@ int libertas_send_specific_BSSID_scan(wl
 	scanCfg.keepPreviousScan = keepPreviousScan;
 
 	wlan_scan_networks(priv, &scanCfg);
+	wait_event_interruptible(priv->adapter->cmd_pending,
+		!priv->adapter->is_cmd_pending);
 
 	LEAVE();
 	return WLAN_STATUS_SUCCESS;
@@ -1596,6 +1599,13 @@ #define RSSI_DIFF    ((u8)(PERFECT_RSSI 
 
 	ENTER();
 
+	/* 
+	 * if there's either commands in the queue or one being 
+	 * processed return -EAGAIN for iwlist to retry later. 
+	 */
+	if (Adapter->is_cmd_pending)
+		return -EAGAIN;
+
 	if (Adapter->MediaConnectStatus == WlanMediaStateConnected)
 		dprintk(1, "Current Ssid: %32s\n",
 		       Adapter->CurBssParams.ssid.Ssid);


More information about the Commits-kernel mailing list