wifi: iwlwifi: mvm: advertise IEEE80211_HW_HANDLES_QUIET_CSA
authorJohannes Berg <johannes.berg@intel.com>
Mon, 11 Mar 2024 06:28:11 +0000 (08:28 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 25 Mar 2024 14:36:04 +0000 (15:36 +0100)
The firmware has handled quiet in CSA for a long time now, but
it didn't really matter much. However, now with quiet CSA on a
perhaps secondary link, we don't want mac80211 to stop queues,
we can continue using a link that's not requiring quiet. Set
the feature flag for MLO-capable devices indicating that we'll
handle the quiet entirely in the driver/device.

However, the firmware doesn't handle quiet in AP mode since we
don't really expect to really be needing that (without radar
detection), but - even for testing - make that work properly
by simply not pulling from TXQs in this scenario.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240311081938.fa75403b5eaa.Ie3ff02215f810fcfefd6a22c481567f94f61c0c6@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h

index ea94246b1dd8a3499f446d2aaf0ec926f92a0265..9856db384de049e62a64bdfdf9e72e688723a2a9 100644 (file)
@@ -359,8 +359,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        /* Set this early since we need to have it for the check below */
        if (mvm->mld_api_is_used && mvm->nvm_data->sku_cap_11be_enable &&
            !iwlwifi_mod_params.disable_11ax &&
-           !iwlwifi_mod_params.disable_11be)
+           !iwlwifi_mod_params.disable_11be) {
                hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
+               /* we handle this already earlier, but need it for MLO */
+               ieee80211_hw_set(hw, HANDLES_QUIET_CSA);
+       }
 
        /* With MLD FW API, it tracks timing by itself,
         * no need for any timing from the host
@@ -903,6 +906,8 @@ void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
                                        &mvmtxq->state) &&
                              !test_bit(IWL_MVM_TXQ_STATE_STOP_REDIRECT,
                                        &mvmtxq->state) &&
+                             !test_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA,
+                                       &mvmtxq->state) &&
                              !test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))) {
                        skb = ieee80211_tx_dequeue(hw, txq);
 
@@ -1421,6 +1426,20 @@ int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd);
 }
 
+static void iwl_mvm_post_csa_tx(void *data, struct ieee80211_sta *sta)
+{
+       struct ieee80211_hw *hw = data;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+               struct iwl_mvm_txq *mvmtxq =
+                       iwl_mvm_txq_from_mac80211(sta->txq[i]);
+
+               clear_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);
+               iwl_mvm_mac_itxq_xmit(hw, sta->txq[i]);
+       }
+}
+
 int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
                                struct ieee80211_bss_conf *link_conf)
@@ -1459,6 +1478,18 @@ int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
 
                        iwl_mvm_stop_session_protection(mvm, vif);
                }
+       } else if (vif->type == NL80211_IFTYPE_AP && mvmvif->csa_blocks_tx) {
+               struct iwl_mvm_txq *mvmtxq =
+                       iwl_mvm_txq_from_mac80211(vif->txq);
+
+               clear_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);
+
+               local_bh_disable();
+               iwl_mvm_mac_itxq_xmit(hw, vif->txq);
+               ieee80211_iterate_stations_atomic(hw, iwl_mvm_post_csa_tx, hw);
+               local_bh_enable();
+
+               mvmvif->csa_blocks_tx = false;
        }
 
        mvmvif->ps_disabled = false;
@@ -5414,6 +5445,18 @@ static int iwl_mvm_old_pre_chan_sw_sta(struct iwl_mvm *mvm,
        return 0;
 }
 
+static void iwl_mvm_csa_block_txqs(void *data, struct ieee80211_sta *sta)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+               struct iwl_mvm_txq *mvmtxq =
+                       iwl_mvm_txq_from_mac80211(sta->txq[i]);
+
+               set_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);
+       }
+}
+
 #define IWL_MAX_CSA_BLOCK_TX 1500
 int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
@@ -5422,6 +5465,7 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        struct ieee80211_vif *csa_vif;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm_txq *mvmtxq;
        int ret;
 
        mutex_lock(&mvm->mutex);
@@ -5464,6 +5508,18 @@ int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
 
                mvmvif->csa_target_freq = chsw->chandef.chan->center_freq;
 
+               if (!chsw->block_tx)
+                       break;
+               /* don't need blocking in driver otherwise - mac80211 will do */
+               if (!ieee80211_hw_check(mvm->hw, HANDLES_QUIET_CSA))
+                       break;
+
+               mvmvif->csa_blocks_tx = true;
+               mvmtxq = iwl_mvm_txq_from_mac80211(vif->txq);
+               set_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);
+               ieee80211_iterate_stations_atomic(mvm->hw,
+                                                 iwl_mvm_csa_block_txqs,
+                                                 NULL);
                break;
        case NL80211_IFTYPE_STATION:
                mvmvif->csa_blocks_tx = chsw->block_tx;
index e39f220349d471660ddbc2c0be8d719b8921be14..d1392c4077c134401c294c94700b69d441e3f11d 100644 (file)
@@ -759,9 +759,10 @@ struct iwl_mvm_txq {
        struct list_head list;
        u16 txq_id;
        atomic_t tx_request;
-#define IWL_MVM_TXQ_STATE_STOP_FULL    0
-#define IWL_MVM_TXQ_STATE_STOP_REDIRECT        1
-#define IWL_MVM_TXQ_STATE_READY                2
+#define IWL_MVM_TXQ_STATE_READY                0
+#define IWL_MVM_TXQ_STATE_STOP_FULL    1
+#define IWL_MVM_TXQ_STATE_STOP_REDIRECT        2
+#define IWL_MVM_TXQ_STATE_STOP_AP_CSA  3
        unsigned long state;
 };