aboutsummaryrefslogtreecommitdiffstats
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.c126
1 files changed, 101 insertions, 25 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 725ba49576bf..0e523e28cabf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -67,6 +67,7 @@
67#include "iwl-prph.h" 67#include "iwl-prph.h"
68#include "fw-api.h" 68#include "fw-api.h"
69#include "mvm.h" 69#include "mvm.h"
70#include "time-event.h"
70 71
71const u8 iwl_mvm_ac_to_tx_fifo[] = { 72const u8 iwl_mvm_ac_to_tx_fifo[] = {
72 IWL_MVM_TX_FIFO_VO, 73 IWL_MVM_TX_FIFO_VO,
@@ -903,7 +904,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
903 struct iwl_mac_beacon_cmd beacon_cmd = {}; 904 struct iwl_mac_beacon_cmd beacon_cmd = {};
904 struct ieee80211_tx_info *info; 905 struct ieee80211_tx_info *info;
905 u32 beacon_skb_len; 906 u32 beacon_skb_len;
906 u32 rate; 907 u32 rate, tx_flags;
907 908
908 if (WARN_ON(!beacon)) 909 if (WARN_ON(!beacon))
909 return -EINVAL; 910 return -EINVAL;
@@ -913,14 +914,17 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
913 /* TODO: for now the beacon template id is set to be the mac context id. 914 /* TODO: for now the beacon template id is set to be the mac context id.
914 * Might be better to handle it as another resource ... */ 915 * Might be better to handle it as another resource ... */
915 beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); 916 beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
917 info = IEEE80211_SKB_CB(beacon);
916 918
917 /* Set up TX command fields */ 919 /* Set up TX command fields */
918 beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len); 920 beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);
919 beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id; 921 beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;
920 beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); 922 beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
921 beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | 923 tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;
922 TX_CMD_FLG_BT_DIS | 924 tx_flags |=
923 TX_CMD_FLG_TSF); 925 iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) <<
926 TX_CMD_FLG_BT_PRIO_POS;
927 beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
924 928
925 mvm->mgmt_last_antenna_idx = 929 mvm->mgmt_last_antenna_idx =
926 iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, 930 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,
930 cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << 934 cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
931 RATE_MCS_ANT_POS); 935 RATE_MCS_ANT_POS);
932 936
933 info = IEEE80211_SKB_CB(beacon);
934
935 if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) { 937 if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) {
936 rate = IWL_FIRST_OFDM_RATE; 938 rate = IWL_FIRST_OFDM_RATE;
937 } else { 939 } else {
@@ -968,7 +970,7 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
968 WARN_ON(vif->type != NL80211_IFTYPE_AP && 970 WARN_ON(vif->type != NL80211_IFTYPE_AP &&
969 vif->type != NL80211_IFTYPE_ADHOC); 971 vif->type != NL80211_IFTYPE_ADHOC);
970 972
971 beacon = ieee80211_beacon_get(mvm->hw, vif); 973 beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL);
972 if (!beacon) 974 if (!beacon)
973 return -ENOMEM; 975 return -ENOMEM;
974 976
@@ -1072,8 +1074,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
1072 /* Fill the common data for all mac context types */ 1074 /* Fill the common data for all mac context types */
1073 iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 1075 iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
1074 1076
1075 /* Also enable probe requests to pass */ 1077 /*
1076 cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); 1078 * pass probe requests and beacons from other APs (needed
1079 * for ht protection)
1080 */
1081 cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
1082 MAC_FILTER_IN_BEACON);
1077 1083
1078 /* Fill the data specific for ap mode */ 1084 /* Fill the data specific for ap mode */
1079 iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap, 1085 iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
@@ -1094,6 +1100,13 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
1094 /* Fill the common data for all mac context types */ 1100 /* Fill the common data for all mac context types */
1095 iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 1101 iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
1096 1102
1103 /*
1104 * pass probe requests and beacons from other APs (needed
1105 * for ht protection)
1106 */
1107 cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
1108 MAC_FILTER_IN_BEACON);
1109
1097 /* Fill the data specific for GO mode */ 1110 /* Fill the data specific for GO mode */
1098 iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap, 1111 iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
1099 action == FW_CTXT_ACTION_ADD); 1112 action == FW_CTXT_ACTION_ADD);
@@ -1199,31 +1212,94 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1199 return 0; 1212 return 0;
1200} 1213}
1201 1214
1215static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,
1216 struct ieee80211_vif *csa_vif, u32 gp2)
1217{
1218 struct iwl_mvm_vif *mvmvif =
1219 iwl_mvm_vif_from_mac80211(csa_vif);
1220
1221 if (!ieee80211_csa_is_complete(csa_vif)) {
1222 int c = ieee80211_csa_update_counter(csa_vif);
1223
1224 iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif);
1225 if (csa_vif->p2p &&
1226 !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) {
1227 u32 rel_time = (c + 1) *
1228 csa_vif->bss_conf.beacon_int -
1229 IWL_MVM_CHANNEL_SWITCH_TIME;
1230 u32 apply_time = gp2 + rel_time * 1024;
1231
1232 iwl_mvm_schedule_csa_noa(mvm, csa_vif,
1233 IWL_MVM_CHANNEL_SWITCH_TIME -
1234 IWL_MVM_CHANNEL_SWITCH_MARGIN,
1235 apply_time);
1236 }
1237 } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) {
1238 /* we don't have CSA NoA scheduled yet, switch now */
1239 ieee80211_csa_finish(csa_vif);
1240 RCU_INIT_POINTER(mvm->csa_vif, NULL);
1241 }
1242}
1243
1202int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, 1244int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
1203 struct iwl_rx_cmd_buffer *rxb, 1245 struct iwl_rx_cmd_buffer *rxb,
1204 struct iwl_device_cmd *cmd) 1246 struct iwl_device_cmd *cmd)
1205{ 1247{
1206 struct iwl_rx_packet *pkt = rxb_addr(rxb); 1248 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1207 struct iwl_beacon_notif *beacon = (void *)pkt->data; 1249 struct iwl_mvm_tx_resp *beacon_notify_hdr;
1208 u16 status __maybe_unused = 1250 struct ieee80211_vif *csa_vif;
1209 le16_to_cpu(beacon->beacon_notify_hdr.status.status); 1251 struct ieee80211_vif *tx_blocked_vif;
1210 u32 rate __maybe_unused = 1252 u64 tsf;
1211 le32_to_cpu(beacon->beacon_notify_hdr.initial_rate);
1212 1253
1213 lockdep_assert_held(&mvm->mutex); 1254 lockdep_assert_held(&mvm->mutex);
1214 1255
1215 IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", 1256 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) {
1216 status & TX_STATUS_MSK, 1257 struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
1217 beacon->beacon_notify_hdr.failure_frame,
1218 le64_to_cpu(beacon->tsf),
1219 rate);
1220 1258
1221 if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { 1259 beacon_notify_hdr = &beacon->beacon_notify_hdr;
1222 if (!ieee80211_csa_is_complete(mvm->csa_vif)) { 1260 tsf = le64_to_cpu(beacon->tsf);
1223 iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm->csa_vif); 1261 mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);
1224 } else { 1262 } else {
1225 ieee80211_csa_finish(mvm->csa_vif); 1263 struct iwl_beacon_notif *beacon = (void *)pkt->data;
1226 mvm->csa_vif = NULL; 1264
1265 beacon_notify_hdr = &beacon->beacon_notify_hdr;
1266 tsf = le64_to_cpu(beacon->tsf);
1267 }
1268
1269 IWL_DEBUG_RX(mvm,
1270 "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n",
1271 le16_to_cpu(beacon_notify_hdr->status.status) &
1272 TX_STATUS_MSK,
1273 beacon_notify_hdr->failure_frame, tsf,
1274 mvm->ap_last_beacon_gp2,
1275 le32_to_cpu(beacon_notify_hdr->initial_rate));
1276
1277 csa_vif = rcu_dereference_protected(mvm->csa_vif,
1278 lockdep_is_held(&mvm->mutex));
1279 if (unlikely(csa_vif && csa_vif->csa_active))
1280 iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2);
1281
1282 tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif,
1283 lockdep_is_held(&mvm->mutex));
1284 if (unlikely(tx_blocked_vif)) {
1285 struct iwl_mvm_vif *mvmvif =
1286 iwl_mvm_vif_from_mac80211(tx_blocked_vif);
1287
1288 /*
1289 * The channel switch is started and we have blocked the
1290 * stations. If this is the first beacon (the timeout wasn't
1291 * set), set the unblock timeout, otherwise countdown
1292 */
1293 if (!mvm->csa_tx_block_bcn_timeout)
1294 mvm->csa_tx_block_bcn_timeout =
1295 IWL_MVM_CS_UNBLOCK_TX_TIMEOUT;
1296 else
1297 mvm->csa_tx_block_bcn_timeout--;
1298
1299 /* Check if the timeout is expired, and unblock tx */
1300 if (mvm->csa_tx_block_bcn_timeout == 0) {
1301 iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false);
1302 RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);
1227 } 1303 }
1228 } 1304 }
1229 1305