diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 126 |
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 | ||
71 | const u8 iwl_mvm_ac_to_tx_fifo[] = { | 72 | const 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 | ||
1215 | static 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 | |||
1202 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | 1244 | int 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 | ||