aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Coelho <luciano.coelho@intel.com>2016-03-11 05:12:16 -0500
committerLuca Coelho <luciano.coelho@intel.com>2016-05-10 15:14:48 -0400
commit71b1230ca97e60d26b4205ac553af6331724ca60 (patch)
tree63e522c0a210fcbd7d07df90275157d3c9166860
parentfa820d696c0ac0bb3cf1b49a817899982d774d61 (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.c1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c11
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;