Commit d2dfe6df authored by Reinette Chatre's avatar Reinette Chatre Committed by John W. Linville

iwlwifi: enable serialization of synchronous commands

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: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4a6547c7
...@@ -3364,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv) ...@@ -3364,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames); INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex); mutex_init(&priv->mutex);
mutex_init(&priv->sync_cmd_mutex);
/* Clear the driver's (not device's) station table */ /* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv); iwl_clear_stations_table(priv);
......
...@@ -603,7 +603,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); ...@@ -603,7 +603,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
/*************** DRIVER STATUS FUNCTIONS *****/ /*************** DRIVER STATUS FUNCTIONS *****/
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ #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_INT_ENABLED 2
#define STATUS_RF_KILL_HW 3 #define STATUS_RF_KILL_HW 3
#define STATUS_CT_KILL 4 #define STATUS_CT_KILL 4
......
...@@ -530,8 +530,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *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", pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
test_bit(STATUS_HCMD_ACTIVE, &priv->status)); 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", pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
test_bit(STATUS_INT_ENABLED, &priv->status)); test_bit(STATUS_INT_ENABLED, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
......
...@@ -1111,6 +1111,7 @@ struct iwl_priv { ...@@ -1111,6 +1111,7 @@ struct iwl_priv {
spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t hcmd_lock; /* protect hcmd */
spinlock_t reg_lock; /* protect hw register access */ spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex; struct mutex mutex;
struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
/* basic pci-network driver stuff */ /* basic pci-network driver stuff */
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
......
...@@ -164,15 +164,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ...@@ -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. */ /* A synchronous command can not have a callback set. */
BUG_ON(cmd->callback); BUG_ON(cmd->callback);
if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
IWL_ERR(priv,
"Error sending %s: Already sending a host command\n",
get_cmd_string(cmd->id)); get_cmd_string(cmd->id));
ret = -EBUSY; mutex_lock(&priv->sync_cmd_mutex);
goto out;
}
set_bit(STATUS_HCMD_ACTIVE, &priv->status); 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); cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) { if (cmd_idx < 0) {
...@@ -193,6 +191,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ...@@ -193,6 +191,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
clear_bit(STATUS_HCMD_ACTIVE, &priv->status); 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; ret = -ETIMEDOUT;
goto cancel; goto cancel;
} }
...@@ -237,7 +237,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ...@@ -237,7 +237,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
cmd->reply_page = 0; cmd->reply_page = 0;
} }
out: out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); mutex_unlock(&priv->sync_cmd_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_send_cmd_sync); EXPORT_SYMBOL(iwl_send_cmd_sync);
......
...@@ -1238,6 +1238,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) ...@@ -1238,6 +1238,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
if (!(meta->flags & CMD_ASYNC)) { if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status); 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); wake_up_interruptible(&priv->wait_command_queue);
} }
} }
......
...@@ -3847,6 +3847,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) ...@@ -3847,6 +3847,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames); INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex); mutex_init(&priv->mutex);
mutex_init(&priv->sync_cmd_mutex);
/* Clear the driver's (not device's) station table */ /* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv); iwl_clear_stations_table(priv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment