mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-22 10:34:55 +08:00
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: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
4a6547c748
commit
d2dfe6df75
@ -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);
|
|||||||
/*************** 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,
|
|||||||
|
|
||||||
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 {
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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 @@ fail:
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user