iwlwifi: mvm: set MAC_FILTER_IN_BEACON correctly for STA/P2P client
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / mvm / mac-ctxt.c
index 8b79081d4885122d8264bbed3c896150b4e206a9..8242e689ddb114af0a2e17a0d5ce266c19392535 100644 (file)
@@ -67,6 +67,7 @@
 #include "iwl-prph.h"
 #include "fw-api.h"
 #include "mvm.h"
+#include "time-event.h"
 
 const u8 iwl_mvm_ac_to_tx_fifo[] = {
        IWL_MVM_TX_FIFO_VO,
@@ -720,11 +721,6 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
            !force_assoc_off) {
                u32 dtim_offs;
 
-               /* Allow beacons to pass through as long as we are not
-                * associated, or we do not have dtim period information.
-                */
-               cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
-
                /*
                 * The DTIM count counts down, so when it is N that means N
                 * more beacon intervals happen until the DTIM TBTT. Therefore
@@ -758,6 +754,11 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
                ctxt_sta->is_assoc = cpu_to_le32(1);
        } else {
                ctxt_sta->is_assoc = cpu_to_le32(0);
+
+               /* Allow beacons to pass through as long as we are not
+                * associated, or we do not have dtim period information.
+                */
+               cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
        }
 
        ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int);
@@ -903,7 +904,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
        struct iwl_mac_beacon_cmd beacon_cmd = {};
        struct ieee80211_tx_info *info;
        u32 beacon_skb_len;
-       u32 rate;
+       u32 rate, tx_flags;
 
        if (WARN_ON(!beacon))
                return -EINVAL;
@@ -913,14 +914,17 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
        /* TODO: for now the beacon template id is set to be the mac context id.
         * Might be better to handle it as another resource ... */
        beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+       info = IEEE80211_SKB_CB(beacon);
 
        /* Set up TX command fields */
        beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);
        beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;
        beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
-       beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
-                                            TX_CMD_FLG_BT_DIS  |
-                                            TX_CMD_FLG_TSF);
+       tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;
+       tx_flags |=
+               iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) <<
+                                               TX_CMD_FLG_BT_PRIO_POS;
+       beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
 
        mvm->mgmt_last_antenna_idx =
                iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
@@ -930,8 +934,6 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
                            RATE_MCS_ANT_POS);
 
-       info = IEEE80211_SKB_CB(beacon);
-
        if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) {
                rate = IWL_FIRST_OFDM_RATE;
        } else {
@@ -968,7 +970,7 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
        WARN_ON(vif->type != NL80211_IFTYPE_AP &&
                vif->type != NL80211_IFTYPE_ADHOC);
 
-       beacon = ieee80211_beacon_get(mvm->hw, vif);
+       beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL);
        if (!beacon)
                return -ENOMEM;
 
@@ -1210,31 +1212,94 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        return 0;
 }
 
+static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,
+                                  struct ieee80211_vif *csa_vif, u32 gp2)
+{
+       struct iwl_mvm_vif *mvmvif =
+                       iwl_mvm_vif_from_mac80211(csa_vif);
+
+       if (!ieee80211_csa_is_complete(csa_vif)) {
+               int c = ieee80211_csa_update_counter(csa_vif);
+
+               iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif);
+               if (csa_vif->p2p &&
+                   !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) {
+                       u32 rel_time = (c + 1) *
+                                      csa_vif->bss_conf.beacon_int -
+                                      IWL_MVM_CHANNEL_SWITCH_TIME;
+                       u32 apply_time = gp2 + rel_time * 1024;
+
+                       iwl_mvm_schedule_csa_noa(mvm, csa_vif,
+                                                IWL_MVM_CHANNEL_SWITCH_TIME -
+                                                IWL_MVM_CHANNEL_SWITCH_MARGIN,
+                                                apply_time);
+               }
+       } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) {
+               /* we don't have CSA NoA scheduled yet, switch now */
+               ieee80211_csa_finish(csa_vif);
+               RCU_INIT_POINTER(mvm->csa_vif, NULL);
+       }
+}
+
 int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
                            struct iwl_rx_cmd_buffer *rxb,
                            struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_beacon_notif *beacon = (void *)pkt->data;
-       u16 status __maybe_unused =
-               le16_to_cpu(beacon->beacon_notify_hdr.status.status);
-       u32 rate __maybe_unused =
-               le32_to_cpu(beacon->beacon_notify_hdr.initial_rate);
+       struct iwl_mvm_tx_resp *beacon_notify_hdr;
+       struct ieee80211_vif *csa_vif;
+       struct ieee80211_vif *tx_blocked_vif;
+       u64 tsf;
 
        lockdep_assert_held(&mvm->mutex);
 
-       IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n",
-                    status & TX_STATUS_MSK,
-                    beacon->beacon_notify_hdr.failure_frame,
-                    le64_to_cpu(beacon->tsf),
-                    rate);
+       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) {
+               struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
 
-       if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) {
-               if (!ieee80211_csa_is_complete(mvm->csa_vif)) {
-                       iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm->csa_vif);
-               } else {
-                       ieee80211_csa_finish(mvm->csa_vif);
-                       mvm->csa_vif = NULL;
+               beacon_notify_hdr = &beacon->beacon_notify_hdr;
+               tsf = le64_to_cpu(beacon->tsf);
+               mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);
+       } else {
+               struct iwl_beacon_notif *beacon = (void *)pkt->data;
+
+               beacon_notify_hdr = &beacon->beacon_notify_hdr;
+               tsf = le64_to_cpu(beacon->tsf);
+       }
+
+       IWL_DEBUG_RX(mvm,
+                    "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n",
+                    le16_to_cpu(beacon_notify_hdr->status.status) &
+                                                               TX_STATUS_MSK,
+                    beacon_notify_hdr->failure_frame, tsf,
+                    mvm->ap_last_beacon_gp2,
+                    le32_to_cpu(beacon_notify_hdr->initial_rate));
+
+       csa_vif = rcu_dereference_protected(mvm->csa_vif,
+                                           lockdep_is_held(&mvm->mutex));
+       if (unlikely(csa_vif && csa_vif->csa_active))
+               iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2);
+
+       tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif,
+                                               lockdep_is_held(&mvm->mutex));
+       if (unlikely(tx_blocked_vif)) {
+               struct iwl_mvm_vif *mvmvif =
+                       iwl_mvm_vif_from_mac80211(tx_blocked_vif);
+
+               /*
+                * The channel switch is started and we have blocked the
+                * stations. If this is the first beacon (the timeout wasn't
+                * set), set the unblock timeout, otherwise countdown
+                */
+               if (!mvm->csa_tx_block_bcn_timeout)
+                       mvm->csa_tx_block_bcn_timeout =
+                               IWL_MVM_CS_UNBLOCK_TX_TIMEOUT;
+               else
+                       mvm->csa_tx_block_bcn_timeout--;
+
+               /* Check if the timeout is expired, and unblock tx */
+               if (mvm->csa_tx_block_bcn_timeout == 0) {
+                       iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false);
+                       RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);
                }
        }
 
This page took 0.053745 seconds and 5 git commands to generate.