aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-05-14 07:53:45 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-05-29 15:56:57 -0400
commitdebff6184c32149bd08cfecfafbebb96201be37d (patch)
tree25feb83b8dd4cc4c119b00245cdebf36435d5698 /drivers
parent774439518ac01049e9bf44f2fa4c604981f39dbf (diff)
iwlwifi: mvm: implement D3 testing
For testing the D3 (WoWLAN) firmware, it is useful to be able to run the firmware with instrumentation while the host isn't sleeping and can poke at the firmware debug logging etc. Implement this by a debugfs file. When the file is opened the D3 firmware is loaded and all regular commands are blocked. While the file is being read, poll the firmware's PME status flag and report EOF once it changes to non-zero. When it is closed, do (most of) the resume processing. This lets a user just "cat" the file. Pressing Ctrl-C to kill the cat process will resume the firwmare as though the platform resumed for non-wireless reason and when the firmware wants to wake up reading from the file automatically completes. Unlike in real suspend, only disable interrupts and don't reset the TX/RX hardware while in the test mode. This is a workaround for some interrupt problems that happen only when the PCIe link isn't fully reset (presumably by changing the PCI config space registers which the core PCI code does.) Note that while regular operations are blocked from sending commands to the firmware, they could still be made and cause strange mac80211 issues. Therefore, while using this testing feature you need to be careful to not try to disconnect, roam or similar, and will see warnings for such attempts. Als note that this requires an upcoming firmware change to tell the driver the location of the PME status flag in SRAM. D3 test will fail if the firmware doesn't report the pointer. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c149
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c10
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c19
8 files changed, 182 insertions, 21 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index ac7ed3f809a0..c0039a992909 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -430,7 +430,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
430 iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, 430 iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
431 CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); 431 CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
432 432
433 iwl_trans_d3_suspend(priv->trans); 433 iwl_trans_d3_suspend(priv->trans, false);
434 434
435 goto out; 435 goto out;
436 436
@@ -504,7 +504,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
504 /* we'll clear ctx->vif during iwlagn_prepare_restart() */ 504 /* we'll clear ctx->vif during iwlagn_prepare_restart() */
505 vif = ctx->vif; 505 vif = ctx->vif;
506 506
507 ret = iwl_trans_d3_resume(priv->trans, &d3_status); 507 ret = iwl_trans_d3_resume(priv->trans, &d3_status, false);
508 if (ret) 508 if (ret)
509 goto out_unlock; 509 goto out_unlock;
510 510
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 84f1c8dc9741..be4b2ac3dbbf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -428,8 +428,9 @@ struct iwl_trans_ops {
428 void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); 428 void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
429 void (*stop_device)(struct iwl_trans *trans); 429 void (*stop_device)(struct iwl_trans *trans);
430 430
431 void (*d3_suspend)(struct iwl_trans *trans); 431 void (*d3_suspend)(struct iwl_trans *trans, bool test);
432 int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status); 432 int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
433 bool test);
433 434
434 int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); 435 int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
435 436
@@ -588,17 +589,18 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
588 trans->state = IWL_TRANS_NO_FW; 589 trans->state = IWL_TRANS_NO_FW;
589} 590}
590 591
591static inline void iwl_trans_d3_suspend(struct iwl_trans *trans) 592static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
592{ 593{
593 might_sleep(); 594 might_sleep();
594 trans->ops->d3_suspend(trans); 595 trans->ops->d3_suspend(trans, test);
595} 596}
596 597
597static inline int iwl_trans_d3_resume(struct iwl_trans *trans, 598static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
598 enum iwl_d3_status *status) 599 enum iwl_d3_status *status,
600 bool test)
599{ 601{
600 might_sleep(); 602 might_sleep();
601 return trans->ops->d3_resume(trans, status); 603 return trans->ops->d3_resume(trans, status, test);
602} 604}
603 605
604static inline int iwl_trans_send_cmd(struct iwl_trans *trans, 606static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 4d3c978b5c76..7a2ef3f013fd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -63,6 +63,7 @@
63 63
64#include <linux/etherdevice.h> 64#include <linux/etherdevice.h>
65#include <linux/ip.h> 65#include <linux/ip.h>
66#include <linux/fs.h>
66#include <net/cfg80211.h> 67#include <net/cfg80211.h>
67#include <net/ipv6.h> 68#include <net/ipv6.h>
68#include <net/tcp.h> 69#include <net/tcp.h>
@@ -756,7 +757,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
756 return 0; 757 return 0;
757} 758}
758 759
759int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 760static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
761 struct cfg80211_wowlan *wowlan,
762 bool test)
760{ 763{
761 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 764 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
762 struct iwl_d3_iter_data suspend_iter_data = { 765 struct iwl_d3_iter_data suspend_iter_data = {
@@ -769,7 +772,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
769 struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; 772 struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
770 struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; 773 struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
771 struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; 774 struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
772 struct iwl_d3_manager_config d3_cfg_cmd = { 775 struct iwl_d3_manager_config d3_cfg_cmd_data = {
773 /* 776 /*
774 * Program the minimum sleep time to 10 seconds, as many 777 * Program the minimum sleep time to 10 seconds, as many
775 * platforms have issues processing a wakeup signal while 778 * platforms have issues processing a wakeup signal while
@@ -777,17 +780,30 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
777 */ 780 */
778 .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), 781 .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
779 }; 782 };
783 struct iwl_host_cmd d3_cfg_cmd = {
784 .id = D3_CONFIG_CMD,
785 .flags = CMD_SYNC | CMD_WANT_SKB,
786 .data[0] = &d3_cfg_cmd_data,
787 .len[0] = sizeof(d3_cfg_cmd_data),
788 };
780 struct wowlan_key_data key_data = { 789 struct wowlan_key_data key_data = {
781 .use_rsc_tsc = false, 790 .use_rsc_tsc = false,
782 .tkip = &tkip_cmd, 791 .tkip = &tkip_cmd,
783 .use_tkip = false, 792 .use_tkip = false,
784 }; 793 };
785 int ret, i; 794 int ret, i;
795 int len __maybe_unused;
786 u16 seq; 796 u16 seq;
787 u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; 797 u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
788 798
789 if (WARN_ON(!wowlan)) 799 if (!wowlan) {
800 /*
801 * mac80211 shouldn't get here, but for D3 test
802 * it doesn't warrant a warning
803 */
804 WARN_ON(!test);
790 return -EINVAL; 805 return -EINVAL;
806 }
791 807
792 key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); 808 key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
793 if (!key_data.rsc_tsc) 809 if (!key_data.rsc_tsc)
@@ -1012,14 +1028,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
1012 goto out; 1028 goto out;
1013 1029
1014 /* must be last -- this switches firmware state */ 1030 /* must be last -- this switches firmware state */
1015 ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, 1031 ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);
1016 sizeof(d3_cfg_cmd), &d3_cfg_cmd);
1017 if (ret) 1032 if (ret)
1018 goto out; 1033 goto out;
1034#ifdef CONFIG_IWLWIFI_DEBUGFS
1035 len = le32_to_cpu(d3_cfg_cmd.resp_pkt->len_n_flags) &
1036 FH_RSCSR_FRAME_SIZE_MSK;
1037 if (len >= sizeof(u32) * 2) {
1038 mvm->d3_test_pme_ptr =
1039 le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);
1040 } else if (test) {
1041 /* in test mode we require the pointer */
1042 ret = -EIO;
1043 goto out;
1044 }
1045#endif
1046 iwl_free_resp(&d3_cfg_cmd);
1019 1047
1020 clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); 1048 clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
1021 1049
1022 iwl_trans_d3_suspend(mvm->trans); 1050 iwl_trans_d3_suspend(mvm->trans, test);
1023 out: 1051 out:
1024 mvm->aux_sta.sta_id = old_aux_sta_id; 1052 mvm->aux_sta.sta_id = old_aux_sta_id;
1025 mvm_ap_sta->sta_id = old_ap_sta_id; 1053 mvm_ap_sta->sta_id = old_ap_sta_id;
@@ -1034,6 +1062,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
1034 return ret; 1062 return ret;
1035} 1063}
1036 1064
1065int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
1066{
1067 return __iwl_mvm_suspend(hw, wowlan, false);
1068}
1069
1037static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, 1070static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
1038 struct ieee80211_vif *vif) 1071 struct ieee80211_vif *vif)
1039{ 1072{
@@ -1238,9 +1271,8 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
1238#endif 1271#endif
1239} 1272}
1240 1273
1241int iwl_mvm_resume(struct ieee80211_hw *hw) 1274static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1242{ 1275{
1243 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1244 struct iwl_d3_iter_data resume_iter_data = { 1276 struct iwl_d3_iter_data resume_iter_data = {
1245 .mvm = mvm, 1277 .mvm = mvm,
1246 }; 1278 };
@@ -1260,7 +1292,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
1260 1292
1261 vif = resume_iter_data.vif; 1293 vif = resume_iter_data.vif;
1262 1294
1263 ret = iwl_trans_d3_resume(mvm->trans, &d3_status); 1295 ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
1264 if (ret) 1296 if (ret)
1265 goto out_unlock; 1297 goto out_unlock;
1266 1298
@@ -1277,7 +1309,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
1277 out_unlock: 1309 out_unlock:
1278 mutex_unlock(&mvm->mutex); 1310 mutex_unlock(&mvm->mutex);
1279 1311
1280 if (vif) 1312 if (!test && vif)
1281 ieee80211_resume_disconnect(vif); 1313 ieee80211_resume_disconnect(vif);
1282 1314
1283 /* return 1 to reconfigure the device */ 1315 /* return 1 to reconfigure the device */
@@ -1285,9 +1317,106 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
1285 return 1; 1317 return 1;
1286} 1318}
1287 1319
1320int iwl_mvm_resume(struct ieee80211_hw *hw)
1321{
1322 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1323
1324 return __iwl_mvm_resume(mvm, false);
1325}
1326
1288void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) 1327void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
1289{ 1328{
1290 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1329 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1291 1330
1292 device_set_wakeup_enable(mvm->trans->dev, enabled); 1331 device_set_wakeup_enable(mvm->trans->dev, enabled);
1293} 1332}
1333
1334#ifdef CONFIG_IWLWIFI_DEBUGFS
1335static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
1336{
1337 struct iwl_mvm *mvm = inode->i_private;
1338 int err;
1339
1340 if (mvm->d3_test_active)
1341 return -EBUSY;
1342
1343 file->private_data = inode->i_private;
1344
1345 ieee80211_stop_queues(mvm->hw);
1346 synchronize_net();
1347
1348 /* start pseudo D3 */
1349 rtnl_lock();
1350 err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);
1351 rtnl_unlock();
1352 if (err > 0)
1353 err = -EINVAL;
1354 if (err) {
1355 ieee80211_wake_queues(mvm->hw);
1356 return err;
1357 }
1358 mvm->d3_test_active = true;
1359 return 0;
1360}
1361
1362static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
1363 size_t count, loff_t *ppos)
1364{
1365 struct iwl_mvm *mvm = file->private_data;
1366 u32 pme_asserted;
1367
1368 while (true) {
1369 pme_asserted = iwl_trans_read_mem32(mvm->trans,
1370 mvm->d3_test_pme_ptr);
1371 if (pme_asserted)
1372 break;
1373 if (msleep_interruptible(100))
1374 break;
1375 }
1376
1377 return 0;
1378}
1379
1380static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,
1381 struct ieee80211_vif *vif)
1382{
1383 if (vif->type == NL80211_IFTYPE_STATION)
1384 ieee80211_connection_loss(vif);
1385}
1386
1387static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
1388{
1389 struct iwl_mvm *mvm = inode->i_private;
1390 int remaining_time = 10;
1391
1392 mvm->d3_test_active = false;
1393 __iwl_mvm_resume(mvm, true);
1394 iwl_abort_notification_waits(&mvm->notif_wait);
1395 ieee80211_restart_hw(mvm->hw);
1396
1397 /* wait for restart and disconnect all interfaces */
1398 while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
1399 remaining_time > 0) {
1400 remaining_time--;
1401 msleep(1000);
1402 }
1403
1404 if (remaining_time == 0)
1405 IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n");
1406
1407 ieee80211_iterate_active_interfaces_atomic(
1408 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1409 iwl_mvm_d3_test_disconn_work_iter, NULL);
1410
1411 ieee80211_wake_queues(mvm->hw);
1412
1413 return 0;
1414}
1415
1416const struct file_operations iwl_dbgfs_d3_test_ops = {
1417 .llseek = no_llseek,
1418 .open = iwl_mvm_d3_test_open,
1419 .read = iwl_mvm_d3_test_read,
1420 .release = iwl_mvm_d3_test_release,
1421};
1422#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 69e0806075a2..b7643c16201f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -938,6 +938,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
938 MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); 938 MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
939#ifdef CONFIG_PM_SLEEP 939#ifdef CONFIG_PM_SLEEP
940 MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); 940 MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
941 MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
941#endif 942#endif
942 943
943 /* 944 /*
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 6a3220b6273e..384259baf525 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -459,8 +459,10 @@ struct iwl_mvm {
459#ifdef CONFIG_PM_SLEEP 459#ifdef CONFIG_PM_SLEEP
460 int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; 460 int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
461#ifdef CONFIG_IWLWIFI_DEBUGFS 461#ifdef CONFIG_IWLWIFI_DEBUGFS
462 bool d3_test_active;
462 bool store_d3_resume_sram; 463 bool store_d3_resume_sram;
463 void *d3_resume_sram; 464 void *d3_resume_sram;
465 u32 d3_test_pme_ptr;
464#endif 466#endif
465#endif 467#endif
466 468
@@ -669,6 +671,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
669 struct inet6_dev *idev); 671 struct inet6_dev *idev);
670void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, 672void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
671 struct ieee80211_vif *vif, int idx); 673 struct ieee80211_vif *vif, int idx);
674extern const struct file_operations iwl_dbgfs_d3_test_ops;
672 675
673/* BT Coex */ 676/* BT Coex */
674int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); 677int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index 1b4db25d53fb..a8652ddd6bed 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -204,7 +204,8 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
204{ 204{
205 int ret; 205 int ret;
206 206
207 WARN_ON(ctxt->ref); 207 WARN_ON(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
208 ctxt->ref);
208 lockdep_assert_held(&mvm->mutex); 209 lockdep_assert_held(&mvm->mutex);
209 210
210 ctxt->channel = chandef->chan; 211 ctxt->channel = chandef->chan;
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index c9b44ab4af07..1e1332839e4a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -76,6 +76,11 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
76{ 76{
77 int ret; 77 int ret;
78 78
79#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)
80 if (WARN_ON(mvm->d3_test_active))
81 return -EIO;
82#endif
83
79 /* 84 /*
80 * Synchronous commands from this op-mode must hold 85 * Synchronous commands from this op-mode must hold
81 * the mutex, this ensures we don't try to send two 86 * the mutex, this ensures we don't try to send two
@@ -125,6 +130,11 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
125 130
126 lockdep_assert_held(&mvm->mutex); 131 lockdep_assert_held(&mvm->mutex);
127 132
133#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)
134 if (WARN_ON(mvm->d3_test_active))
135 return -EIO;
136#endif
137
128 /* 138 /*
129 * Only synchronous commands can wait for status, 139 * Only synchronous commands can wait for status,
130 * we use WANT_SKB so the caller can't. 140 * we use WANT_SKB so the caller can't.
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 0b021305eedf..197dbe0a868c 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -578,9 +578,17 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
578 clear_bit(STATUS_RFKILL, &trans_pcie->status); 578 clear_bit(STATUS_RFKILL, &trans_pcie->status);
579} 579}
580 580
581static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) 581static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
582{ 582{
583 iwl_disable_interrupts(trans); 583 iwl_disable_interrupts(trans);
584
585 /*
586 * in testing mode, the host stays awake and the
587 * hardware won't be reset (not even partially)
588 */
589 if (test)
590 return;
591
584 iwl_pcie_disable_ict(trans); 592 iwl_pcie_disable_ict(trans);
585 593
586 iwl_clear_bit(trans, CSR_GP_CNTRL, 594 iwl_clear_bit(trans, CSR_GP_CNTRL,
@@ -599,11 +607,18 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
599} 607}
600 608
601static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, 609static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
602 enum iwl_d3_status *status) 610 enum iwl_d3_status *status,
611 bool test)
603{ 612{
604 u32 val; 613 u32 val;
605 int ret; 614 int ret;
606 615
616 if (test) {
617 iwl_enable_interrupts(trans);
618 *status = IWL_D3_STATUS_ALIVE;
619 return 0;
620 }
621
607 iwl_pcie_set_pwr(trans, false); 622 iwl_pcie_set_pwr(trans, false);
608 623
609 val = iwl_read32(trans, CSR_RESET); 624 val = iwl_read32(trans, CSR_RESET);