Commit d9bcbcb7 authored by Avraham Stern's avatar Avraham Stern Committed by Greg Kroah-Hartman

iwlwifi: mvm: Send LQ command as async when necessary

commit 3baf7528 upstream.

The parameter that indicated whether the LQ command should be sent
as sync or async was removed, causing the LQ command to be sent as
sync from interrupt context (e.g. from the RX path). This resulted
in a kernel warning: "scheduling while atomic" and failing to send
the LQ command, which ultimately leads to a queue hang.

Fix it by adding back the required parameter to send the command as
sync only when it is allowed.

Fixes: d94c5a82 ("iwlwifi: mvm: open BA session only when sta is authorized")
Signed-off-by: default avatarAvraham Stern <avraham.stern@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0d73e773
...@@ -2938,7 +2938,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ...@@ -2938,7 +2938,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
} }
iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
false);
ret = iwl_mvm_update_sta(mvm, vif, sta); ret = iwl_mvm_update_sta(mvm, vif, sta);
} else if (old_state == IEEE80211_STA_ASSOC && } else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) { new_state == IEEE80211_STA_AUTHORIZED) {
...@@ -2954,7 +2955,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ...@@ -2954,7 +2955,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
/* enable beacon filtering */ /* enable beacon filtering */
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
true);
ret = 0; ret = 0;
} else if (old_state == IEEE80211_STA_AUTHORIZED && } else if (old_state == IEEE80211_STA_AUTHORIZED &&
......
...@@ -1685,7 +1685,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ...@@ -1685,7 +1685,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
#endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUGFS */
/* rate scaling */ /* rate scaling */
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync);
void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg); void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg);
int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate); int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate);
void rs_update_last_rssi(struct iwl_mvm *mvm, void rs_update_last_rssi(struct iwl_mvm *mvm,
......
...@@ -1280,7 +1280,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -1280,7 +1280,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
(unsigned long)(lq_sta->last_tx + (unsigned long)(lq_sta->last_tx +
(IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
iwl_mvm_rs_rate_init(mvm, sta, info->band); iwl_mvm_rs_rate_init(mvm, sta, info->band, true);
return; return;
} }
lq_sta->last_tx = jiffies; lq_sta->last_tx = jiffies;
...@@ -2870,9 +2870,8 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, ...@@ -2870,9 +2870,8 @@ void rs_update_last_rssi(struct iwl_mvm *mvm,
static void rs_initialize_lq(struct iwl_mvm *mvm, static void rs_initialize_lq(struct iwl_mvm *mvm,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
enum nl80211_band band) enum nl80211_band band, bool update)
{ {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_scale_tbl_info *tbl; struct iwl_scale_tbl_info *tbl;
struct rs_rate *rate; struct rs_rate *rate;
u8 active_tbl = 0; u8 active_tbl = 0;
...@@ -2901,8 +2900,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, ...@@ -2901,8 +2900,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rs_set_expected_tpt_table(lq_sta, tbl); rs_set_expected_tpt_table(lq_sta, tbl);
rs_fill_lq_cmd(mvm, sta, lq_sta, rate); rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
/* TODO restore station should remember the lq cmd */ /* TODO restore station should remember the lq cmd */
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, !update);
mvmsta->sta_state < IEEE80211_STA_AUTHORIZED);
} }
static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
...@@ -3155,7 +3153,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) ...@@ -3155,7 +3153,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
* Called after adding a new station to initialize rate scaling * Called after adding a new station to initialize rate scaling
*/ */
static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum nl80211_band band) enum nl80211_band band, bool update)
{ {
int i, j; int i, j;
struct ieee80211_hw *hw = mvm->hw; struct ieee80211_hw *hw = mvm->hw;
...@@ -3235,7 +3233,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -3235,7 +3233,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm); iwl_mvm_reset_frame_stats(mvm);
#endif #endif
rs_initialize_lq(mvm, sta, lq_sta, band); rs_initialize_lq(mvm, sta, lq_sta, band, update);
} }
static void rs_drv_rate_update(void *mvm_r, static void rs_drv_rate_update(void *mvm_r,
...@@ -3255,7 +3253,7 @@ static void rs_drv_rate_update(void *mvm_r, ...@@ -3255,7 +3253,7 @@ static void rs_drv_rate_update(void *mvm_r,
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
ieee80211_stop_tx_ba_session(sta, tid); ieee80211_stop_tx_ba_session(sta, tid);
iwl_mvm_rs_rate_init(mvm, sta, sband->band); iwl_mvm_rs_rate_init(mvm, sta, sband->band, true);
} }
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
...@@ -4112,12 +4110,12 @@ static const struct rate_control_ops rs_mvm_ops_drv = { ...@@ -4112,12 +4110,12 @@ static const struct rate_control_ops rs_mvm_ops_drv = {
}; };
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum nl80211_band band) enum nl80211_band band, bool update)
{ {
if (iwl_mvm_has_tlc_offload(mvm)) if (iwl_mvm_has_tlc_offload(mvm))
rs_fw_rate_init(mvm, sta, band); rs_fw_rate_init(mvm, sta, band);
else else
rs_drv_rate_init(mvm, sta, band); rs_drv_rate_init(mvm, sta, band, update);
} }
int iwl_mvm_rate_control_register(void) int iwl_mvm_rate_control_register(void)
......
...@@ -420,7 +420,7 @@ struct iwl_lq_sta { ...@@ -420,7 +420,7 @@ struct iwl_lq_sta {
/* Initialize station's rate scaling information after adding station */ /* Initialize station's rate scaling information after adding station */
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum nl80211_band band); enum nl80211_band band, bool init);
/* Notify RS about Tx status */ /* Notify RS about Tx status */
void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
......
...@@ -900,20 +900,19 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, ...@@ -900,20 +900,19 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
/** /**
* iwl_mvm_send_lq_cmd() - Send link quality command * iwl_mvm_send_lq_cmd() - Send link quality command
* @init: This command is sent as part of station initialization right * @sync: This command can be sent synchronously.
* after station has been added.
* *
* The link quality command is sent as the last step of station creation. * The link quality command is sent as the last step of station creation.
* This is the special case in which init is set and we call a callback in * This is the special case in which init is set and we call a callback in
* this case to clear the state indicating that station creation is in * this case to clear the state indicating that station creation is in
* progress. * progress.
*/ */
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init) int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync)
{ {
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = LQ_CMD, .id = LQ_CMD,
.len = { sizeof(struct iwl_lq_cmd), }, .len = { sizeof(struct iwl_lq_cmd), },
.flags = init ? 0 : CMD_ASYNC, .flags = sync ? 0 : CMD_ASYNC,
.data = { lq, }, .data = { lq, },
}; };
......
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