iwlwifi: mvm: remove non-DQA mode
All the firmware versions the driver supports enable DQA, and thus the only way to get non-DQA mode is to modify the source. Remove this mode to simplify the code. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
This commit is contained in:
parent
d197358b75
commit
c8f54701bd
|
@ -62,12 +62,6 @@
|
|||
#ifndef __iwl_fw_api_txq_h__
|
||||
#define __iwl_fw_api_txq_h__
|
||||
|
||||
/* Tx queue numbers for non-DQA mode */
|
||||
enum {
|
||||
IWL_MVM_OFFCHANNEL_QUEUE = 8,
|
||||
IWL_MVM_CMD_QUEUE = 9,
|
||||
};
|
||||
|
||||
/*
|
||||
* DQA queue numbers
|
||||
*
|
||||
|
|
|
@ -331,10 +331,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
|
|||
*/
|
||||
|
||||
memset(&mvm->queue_info, 0, sizeof(mvm->queue_info));
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].hw_queue_refcount = 1;
|
||||
else
|
||||
mvm->queue_info[IWL_MVM_CMD_QUEUE].hw_queue_refcount = 1;
|
||||
mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].hw_queue_refcount = 1;
|
||||
|
||||
for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
|
||||
atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
|
||||
|
@ -1137,14 +1134,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||
/* reset quota debouncing buffer - 0xff will yield invalid data */
|
||||
memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
|
||||
|
||||
/* Enable DQA-mode if required */
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
ret = iwl_mvm_send_dqa_cmd(mvm);
|
||||
if (ret)
|
||||
goto error;
|
||||
} else {
|
||||
IWL_DEBUG_FW(mvm, "Working in non-DQA mode\n");
|
||||
}
|
||||
ret = iwl_mvm_send_dqa_cmd(mvm);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* Add auxiliary station for scanning */
|
||||
ret = iwl_mvm_add_aux_sta(mvm);
|
||||
|
|
|
@ -241,32 +241,17 @@ static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac,
|
|||
data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_sta_hw_queues_iter(void *_data,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_mvm_hw_queues_iface_iterator_data *data = _data;
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
/* Mark the queues used by the sta */
|
||||
data->used_hw_queues |= mvmsta->tfd_queue_msk;
|
||||
}
|
||||
|
||||
unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *exclude_vif)
|
||||
{
|
||||
u8 sta_id;
|
||||
struct iwl_mvm_hw_queues_iface_iterator_data data = {
|
||||
.exclude_vif = exclude_vif,
|
||||
.used_hw_queues =
|
||||
BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
|
||||
BIT(mvm->aux_queue),
|
||||
BIT(mvm->aux_queue) |
|
||||
BIT(IWL_MVM_DQA_GCAST_QUEUE),
|
||||
};
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
data.used_hw_queues |= BIT(IWL_MVM_DQA_GCAST_QUEUE);
|
||||
else
|
||||
data.used_hw_queues |= BIT(IWL_MVM_CMD_QUEUE);
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/* mark all VIF used hw queues */
|
||||
|
@ -274,26 +259,6 @@ unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
|
|||
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
iwl_mvm_iface_hw_queues_iter, &data);
|
||||
|
||||
/*
|
||||
* for DQA, the hw_queue in mac80211 is never really used for
|
||||
* real traffic (only the few queue IDs covered above), so
|
||||
* we can reuse the real HW queue IDs the stations use
|
||||
*/
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
return data.used_hw_queues;
|
||||
|
||||
/* don't assign the same hw queues as TDLS stations */
|
||||
ieee80211_iterate_stations_atomic(mvm->hw,
|
||||
iwl_mvm_mac_sta_hw_queues_iter,
|
||||
&data);
|
||||
|
||||
/*
|
||||
* Some TDLS stations may be removed but are in the process of being
|
||||
* drained. Don't touch their queues.
|
||||
*/
|
||||
for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT)
|
||||
data.used_hw_queues |= mvm->tfd_drained[sta_id];
|
||||
|
||||
return data.used_hw_queues;
|
||||
}
|
||||
|
||||
|
@ -344,8 +309,7 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
|
|||
NUM_TSF_IDS);
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm_mac_iface_iterator_data data = {
|
||||
|
@ -361,6 +325,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
int ret, i, queue_limit;
|
||||
unsigned long used_hw_queues;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/*
|
||||
* Allocate a MAC ID and a TSF for this MAC, along with the queues
|
||||
* and other resources.
|
||||
|
@ -444,19 +410,14 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
/*
|
||||
* queues in mac80211 almost entirely independent of
|
||||
* the ones here - no real limit
|
||||
*/
|
||||
queue_limit = IEEE80211_MAX_QUEUES;
|
||||
BUILD_BUG_ON(IEEE80211_MAX_QUEUES >
|
||||
BITS_PER_BYTE *
|
||||
sizeof(mvm->hw_queue_to_mac80211[0]));
|
||||
} else {
|
||||
/* need to not use too many in this case */
|
||||
queue_limit = mvm->first_agg_queue;
|
||||
}
|
||||
/*
|
||||
* queues in mac80211 almost entirely independent of
|
||||
* the ones here - no real limit
|
||||
*/
|
||||
queue_limit = IEEE80211_MAX_QUEUES;
|
||||
BUILD_BUG_ON(IEEE80211_MAX_QUEUES >
|
||||
BITS_PER_BYTE *
|
||||
sizeof(mvm->hw_queue_to_mac80211[0]));
|
||||
|
||||
/*
|
||||
* Find available queues, and allocate them to the ACs. When in
|
||||
|
@ -478,27 +439,12 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
|
||||
/* Allocate the CAB queue for softAP and GO interfaces */
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
u8 queue;
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
queue = find_first_zero_bit(&used_hw_queues,
|
||||
mvm->first_agg_queue);
|
||||
|
||||
if (queue >= mvm->first_agg_queue) {
|
||||
IWL_ERR(mvm, "Failed to allocate cab queue\n");
|
||||
ret = -EIO;
|
||||
goto exit_fail;
|
||||
}
|
||||
} else {
|
||||
queue = IWL_MVM_DQA_GCAST_QUEUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* For TVQM this will be overwritten later with the FW assigned
|
||||
* queue value (when queue is enabled).
|
||||
*/
|
||||
mvmvif->cab_queue = queue;
|
||||
vif->cab_queue = queue;
|
||||
mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
|
||||
vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
|
||||
} else {
|
||||
vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
|
||||
}
|
||||
|
@ -519,78 +465,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
unsigned int wdg_timeout =
|
||||
iwl_mvm_get_wd_timeout(mvm, vif, false, false);
|
||||
u32 ac;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
ret = iwl_mvm_mac_ctxt_allocate_resources(mvm, vif);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If DQA is supported - queues will be enabled when needed */
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
return 0;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_TX_FIFO_VO, 0, wdg_timeout);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, vif->cab_queue,
|
||||
IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
|
||||
/* fall through */
|
||||
default:
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],
|
||||
vif->hw_queue[ac],
|
||||
iwl_mvm_ac_to_tx_fifo[ac], 0,
|
||||
wdg_timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
int ac;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/*
|
||||
* If DQA is supported - queues were already disabled, since in
|
||||
* DQA-mode the queues are a property of the STA and not of the
|
||||
* vif, and at this point the STA was already deleted
|
||||
*/
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
return;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MVM_OFFCHANNEL_QUEUE,
|
||||
IWL_MAX_TID_COUNT, 0);
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue,
|
||||
IWL_MAX_TID_COUNT, 0);
|
||||
/* fall through */
|
||||
default:
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
iwl_mvm_disable_txq(mvm, vif->hw_queue[ac],
|
||||
vif->hw_queue[ac],
|
||||
IWL_MAX_TID_COUNT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_ack_rates(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
enum nl80211_band band,
|
||||
|
@ -914,18 +788,12 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
|
|||
{
|
||||
struct iwl_mac_ctx_cmd cmd = {};
|
||||
u32 tfd_queue_msk = 0;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
|
||||
|
||||
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++)
|
||||
if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
|
||||
tfd_queue_msk |= BIT(vif->hw_queue[i]);
|
||||
}
|
||||
|
||||
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
|
||||
MAC_FILTER_IN_CONTROL_AND_MGMT |
|
||||
MAC_FILTER_IN_BEACON |
|
||||
|
|
|
@ -464,10 +464,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
if (mvm->trans->max_skb_frags)
|
||||
hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
hw->queues = mvm->first_agg_queue;
|
||||
else
|
||||
hw->queues = IEEE80211_MAX_QUEUES;
|
||||
hw->queues = IEEE80211_MAX_QUEUES;
|
||||
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
|
||||
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
|
||||
IEEE80211_RADIOTAP_MCS_HAVE_STBC;
|
||||
|
@ -1067,9 +1064,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
|||
|
||||
iwl_mvm_reset_phy_ctxts(mvm);
|
||||
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
|
||||
memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
|
||||
memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames));
|
||||
memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
|
||||
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
|
||||
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
|
||||
|
||||
|
@ -1372,17 +1367,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|||
goto out_release;
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
/*
|
||||
* Only queue for this station is the mcast queue,
|
||||
* which shouldn't be in TFD mask anyway
|
||||
*/
|
||||
ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->mcast_sta,
|
||||
0, vif->type,
|
||||
IWL_STA_MULTICAST);
|
||||
if (ret)
|
||||
goto out_release;
|
||||
}
|
||||
/*
|
||||
* Only queue for this station is the mcast queue,
|
||||
* which shouldn't be in TFD mask anyway
|
||||
*/
|
||||
ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->mcast_sta,
|
||||
0, vif->type,
|
||||
IWL_STA_MULTICAST);
|
||||
if (ret)
|
||||
goto out_release;
|
||||
|
||||
iwl_mvm_vif_dbgfs_register(mvm, vif);
|
||||
goto out_unlock;
|
||||
|
@ -1456,8 +1449,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|||
out_release:
|
||||
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
|
||||
mvm->vif_count--;
|
||||
|
||||
iwl_mvm_mac_ctxt_release(mvm, vif);
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
|
@ -1469,40 +1460,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|||
static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
|
||||
|
||||
if (tfd_msk && !iwl_mvm_is_dqa_supported(mvm)) {
|
||||
/*
|
||||
* mac80211 first removes all the stations of the vif and
|
||||
* then removes the vif. When it removes a station it also
|
||||
* flushes the AMPDU session. So by now, all the AMPDU sessions
|
||||
* of all the stations of this vif are closed, and the queues
|
||||
* of these AMPDU sessions are properly closed.
|
||||
* We still need to take care of the shared queues of the vif.
|
||||
* Flush them here.
|
||||
* For DQA mode there is no need - broacast and multicast queue
|
||||
* are flushed separately.
|
||||
*/
|
||||
mutex_lock(&mvm->mutex);
|
||||
iwl_mvm_flush_tx_path(mvm, tfd_msk, 0);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
/*
|
||||
* There are transports that buffer a few frames in the host.
|
||||
* For these, the flush above isn't enough since while we were
|
||||
* flushing, the transport might have sent more frames to the
|
||||
* device. To solve this, wait here until the transport is
|
||||
* empty. Technically, this could have replaced the flush
|
||||
* above, but flush is much faster than draining. So flush
|
||||
* first, and drain to make sure we have no frames in the
|
||||
* transport anymore.
|
||||
* If a station still had frames on the shared queues, it is
|
||||
* already marked as draining, so to complete the draining, we
|
||||
* just need to wait until the transport is empty.
|
||||
*/
|
||||
iwl_trans_wait_tx_queues_empty(mvm->trans, tfd_msk);
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
/*
|
||||
* Flush the ROC worker which will flush the OFFCHANNEL queue.
|
||||
|
@ -1510,14 +1467,6 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
|
|||
* queue are sent in ROC session.
|
||||
*/
|
||||
flush_work(&mvm->roc_done_wk);
|
||||
} else {
|
||||
/*
|
||||
* By now, all the AC queues are empty. The AGG queues are
|
||||
* empty too. We already got all the Tx responses for all the
|
||||
* packets in the queues. The drain work can have been
|
||||
* triggered. Flush it.
|
||||
*/
|
||||
flush_work(&mvm->sta_drained_wk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1571,7 +1520,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
iwl_mvm_mac_ctxt_remove(mvm, vif);
|
||||
|
||||
out_release:
|
||||
iwl_mvm_mac_ctxt_release(mvm, vif);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
|
@ -2419,11 +2367,6 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
|
|||
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
|
||||
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) &&
|
||||
tid_data->state != IWL_AGG_ON &&
|
||||
tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
|
||||
continue;
|
||||
|
||||
if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE)
|
||||
continue;
|
||||
|
||||
|
@ -2437,9 +2380,6 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
|
|||
|
||||
switch (cmd) {
|
||||
case STA_NOTIFY_SLEEP:
|
||||
if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
|
||||
ieee80211_sta_block_awake(hw, sta, true);
|
||||
|
||||
for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT)
|
||||
ieee80211_sta_set_buffered(sta, tid, true);
|
||||
|
||||
|
@ -2632,9 +2572,6 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
|
|||
if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
|
||||
return -EINVAL;
|
||||
|
||||
/* if a STA is being removed, reuse its ID */
|
||||
flush_work(&mvm->sta_drained_wk);
|
||||
|
||||
/*
|
||||
* If we are in a STA removal flow and in DQA mode:
|
||||
*
|
||||
|
@ -2649,8 +2586,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
|
|||
* make sure the worker is no longer handling frames for this STA.
|
||||
*/
|
||||
if (old_state == IEEE80211_STA_NONE &&
|
||||
new_state == IEEE80211_STA_NOTEXIST &&
|
||||
iwl_mvm_is_dqa_supported(mvm)) {
|
||||
new_state == IEEE80211_STA_NOTEXIST) {
|
||||
iwl_mvm_purge_deferred_tx_frames(mvm, mvm_sta);
|
||||
flush_work(&mvm->add_stream_wk);
|
||||
|
||||
|
@ -4032,8 +3968,7 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
|
|||
return;
|
||||
|
||||
/* Make sure we're done with the deferred traffic before flushing */
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
flush_work(&mvm->add_stream_wk);
|
||||
flush_work(&mvm->add_stream_wk);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
|
|
@ -121,6 +121,9 @@
|
|||
*/
|
||||
#define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3
|
||||
|
||||
/* offchannel queue towards mac80211 */
|
||||
#define IWL_MVM_OFFCHANNEL_QUEUE 0
|
||||
|
||||
extern const struct ieee80211_ops iwl_mvm_hw_ops;
|
||||
|
||||
/**
|
||||
|
@ -783,11 +786,7 @@ struct iwl_mvm {
|
|||
/* data related to data path */
|
||||
struct iwl_rx_phy_info last_phy_info;
|
||||
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
|
||||
struct work_struct sta_drained_wk;
|
||||
unsigned long sta_deferred_frames[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
|
||||
unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
|
||||
atomic_t pending_frames[IWL_MVM_STATION_COUNT];
|
||||
u32 tfd_drained[IWL_MVM_STATION_COUNT];
|
||||
u8 rx_ba_sessions;
|
||||
|
||||
/* configured by mac80211 */
|
||||
|
@ -960,9 +959,6 @@ struct iwl_mvm {
|
|||
u16 probe_queue;
|
||||
u16 p2p_dev_queue;
|
||||
|
||||
u8 first_agg_queue;
|
||||
u8 last_agg_queue;
|
||||
|
||||
/* Indicate if device power save is allowed */
|
||||
u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
|
||||
unsigned int max_amsdu_len; /* used for debugfs only */
|
||||
|
@ -1125,12 +1121,6 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
|
|||
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
return fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_DQA_SUPPORT);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
|
||||
{
|
||||
/* For now we only use this mode to differentiate between
|
||||
|
@ -1469,7 +1459,6 @@ u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef);
|
|||
|
||||
/* MAC (virtual interface) programming */
|
||||
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
bool force_assoc_off, const u8 *bssid_override);
|
||||
|
@ -1720,10 +1709,6 @@ bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
|||
int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
|
||||
u8 sta_id, u8 tid, unsigned int timeout);
|
||||
|
||||
/*
|
||||
* Disable a TXQ.
|
||||
* Note that in non-DQA mode the %mac80211_queue and %tid params are ignored.
|
||||
*/
|
||||
int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
||||
u8 tid, u8 flags);
|
||||
int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq);
|
||||
|
@ -1733,25 +1718,8 @@ int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq);
|
|||
*/
|
||||
static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)
|
||||
{
|
||||
u32 cmd_queue = iwl_mvm_is_dqa_supported(mvm) ? IWL_MVM_DQA_CMD_QUEUE :
|
||||
IWL_MVM_CMD_QUEUE;
|
||||
|
||||
return ((BIT(mvm->cfg->base_params->num_of_queues) - 1) &
|
||||
~BIT(cmd_queue));
|
||||
}
|
||||
|
||||
static inline
|
||||
void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
||||
u8 fifo, u16 ssn, unsigned int wdg_timeout)
|
||||
{
|
||||
struct iwl_trans_txq_scd_cfg cfg = {
|
||||
.fifo = fifo,
|
||||
.tid = IWL_MAX_TID_COUNT,
|
||||
.aggregate = false,
|
||||
.frame_limit = IWL_FRAME_LIMIT,
|
||||
};
|
||||
|
||||
iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout);
|
||||
~BIT(IWL_MVM_DQA_CMD_QUEUE));
|
||||
}
|
||||
|
||||
static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
|
||||
|
|
|
@ -623,27 +623,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0;
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1;
|
||||
mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE;
|
||||
mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
|
||||
mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE;
|
||||
|
||||
if (mvm->cfg->base_params->num_of_queues == 16) {
|
||||
mvm->aux_queue = 11;
|
||||
mvm->first_agg_queue = 12;
|
||||
BUILD_BUG_ON(BITS_PER_BYTE *
|
||||
sizeof(mvm->hw_queue_to_mac80211[0]) < 12);
|
||||
} else {
|
||||
mvm->aux_queue = 15;
|
||||
mvm->first_agg_queue = 16;
|
||||
BUILD_BUG_ON(BITS_PER_BYTE *
|
||||
sizeof(mvm->hw_queue_to_mac80211[0]) < 16);
|
||||
}
|
||||
} else {
|
||||
mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE;
|
||||
mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
|
||||
mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE;
|
||||
mvm->first_agg_queue = IWL_MVM_DQA_MIN_DATA_QUEUE;
|
||||
mvm->last_agg_queue = IWL_MVM_DQA_MAX_DATA_QUEUE;
|
||||
}
|
||||
mvm->sf_state = SF_UNINIT;
|
||||
if (iwl_mvm_has_unified_ucode(mvm))
|
||||
iwl_fw_set_current_image(&mvm->fwrt, IWL_UCODE_REGULAR);
|
||||
|
@ -662,7 +645,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
|
||||
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
|
||||
INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
|
||||
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
|
||||
INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);
|
||||
INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk);
|
||||
|
@ -714,10 +696,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
trans_cfg.command_groups = iwl_mvm_groups;
|
||||
trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups);
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
trans_cfg.cmd_queue = IWL_MVM_DQA_CMD_QUEUE;
|
||||
else
|
||||
trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
|
||||
trans_cfg.cmd_queue = IWL_MVM_DQA_CMD_QUEUE;
|
||||
trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
|
||||
trans_cfg.scd_set_active = true;
|
||||
|
||||
|
|
|
@ -284,60 +284,6 @@ static void iwl_mvm_rx_agg_session_expired(unsigned long data)
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
unsigned long used_hw_queues;
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
unsigned int wdg_timeout =
|
||||
iwl_mvm_get_wd_timeout(mvm, NULL, true, false);
|
||||
u32 ac;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, NULL);
|
||||
|
||||
/* Find available queues, and allocate them to the ACs */
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
u8 queue = find_first_zero_bit(&used_hw_queues,
|
||||
mvm->first_agg_queue);
|
||||
|
||||
if (queue >= mvm->first_agg_queue) {
|
||||
IWL_ERR(mvm, "Failed to allocate STA queue\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
__set_bit(queue, &used_hw_queues);
|
||||
mvmsta->hw_queue[ac] = queue;
|
||||
}
|
||||
|
||||
/* Found a place for all queues - enable them */
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac],
|
||||
mvmsta->hw_queue[ac],
|
||||
iwl_mvm_mac_ac_to_tx_fifo(mvm, ac), 0,
|
||||
wdg_timeout);
|
||||
mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
unsigned long sta_msk;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/* disable the TDLS STA-specific queues */
|
||||
sta_msk = mvmsta->tfd_queue_msk;
|
||||
for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE)
|
||||
iwl_mvm_disable_txq(mvm, i, i, IWL_MAX_TID_COUNT, 0);
|
||||
}
|
||||
|
||||
/* Disable aggregations for a bitmap of TIDs for a given station */
|
||||
static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue,
|
||||
unsigned long disable_agg_tids,
|
||||
|
@ -1317,8 +1263,6 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
|
|||
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_set(&mvm->pending_frames[mvm_sta->sta_id], 0);
|
||||
}
|
||||
|
||||
int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
||||
|
@ -1343,9 +1287,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
|||
|
||||
spin_lock_init(&mvm_sta->lock);
|
||||
|
||||
/* In DQA mode, if this is a HW restart, re-alloc existing queues */
|
||||
if (iwl_mvm_is_dqa_supported(mvm) &&
|
||||
test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
|
||||
/* if this is a HW restart re-alloc existing queues */
|
||||
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
|
||||
iwl_mvm_realloc_queues_after_restart(mvm, mvm_sta);
|
||||
goto update_fw;
|
||||
}
|
||||
|
@ -1363,33 +1306,15 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
|||
mvm_sta->sta_type = sta->tdls ? IWL_STA_TDLS_LINK : IWL_STA_LINK;
|
||||
|
||||
/* HW restart, don't assume the memory has been zeroed */
|
||||
atomic_set(&mvm->pending_frames[sta_id], 0);
|
||||
mvm_sta->tid_disable_agg = 0xffff; /* No aggs at first */
|
||||
mvm_sta->tfd_queue_msk = 0;
|
||||
|
||||
/*
|
||||
* Allocate new queues for a TDLS station, unless we're in DQA mode,
|
||||
* and then they'll be allocated dynamically
|
||||
*/
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) {
|
||||
ret = iwl_mvm_tdls_sta_init(mvm, sta);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++)
|
||||
if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
|
||||
mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
|
||||
}
|
||||
|
||||
/* for HW restart - reset everything but the sequence number */
|
||||
for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
|
||||
u16 seq = mvm_sta->tid_data[i].seq_number;
|
||||
memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i]));
|
||||
mvm_sta->tid_data[i].seq_number = seq;
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Mark all queues for this STA as unallocated and defer TX
|
||||
* frames until the queue is allocated
|
||||
|
@ -1423,7 +1348,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
|||
mvm_sta->dup_data = dup_data;
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm) && !iwl_mvm_has_new_tx_api(mvm)) {
|
||||
if (!iwl_mvm_has_new_tx_api(mvm)) {
|
||||
ret = iwl_mvm_reserve_sta_stream(mvm, sta,
|
||||
ieee80211_vif_type_p2p(vif));
|
||||
if (ret)
|
||||
|
@ -1449,8 +1374,6 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
|||
return 0;
|
||||
|
||||
err:
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls)
|
||||
iwl_mvm_tdls_sta_deinit(mvm, sta);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1523,79 +1446,6 @@ static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void iwl_mvm_sta_drained_wk(struct work_struct *wk)
|
||||
{
|
||||
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, sta_drained_wk);
|
||||
u8 sta_id;
|
||||
|
||||
/*
|
||||
* The mutex is needed because of the SYNC cmd, but not only: if the
|
||||
* work would run concurrently with iwl_mvm_rm_sta, it would run before
|
||||
* iwl_mvm_rm_sta sets the station as busy, and exit. Then
|
||||
* iwl_mvm_rm_sta would set the station as busy, and nobody will clean
|
||||
* that later.
|
||||
*/
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) {
|
||||
int ret;
|
||||
struct ieee80211_sta *sta =
|
||||
rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
|
||||
/*
|
||||
* This station is in use or RCU-removed; the latter happens in
|
||||
* managed mode, where mac80211 removes the station before we
|
||||
* can remove it from firmware (we can only do that after the
|
||||
* MAC is marked unassociated), and possibly while the deauth
|
||||
* frame to disconnect from the AP is still queued. Then, the
|
||||
* station pointer is -ENOENT when the last skb is reclaimed.
|
||||
*/
|
||||
if (!IS_ERR(sta) || PTR_ERR(sta) == -ENOENT)
|
||||
continue;
|
||||
|
||||
if (PTR_ERR(sta) == -EINVAL) {
|
||||
IWL_ERR(mvm, "Drained sta %d, but it is internal?\n",
|
||||
sta_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sta) {
|
||||
IWL_ERR(mvm, "Drained sta %d, but it was NULL?\n",
|
||||
sta_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
WARN_ON(PTR_ERR(sta) != -EBUSY);
|
||||
/* This station was removed and we waited until it got drained,
|
||||
* we can now proceed and remove it.
|
||||
*/
|
||||
ret = iwl_mvm_rm_sta_common(mvm, sta_id);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Couldn't remove sta %d after it was drained\n",
|
||||
sta_id);
|
||||
continue;
|
||||
}
|
||||
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
|
||||
clear_bit(sta_id, mvm->sta_drained);
|
||||
|
||||
if (mvm->tfd_drained[sta_id]) {
|
||||
unsigned long i, msk = mvm->tfd_drained[sta_id];
|
||||
|
||||
for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE)
|
||||
iwl_mvm_disable_txq(mvm, i, i,
|
||||
IWL_MAX_TID_COUNT, 0);
|
||||
|
||||
mvm->tfd_drained[sta_id] = 0;
|
||||
IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n",
|
||||
sta_id, msk);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_mvm_sta *mvm_sta)
|
||||
|
@ -1654,79 +1504,65 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
|
|||
if (iwl_mvm_has_new_rx_api(mvm))
|
||||
kfree(mvm_sta->dup_data);
|
||||
|
||||
if ((vif->type == NL80211_IFTYPE_STATION &&
|
||||
mvmvif->ap_sta_id == sta_id) ||
|
||||
iwl_mvm_is_dqa_supported(mvm)){
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* flush its queues here since we are freeing mvm_sta */
|
||||
ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (iwl_mvm_has_new_tx_api(mvm)) {
|
||||
ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta);
|
||||
} else {
|
||||
u32 q_mask = mvm_sta->tfd_queue_msk;
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iwl_trans_wait_tx_queues_empty(mvm->trans,
|
||||
q_mask);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, false);
|
||||
/* flush its queues here since we are freeing mvm_sta */
|
||||
ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (iwl_mvm_has_new_tx_api(mvm)) {
|
||||
ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta);
|
||||
} else {
|
||||
u32 q_mask = mvm_sta->tfd_queue_msk;
|
||||
|
||||
/* If DQA is supported - the queues can be disabled now */
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta);
|
||||
/*
|
||||
* If pending_frames is set at this point - it must be
|
||||
* driver internal logic error, since queues are empty
|
||||
* and removed successuly.
|
||||
* warn on it but set it to 0 anyway to avoid station
|
||||
* not being removed later in the function
|
||||
*/
|
||||
WARN_ON(atomic_xchg(&mvm->pending_frames[sta_id], 0));
|
||||
}
|
||||
ret = iwl_trans_wait_tx_queues_empty(mvm->trans,
|
||||
q_mask);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If there is a TXQ still marked as reserved - free it */
|
||||
if (iwl_mvm_is_dqa_supported(mvm) &&
|
||||
mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) {
|
||||
u8 reserved_txq = mvm_sta->reserved_queue;
|
||||
enum iwl_mvm_queue_status *status;
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, false);
|
||||
|
||||
/*
|
||||
* If no traffic has gone through the reserved TXQ - it
|
||||
* is still marked as IWL_MVM_QUEUE_RESERVED, and
|
||||
* should be manually marked as free again
|
||||
*/
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
status = &mvm->queue_info[reserved_txq].status;
|
||||
if (WARN((*status != IWL_MVM_QUEUE_RESERVED) &&
|
||||
(*status != IWL_MVM_QUEUE_FREE),
|
||||
"sta_id %d reserved txq %d status %d",
|
||||
sta_id, reserved_txq, *status)) {
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta);
|
||||
|
||||
*status = IWL_MVM_QUEUE_FREE;
|
||||
/* If there is a TXQ still marked as reserved - free it */
|
||||
if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) {
|
||||
u8 reserved_txq = mvm_sta->reserved_queue;
|
||||
enum iwl_mvm_queue_status *status;
|
||||
|
||||
/*
|
||||
* If no traffic has gone through the reserved TXQ - it
|
||||
* is still marked as IWL_MVM_QUEUE_RESERVED, and
|
||||
* should be manually marked as free again
|
||||
*/
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
status = &mvm->queue_info[reserved_txq].status;
|
||||
if (WARN((*status != IWL_MVM_QUEUE_RESERVED) &&
|
||||
(*status != IWL_MVM_QUEUE_FREE),
|
||||
"sta_id %d reserved txq %d status %d",
|
||||
sta_id, reserved_txq, *status)) {
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION &&
|
||||
mvmvif->ap_sta_id == sta_id) {
|
||||
/* if associated - we can't remove the AP STA now */
|
||||
if (vif->bss_conf.assoc)
|
||||
return ret;
|
||||
*status = IWL_MVM_QUEUE_FREE;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
}
|
||||
|
||||
/* unassoc - go ahead - remove the AP STA now */
|
||||
mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;
|
||||
if (vif->type == NL80211_IFTYPE_STATION &&
|
||||
mvmvif->ap_sta_id == sta_id) {
|
||||
/* if associated - we can't remove the AP STA now */
|
||||
if (vif->bss_conf.assoc)
|
||||
return ret;
|
||||
|
||||
/* clear d0i3_ap_sta_id if no longer relevant */
|
||||
if (mvm->d0i3_ap_sta_id == sta_id)
|
||||
mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA;
|
||||
}
|
||||
/* unassoc - go ahead - remove the AP STA now */
|
||||
mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;
|
||||
|
||||
/* clear d0i3_ap_sta_id if no longer relevant */
|
||||
if (mvm->d0i3_ap_sta_id == sta_id)
|
||||
mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1743,32 +1579,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
|
|||
* calls the drain worker.
|
||||
*/
|
||||
spin_lock_bh(&mvm_sta->lock);
|
||||
spin_unlock_bh(&mvm_sta->lock);
|
||||
|
||||
/*
|
||||
* There are frames pending on the AC queues for this station.
|
||||
* We need to wait until all the frames are drained...
|
||||
*/
|
||||
if (atomic_read(&mvm->pending_frames[sta_id])) {
|
||||
rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id],
|
||||
ERR_PTR(-EBUSY));
|
||||
spin_unlock_bh(&mvm_sta->lock);
|
||||
|
||||
/* disable TDLS sta queues on drain complete */
|
||||
if (sta->tdls) {
|
||||
mvm->tfd_drained[sta_id] = mvm_sta->tfd_queue_msk;
|
||||
IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n", sta_id);
|
||||
}
|
||||
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
|
||||
} else {
|
||||
spin_unlock_bh(&mvm_sta->lock);
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls)
|
||||
iwl_mvm_tdls_sta_deinit(mvm, sta);
|
||||
|
||||
ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
|
||||
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
|
||||
}
|
||||
ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
|
||||
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1867,7 +1681,7 @@ static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm)
|
|||
IWL_MAX_TID_COUNT,
|
||||
wdg_timeout);
|
||||
mvm->aux_queue = queue;
|
||||
} else if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
} else {
|
||||
struct iwl_trans_txq_scd_cfg cfg = {
|
||||
.fifo = IWL_MVM_TX_FIFO_MCAST,
|
||||
.sta_id = mvm->aux_sta.sta_id,
|
||||
|
@ -1878,9 +1692,6 @@ static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm)
|
|||
|
||||
iwl_mvm_enable_txq(mvm, mvm->aux_queue, mvm->aux_queue, 0, &cfg,
|
||||
wdg_timeout);
|
||||
} else {
|
||||
iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue,
|
||||
IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1980,7 +1791,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm) && !iwl_mvm_has_new_tx_api(mvm)) {
|
||||
if (!iwl_mvm_has_new_tx_api(mvm)) {
|
||||
if (vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC)
|
||||
queue = mvm->probe_queue;
|
||||
|
@ -2066,8 +1877,7 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
iwl_mvm_free_bcast_sta_queues(mvm, vif);
|
||||
iwl_mvm_free_bcast_sta_queues(mvm, vif);
|
||||
|
||||
ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id);
|
||||
if (ret)
|
||||
|
@ -2078,23 +1888,10 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
u32 qmask = 0;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
qmask = iwl_mvm_mac_get_queues_mask(vif);
|
||||
|
||||
/*
|
||||
* The firmware defines the TFD queue mask to only be relevant
|
||||
* for *unicast* queues, so the multicast (CAB) queue shouldn't
|
||||
* be included. This only happens in NL80211_IFTYPE_AP vif type,
|
||||
* so the next line will only have an effect there.
|
||||
*/
|
||||
qmask &= ~BIT(vif->cab_queue);
|
||||
}
|
||||
|
||||
return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask,
|
||||
return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, 0,
|
||||
ieee80211_vif_type_p2p(vif),
|
||||
IWL_STA_GENERAL_PURPOSE);
|
||||
}
|
||||
|
@ -2176,9 +1973,6 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_AP &&
|
||||
vif->type != NL80211_IFTYPE_ADHOC))
|
||||
return -ENOTSUPP;
|
||||
|
@ -2243,9 +2037,6 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
return 0;
|
||||
|
||||
iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0);
|
||||
|
||||
iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue,
|
||||
|
@ -2495,8 +2286,6 @@ int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
mvm_sta->tid_disable_agg &= ~BIT(tid);
|
||||
} else {
|
||||
/* In DQA-mode the queue isn't removed on agg termination */
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
mvm_sta->tfd_queue_msk &= ~BIT(queue);
|
||||
mvm_sta->tid_disable_agg |= BIT(tid);
|
||||
}
|
||||
|
||||
|
@ -2599,19 +2388,17 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
ret = -ENXIO;
|
||||
goto release_locks;
|
||||
}
|
||||
} else if (iwl_mvm_is_dqa_supported(mvm) &&
|
||||
unlikely(mvm->queue_info[txq_id].status ==
|
||||
} else if (unlikely(mvm->queue_info[txq_id].status ==
|
||||
IWL_MVM_QUEUE_SHARED)) {
|
||||
ret = -ENXIO;
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"Can't start tid %d agg on shared queue!\n",
|
||||
tid);
|
||||
goto release_locks;
|
||||
} else if (!iwl_mvm_is_dqa_supported(mvm) ||
|
||||
mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) {
|
||||
} else if (mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) {
|
||||
txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
|
||||
mvm->first_agg_queue,
|
||||
mvm->last_agg_queue);
|
||||
IWL_MVM_DQA_MIN_DATA_QUEUE,
|
||||
IWL_MVM_DQA_MAX_DATA_QUEUE);
|
||||
if (txq_id < 0) {
|
||||
ret = txq_id;
|
||||
IWL_ERR(mvm, "Failed to allocate agg queue\n");
|
||||
|
@ -2729,37 +2516,34 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
queue_status = mvm->queue_info[queue].status;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/* In DQA mode, the existing queue might need to be reconfigured */
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
/* Maybe there is no need to even alloc a queue... */
|
||||
if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_READY)
|
||||
alloc_queue = false;
|
||||
/* Maybe there is no need to even alloc a queue... */
|
||||
if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_READY)
|
||||
alloc_queue = false;
|
||||
|
||||
/*
|
||||
* Only reconfig the SCD for the queue if the window size has
|
||||
* changed from current (become smaller)
|
||||
*/
|
||||
if (!alloc_queue && buf_size < mvmsta->max_agg_bufsize) {
|
||||
/*
|
||||
* Only reconfig the SCD for the queue if the window size has
|
||||
* changed from current (become smaller)
|
||||
* If reconfiguring an existing queue, it first must be
|
||||
* drained
|
||||
*/
|
||||
if (!alloc_queue && buf_size < mvmsta->max_agg_bufsize) {
|
||||
/*
|
||||
* If reconfiguring an existing queue, it first must be
|
||||
* drained
|
||||
*/
|
||||
ret = iwl_trans_wait_tx_queues_empty(mvm->trans,
|
||||
BIT(queue));
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Error draining queue before reconfig\n");
|
||||
return ret;
|
||||
}
|
||||
ret = iwl_trans_wait_tx_queues_empty(mvm->trans,
|
||||
BIT(queue));
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Error draining queue before reconfig\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_reconfig_scd(mvm, queue, cfg.fifo,
|
||||
mvmsta->sta_id, tid,
|
||||
buf_size, ssn);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Error reconfiguring TXQ #%d\n", queue);
|
||||
return ret;
|
||||
}
|
||||
ret = iwl_mvm_reconfig_scd(mvm, queue, cfg.fifo,
|
||||
mvmsta->sta_id, tid,
|
||||
buf_size, ssn);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Error reconfiguring TXQ #%d\n", queue);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2855,18 +2639,6 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
"ssn = %d, next_recl = %d\n",
|
||||
tid_data->ssn, tid_data->next_reclaimed);
|
||||
|
||||
/*
|
||||
* There are still packets for this RA / TID in the HW.
|
||||
* Not relevant for DQA mode, since there is no need to disable
|
||||
* the queue.
|
||||
*/
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) &&
|
||||
tid_data->ssn != tid_data->next_reclaimed) {
|
||||
tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
tid_data->ssn = 0xffff;
|
||||
tid_data->state = IWL_AGG_OFF;
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
@ -2874,12 +2646,6 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
|
||||
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
int mac_queue = vif->hw_queue[tid_to_mac80211_ac[tid]];
|
||||
|
||||
iwl_mvm_disable_txq(mvm, txq_id, mac_queue, tid, 0);
|
||||
}
|
||||
return 0;
|
||||
case IWL_AGG_STARTING:
|
||||
case IWL_EMPTYING_HW_QUEUE_ADDBA:
|
||||
|
@ -2949,13 +2715,6 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
iwl_mvm_drain_sta(mvm, mvmsta, false);
|
||||
|
||||
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
int mac_queue = vif->hw_queue[tid_to_mac80211_ac[tid]];
|
||||
|
||||
iwl_mvm_disable_txq(mvm, tid_data->txq_id, mac_queue,
|
||||
tid, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3574,15 +3333,6 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
|
|||
u16 n_queued;
|
||||
|
||||
tid_data = &mvmsta->tid_data[tid];
|
||||
if (WARN(!iwl_mvm_is_dqa_supported(mvm) &&
|
||||
tid_data->state != IWL_AGG_ON &&
|
||||
tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA,
|
||||
"TID %d state is %d\n",
|
||||
tid, tid_data->state)) {
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
ieee80211_sta_eosp(sta);
|
||||
return;
|
||||
}
|
||||
|
||||
n_queued = iwl_mvm_tid_queued(mvm, tid_data);
|
||||
if (n_queued > remaining) {
|
||||
|
@ -3676,13 +3426,8 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
|
|||
|
||||
mvm_sta->disable_tx = disable;
|
||||
|
||||
/*
|
||||
* Tell mac80211 to start/stop queuing tx for this station,
|
||||
* but don't stop queuing if there are still pending frames
|
||||
* for this station.
|
||||
*/
|
||||
if (disable || !atomic_read(&mvm->pending_frames[mvm_sta->sta_id]))
|
||||
ieee80211_sta_block_awake(mvm->hw, sta, disable);
|
||||
/* Tell mac80211 to start/stop queuing tx for this station */
|
||||
ieee80211_sta_block_awake(mvm->hw, sta, disable);
|
||||
|
||||
iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable);
|
||||
|
||||
|
|
|
@ -222,16 +222,7 @@ struct iwl_mvm_vif;
|
|||
* we remove the STA of the AP. The flush can be done synchronously against the
|
||||
* fw.
|
||||
* Drain means that the fw will drop all the frames sent to a specific station.
|
||||
* This is useful when a client (if we are IBSS / GO or AP) disassociates. In
|
||||
* that case, we need to drain all the frames for that client from the AC queues
|
||||
* that are shared with the other clients. Only then, we can remove the STA in
|
||||
* the fw. In order to do so, we track the non-AMPDU packets for each station.
|
||||
* If mac80211 removes a STA and if it still has non-AMPDU packets pending in
|
||||
* the queues, we mark this station as %EBUSY in %fw_id_to_mac_id, and drop all
|
||||
* the frames for this STA (%iwl_mvm_rm_sta). When the last frame is dropped
|
||||
* (we know about it with its Tx response), we remove the station in fw and set
|
||||
* it as %NULL in %fw_id_to_mac_id: this is the purpose of
|
||||
* %iwl_mvm_sta_drained_wk.
|
||||
* This is useful when a client (if we are IBSS / GO or AP) disassociates.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -371,7 +362,6 @@ struct iwl_mvm_rxq_dup_data {
|
|||
* struct iwl_mvm_sta - representation of a station in the driver
|
||||
* @sta_id: the index of the station in the fw (will be replaced by id_n_color)
|
||||
* @tfd_queue_msk: the tfd queues used by the station
|
||||
* @hw_queue: per-AC mapping of the TFD queues used by station
|
||||
* @mac_id_n_color: the MAC context this station is linked to
|
||||
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
|
||||
* tid.
|
||||
|
@ -409,7 +399,6 @@ struct iwl_mvm_rxq_dup_data {
|
|||
struct iwl_mvm_sta {
|
||||
u32 sta_id;
|
||||
u32 tfd_queue_msk;
|
||||
u8 hw_queue[IEEE80211_NUM_ACS];
|
||||
u32 mac_id_n_color;
|
||||
u16 tid_disable_agg;
|
||||
u8 max_agg_bufsize;
|
||||
|
@ -548,7 +537,6 @@ int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
|||
int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm);
|
||||
|
||||
void iwl_mvm_sta_drained_wk(struct work_struct *wk);
|
||||
void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta);
|
||||
void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
|
||||
|
|
|
@ -129,10 +129,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
|
|||
* issue as it will have to complete before the next command is
|
||||
* executed, and a new time event means a new command.
|
||||
*/
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC);
|
||||
else
|
||||
iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC);
|
||||
iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC);
|
||||
}
|
||||
|
||||
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
|
||||
|
|
|
@ -552,9 +552,6 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
|
|||
{
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
return info->hw_queue;
|
||||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif);
|
||||
|
||||
switch (info->control.vif->type) {
|
||||
|
@ -653,8 +650,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
|
||||
if (ap_sta_id != IWL_MVM_INVALID_STA)
|
||||
sta_id = ap_sta_id;
|
||||
} else if (iwl_mvm_is_dqa_supported(mvm) &&
|
||||
info.control.vif->type == NL80211_IFTYPE_MONITOR) {
|
||||
} else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
|
||||
queue = mvm->aux_queue;
|
||||
}
|
||||
}
|
||||
|
@ -673,17 +669,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increase the pending frames counter, so that later when a reply comes
|
||||
* in and the counter is decreased - we don't start getting negative
|
||||
* values.
|
||||
* Note that we don't need to make sure it isn't agg'd, since we're
|
||||
* TXing non-sta
|
||||
* For DQA mode - we shouldn't increase it though
|
||||
*/
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
atomic_inc(&mvm->pending_frames[sta_id]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -994,22 +979,13 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
}
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm) || is_ampdu)
|
||||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
|
||||
if (sta->tdls && !iwl_mvm_is_dqa_supported(mvm)) {
|
||||
/* default to TID 0 for non-QoS packets */
|
||||
u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid;
|
||||
|
||||
txq_id = mvmsta->hw_queue[tid_to_mac80211_ac[tdls_tid]];
|
||||
}
|
||||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
|
||||
WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
|
||||
|
||||
/* Check if TXQ needs to be allocated or re-activated */
|
||||
if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE ||
|
||||
!mvmsta->tid_data[tid].is_tid_active) &&
|
||||
iwl_mvm_is_dqa_supported(mvm)) {
|
||||
!mvmsta->tid_data[tid].is_tid_active)) {
|
||||
/* If TXQ needs to be allocated... */
|
||||
if (txq_id == IWL_MVM_INVALID_QUEUE) {
|
||||
iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb);
|
||||
|
@ -1036,7 +1012,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
txq_id);
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm) && !iwl_mvm_has_new_tx_api(mvm)) {
|
||||
if (!iwl_mvm_has_new_tx_api(mvm)) {
|
||||
/* Keep track of the time of the last frame for this RA/TID */
|
||||
mvm->queue_info[txq_id].last_frame_time[tid] = jiffies;
|
||||
|
||||
|
@ -1070,10 +1046,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
|
||||
spin_unlock(&mvmsta->lock);
|
||||
|
||||
/* Increase pending frames count if this isn't AMPDU or DQA queue */
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu)
|
||||
atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
|
||||
|
||||
return 0;
|
||||
|
||||
drop_unlock_sta:
|
||||
|
@ -1142,8 +1114,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
|
|||
lockdep_assert_held(&mvmsta->lock);
|
||||
|
||||
if ((tid_data->state == IWL_AGG_ON ||
|
||||
tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA ||
|
||||
iwl_mvm_is_dqa_supported(mvm)) &&
|
||||
tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) &&
|
||||
iwl_mvm_tid_queued(mvm, tid_data) == 0) {
|
||||
/*
|
||||
* Now that this aggregation or DQA queue is empty tell
|
||||
|
@ -1177,13 +1148,6 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
|
|||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"Can continue DELBA flow ssn = next_recl = %d\n",
|
||||
tid_data->next_reclaimed);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
u8 mac80211_ac = tid_to_mac80211_ac[tid];
|
||||
|
||||
iwl_mvm_disable_txq(mvm, tid_data->txq_id,
|
||||
vif->hw_queue[mac80211_ac], tid,
|
||||
CMD_ASYNC);
|
||||
}
|
||||
tid_data->state = IWL_AGG_OFF;
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
|
@ -1381,10 +1345,10 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
break;
|
||||
case TX_STATUS_FAIL_DEST_PS:
|
||||
/* In DQA, the FW should have stopped the queue and not
|
||||
/* the FW should have stopped the queue and not
|
||||
* return this status
|
||||
*/
|
||||
WARN_ON(iwl_mvm_is_dqa_supported(mvm));
|
||||
WARN_ON(1);
|
||||
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
||||
break;
|
||||
default:
|
||||
|
@ -1440,26 +1404,21 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
ieee80211_tx_status(mvm->hw, skb);
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue) {
|
||||
/* If this is an aggregation queue, we use the ssn since:
|
||||
* ssn = wifi seq_num % 256.
|
||||
* The seq_ctl is the sequence control of the packet to which
|
||||
* this Tx response relates. But if there is a hole in the
|
||||
* bitmap of the BA we received, this Tx response may allow to
|
||||
* reclaim the hole and all the subsequent packets that were
|
||||
* already acked. In that case, seq_ctl != ssn, and the next
|
||||
* packet to be reclaimed will be ssn and not seq_ctl. In that
|
||||
* case, several packets will be reclaimed even if
|
||||
* frame_count = 1.
|
||||
*
|
||||
* The ssn is the index (% 256) of the latest packet that has
|
||||
* treated (acked / dropped) + 1.
|
||||
*/
|
||||
next_reclaimed = ssn;
|
||||
} else {
|
||||
/* The next packet to be reclaimed is the one after this one */
|
||||
next_reclaimed = IEEE80211_SEQ_TO_SN(seq_ctl + 0x10);
|
||||
}
|
||||
/* This is an aggregation queue or might become one, so we use
|
||||
* the ssn since: ssn = wifi seq_num % 256.
|
||||
* The seq_ctl is the sequence control of the packet to which
|
||||
* this Tx response relates. But if there is a hole in the
|
||||
* bitmap of the BA we received, this Tx response may allow to
|
||||
* reclaim the hole and all the subsequent packets that were
|
||||
* already acked. In that case, seq_ctl != ssn, and the next
|
||||
* packet to be reclaimed will be ssn and not seq_ctl. In that
|
||||
* case, several packets will be reclaimed even if
|
||||
* frame_count = 1.
|
||||
*
|
||||
* The ssn is the index (% 256) of the latest packet that has
|
||||
* treated (acked / dropped) + 1.
|
||||
*/
|
||||
next_reclaimed = ssn;
|
||||
|
||||
IWL_DEBUG_TX_REPLY(mvm,
|
||||
"TXQ %d status %s (0x%08x)\n",
|
||||
|
@ -1542,49 +1501,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
mvmsta = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the txq is not an AMPDU queue, there is no chance we freed
|
||||
* several skbs. Check that out...
|
||||
*/
|
||||
if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue)
|
||||
goto out;
|
||||
|
||||
/* We can't free more than one frame at once on a shared queue */
|
||||
WARN_ON(skb_freed > 1);
|
||||
|
||||
/* If we have still frames for this STA nothing to do here */
|
||||
if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id]))
|
||||
goto out;
|
||||
|
||||
if (mvmsta && mvmsta->vif->type == NL80211_IFTYPE_AP) {
|
||||
|
||||
/*
|
||||
* If there are no pending frames for this STA and
|
||||
* the tx to this station is not disabled, notify
|
||||
* mac80211 that this station can now wake up in its
|
||||
* STA table.
|
||||
* If mvmsta is not NULL, sta is valid.
|
||||
*/
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
|
||||
if (!mvmsta->disable_tx)
|
||||
ieee80211_sta_block_awake(mvm->hw, sta, false);
|
||||
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
}
|
||||
|
||||
if (PTR_ERR(sta) == -EBUSY || PTR_ERR(sta) == -ENOENT) {
|
||||
/*
|
||||
* We are draining and this was the last packet - pre_rcu_remove
|
||||
* has been called already. We might be after the
|
||||
* synchronize_net already.
|
||||
* Don't rely on iwl_mvm_rm_sta to see the empty Tx queues.
|
||||
*/
|
||||
set_bit(sta_id, mvm->sta_drained);
|
||||
schedule_work(&mvm->sta_drained_wk);
|
||||
}
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -1648,9 +1564,8 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
|
|||
struct iwl_mvm_sta *mvmsta;
|
||||
int queue = SEQ_TO_QUEUE(sequence);
|
||||
|
||||
if (WARN_ON_ONCE(queue < mvm->first_agg_queue &&
|
||||
(!iwl_mvm_is_dqa_supported(mvm) ||
|
||||
(queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE))))
|
||||
if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE &&
|
||||
(queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
|
||||
|
|
Loading…
Reference in New Issue