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)
{
(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;
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);
}
/*
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)
* 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>
/* 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
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
*/
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);
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)