diff options
author | Luca Coelho <luciano.coelho@intel.com> | 2016-03-11 05:12:16 -0500 |
---|---|---|
committer | Luca Coelho <luciano.coelho@intel.com> | 2016-05-10 15:14:48 -0400 |
commit | 71b1230ca97e60d26b4205ac553af6331724ca60 (patch) | |
tree | 63e522c0a210fcbd7d07df90275157d3c9166860 | |
parent | fa820d696c0ac0bb3cf1b49a817899982d774d61 (diff) |
iwlwifi: wake from runtime suspend before sending sync commands
If a host command was queued while in runtime suspend, it would go out
before the D0I3_END_CMD was sent. Sometimes it works, but sometimes
it fails, and it is obviously the wrong thing to do.
To fix this, have the opmode take a reference before sending a SYNC
command and make the pcie trans wait for the runtime state to become
active before actually queueing the command.
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 11 |
4 files changed, 20 insertions, 1 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 362a54601a80..513a85403924 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | |||
@@ -1309,6 +1309,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, | |||
1309 | PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); | 1309 | PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); |
1310 | PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT); | 1310 | PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT); |
1311 | PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE); | 1311 | PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE); |
1312 | PRINT_MVM_REF(IWL_MVM_REF_SENDING_CMD); | ||
1312 | 1313 | ||
1313 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1314 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
1314 | } | 1315 | } |
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 72c04672143f..23d7539edf17 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | |||
@@ -301,6 +301,7 @@ enum iwl_mvm_ref_type { | |||
301 | IWL_MVM_REF_PROTECT_CSA, | 301 | IWL_MVM_REF_PROTECT_CSA, |
302 | IWL_MVM_REF_FW_DBG_COLLECT, | 302 | IWL_MVM_REF_FW_DBG_COLLECT, |
303 | IWL_MVM_REF_INIT_UCODE, | 303 | IWL_MVM_REF_INIT_UCODE, |
304 | IWL_MVM_REF_SENDING_CMD, | ||
304 | 305 | ||
305 | /* update debugfs.c when changing this */ | 306 | /* update debugfs.c when changing this */ |
306 | 307 | ||
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index f0ffd62f02d3..eb41d3bd8059 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c | |||
@@ -90,11 +90,17 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) | |||
90 | * the mutex, this ensures we don't try to send two | 90 | * the mutex, this ensures we don't try to send two |
91 | * (or more) synchronous commands at a time. | 91 | * (or more) synchronous commands at a time. |
92 | */ | 92 | */ |
93 | if (!(cmd->flags & CMD_ASYNC)) | 93 | if (!(cmd->flags & CMD_ASYNC)) { |
94 | lockdep_assert_held(&mvm->mutex); | 94 | lockdep_assert_held(&mvm->mutex); |
95 | if (!(cmd->flags & CMD_SEND_IN_IDLE)) | ||
96 | iwl_mvm_ref(mvm, IWL_MVM_REF_SENDING_CMD); | ||
97 | } | ||
95 | 98 | ||
96 | ret = iwl_trans_send_cmd(mvm->trans, cmd); | 99 | ret = iwl_trans_send_cmd(mvm->trans, cmd); |
97 | 100 | ||
101 | if (!(cmd->flags & (CMD_ASYNC | CMD_SEND_IN_IDLE))) | ||
102 | iwl_mvm_unref(mvm, IWL_MVM_REF_SENDING_CMD); | ||
103 | |||
98 | /* | 104 | /* |
99 | * If the caller wants the SKB, then don't hide any problems, the | 105 | * If the caller wants the SKB, then don't hide any problems, the |
100 | * caller might access the response buffer which will be NULL if | 106 | * caller might access the response buffer which will be NULL if |
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index e2eb130dae98..d6beac9af029 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/ieee80211.h> | 32 | #include <linux/ieee80211.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
35 | #include <linux/pm_runtime.h> | ||
35 | #include <net/ip6_checksum.h> | 36 | #include <net/ip6_checksum.h> |
36 | #include <net/tso.h> | 37 | #include <net/tso.h> |
37 | 38 | ||
@@ -1799,6 +1800,16 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, | |||
1799 | IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", | 1800 | IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", |
1800 | iwl_get_cmd_string(trans, cmd->id)); | 1801 | iwl_get_cmd_string(trans, cmd->id)); |
1801 | 1802 | ||
1803 | if (pm_runtime_suspended(&trans_pcie->pci_dev->dev)) { | ||
1804 | ret = wait_event_timeout(trans_pcie->d0i3_waitq, | ||
1805 | pm_runtime_active(&trans_pcie->pci_dev->dev), | ||
1806 | msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT)); | ||
1807 | if (!ret) { | ||
1808 | IWL_ERR(trans, "Timeout exiting D0i3 before hcmd\n"); | ||
1809 | return -ETIMEDOUT; | ||
1810 | } | ||
1811 | } | ||
1812 | |||
1802 | cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd); | 1813 | cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd); |
1803 | if (cmd_idx < 0) { | 1814 | if (cmd_idx < 0) { |
1804 | ret = cmd_idx; | 1815 | ret = cmd_idx; |