iwlwifi: pcie: poke device when commands don't complete quickly
In certain corner cases in the firmware implementation, powersave transitions can cause the firmware to miss the fact that commands were added to the queue/FIFO and thus never processes them. Since the commands really are in the queue, try to poke the firmware in such cases (by grabbing NIC access, which wakes up the NIC) so it notices the new command and processes it. Reviewed-by: Alexander Bondar <alexander.bondar@intel.com> Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
5a3e9f7f8c
commit
9439eac79f
|
@ -1465,7 +1465,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
|
|||
spin_unlock_bh(&txq->lock);
|
||||
}
|
||||
|
||||
#define HOST_COMPLETE_TIMEOUT (2 * HZ)
|
||||
#define HOST_COMPLETE_TIMEOUT (2 * HZ)
|
||||
#define COMMAND_POKE_TIMEOUT (HZ / 10)
|
||||
|
||||
static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
|
||||
struct iwl_host_cmd *cmd)
|
||||
|
@ -1493,6 +1494,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
|
|||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int cmd_idx;
|
||||
int ret;
|
||||
int timeout = HOST_COMPLETE_TIMEOUT;
|
||||
|
||||
IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
|
||||
get_cmd_string(trans_pcie, cmd->id));
|
||||
|
@ -1517,10 +1519,29 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_event_timeout(trans_pcie->wait_command_queue,
|
||||
!test_bit(STATUS_HCMD_ACTIVE,
|
||||
&trans_pcie->status),
|
||||
HOST_COMPLETE_TIMEOUT);
|
||||
while (timeout > 0) {
|
||||
unsigned long flags;
|
||||
|
||||
timeout -= COMMAND_POKE_TIMEOUT;
|
||||
ret = wait_event_timeout(trans_pcie->wait_command_queue,
|
||||
!test_bit(STATUS_HCMD_ACTIVE,
|
||||
&trans_pcie->status),
|
||||
COMMAND_POKE_TIMEOUT);
|
||||
if (ret)
|
||||
break;
|
||||
/* poke the device - it may have lost the command */
|
||||
if (iwl_trans_grab_nic_access(trans, true, &flags)) {
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
IWL_DEBUG_INFO(trans,
|
||||
"Tried to wake NIC for command %s\n",
|
||||
get_cmd_string(trans_pcie, cmd->id));
|
||||
} else {
|
||||
IWL_ERR(trans, "Failed to poke NIC for command %s\n",
|
||||
get_cmd_string(trans_pcie, cmd->id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
|
||||
struct iwl_txq *txq =
|
||||
|
|
Loading…
Reference in New Issue