From fd89017061fc9e11c32ba2bada6fb175d5894417 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov Date: Wed, 31 Jul 2019 18:48:56 +0200 Subject: [PATCH 7/7] Revert "iwlwifi: mvm: support mac80211 TXQs model" This reverts commit cfbc6c4c5b91c7725ef14465b98ac347d31f2334. --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 8 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 5 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 72 ++++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 143 ++------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 53 +--- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 87 +++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 360 +++++++++++++--------- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 + drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 69 ++++- 9 files changed, 442 insertions(+), 359 deletions(-) Index: src/drivers/net/wireless/intel/iwlwifi/mvm/d3.c =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/d3.c 2019-06-27 14:54:04.132678349 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/d3.c 2019-07-31 18:51:11.751815280 +0200 @@ -2231,6 +2231,7 @@ file->private_data = inode->i_private; + ieee80211_stop_queues(mvm->hw); synchronize_net(); mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; @@ -2245,9 +2246,10 @@ rtnl_unlock(); if (err > 0) err = -EINVAL; - if (err) + if (err) { + ieee80211_wake_queues(mvm->hw); return err; - + } mvm->d3_test_active = true; mvm->keep_vif = NULL; return 0; @@ -2327,6 +2329,8 @@ mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif); + ieee80211_wake_queues(mvm->hw); + return 0; } Index: src/drivers/net/wireless/intel/iwlwifi/mvm/fw.c =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/fw.c 2019-06-27 14:54:04.134678325 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/fw.c 2019-07-31 18:51:11.752815267 +0200 @@ -308,7 +308,7 @@ struct iwl_notification_wait alive_wait; struct iwl_mvm_alive_data alive_data = {}; const struct fw_img *fw; - int ret; + int ret, i; enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; static const u16 alive_cmd[] = { MVM_ALIVE }; @@ -390,6 +390,9 @@ mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap = BIT(IWL_MAX_TID_COUNT + 2); + for (i = 0; i < IEEE80211_MAX_QUEUES; i++) + atomic_set(&mvm->mac80211_queue_stop_count[i], 0); + set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_fw_set_dbg_rec_on(&mvm->fwrt); Index: src/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c 2019-07-31 18:51:06.045891463 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c 2019-07-31 18:51:11.752815267 +0200 @@ -97,6 +97,11 @@ bool found_vif; }; +struct iwl_mvm_hw_queues_iface_iterator_data { + struct ieee80211_vif *exclude_vif; + unsigned long used_hw_queues; +}; + static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { @@ -203,6 +208,61 @@ data->preferred_tsf = NUM_TSF_IDS; } +/* + * Get the mask of the queues used by the vif + */ +u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) +{ + u32 qmask = 0, ac; + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + return BIT(IWL_MVM_OFFCHANNEL_QUEUE); + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) + qmask |= BIT(vif->hw_queue[ac]); + } + + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) + qmask |= BIT(vif->cab_queue); + + return qmask; +} + +static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_hw_queues_iface_iterator_data *data = _data; + + /* exclude the given vif */ + if (vif == data->exclude_vif) + return; + + data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif); +} + +unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, + struct ieee80211_vif *exclude_vif) +{ + 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(IWL_MVM_DQA_GCAST_QUEUE), + }; + + lockdep_assert_held(&mvm->mutex); + + /* mark all VIF used hw queues */ + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + iwl_mvm_iface_hw_queues_iter, &data); + + return data.used_hw_queues; +} + static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { @@ -300,6 +360,8 @@ mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, iwl_mvm_mac_iface_iterator, &data); + used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, vif); + /* * In the case we're getting here during resume, it's similar to * firmware restart, and with RESUME_ALL the iterator will find @@ -354,6 +416,9 @@ * 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 @@ -381,6 +446,9 @@ * queue value (when queue is enabled). */ mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; + vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; + } else { + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; } mvmvif->bcast_sta.sta_id = IWL_MVM_INVALID_STA; @@ -394,6 +462,8 @@ exit_fail: memset(mvmvif, 0, sizeof(struct iwl_mvm_vif)); + memset(vif->hw_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(vif->hw_queue)); + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; return ret; } @@ -1120,7 +1190,7 @@ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) - ctxt_ap->mcast_qid = cpu_to_le32(mvmvif->cab_queue); + ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue); /* * Only set the beacon time when the MAC is being added, when we Index: src/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c 2019-07-31 18:50:40.636230724 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c 2019-07-31 18:51:11.753815253 +0200 @@ -414,6 +414,7 @@ ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, SPECTRUM_MGMT); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, QUEUE_CONTROL); ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); @@ -427,8 +428,6 @@ ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP); ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); - ieee80211_hw_set(hw, BUFF_MMPDU_TXQ); - ieee80211_hw_set(hw, STA_MMPDU_TXQ); if (iwl_mvm_has_tlc_offload(mvm)) { ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); @@ -539,7 +538,6 @@ hw->sta_data_size = sizeof(struct iwl_mvm_sta); hw->vif_data_size = sizeof(struct iwl_mvm_vif); hw->chanctx_data_size = sizeof(u16); - hw->txq_data_size = sizeof(struct iwl_mvm_txq); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) | @@ -785,6 +783,7 @@ goto out; __skb_queue_tail(&mvm->d0i3_tx, skb); + ieee80211_stop_queues(mvm->hw); /* trigger wakeup */ iwl_mvm_ref(mvm, IWL_MVM_REF_TX); @@ -804,15 +803,13 @@ struct ieee80211_sta *sta = control->sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *)skb->data; - bool offchannel = IEEE80211_SKB_CB(skb)->flags & - IEEE80211_TX_CTL_TX_OFFCHAN; if (iwl_mvm_is_radio_killed(mvm)) { IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); goto drop; } - if (offchannel && + if (info->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) && !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) goto drop; @@ -825,8 +822,8 @@ sta = NULL; /* If there is no sta, and it's not offchannel - send through AP */ - if (!sta && info->control.vif->type == NL80211_IFTYPE_STATION && - !offchannel) { + if (info->control.vif->type == NL80211_IFTYPE_STATION && + info->hw_queue != IWL_MVM_OFFCHANNEL_QUEUE && !sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); u8 ap_sta_id = READ_ONCE(mvmvif->ap_sta_id); @@ -854,107 +851,6 @@ ieee80211_free_txskb(hw, skb); } -void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq); - struct sk_buff *skb = NULL; - - /* - * No need for threads to be pending here, they can leave the first - * taker all the work. - * - * mvmtxq->tx_request logic: - * - * If 0, no one is currently TXing, set to 1 to indicate current thread - * will now start TX and other threads should quit. - * - * If 1, another thread is currently TXing, set to 2 to indicate to - * that thread that there was another request. Since that request may - * have raced with the check whether the queue is empty, the TXing - * thread should check the queue's status one more time before leaving. - * This check is done in order to not leave any TX hanging in the queue - * until the next TX invocation (which may not even happen). - * - * If 2, another thread is currently TXing, and it will already double - * check the queue, so do nothing. - */ -#if 0 /* Not in RHEL */ - if (atomic_fetch_add_unless(&mvmtxq->tx_request, 1, 2)) -#else - if (__atomic_add_unless(&mvmtxq->tx_request, 1, 2)) -#endif - return; - - - rcu_read_lock(); - do { - while (likely(!mvmtxq->stopped && - (mvm->trans->system_pm_mode == - IWL_PLAT_PM_MODE_DISABLED))) { - skb = ieee80211_tx_dequeue(hw, txq); - - if (!skb) { - if (txq->sta) - IWL_DEBUG_TX(mvm, - "TXQ of sta %pM tid %d is now empty\n", - txq->sta->addr, - txq->tid); - break; - } - - if (!txq->sta) - iwl_mvm_tx_skb_non_sta(mvm, skb); - else - iwl_mvm_tx_skb(mvm, skb, txq->sta); - } - } while (atomic_dec_return(&mvmtxq->tx_request)); - rcu_read_unlock(); -} - -static void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq); - - /* - * Please note that racing is handled very carefully here: - * mvmtxq->txq_id is updated during allocation, and mvmtxq->list is - * deleted afterwards. - * This means that if: - * mvmtxq->txq_id != INVALID_QUEUE && list_empty(&mvmtxq->list): - * queue is allocated and we can TX. - * mvmtxq->txq_id != INVALID_QUEUE && !list_empty(&mvmtxq->list): - * a race, should defer the frame. - * mvmtxq->txq_id == INVALID_QUEUE && list_empty(&mvmtxq->list): - * need to allocate the queue and defer the frame. - * mvmtxq->txq_id == INVALID_QUEUE && !list_empty(&mvmtxq->list): - * queue is already scheduled for allocation, no need to allocate, - * should defer the frame. - */ - - /* If the queue is allocated TX and return. */ - if (!txq->sta || mvmtxq->txq_id != IWL_MVM_INVALID_QUEUE) { - /* - * Check that list is empty to avoid a race where txq_id is - * already updated, but the queue allocation work wasn't - * finished - */ - if (unlikely(txq->sta && !list_empty(&mvmtxq->list))) - return; - - iwl_mvm_mac_itxq_xmit(hw, txq); - return; - } - - /* The list is being deleted only after the queue is fully allocated. */ - if (!list_empty(&mvmtxq->list)) - return; - - list_add_tail(&mvmtxq->list, &mvm->add_stream_txqs); - schedule_work(&mvm->add_stream_wk); -} #define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \ do { \ @@ -1172,6 +1068,7 @@ iwl_mvm_reset_phy_ctxts(mvm); memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); + memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames)); memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); @@ -3086,6 +2983,32 @@ peer_addr, action); } +static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvm_sta) +{ + struct iwl_mvm_tid_data *tid_data; + struct sk_buff *skb; + int i; + + spin_lock_bh(&mvm_sta->lock); + for (i = 0; i <= IWL_MAX_TID_COUNT; i++) { + tid_data = &mvm_sta->tid_data[i]; + + while ((skb = __skb_dequeue(&tid_data->deferred_tx_frames))) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + /* + * The first deferred frame should've stopped the MAC + * queues, so we should never get a second deferred + * frame for the RA/TID. + */ + iwl_mvm_start_mac_queues(mvm, BIT(info->hw_queue)); + ieee80211_free_txskb(mvm->hw, skb); + } + } + spin_unlock_bh(&mvm_sta->lock); +} + static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -3119,6 +3042,7 @@ */ if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) { + iwl_mvm_purge_deferred_tx_frames(mvm, mvm_sta); flush_work(&mvm->add_stream_wk); /* @@ -4914,7 +4838,6 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .tx = iwl_mvm_mac_tx, - .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, .ampdu_action = iwl_mvm_mac_ampdu_action, .start = iwl_mvm_mac_start, .reconfig_complete = iwl_mvm_mac_reconfig_complete, Index: src/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h 2019-07-31 18:50:40.637230710 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h 2019-07-31 18:51:11.753815253 +0200 @@ -805,39 +805,6 @@ u8 values[ACPI_GEO_TABLE_SIZE]; }; -struct iwl_mvm_txq { - struct list_head list; - u16 txq_id; - atomic_t tx_request; - bool stopped; -}; - -static inline struct iwl_mvm_txq * -iwl_mvm_txq_from_mac80211(struct ieee80211_txq *txq) -{ - return (void *)txq->drv_priv; -} - -static inline struct iwl_mvm_txq * -iwl_mvm_txq_from_tid(struct ieee80211_sta *sta, u8 tid) -{ - if (tid == IWL_MAX_TID_COUNT) - tid = IEEE80211_NUM_TIDS; - - return (void *)sta->txq[tid]->drv_priv; -} - -/** - * struct iwl_mvm_tvqm_txq_info - maps TVQM hw queue to tid - * - * @sta_id: sta id - * @txq_tid: txq tid - */ -struct iwl_mvm_tvqm_txq_info { - u8 sta_id; - u8 txq_tid; -}; - struct iwl_mvm_dqa_txq_info { u8 ra_sta_id; /* The RA this queue is mapped to, if exists */ bool reserved; /* Is this the TXQ reserved for a STA */ @@ -900,13 +867,13 @@ u64 on_time_scan; } radio_stats, accu_radio_stats; - struct list_head add_stream_txqs; - union { - struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES]; - struct iwl_mvm_tvqm_txq_info tvqm_info[IWL_MAX_TVQM_QUEUES]; - }; + u16 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES]; + + struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES]; struct work_struct add_stream_wk; /* To add streams to queues */ + atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES]; + const char *nvm_file_name; struct iwl_nvm_data *nvm_data; /* NVM sections */ @@ -920,6 +887,7 @@ /* 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]; + unsigned long sta_deferred_frames[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; u8 rx_ba_sessions; /* configured by mac80211 */ @@ -1552,8 +1520,6 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, __le16 fc); -void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq); - #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_mvm_get_tx_fail_reason(u32 status); #else @@ -1684,6 +1650,7 @@ int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool force_assoc_off, const u8 *bssid_override); int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, @@ -1710,6 +1677,8 @@ struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, + struct ieee80211_vif *exclude_vif); void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, @@ -2020,6 +1989,10 @@ iwl_fw_dump_conf_clear(&mvm->fwrt); } +/* Stop/start all mac queues in a given bitmap */ +void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq); +void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq); + /* Re-configure the SCD for a queue that has already been configured */ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn); Index: src/drivers/net/wireless/intel/iwlwifi/mvm/ops.c =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/ops.c 2019-07-31 18:50:59.172983228 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/ops.c 2019-07-31 18:51:11.754815240 +0200 @@ -707,7 +707,6 @@ 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); INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk); - INIT_LIST_HEAD(&mvm->add_stream_txqs); spin_lock_init(&mvm->d0i3_tx_lock); spin_lock_init(&mvm->refs_lock); @@ -1091,6 +1090,24 @@ iwl_mvm_rx_common(mvm, rxb, pkt); } +void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq) +{ + int q; + + if (WARN_ON_ONCE(!mq)) + return; + + for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) { + if (atomic_inc_return(&mvm->mac80211_queue_stop_count[q]) > 1) { + IWL_DEBUG_TX_QUEUES(mvm, + "mac80211 %d already stopped\n", q); + continue; + } + + ieee80211_stop_queue(mvm->hw, q); + } +} + static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode, const struct iwl_device_cmd *cmd) { @@ -1103,66 +1120,38 @@ iwl_trans_block_txq_ptrs(mvm->trans, false); } -static void iwl_mvm_queue_state_change(struct iwl_op_mode *op_mode, - int hw_queue, bool start) +static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - struct ieee80211_sta *sta; - struct ieee80211_txq *txq; - struct iwl_mvm_txq *mvmtxq; - int i; - unsigned long tid_bitmap; - struct iwl_mvm_sta *mvmsta; - u8 sta_id; - - sta_id = iwl_mvm_has_new_tx_api(mvm) ? - mvm->tvqm_info[hw_queue].sta_id : - mvm->queue_info[hw_queue].ra_sta_id; - - if (WARN_ON_ONCE(sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) - return; + unsigned long mq = mvm->hw_queue_to_mac80211[hw_queue]; - rcu_read_lock(); - - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - if (IS_ERR_OR_NULL(sta)) - goto out; - mvmsta = iwl_mvm_sta_from_mac80211(sta); - - if (iwl_mvm_has_new_tx_api(mvm)) { - int tid = mvm->tvqm_info[hw_queue].txq_tid; - - tid_bitmap = BIT(tid); - } else { - tid_bitmap = mvm->queue_info[hw_queue].tid_bitmap; - } + iwl_mvm_stop_mac_queues(mvm, mq); +} - for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { - int tid = i; +void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq) +{ + int q; - if (tid == IWL_MAX_TID_COUNT) - tid = IEEE80211_NUM_TIDS; + if (WARN_ON_ONCE(!mq)) + return; - txq = sta->txq[tid]; - mvmtxq = iwl_mvm_txq_from_mac80211(txq); - mvmtxq->stopped = !start; + for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) { + if (atomic_dec_return(&mvm->mac80211_queue_stop_count[q]) > 0) { + IWL_DEBUG_TX_QUEUES(mvm, + "mac80211 %d still stopped\n", q); + continue; + } - if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST) - iwl_mvm_mac_itxq_xmit(mvm->hw, txq); + ieee80211_wake_queue(mvm->hw, q); } - -out: - rcu_read_unlock(); -} - -static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) -{ - iwl_mvm_queue_state_change(op_mode, hw_queue, false); } static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) { - iwl_mvm_queue_state_change(op_mode, hw_queue, true); + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + unsigned long mq = mvm->hw_queue_to_mac80211[hw_queue]; + + iwl_mvm_start_mac_queues(mvm, mq); } static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm) Index: src/drivers/net/wireless/intel/iwlwifi/mvm/sta.c =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/sta.c 2019-07-31 18:50:53.312061481 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/sta.c 2019-07-31 18:51:11.755815227 +0200 @@ -353,16 +353,24 @@ &cmd, &status); } -static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int queue, u8 tid, u8 flags) +static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, + int mac80211_queue, u8 tid, u8 flags) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; + bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE; int ret; + if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES)) + return -EINVAL; + if (iwl_mvm_has_new_tx_api(mvm)) { + if (remove_mac_queue) + mvm->hw_queue_to_mac80211[queue] &= + ~BIT(mac80211_queue); + iwl_trans_txq_free(mvm->trans, queue); return 0; @@ -373,15 +381,36 @@ mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); + /* + * If there is another TID with the same AC - don't remove the MAC queue + * from the mapping + */ + if (tid < IWL_MAX_TID_COUNT) { + unsigned long tid_bitmap = + mvm->queue_info[queue].tid_bitmap; + int ac = tid_to_mac80211_ac[tid]; + int i; + + for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) { + if (tid_to_mac80211_ac[i] == ac) + remove_mac_queue = false; + } + } + + if (remove_mac_queue) + mvm->hw_queue_to_mac80211[queue] &= + ~BIT(mac80211_queue); + cmd.action = mvm->queue_info[queue].tid_bitmap ? SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE; if (cmd.action == SCD_CFG_DISABLE_QUEUE) mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE; IWL_DEBUG_TX_QUEUES(mvm, - "Disabling TXQ #%d tids=0x%x\n", + "Disabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n", queue, - mvm->queue_info[queue].tid_bitmap); + mvm->queue_info[queue].tid_bitmap, + mvm->hw_queue_to_mac80211[queue]); /* If the queue is still enabled - nothing left to do in this func */ if (cmd.action == SCD_CFG_ENABLE_QUEUE) @@ -391,19 +420,15 @@ cmd.tid = mvm->queue_info[queue].txq_tid; /* Make sure queue info is correct even though we overwrite it */ - WARN(mvm->queue_info[queue].tid_bitmap, - "TXQ #%d info out-of-sync - tids=0x%x\n", - queue, mvm->queue_info[queue].tid_bitmap); + WARN(mvm->queue_info[queue].tid_bitmap || + mvm->hw_queue_to_mac80211[queue], + "TXQ #%d info out-of-sync - mac map=0x%x, tids=0x%x\n", + queue, mvm->hw_queue_to_mac80211[queue], + mvm->queue_info[queue].tid_bitmap); /* If we are here - the queue is freed and we can zero out these vals */ mvm->queue_info[queue].tid_bitmap = 0; - - if (sta) { - struct iwl_mvm_txq *mvmtxq = - iwl_mvm_txq_from_tid(sta, tid); - - mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; - } + mvm->hw_queue_to_mac80211[queue] = 0; /* Regardless if this is a reserved TXQ for a STA - mark it as false */ mvm->queue_info[queue].reserved = false; @@ -489,14 +514,9 @@ spin_lock_bh(&mvmsta->lock); /* Unmap MAC queues and TIDs from this queue */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { - struct iwl_mvm_txq *mvmtxq = - iwl_mvm_txq_from_tid(sta, tid); - if (mvmsta->tid_data[tid].state == IWL_AGG_ON) disable_agg_tids |= BIT(tid); mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; - - mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; } mvmsta->tfd_queue_msk &= ~BIT(queue); /* Don't use this queue anymore */ @@ -518,11 +538,10 @@ } static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, - struct ieee80211_sta *old_sta, u8 new_sta_id) { struct iwl_mvm_sta *mvmsta; - u8 sta_id, tid; + u8 txq_curr_ac, sta_id, tid; unsigned long disable_agg_tids = 0; bool same_sta; int ret; @@ -532,6 +551,7 @@ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; + txq_curr_ac = mvm->queue_info[queue].mac80211_ac; sta_id = mvm->queue_info[queue].ra_sta_id; tid = mvm->queue_info[queue].txq_tid; @@ -547,7 +567,9 @@ iwl_mvm_invalidate_sta_queue(mvm, queue, disable_agg_tids, false); - ret = iwl_mvm_disable_txq(mvm, old_sta, queue, tid, 0); + ret = iwl_mvm_disable_txq(mvm, queue, + mvmsta->vif->hw_queue[txq_curr_ac], + tid, 0); if (ret) { IWL_ERR(mvm, "Failed to free inactive queue %d (ret=%d)\n", @@ -637,15 +659,16 @@ * in such a case, otherwise - if no redirection required - it does nothing, * unless the %force param is true. */ -static int iwl_mvm_redirect_queue(struct iwl_mvm *mvm, int queue, int tid, - int ac, int ssn, unsigned int wdg_timeout, - bool force, struct iwl_mvm_txq *txq) +static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, + int ac, int ssn, unsigned int wdg_timeout, + bool force) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; bool shared_queue; + unsigned long mq; int ret; if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) @@ -669,14 +692,14 @@ cmd.sta_id = mvm->queue_info[queue].ra_sta_id; cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac]; cmd.tid = mvm->queue_info[queue].txq_tid; + mq = mvm->hw_queue_to_mac80211[queue]; shared_queue = hweight16(mvm->queue_info[queue].tid_bitmap) > 1; IWL_DEBUG_TX_QUEUES(mvm, "Redirecting TXQ #%d to FIFO #%d\n", queue, iwl_mvm_ac_to_tx_fifo[ac]); - /* Stop the queue and wait for it to empty */ - txq->stopped = true; - + /* Stop MAC queues and wait for this queue to empty */ + iwl_mvm_stop_mac_queues(mvm, mq); ret = iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(queue)); if (ret) { IWL_ERR(mvm, "Error draining queue %d before reconfig\n", @@ -717,8 +740,8 @@ iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); out: - /* Continue using the queue */ - txq->stopped = false; + /* Continue using the MAC queues */ + iwl_mvm_start_mac_queues(mvm, mq); return ret; } @@ -743,7 +766,7 @@ return -ENOSPC; } -static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, +static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, u8 sta_id, u8 tid, unsigned int timeout) { int queue, size = max_t(u32, IWL_DEFAULT_QUEUE_SIZE, @@ -768,7 +791,10 @@ IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n", queue, sta_id, tid); - IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d\n", queue); + mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + IWL_DEBUG_TX_QUEUES(mvm, + "Enabling TXQ #%d (mac80211 map:0x%x)\n", + queue, mvm->hw_queue_to_mac80211[queue]); return queue; } @@ -778,10 +804,9 @@ int tid) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_mvm_txq *mvmtxq = - iwl_mvm_txq_from_tid(sta, tid); unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); + u8 mac_queue = mvmsta->vif->hw_queue[ac]; int queue = -1; lockdep_assert_held(&mvm->mutex); @@ -789,16 +814,11 @@ IWL_DEBUG_TX_QUEUES(mvm, "Allocating queue for sta %d on tid %d\n", mvmsta->sta_id, tid); - queue = iwl_mvm_tvqm_enable_txq(mvm, mvmsta->sta_id, tid, wdg_timeout); + queue = iwl_mvm_tvqm_enable_txq(mvm, mac_queue, mvmsta->sta_id, tid, + wdg_timeout); if (queue < 0) return queue; - if (sta) { - mvmtxq->txq_id = queue; - mvm->tvqm_info[queue].txq_tid = tid; - mvm->tvqm_info[queue].sta_id = mvmsta->sta_id; - } - IWL_DEBUG_TX_QUEUES(mvm, "Allocated queue is %d\n", queue); spin_lock_bh(&mvmsta->lock); @@ -808,9 +828,8 @@ return 0; } -static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, - int queue, u8 sta_id, u8 tid) +static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, + int mac80211_queue, u8 sta_id, u8 tid) { bool enable_queue = true; @@ -825,6 +844,14 @@ if (mvm->queue_info[queue].tid_bitmap) enable_queue = false; + if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) { + WARN(mac80211_queue >= + BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]), + "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n", + mac80211_queue, queue, sta_id, tid); + mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + } + mvm->queue_info[queue].tid_bitmap |= BIT(tid); mvm->queue_info[queue].ra_sta_id = sta_id; @@ -838,22 +865,16 @@ mvm->queue_info[queue].txq_tid = tid; } - if (sta) { - struct iwl_mvm_txq *mvmtxq = - iwl_mvm_txq_from_tid(sta, tid); - - mvmtxq->txq_id = queue; - } - IWL_DEBUG_TX_QUEUES(mvm, - "Enabling TXQ #%d tids=0x%x\n", - queue, mvm->queue_info[queue].tid_bitmap); + "Enabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n", + queue, mvm->queue_info[queue].tid_bitmap, + mvm->hw_queue_to_mac80211[queue]); return enable_queue; } -static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - int queue, u16 ssn, +static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, + int mac80211_queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout) { @@ -873,7 +894,8 @@ return false; /* Send the enabling command if we need to */ - if (!iwl_mvm_update_txq_mapping(mvm, sta, queue, cfg->sta_id, cfg->tid)) + if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, + cfg->sta_id, cfg->tid)) return false; inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, @@ -966,10 +988,9 @@ ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number); - ret = iwl_mvm_redirect_queue(mvm, queue, tid, - tid_to_mac80211_ac[tid], ssn, - wdg_timeout, true, - iwl_mvm_txq_from_tid(sta, tid)); + ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, + tid_to_mac80211_ac[tid], ssn, + wdg_timeout, true); if (ret) { IWL_ERR(mvm, "Failed to redirect TXQ %d\n", queue); return; @@ -1046,9 +1067,11 @@ * Remove the ones that did. */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]; u16 tid_bitmap; mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; + mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue); mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); tid_bitmap = mvm->queue_info[queue].tid_bitmap; @@ -1081,6 +1104,10 @@ * sure all TIDs have existing corresponding mac queues enabled */ tid_bitmap = mvm->queue_info[queue].tid_bitmap; + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + mvm->hw_queue_to_mac80211[queue] |= + BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]); + } /* If the queue is marked as shared - "unshare" it */ if (hweight16(mvm->queue_info[queue].tid_bitmap) == 1 && @@ -1108,7 +1135,6 @@ unsigned long unshare_queues = 0; unsigned long changetid_queues = 0; int i, ret, free_queue = -ENOSPC; - struct ieee80211_sta *queue_owner = NULL; lockdep_assert_held(&mvm->mutex); @@ -1174,14 +1200,13 @@ inactive_tid_bitmap, &unshare_queues, &changetid_queues); - if (ret >= 0 && free_queue < 0) { - queue_owner = sta; + if (ret >= 0 && free_queue < 0) free_queue = ret; - } /* only unlock sta lock - we still need the queue info lock */ spin_unlock_bh(&mvmsta->lock); } + rcu_read_unlock(); /* Reconfigure queues requiring reconfiguation */ for_each_set_bit(i, &unshare_queues, IWL_MAX_HW_QUEUES) @@ -1190,21 +1215,18 @@ iwl_mvm_change_queue_tid(mvm, i); if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) { - ret = iwl_mvm_free_inactive_queue(mvm, free_queue, queue_owner, + ret = iwl_mvm_free_inactive_queue(mvm, free_queue, alloc_for_sta); - if (ret) { - rcu_read_unlock(); + if (ret) return ret; - } } - rcu_read_unlock(); - return free_queue; } static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, u8 ac, int tid) + struct ieee80211_sta *sta, u8 ac, int tid, + struct ieee80211_hdr *hdr) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_trans_txq_scd_cfg cfg = { @@ -1215,6 +1237,7 @@ }; unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); + u8 mac_queue = mvmsta->vif->hw_queue[ac]; int queue = -1; unsigned long disable_agg_tids = 0; enum iwl_mvm_agg_state queue_state; @@ -1233,7 +1256,12 @@ ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number); spin_unlock_bh(&mvmsta->lock); - if (tid == IWL_MAX_TID_COUNT) { + /* + * Non-QoS, QoS NDP and MGMT frames should go to a MGMT queue, if one + * exists + */ + if (!ieee80211_is_data_qos(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) { queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, IWL_MVM_DQA_MIN_MGMT_QUEUE, IWL_MVM_DQA_MAX_MGMT_QUEUE); @@ -1312,7 +1340,8 @@ } } - inc_ssn = iwl_mvm_enable_txq(mvm, sta, queue, ssn, &cfg, wdg_timeout); + inc_ssn = iwl_mvm_enable_txq(mvm, queue, mac_queue, + ssn, &cfg, wdg_timeout); /* * Mark queue as shared in transport if shared @@ -1354,9 +1383,8 @@ } } else { /* Redirect queue, if needed */ - ret = iwl_mvm_redirect_queue(mvm, queue, tid, ac, ssn, - wdg_timeout, false, - iwl_mvm_txq_from_tid(sta, tid)); + ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, ac, ssn, + wdg_timeout, false); if (ret) goto out_err; } @@ -1364,7 +1392,7 @@ return 0; out_err: - iwl_mvm_disable_txq(mvm, sta, queue, tid, 0); + iwl_mvm_disable_txq(mvm, queue, mac_queue, tid, 0); return ret; } @@ -1377,34 +1405,87 @@ return tid_to_mac80211_ac[tid]; } +static void iwl_mvm_tx_deferred_stream(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, int tid) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + struct sk_buff_head deferred_tx; + u8 mac_queue; + bool no_queue = false; /* Marks if there is a problem with the queue */ + u8 ac; + + lockdep_assert_held(&mvm->mutex); + + skb = skb_peek(&tid_data->deferred_tx_frames); + if (!skb) + return; + hdr = (void *)skb->data; + + ac = iwl_mvm_tid_to_ac_queue(tid); + mac_queue = IEEE80211_SKB_CB(skb)->hw_queue; + + if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE && + iwl_mvm_sta_alloc_queue(mvm, sta, ac, tid, hdr)) { + IWL_ERR(mvm, + "Can't alloc TXQ for sta %d tid %d - dropping frame\n", + mvmsta->sta_id, tid); + + /* + * Mark queue as problematic so later the deferred traffic is + * freed, as we can do nothing with it + */ + no_queue = true; + } + + __skb_queue_head_init(&deferred_tx); + + /* Disable bottom-halves when entering TX path */ + local_bh_disable(); + spin_lock(&mvmsta->lock); + skb_queue_splice_init(&tid_data->deferred_tx_frames, &deferred_tx); + mvmsta->deferred_traffic_tid_map &= ~BIT(tid); + spin_unlock(&mvmsta->lock); + + while ((skb = __skb_dequeue(&deferred_tx))) + if (no_queue || iwl_mvm_tx_skb(mvm, skb, sta)) + ieee80211_free_txskb(mvm->hw, skb); + local_bh_enable(); + + /* Wake queue */ + iwl_mvm_start_mac_queues(mvm, BIT(mac_queue)); +} + void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) { struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, add_stream_wk); + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + unsigned long deferred_tid_traffic; + int sta_id, tid; mutex_lock(&mvm->mutex); iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); - while (!list_empty(&mvm->add_stream_txqs)) { - struct iwl_mvm_txq *mvmtxq; - struct ieee80211_txq *txq; - u8 tid; - - mvmtxq = list_first_entry(&mvm->add_stream_txqs, - struct iwl_mvm_txq, list); - - txq = container_of((void *)mvmtxq, struct ieee80211_txq, - drv_priv); - tid = txq->tid; - if (tid == IEEE80211_NUM_TIDS) - tid = IWL_MAX_TID_COUNT; - - iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, tid); - list_del_init(&mvmtxq->list); - local_bh_disable(); - iwl_mvm_mac_itxq_xmit(mvm->hw, txq); - local_bh_enable(); + /* Go over all stations with deferred traffic */ + for_each_set_bit(sta_id, mvm->sta_deferred_frames, + IWL_MVM_STATION_COUNT) { + clear_bit(sta_id, mvm->sta_deferred_frames); + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], + lockdep_is_held(&mvm->mutex)); + if (IS_ERR_OR_NULL(sta)) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + deferred_tid_traffic = mvmsta->deferred_traffic_tid_map; + + for_each_set_bit(tid, &deferred_tid_traffic, + IWL_MAX_TID_COUNT + 1) + iwl_mvm_tx_deferred_stream(mvm, sta, tid); } mutex_unlock(&mvm->mutex); @@ -1460,11 +1541,10 @@ * Note that re-enabling aggregations isn't done in this function. */ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, - struct ieee80211_sta *sta) + struct iwl_mvm_sta *mvm_sta) { - struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); - unsigned int wdg = - iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false); + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false); int i; struct iwl_trans_txq_scd_cfg cfg = { .sta_id = mvm_sta->sta_id, @@ -1480,18 +1560,23 @@ struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i]; int txq_id = tid_data->txq_id; int ac; + u8 mac_queue; if (txq_id == IWL_MVM_INVALID_QUEUE) continue; + skb_queue_head_init(&tid_data->deferred_tx_frames); + ac = tid_to_mac80211_ac[i]; + mac_queue = mvm_sta->vif->hw_queue[ac]; if (iwl_mvm_has_new_tx_api(mvm)) { IWL_DEBUG_TX_QUEUES(mvm, "Re-mapping sta %d tid %d\n", mvm_sta->sta_id, i); - txq_id = iwl_mvm_tvqm_enable_txq(mvm, mvm_sta->sta_id, - i, wdg); + txq_id = iwl_mvm_tvqm_enable_txq(mvm, mac_queue, + mvm_sta->sta_id, + i, wdg_timeout); tid_data->txq_id = txq_id; /* @@ -1514,7 +1599,8 @@ "Re-mapping sta %d tid %d to queue %d\n", mvm_sta->sta_id, i, txq_id); - iwl_mvm_enable_txq(mvm, sta, txq_id, seq, &cfg, wdg); + iwl_mvm_enable_txq(mvm, txq_id, mac_queue, seq, &cfg, + wdg_timeout); mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY; } } @@ -1604,7 +1690,7 @@ if (ret) goto err; - iwl_mvm_realloc_queues_after_restart(mvm, sta); + iwl_mvm_realloc_queues_after_restart(mvm, mvm_sta); sta_update = true; sta_flags = iwl_mvm_has_new_tx_api(mvm) ? 0 : STA_MODIFY_QUEUES; goto update_fw; @@ -1637,17 +1723,9 @@ * frames until the queue is allocated */ mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE; + skb_queue_head_init(&mvm_sta->tid_data[i].deferred_tx_frames); } - - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { - struct iwl_mvm_txq *mvmtxq = - iwl_mvm_txq_from_mac80211(sta->txq[i]); - - mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; - INIT_LIST_HEAD(&mvmtxq->list); - atomic_set(&mvmtxq->tx_request, 0); - } - + mvm_sta->deferred_traffic_tid_map = 0; mvm_sta->agg_tids = 0; if (iwl_mvm_has_new_rx_api(mvm) && @@ -1782,9 +1860,9 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct iwl_mvm_sta *mvm_sta) { - struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + int ac; int i; lockdep_assert_held(&mvm->mutex); @@ -1793,17 +1871,11 @@ if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE) continue; - iwl_mvm_disable_txq(mvm, sta, mvm_sta->tid_data[i].txq_id, i, - 0); + ac = iwl_mvm_tid_to_ac_queue(i); + iwl_mvm_disable_txq(mvm, mvm_sta->tid_data[i].txq_id, + vif->hw_queue[ac], i, 0); mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE; } - - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { - struct iwl_mvm_txq *mvmtxq = - iwl_mvm_txq_from_mac80211(sta->txq[i]); - - mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; - } } int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, @@ -1865,7 +1937,7 @@ ret = iwl_mvm_drain_sta(mvm, mvm_sta, false); - iwl_mvm_disable_sta_queues(mvm, vif, sta); + iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); /* If there is a TXQ still marked as reserved - free it */ if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) { @@ -1971,7 +2043,7 @@ if (iwl_mvm_has_new_tx_api(mvm)) { int tvqm_queue = - iwl_mvm_tvqm_enable_txq(mvm, sta_id, + iwl_mvm_tvqm_enable_txq(mvm, *queue, sta_id, IWL_MAX_TID_COUNT, wdg_timeout); *queue = tvqm_queue; @@ -1984,7 +2056,7 @@ .frame_limit = IWL_FRAME_LIMIT, }; - iwl_mvm_enable_txq(mvm, NULL, *queue, 0, &cfg, wdg_timeout); + iwl_mvm_enable_txq(mvm, *queue, *queue, 0, &cfg, wdg_timeout); } } @@ -2062,7 +2134,8 @@ lockdep_assert_held(&mvm->mutex); - iwl_mvm_disable_txq(mvm, NULL, mvm->snif_queue, IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, mvm->snif_queue, mvm->snif_queue, + IWL_MAX_TID_COUNT, 0); ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2123,7 +2196,8 @@ bsta->tfd_queue_msk |= BIT(queue); - iwl_mvm_enable_txq(mvm, NULL, queue, 0, &cfg, wdg_timeout); + iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, + &cfg, wdg_timeout); } if (vif->type == NL80211_IFTYPE_ADHOC) @@ -2142,7 +2216,8 @@ * to firmware so enable queue here - after the station was added */ if (iwl_mvm_has_new_tx_api(mvm)) { - queue = iwl_mvm_tvqm_enable_txq(mvm, bsta->sta_id, + queue = iwl_mvm_tvqm_enable_txq(mvm, vif->hw_queue[0], + bsta->sta_id, IWL_MAX_TID_COUNT, wdg_timeout); @@ -2180,7 +2255,7 @@ return; } - iwl_mvm_disable_txq(mvm, NULL, queue, IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, queue, vif->hw_queue[0], IWL_MAX_TID_COUNT, 0); if (iwl_mvm_has_new_tx_api(mvm)) return; @@ -2304,8 +2379,10 @@ * Note that this is done here as we want to avoid making DQA * changes in mac80211 layer. */ - if (vif->type == NL80211_IFTYPE_ADHOC) - mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; + if (vif->type == NL80211_IFTYPE_ADHOC) { + vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; + mvmvif->cab_queue = vif->cab_queue; + } /* * While in previous FWs we had to exclude cab queue from TFD queue @@ -2313,9 +2390,9 @@ */ if (!iwl_mvm_has_new_tx_api(mvm) && fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) { - iwl_mvm_enable_txq(mvm, NULL, mvmvif->cab_queue, 0, &cfg, - timeout); - msta->tfd_queue_msk |= BIT(mvmvif->cab_queue); + iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, + &cfg, timeout); + msta->tfd_queue_msk |= BIT(vif->cab_queue); } ret = iwl_mvm_add_int_sta_common(mvm, msta, maddr, mvmvif->id, mvmvif->color); @@ -2332,14 +2409,15 @@ * tfd_queue_mask. */ if (iwl_mvm_has_new_tx_api(mvm)) { - int queue = iwl_mvm_tvqm_enable_txq(mvm, msta->sta_id, + int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue, + msta->sta_id, 0, timeout); mvmvif->cab_queue = queue; } else if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) - iwl_mvm_enable_txq(mvm, NULL, mvmvif->cab_queue, 0, &cfg, - timeout); + iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, + &cfg, timeout); return 0; } @@ -2410,7 +2488,8 @@ iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0); - iwl_mvm_disable_txq(mvm, NULL, mvmvif->cab_queue, 0, 0); + iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, + 0, 0); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id); if (ret) @@ -2946,7 +3025,8 @@ } if (alloc_queue) - iwl_mvm_enable_txq(mvm, sta, queue, ssn, + iwl_mvm_enable_txq(mvm, queue, + vif->hw_queue[tid_to_mac80211_ac[tid]], ssn, &cfg, wdg_timeout); /* Send ADD_STA command to enable aggs only if the queue isn't shared */ Index: src/drivers/net/wireless/intel/iwlwifi/mvm/sta.h =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/sta.h 2019-06-27 14:54:04.140678253 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/sta.h 2019-07-31 18:51:11.756815213 +0200 @@ -297,6 +297,7 @@ /** * struct iwl_mvm_tid_data - holds the states for each RA / TID + * @deferred_tx_frames: deferred TX frames for this RA/TID * @seq_number: the next WiFi sequence number to use * @next_reclaimed: the WiFi sequence number of the next packet to be acked. * This is basically (last acked packet++). @@ -317,6 +318,7 @@ * tpt_meas_start */ struct iwl_mvm_tid_data { + struct sk_buff_head deferred_tx_frames; u16 seq_number; u16 next_reclaimed; /* The rest is Tx AGG related */ @@ -425,6 +427,8 @@ struct iwl_mvm_key_pn __rcu *ptk_pn[4]; struct iwl_mvm_rxq_dup_data *dup_data; + u16 deferred_traffic_tid_map; + u8 reserved_queue; /* Temporary, until the new TLC will control the Tx protection */ Index: src/drivers/net/wireless/intel/iwlwifi/mvm/tx.c =================================================================== --- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/tx.c 2019-07-31 18:50:40.639230684 +0200 +++ src/drivers/net/wireless/intel/iwlwifi/mvm/tx.c 2019-07-31 18:51:11.756815213 +0200 @@ -605,12 +605,11 @@ } static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr) + struct ieee80211_tx_info *info, __le16 fc) { - struct iwl_mvm_vif *mvmvif = - iwl_mvm_vif_from_mac80211(info->control.vif); - __le16 fc = hdr->frame_control; + struct iwl_mvm_vif *mvmvif; + + mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); switch (info->control.vif->type) { case NL80211_IFTYPE_AP: @@ -629,9 +628,7 @@ (!ieee80211_is_bufferable_mmpdu(fc) || ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc))) return mvm->probe_queue; - - if (!ieee80211_has_order(fc) && !ieee80211_is_probe_req(fc) && - is_multicast_ether_addr(hdr->addr1)) + if (info->hw_queue == info->control.vif->cab_queue) return mvmvif->cab_queue; WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC, @@ -640,6 +637,8 @@ case NL80211_IFTYPE_P2P_DEVICE: if (ieee80211_is_mgmt(fc)) return mvm->p2p_dev_queue; + if (info->hw_queue == info->control.vif->cab_queue) + return mvmvif->cab_queue; WARN_ON_ONCE(1); return mvm->p2p_dev_queue; @@ -717,8 +716,6 @@ u8 sta_id; int hdrlen = ieee80211_hdrlen(hdr->frame_control); __le16 fc = hdr->frame_control; - bool offchannel = IEEE80211_SKB_CB(skb)->flags & - IEEE80211_TX_CTL_TX_OFFCHAN; int queue = -1; if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc)) @@ -729,6 +726,11 @@ if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_AMPDU)) return -1; + if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && + (!info.control.vif || + info.hw_queue != info.control.vif->cab_queue))) + return -1; + if (info.control.vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(info.control.vif); @@ -741,12 +743,14 @@ else sta_id = mvmvif->mcast_sta.sta_id; - queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr); + queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, + hdr->frame_control); + } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { queue = mvm->snif_queue; sta_id = mvm->snif_sta.sta_id; } else if (info.control.vif->type == NL80211_IFTYPE_STATION && - offchannel) { + info.hw_queue == IWL_MVM_OFFCHANNEL_QUEUE) { /* * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets * that can be used in 2 different types of vifs, P2P & @@ -760,10 +764,8 @@ } } - if (queue < 0) { - IWL_ERR(mvm, "No queue was found. Dropping TX\n"); + if (queue < 0) return -1; - } if (unlikely(ieee80211_is_probe_resp(fc))) iwl_mvm_probe_resp_set_noa(mvm, skb); @@ -1006,6 +1008,34 @@ } #endif +static void iwl_mvm_tx_add_stream(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvm_sta, u8 tid, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 mac_queue = info->hw_queue; + struct sk_buff_head *deferred_tx_frames; + + lockdep_assert_held(&mvm_sta->lock); + + mvm_sta->deferred_traffic_tid_map |= BIT(tid); + set_bit(mvm_sta->sta_id, mvm->sta_deferred_frames); + + deferred_tx_frames = &mvm_sta->tid_data[tid].deferred_tx_frames; + + skb_queue_tail(deferred_tx_frames, skb); + + /* + * The first deferred frame should've stopped the MAC queues, so we + * should never get a second deferred frame for the RA/TID. + * In case of GSO the first packet may have been split, so don't warn. + */ + if (skb_queue_len(deferred_tx_frames) == 1) { + iwl_mvm_stop_mac_queues(mvm, BIT(mac_queue)); + schedule_work(&mvm->add_stream_wk); + } +} + /* Check if there are any timed-out TIDs on a given shared TXQ */ static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id) { @@ -1076,7 +1106,7 @@ __le16 fc; u16 seq_number = 0; u8 tid = IWL_MAX_TID_COUNT; - u16 txq_id; + u16 txq_id = info->hw_queue; bool is_ampdu = false; int hdrlen; @@ -1145,7 +1175,14 @@ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); + /* Check if TXQ needs to be allocated or re-activated */ if (WARN_ONCE(txq_id == IWL_MVM_INVALID_QUEUE, "Invalid TXQ id")) { + iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb); + + /* + * The frame is now deferred, and the worker scheduled + * will re-allocate it, so we can free it for now. + */ iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); spin_unlock(&mvmsta->lock); return 0;