diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 42 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 1 |
4 files changed, 51 insertions, 5 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 8c9069f28a58..02b4ef92543f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1197,6 +1197,27 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr) return tid; } +void iwl_mvm_rs_init_wk(struct work_struct *wk) +{ + struct iwl_mvm_sta *mvmsta = container_of(wk, struct iwl_mvm_sta, + rs_init_wk); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + struct ieee80211_sta *sta; + + rcu_read_lock(); + + sta = rcu_dereference(mvmvif->mvm->fw_id_to_mac_id[mvmsta->sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return; + } + + iwl_mvm_rs_rate_init(mvmvif->mvm, sta, mvmvif->phy_ctxt->channel->band, + true); + + rcu_read_unlock(); +} + void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, struct ieee80211_tx_info *info, bool ndp) { @@ -1269,7 +1290,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, (unsigned long)(lq_sta->last_tx + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); - iwl_mvm_rs_rate_init(mvm, sta, info->band, true); + schedule_work(&mvmsta->rs_init_wk); return; } lq_sta->last_tx = jiffies; @@ -1442,16 +1463,24 @@ static void rs_drv_mac80211_tx_status(void *mvm_r, struct iwl_op_mode *op_mode = mvm_r; struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (!iwl_mvm_sta_from_mac80211(sta)->vif) + if (!mvmsta->vif) return; if (!ieee80211_is_data(hdr->frame_control) || info->flags & IEEE80211_TX_CTL_NO_ACK) return; + /* If it's locked we are in middle of init flow + * just wait for next tx status to update the lq_sta data + */ + if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex)) + return; + iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info, ieee80211_is_qos_nullfunc(hdr->frame_control)); + mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); } /* @@ -4132,10 +4161,15 @@ static const struct rate_control_ops rs_mvm_ops_drv = { void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, 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, update); - else + } else { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + + mutex_lock(&mvmsta->lq_sta.rs_drv.mutex); rs_drv_rate_init(mvm, sta, band, update); + mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex); + } } int iwl_mvm_rate_control_register(void) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index f7eb60dbaf20..086f47e2a4f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -4,7 +4,7 @@ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * Contact Information: * Intel Linux Wireless <linuxwifi@intel.com> @@ -376,6 +376,9 @@ struct iwl_lq_sta { /* tx power reduce for this sta */ int tpc_reduce; + /* avoid races of reinit and update table from rx_tx */ + struct mutex mutex; + /* persistent fields - initialized only once - keep last! */ struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS @@ -440,6 +443,8 @@ struct iwl_mvm_sta; int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); +void iwl_mvm_rs_init_wk(struct work_struct *wk); + #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm); #endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index f545a737a92d..ac9bc65c4d15 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1684,6 +1684,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, */ if (iwl_mvm_has_tlc_offload(mvm)) iwl_mvm_rs_add_sta(mvm, mvm_sta); + else + mutex_init(&mvm_sta->lq_sta.rs_drv.mutex); + + INIT_WORK(&mvm_sta->rs_init_wk, iwl_mvm_rs_init_wk); iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant); @@ -1846,6 +1850,8 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (ret) return ret; + cancel_work_sync(&mvm_sta->rs_init_wk); + /* flush its queues here since we are freeing mvm_sta */ ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 4487cc3e07c1..84139fc38c34 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -424,6 +424,7 @@ struct iwl_mvm_sta { struct iwl_lq_sta_rs_fw rs_fw; struct iwl_lq_sta rs_drv; } lq_sta; + struct work_struct rs_init_wk; struct ieee80211_vif *vif; struct iwl_mvm_key_pn __rcu *ptk_pn[4]; struct iwl_mvm_rxq_dup_data *dup_data; |