iwlwifi: enable serialization of synchronous commands
authorReinette Chatre <reinette.chatre@intel.com>
Fri, 19 Feb 2010 06:03:04 +0000 (22:03 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 19 Feb 2010 20:52:49 +0000 (15:52 -0500)
Until now it was only possible to have one synchronous command running at
any time. If a synchronous command is in progress when a second request
arrives then the second command will fail. Create a new mutex specific for
this purpose to only allow one synchronous command at a time, but enable
other commands to wait instead of fail if a synchronous command is in
progress.

Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c

index 4157c6c8645faf1434300024e5311867f242abb7..52b6beb371fe846f0c0e648d56a4c69c17f45913 100644 (file)
@@ -3364,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
        INIT_LIST_HEAD(&priv->free_frames);
 
        mutex_init(&priv->mutex);
+       mutex_init(&priv->sync_cmd_mutex);
 
        /* Clear the driver's (not device's) station table */
        iwl_clear_stations_table(priv);
index 530fae8cf16dd941fe9eab025ceb3f52acd8677d..6347d4b5c22f899a4544d9b6ac08e71753a80018 100644 (file)
@@ -603,7 +603,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 /*************** DRIVER STATUS FUNCTIONS   *****/
 
 #define STATUS_HCMD_ACTIVE     0       /* host command in progress */
-#define STATUS_HCMD_SYNC_ACTIVE        1       /* sync host command in progress */
+/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
 #define STATUS_INT_ENABLED     2
 #define STATUS_RF_KILL_HW      3
 #define STATUS_CT_KILL         4
index 78298be0bdb609173fc54be97a495d429d72d523..7241fda022c56b6271c9c1df9b46bbe4b4615960 100644 (file)
@@ -530,8 +530,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
 
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
                test_bit(STATUS_HCMD_ACTIVE, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_SYNC_ACTIVE: %d\n",
-               test_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
                test_bit(STATUS_INT_ENABLED, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
index f81317d478ee1b20b8bbde0162ef95d8feabae4a..021c68658718ce45fba35b43d522f44d2da059f5 100644 (file)
@@ -1111,6 +1111,7 @@ struct iwl_priv {
        spinlock_t hcmd_lock;   /* protect hcmd */
        spinlock_t reg_lock;    /* protect hw register access */
        struct mutex mutex;
+       struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
 
        /* basic pci-network driver stuff */
        struct pci_dev *pci_dev;
index 86783c27d97c9a930e94befabfdf75878dc70215..73681c4fefe718232eeb96163c5c5a33e137a871 100644 (file)
@@ -164,15 +164,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
         /* A synchronous command can not have a callback set. */
        BUG_ON(cmd->callback);
 
-       if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
-               IWL_ERR(priv,
-                       "Error sending %s: Already sending a host command\n",
+       IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
                        get_cmd_string(cmd->id));
-               ret = -EBUSY;
-               goto out;
-       }
+       mutex_lock(&priv->sync_cmd_mutex);
 
        set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+       IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s \n",
+                       get_cmd_string(cmd->id));
 
        cmd_idx = iwl_enqueue_hcmd(priv, cmd);
        if (cmd_idx < 0) {
@@ -193,6 +191,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
                        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+                       IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+                                      get_cmd_string(cmd->id));
                        ret = -ETIMEDOUT;
                        goto cancel;
                }
@@ -237,7 +237,7 @@ fail:
                cmd->reply_page = 0;
        }
 out:
-       clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
+       mutex_unlock(&priv->sync_cmd_mutex);
        return ret;
 }
 EXPORT_SYMBOL(iwl_send_cmd_sync);
index d8c11f955e4234bdd501f17da877c4d66cdfcbf4..38655ad8f43cd85f12b16eadeb1e96f0ff93f89e 100644 (file)
@@ -1238,6 +1238,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
        if (!(meta->flags & CMD_ASYNC)) {
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+               IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+                              get_cmd_string(cmd->hdr.cmd));
                wake_up_interruptible(&priv->wait_command_queue);
        }
 }
index 0e5a1ca3033406d4667dad9059d459dad957f791..54daa38ecba3b1475bcff226be08b8be1375f9d1 100644 (file)
@@ -3847,6 +3847,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        INIT_LIST_HEAD(&priv->free_frames);
 
        mutex_init(&priv->mutex);
+       mutex_init(&priv->sync_cmd_mutex);
 
        /* Clear the driver's (not device's) station table */
        iwl_clear_stations_table(priv);