summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c111
1 files changed, 88 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 8b79081d4885..0e523e28cabf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -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,
@@ -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);
}
}