Commit d15a747f authored by Eliad Peller's avatar Eliad Peller Committed by Emmanuel Grumbach

iwlwifi: mvm: don't use d3 fw if d0i3 is used

bail out from the suspend/resume callbacks if
d0i3 is used.

declare support for ANY wowlan trigger (i.e.
normal operation).

On resume, we shouldn't execute the d0i3 exit
flow (which might disconnect stations, etc.)
until mac80211 was resumed.
Add new flags to indicate we are in suspend,
and call the pending exit work on resume.

Since the resume flow can take some time, add
a new EXIT_WORK reference type to prevent going
back to d0i3 at this stage.
Signed-off-by: default avatarEliad Peller <eliadx.peller@intel.com>
Signed-off-by: default avatarArik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent f0d5bb07
...@@ -1074,6 +1074,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, ...@@ -1074,6 +1074,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (iwl_mvm_is_d0i3_supported(mvm)) {
mutex_lock(&mvm->d0i3_suspend_mutex);
__set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
mutex_unlock(&mvm->d0i3_suspend_mutex);
return 0;
}
return __iwl_mvm_suspend(hw, wowlan, false); return __iwl_mvm_suspend(hw, wowlan, false);
} }
...@@ -1646,6 +1655,19 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) ...@@ -1646,6 +1655,19 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (iwl_mvm_is_d0i3_supported(mvm)) {
bool exit_now;
mutex_lock(&mvm->d0i3_suspend_mutex);
__clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP,
&mvm->d0i3_suspend_flags);
mutex_unlock(&mvm->d0i3_suspend_mutex);
if (exit_now)
_iwl_mvm_exit_d0i3(mvm);
return 0;
}
return __iwl_mvm_resume(mvm, false); return __iwl_mvm_resume(mvm, false);
} }
......
...@@ -1001,6 +1001,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, ...@@ -1001,6 +1001,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
PRINT_MVM_REF(IWL_MVM_REF_USER); PRINT_MVM_REF(IWL_MVM_REF_USER);
PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos); return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
} }
......
...@@ -381,7 +381,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -381,7 +381,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && if (iwl_mvm_is_d0i3_supported(mvm) &&
device_can_wakeup(mvm->trans->dev)) {
mvm->wowlan.flags = WIPHY_WOWLAN_ANY;
hw->wiphy->wowlan = &mvm->wowlan;
} else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
mvm->trans->ops->d3_suspend && mvm->trans->ops->d3_suspend &&
mvm->trans->ops->d3_resume && mvm->trans->ops->d3_resume &&
device_can_wakeup(mvm->trans->dev)) { device_can_wakeup(mvm->trans->dev)) {
......
...@@ -230,6 +230,7 @@ enum iwl_mvm_ref_type { ...@@ -230,6 +230,7 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_USER, IWL_MVM_REF_USER,
IWL_MVM_REF_TX, IWL_MVM_REF_TX,
IWL_MVM_REF_TX_AGG, IWL_MVM_REF_TX_AGG,
IWL_MVM_REF_EXIT_WORK,
IWL_MVM_REF_COUNT, IWL_MVM_REF_COUNT,
}; };
...@@ -451,6 +452,11 @@ struct iwl_mvm_frame_stats { ...@@ -451,6 +452,11 @@ struct iwl_mvm_frame_stats {
int last_frame_idx; int last_frame_idx;
}; };
enum {
D0I3_DEFER_WAKEUP,
D0I3_PENDING_WAKEUP,
};
struct iwl_mvm { struct iwl_mvm {
/* for logger access */ /* for logger access */
struct device *dev; struct device *dev;
...@@ -605,6 +611,9 @@ struct iwl_mvm { ...@@ -605,6 +611,9 @@ struct iwl_mvm {
bool d0i3_offloading; bool d0i3_offloading;
struct work_struct d0i3_exit_work; struct work_struct d0i3_exit_work;
struct sk_buff_head d0i3_tx; struct sk_buff_head d0i3_tx;
/* protect d0i3_suspend_flags */
struct mutex d0i3_suspend_mutex;
unsigned long d0i3_suspend_flags;
/* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */ /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */
spinlock_t d0i3_tx_lock; spinlock_t d0i3_tx_lock;
wait_queue_head_t d0i3_exit_waitq; wait_queue_head_t d0i3_exit_waitq;
...@@ -923,6 +932,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, ...@@ -923,6 +932,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
/* BT Coex */ /* BT Coex */
int iwl_send_bt_init_conf(struct iwl_mvm *mvm); int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
......
...@@ -402,6 +402,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -402,6 +402,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->sf_state = SF_UNINIT; mvm->sf_state = SF_UNINIT;
mutex_init(&mvm->mutex); mutex_init(&mvm->mutex);
mutex_init(&mvm->d0i3_suspend_mutex);
spin_lock_init(&mvm->async_handlers_lock); spin_lock_init(&mvm->async_handlers_lock);
INIT_LIST_HEAD(&mvm->time_event_list); INIT_LIST_HEAD(&mvm->time_event_list);
INIT_LIST_HEAD(&mvm->async_handlers_list); INIT_LIST_HEAD(&mvm->async_handlers_list);
...@@ -1174,18 +1175,27 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) ...@@ -1174,18 +1175,27 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
iwl_free_resp(&get_status_cmd); iwl_free_resp(&get_status_cmd);
out: out:
iwl_mvm_d0i3_enable_tx(mvm, qos_seq); iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK);
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
} }
static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm)
{ {
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE |
CMD_WAKE_UP_TRANS; CMD_WAKE_UP_TRANS;
int ret; int ret;
IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n");
mutex_lock(&mvm->d0i3_suspend_mutex);
if (test_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags)) {
IWL_DEBUG_RPM(mvm, "Deferring d0i3 exit until resume\n");
__set_bit(D0I3_PENDING_WAKEUP, &mvm->d0i3_suspend_flags);
mutex_unlock(&mvm->d0i3_suspend_mutex);
return 0;
}
mutex_unlock(&mvm->d0i3_suspend_mutex);
ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL);
if (ret) if (ret)
goto out; goto out;
...@@ -1199,6 +1209,14 @@ static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) ...@@ -1199,6 +1209,14 @@ static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
return ret; return ret;
} }
static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
iwl_mvm_ref(mvm, IWL_MVM_REF_EXIT_WORK);
return _iwl_mvm_exit_d0i3(mvm);
}
static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode, static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode,
struct napi_struct *napi, struct napi_struct *napi,
struct net_device *napi_dev, struct net_device *napi_dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment