Commit 7498cf4c authored by Eliad Peller's avatar Eliad Peller Committed by Emmanuel Grumbach

iwlwifi: mvm: allow transport sleep when FW is operational

Hold a bitmap of taken references, according to the
reference reason (e.g. down, scan).

This will allow us validate our state and add some debugfs
entries later on.

Unref the transport when the FW is fully initialized,
allowing it to go into a low power mode.

Disallow the transition to low-power while recovery is in
progress.
Signed-off-by: default avatarArik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: default avatarEliad Peller <eliadx.peller@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent d6230972
......@@ -446,6 +446,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
goto error;
/* allow FW/transport low power modes if not during restart */
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0;
error:
......
......@@ -202,6 +202,44 @@ static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = {
};
#endif
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
{
if (!mvm->trans->cfg->d0i3)
return;
IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type);
WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap));
iwl_trans_ref(mvm->trans);
}
void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
{
if (!mvm->trans->cfg->d0i3)
return;
IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap));
iwl_trans_unref(mvm->trans);
}
static void
iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref)
{
int i;
if (!mvm->trans->cfg->d0i3)
return;
for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) {
if (ref == i)
continue;
IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i);
clear_bit(i, mvm->ref_bitmap);
iwl_trans_unref(mvm->trans);
}
}
static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
{
int i;
......@@ -516,6 +554,10 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
ieee80211_wake_queues(mvm->hw);
/* cleanup all stale references (scan, roc), but keep the
* ucode_down ref until reconfig is complete */
iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
mvm->vif_count = 0;
mvm->rx_ba_sessions = 0;
}
......@@ -550,6 +592,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
ret);
/* allow transport/FW low power modes */
iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
mutex_unlock(&mvm->mutex);
}
......@@ -560,6 +605,10 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
flush_work(&mvm->async_handlers_wk);
mutex_lock(&mvm->mutex);
/* disallow low power states when the FW is down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
/* async_handlers_wk is now blocked */
/*
......
......@@ -239,6 +239,12 @@ enum iwl_mvm_smps_type_request {
NUM_IWL_MVM_SMPS_REQ,
};
enum iwl_mvm_ref_type {
IWL_MVM_REF_UCODE_DOWN,
IWL_MVM_REF_COUNT,
};
/**
* struct iwl_mvm_vif_bf_data - beacon filtering related data
* @bf_enabled: indicates if beacon filtering is enabled
......@@ -542,6 +548,9 @@ struct iwl_mvm {
*/
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
/* A bitmap of reference types taken by the driver. */
unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)];
u8 vif_count;
/* -1 for always, 0 for never, >0 for that many times */
......@@ -877,6 +886,10 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
}
#endif
/* D0i3 */
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);
/* BT Coex */
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
......
......@@ -501,6 +501,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
/* rpm starts with a taken ref. only set the appropriate bit here. */
set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap);
return op_mode;
out_unregister:
......@@ -788,6 +791,9 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
schedule_work(&reprobe->work);
} else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) {
/* don't let the transport/FW power down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
if (mvm->restart_fw > 0)
mvm->restart_fw--;
ieee80211_restart_hw(mvm->hw);
......
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