From afc66bb734d44ea64cc78ae8d8034886e8cfb2c7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 3 May 2013 11:44:16 +0200 Subject: iwlwifi: mvm: optionally store D3 SRAM after resume The D3 image SRAM is overwritten by the runtime image, so it can't be accessed after resume. However, it can be very useful to look at it to know what happened during D3, so add the ability to store the image and make it available in debugfs. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/d3.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 16bbdcc8627a..63d788aef3f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1214,6 +1214,26 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, iwl_free_resp(&cmd); } +static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) +{ +#ifdef CONFIG_IWLWIFI_DEBUGFS + const struct fw_img *img = &mvm->fw->img[IWL_UCODE_WOWLAN]; + u32 len = img->sec[IWL_UCODE_SECTION_DATA].len; + u32 offs = img->sec[IWL_UCODE_SECTION_DATA].offset; + + if (!mvm->store_d3_resume_sram) + return; + + if (!mvm->d3_resume_sram) { + mvm->d3_resume_sram = kzalloc(len, GFP_KERNEL); + if (!mvm->d3_resume_sram) + return; + } + + iwl_trans_read_mem_bytes(mvm->trans, offs, mvm->d3_resume_sram, len); +#endif +} + int iwl_mvm_resume(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -1245,6 +1265,9 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) goto out_unlock; } + /* query SRAM first in case we want event logging */ + iwl_mvm_read_d3_sram(mvm); + iwl_mvm_query_wakeup_reasons(mvm, vif); out_unlock: -- cgit v1.2.3 From ee1e84225f779386858702872fb299457e7941f9 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Tue, 23 Apr 2013 13:52:10 +0300 Subject: iwlwifi: mvm: configure power management in D3 Configure power management in the D3 firmware by sending the power table command to it when suspending; this uses some values that are more suitable to a low power state. Signed-off-by: Alexander Bondar Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/d3.c | 4 ++++ drivers/net/wireless/iwlwifi/mvm/power.c | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 63d788aef3f4..4d3c978b5c76 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1007,6 +1007,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) if (ret) goto out; + ret = iwl_mvm_power_update_mode(mvm, vif); + if (ret) + goto out; + /* must be last -- this switches firmware state */ ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, sizeof(d3_cfg_cmd), &d3_cfg_cmd); diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 6c5dfc9a8d43..f5bdfb71c790 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -138,7 +138,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* Check skip over DTIM conditions */ if (!radar_detect && (dtimper <= 10) && - (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) { + (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || + mvm->cur_ucode == IWL_UCODE_WOWLAN)) { cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); cmd->num_skip_dtim = cpu_to_le32(2); } @@ -150,8 +151,13 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); cmd->keep_alive_seconds = keep_alive; - cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); - cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); + if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { + cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); + cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); + } else { + cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); + cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); + } } int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -- cgit v1.2.3 From debff6184c32149bd08cfecfafbebb96201be37d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 May 2013 13:53:45 +0200 Subject: 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 Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 4 +- drivers/net/wireless/iwlwifi/iwl-trans.h | 14 +-- drivers/net/wireless/iwlwifi/mvm/d3.c | 149 ++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 1 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 + drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 3 +- drivers/net/wireless/iwlwifi/mvm/utils.c | 10 ++ drivers/net/wireless/iwlwifi/pcie/trans.c | 19 +++- 8 files changed, 182 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') 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, iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - iwl_trans_d3_suspend(priv->trans); + iwl_trans_d3_suspend(priv->trans, false); goto out; @@ -504,7 +504,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) /* we'll clear ctx->vif during iwlagn_prepare_restart() */ vif = ctx->vif; - ret = iwl_trans_d3_resume(priv->trans, &d3_status); + ret = iwl_trans_d3_resume(priv->trans, &d3_status, false); if (ret) goto out_unlock; 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 { void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); void (*stop_device)(struct iwl_trans *trans); - void (*d3_suspend)(struct iwl_trans *trans); - int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status); + void (*d3_suspend)(struct iwl_trans *trans, bool test); + int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status, + bool test); int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); @@ -588,17 +589,18 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans) trans->state = IWL_TRANS_NO_FW; } -static inline void iwl_trans_d3_suspend(struct iwl_trans *trans) +static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test) { might_sleep(); - trans->ops->d3_suspend(trans); + trans->ops->d3_suspend(trans, test); } static inline int iwl_trans_d3_resume(struct iwl_trans *trans, - enum iwl_d3_status *status) + enum iwl_d3_status *status, + bool test) { might_sleep(); - return trans->ops->d3_resume(trans, status); + return trans->ops->d3_resume(trans, status, test); } static 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 @@ #include #include +#include #include #include #include @@ -756,7 +757,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } -int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) +static int __iwl_mvm_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan, + bool test) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_d3_iter_data suspend_iter_data = { @@ -769,7 +772,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; - struct iwl_d3_manager_config d3_cfg_cmd = { + struct iwl_d3_manager_config d3_cfg_cmd_data = { /* * Program the minimum sleep time to 10 seconds, as many * platforms have issues processing a wakeup signal while @@ -777,17 +780,30 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) */ .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), }; + struct iwl_host_cmd d3_cfg_cmd = { + .id = D3_CONFIG_CMD, + .flags = CMD_SYNC | CMD_WANT_SKB, + .data[0] = &d3_cfg_cmd_data, + .len[0] = sizeof(d3_cfg_cmd_data), + }; struct wowlan_key_data key_data = { .use_rsc_tsc = false, .tkip = &tkip_cmd, .use_tkip = false, }; int ret, i; + int len __maybe_unused; u16 seq; u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; - if (WARN_ON(!wowlan)) + if (!wowlan) { + /* + * mac80211 shouldn't get here, but for D3 test + * it doesn't warrant a warning + */ + WARN_ON(!test); return -EINVAL; + } key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); if (!key_data.rsc_tsc) @@ -1012,14 +1028,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) goto out; /* must be last -- this switches firmware state */ - ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, - sizeof(d3_cfg_cmd), &d3_cfg_cmd); + ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); if (ret) goto out; +#ifdef CONFIG_IWLWIFI_DEBUGFS + len = le32_to_cpu(d3_cfg_cmd.resp_pkt->len_n_flags) & + FH_RSCSR_FRAME_SIZE_MSK; + if (len >= sizeof(u32) * 2) { + mvm->d3_test_pme_ptr = + le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data); + } else if (test) { + /* in test mode we require the pointer */ + ret = -EIO; + goto out; + } +#endif + iwl_free_resp(&d3_cfg_cmd); clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - iwl_trans_d3_suspend(mvm->trans); + iwl_trans_d3_suspend(mvm->trans, test); out: mvm->aux_sta.sta_id = old_aux_sta_id; 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) return ret; } +int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) +{ + return __iwl_mvm_suspend(hw, wowlan, false); +} + static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -1238,9 +1271,8 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) #endif } -int iwl_mvm_resume(struct ieee80211_hw *hw) +static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_d3_iter_data resume_iter_data = { .mvm = mvm, }; @@ -1260,7 +1292,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) vif = resume_iter_data.vif; - ret = iwl_trans_d3_resume(mvm->trans, &d3_status); + ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test); if (ret) goto out_unlock; @@ -1277,7 +1309,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) out_unlock: mutex_unlock(&mvm->mutex); - if (vif) + if (!test && vif) ieee80211_resume_disconnect(vif); /* return 1 to reconfigure the device */ @@ -1285,9 +1317,106 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) return 1; } +int iwl_mvm_resume(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + return __iwl_mvm_resume(mvm, false); +} + void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); device_set_wakeup_enable(mvm->trans->dev, enabled); } + +#ifdef CONFIG_IWLWIFI_DEBUGFS +static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) +{ + struct iwl_mvm *mvm = inode->i_private; + int err; + + if (mvm->d3_test_active) + return -EBUSY; + + file->private_data = inode->i_private; + + ieee80211_stop_queues(mvm->hw); + synchronize_net(); + + /* start pseudo D3 */ + rtnl_lock(); + err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); + rtnl_unlock(); + if (err > 0) + err = -EINVAL; + if (err) { + ieee80211_wake_queues(mvm->hw); + return err; + } + mvm->d3_test_active = true; + return 0; +} + +static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + u32 pme_asserted; + + while (true) { + pme_asserted = iwl_trans_read_mem32(mvm->trans, + mvm->d3_test_pme_ptr); + if (pme_asserted) + break; + if (msleep_interruptible(100)) + break; + } + + return 0; +} + +static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + if (vif->type == NL80211_IFTYPE_STATION) + ieee80211_connection_loss(vif); +} + +static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) +{ + struct iwl_mvm *mvm = inode->i_private; + int remaining_time = 10; + + mvm->d3_test_active = false; + __iwl_mvm_resume(mvm, true); + iwl_abort_notification_waits(&mvm->notif_wait); + ieee80211_restart_hw(mvm->hw); + + /* wait for restart and disconnect all interfaces */ + while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && + remaining_time > 0) { + remaining_time--; + msleep(1000); + } + + if (remaining_time == 0) + IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n"); + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_d3_test_disconn_work_iter, NULL); + + ieee80211_wake_queues(mvm->hw); + + return 0; +} + +const struct file_operations iwl_dbgfs_d3_test_ops = { + .llseek = no_llseek, + .open = iwl_mvm_d3_test_open, + .read = iwl_mvm_d3_test_read, + .release = iwl_mvm_d3_test_release, +}; +#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) MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); #endif /* 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 { #ifdef CONFIG_PM_SLEEP int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; #ifdef CONFIG_IWLWIFI_DEBUGFS + bool d3_test_active; bool store_d3_resume_sram; void *d3_resume_sram; + u32 d3_test_pme_ptr; #endif #endif @@ -669,6 +671,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, struct inet6_dev *idev); void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); +extern const struct file_operations iwl_dbgfs_d3_test_ops; /* BT Coex */ int 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, { int ret; - WARN_ON(ctxt->ref); + WARN_ON(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && + ctxt->ref); lockdep_assert_held(&mvm->mutex); 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) { int ret; +#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) + if (WARN_ON(mvm->d3_test_active)) + return -EIO; +#endif + /* * Synchronous commands from this op-mode must hold * 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, lockdep_assert_held(&mvm->mutex); +#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) + if (WARN_ON(mvm->d3_test_active)) + return -EIO; +#endif + /* * Only synchronous commands can wait for status, * 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) clear_bit(STATUS_RFKILL, &trans_pcie->status); } -static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) +static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) { iwl_disable_interrupts(trans); + + /* + * in testing mode, the host stays awake and the + * hardware won't be reset (not even partially) + */ + if (test) + return; + iwl_pcie_disable_ict(trans); iwl_clear_bit(trans, CSR_GP_CNTRL, @@ -599,11 +607,18 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) } static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, - enum iwl_d3_status *status) + enum iwl_d3_status *status, + bool test) { u32 val; int ret; + if (test) { + iwl_enable_interrupts(trans); + *status = IWL_D3_STATUS_ALIVE; + return 0; + } + iwl_pcie_set_pwr(trans, false); val = iwl_read32(trans, CSR_RESET); -- cgit v1.2.3 From b002c7e1f327bb56fe068bf76fd7179b1b490e02 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Wed, 12 Jun 2013 20:37:03 +0300 Subject: iwlwifi: mvm: removed an unused parameter from a function Remove the unused iwl_mvm *mvm parameter from the iwl_mvm_send_remote_wake_cfg function in D3.c. Signed-off-by: Oren Givon Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/d3.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 7a2ef3f013fd..8c49db02c9c1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -420,8 +420,7 @@ static __le16 pseudo_hdr_check(int len, __be32 saddr, __be32 daddr) return cpu_to_le16(be16_to_cpu((__force __be16)check)); } -static void iwl_mvm_build_tcp_packet(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, +static void iwl_mvm_build_tcp_packet(struct ieee80211_vif *vif, struct cfg80211_wowlan_tcp *tcp, void *_pkt, u8 *mask, __le16 *pseudo_hdr_csum, @@ -567,21 +566,21 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm, /* SYN (TX) */ iwl_mvm_build_tcp_packet( - mvm, vif, tcp, cfg->syn_tx.data, NULL, + vif, tcp, cfg->syn_tx.data, NULL, &cfg->syn_tx.info.tcp_pseudo_header_checksum, MVM_TCP_TX_SYN); cfg->syn_tx.info.tcp_payload_length = 0; /* SYN/ACK (RX) */ iwl_mvm_build_tcp_packet( - mvm, vif, tcp, cfg->synack_rx.data, cfg->synack_rx.rx_mask, + vif, tcp, cfg->synack_rx.data, cfg->synack_rx.rx_mask, &cfg->synack_rx.info.tcp_pseudo_header_checksum, MVM_TCP_RX_SYNACK); cfg->synack_rx.info.tcp_payload_length = 0; /* KEEPALIVE/ACK (TX) */ iwl_mvm_build_tcp_packet( - mvm, vif, tcp, cfg->keepalive_tx.data, NULL, + vif, tcp, cfg->keepalive_tx.data, NULL, &cfg->keepalive_tx.info.tcp_pseudo_header_checksum, MVM_TCP_TX_DATA); cfg->keepalive_tx.info.tcp_payload_length = @@ -605,7 +604,7 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm, /* ACK (RX) */ iwl_mvm_build_tcp_packet( - mvm, vif, tcp, cfg->keepalive_ack_rx.data, + vif, tcp, cfg->keepalive_ack_rx.data, cfg->keepalive_ack_rx.rx_mask, &cfg->keepalive_ack_rx.info.tcp_pseudo_header_checksum, MVM_TCP_RX_ACK); @@ -613,7 +612,7 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm, /* WAKEUP (RX) */ iwl_mvm_build_tcp_packet( - mvm, vif, tcp, cfg->wake_rx.data, cfg->wake_rx.rx_mask, + vif, tcp, cfg->wake_rx.data, cfg->wake_rx.rx_mask, &cfg->wake_rx.info.tcp_pseudo_header_checksum, MVM_TCP_RX_WAKE); cfg->wake_rx.info.tcp_payload_length = @@ -621,7 +620,7 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm, /* FIN */ iwl_mvm_build_tcp_packet( - mvm, vif, tcp, cfg->fin_tx.data, NULL, + vif, tcp, cfg->fin_tx.data, NULL, &cfg->fin_tx.info.tcp_pseudo_header_checksum, MVM_TCP_TX_FIN); cfg->fin_tx.info.tcp_payload_length = 0; -- cgit v1.2.3 From b01147140a2a609d91538fdfec8e2d688d379662 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Jun 2013 14:55:40 +0200 Subject: iwlwifi: mvm: allow firmware crashes to wake system for debug When the D3 firmware crashes, it can be helpful for debugging to resume the system to get the SRAM snapshot to see why it crashed. Allow enabling this with a debugfs option. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/d3.c | 6 ++++++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 3 +++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 3 files changed, 10 insertions(+) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 8c49db02c9c1..7e5e5c2f9f87 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1026,6 +1026,12 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out; +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvm->d3_wake_sysassert) + d3_cfg_cmd_data.wakeup_flags |= + cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR); +#endif + /* must be last -- this switches firmware state */ ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); if (ret) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index b7643c16201f..63d19d94b018 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -939,6 +939,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); + if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, + mvm->debugfs_dir, &mvm->d3_wake_sysassert)) + goto err; #endif /* diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ad39a22f79fa..fbc0acb52191 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -460,6 +460,7 @@ struct iwl_mvm { #ifdef CONFIG_PM_SLEEP int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; #ifdef CONFIG_IWLWIFI_DEBUGFS + u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */ bool d3_test_active; bool store_d3_resume_sram; void *d3_resume_sram; -- cgit v1.2.3