diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 160 |
1 files changed, 112 insertions, 48 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index fb93961da750..ba723d50939a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
7 | * | 7 | * |
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of version 2 of the GNU General Public License as | 11 | * it under the terms of version 2 of the GNU General Public License as |
@@ -30,7 +30,7 @@ | |||
30 | * | 30 | * |
31 | * BSD LICENSE | 31 | * BSD LICENSE |
32 | * | 32 | * |
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
34 | * All rights reserved. | 34 | * All rights reserved. |
35 | * | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without |
@@ -69,10 +69,10 @@ | |||
69 | #include "mvm.h" | 69 | #include "mvm.h" |
70 | 70 | ||
71 | const u8 iwl_mvm_ac_to_tx_fifo[] = { | 71 | const u8 iwl_mvm_ac_to_tx_fifo[] = { |
72 | IWL_MVM_TX_FIFO_BK, | ||
73 | IWL_MVM_TX_FIFO_BE, | ||
74 | IWL_MVM_TX_FIFO_VI, | ||
75 | IWL_MVM_TX_FIFO_VO, | 72 | IWL_MVM_TX_FIFO_VO, |
73 | IWL_MVM_TX_FIFO_VI, | ||
74 | IWL_MVM_TX_FIFO_BE, | ||
75 | IWL_MVM_TX_FIFO_BK, | ||
76 | }; | 76 | }; |
77 | 77 | ||
78 | struct iwl_mvm_mac_iface_iterator_data { | 78 | struct iwl_mvm_mac_iface_iterator_data { |
@@ -85,35 +85,15 @@ struct iwl_mvm_mac_iface_iterator_data { | |||
85 | bool found_vif; | 85 | bool found_vif; |
86 | }; | 86 | }; |
87 | 87 | ||
88 | static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | 88 | static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, |
89 | struct ieee80211_vif *vif) | 89 | struct ieee80211_vif *vif) |
90 | { | 90 | { |
91 | struct iwl_mvm_mac_iface_iterator_data *data = _data; | 91 | struct iwl_mvm_mac_iface_iterator_data *data = _data; |
92 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 92 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
93 | u32 ac; | ||
94 | 93 | ||
95 | /* Iterator may already find the interface being added -- skip it */ | 94 | /* Skip the interface for which we are trying to assign a tsf_id */ |
96 | if (vif == data->vif) { | 95 | if (vif == data->vif) |
97 | data->found_vif = true; | ||
98 | return; | 96 | return; |
99 | } | ||
100 | |||
101 | /* Mark the queues used by the vif */ | ||
102 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
103 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
104 | __set_bit(vif->hw_queue[ac], data->used_hw_queues); | ||
105 | |||
106 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | ||
107 | __set_bit(vif->cab_queue, data->used_hw_queues); | ||
108 | |||
109 | /* | ||
110 | * Mark MAC IDs as used by clearing the available bit, and | ||
111 | * (below) mark TSFs as used if their existing use is not | ||
112 | * compatible with the new interface type. | ||
113 | * No locking or atomic bit operations are needed since the | ||
114 | * data is on the stack of the caller function. | ||
115 | */ | ||
116 | __clear_bit(mvmvif->id, data->available_mac_ids); | ||
117 | 97 | ||
118 | /* | 98 | /* |
119 | * The TSF is a hardware/firmware resource, there are 4 and | 99 | * The TSF is a hardware/firmware resource, there are 4 and |
@@ -135,21 +115,26 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | |||
135 | case NL80211_IFTYPE_STATION: | 115 | case NL80211_IFTYPE_STATION: |
136 | /* | 116 | /* |
137 | * The new interface is client, so if the existing one | 117 | * The new interface is client, so if the existing one |
138 | * we're iterating is an AP, the TSF should be used to | 118 | * we're iterating is an AP, and both interfaces have the |
119 | * same beacon interval, the same TSF should be used to | ||
139 | * avoid drift between the new client and existing AP, | 120 | * avoid drift between the new client and existing AP, |
140 | * the existing AP will get drift updates from the new | 121 | * the existing AP will get drift updates from the new |
141 | * client context in this case | 122 | * client context in this case |
142 | */ | 123 | */ |
143 | if (vif->type == NL80211_IFTYPE_AP) { | 124 | if (vif->type == NL80211_IFTYPE_AP) { |
144 | if (data->preferred_tsf == NUM_TSF_IDS && | 125 | if (data->preferred_tsf == NUM_TSF_IDS && |
145 | test_bit(mvmvif->tsf_id, data->available_tsf_ids)) | 126 | test_bit(mvmvif->tsf_id, data->available_tsf_ids) && |
127 | (vif->bss_conf.beacon_int == | ||
128 | data->vif->bss_conf.beacon_int)) { | ||
146 | data->preferred_tsf = mvmvif->tsf_id; | 129 | data->preferred_tsf = mvmvif->tsf_id; |
147 | return; | 130 | return; |
131 | } | ||
148 | } | 132 | } |
149 | break; | 133 | break; |
150 | case NL80211_IFTYPE_AP: | 134 | case NL80211_IFTYPE_AP: |
151 | /* | 135 | /* |
152 | * The new interface is AP/GO, so should get drift | 136 | * The new interface is AP/GO, so in case both interfaces |
137 | * have the same beacon interval, it should get drift | ||
153 | * updates from an existing client or use the same | 138 | * updates from an existing client or use the same |
154 | * TSF as an existing GO. There's no drift between | 139 | * TSF as an existing GO. There's no drift between |
155 | * TSFs internally but if they used different TSFs | 140 | * TSFs internally but if they used different TSFs |
@@ -159,9 +144,12 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | |||
159 | if (vif->type == NL80211_IFTYPE_STATION || | 144 | if (vif->type == NL80211_IFTYPE_STATION || |
160 | vif->type == NL80211_IFTYPE_AP) { | 145 | vif->type == NL80211_IFTYPE_AP) { |
161 | if (data->preferred_tsf == NUM_TSF_IDS && | 146 | if (data->preferred_tsf == NUM_TSF_IDS && |
162 | test_bit(mvmvif->tsf_id, data->available_tsf_ids)) | 147 | test_bit(mvmvif->tsf_id, data->available_tsf_ids) && |
148 | (vif->bss_conf.beacon_int == | ||
149 | data->vif->bss_conf.beacon_int)) { | ||
163 | data->preferred_tsf = mvmvif->tsf_id; | 150 | data->preferred_tsf = mvmvif->tsf_id; |
164 | return; | 151 | return; |
152 | } | ||
165 | } | 153 | } |
166 | break; | 154 | break; |
167 | default: | 155 | default: |
@@ -187,6 +175,39 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | |||
187 | data->preferred_tsf = NUM_TSF_IDS; | 175 | data->preferred_tsf = NUM_TSF_IDS; |
188 | } | 176 | } |
189 | 177 | ||
178 | static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | ||
179 | struct ieee80211_vif *vif) | ||
180 | { | ||
181 | struct iwl_mvm_mac_iface_iterator_data *data = _data; | ||
182 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
183 | u32 ac; | ||
184 | |||
185 | /* Iterator may already find the interface being added -- skip it */ | ||
186 | if (vif == data->vif) { | ||
187 | data->found_vif = true; | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | /* Mark the queues used by the vif */ | ||
192 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
193 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
194 | __set_bit(vif->hw_queue[ac], data->used_hw_queues); | ||
195 | |||
196 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | ||
197 | __set_bit(vif->cab_queue, data->used_hw_queues); | ||
198 | |||
199 | /* Mark MAC IDs as used by clearing the available bit, and | ||
200 | * (below) mark TSFs as used if their existing use is not | ||
201 | * compatible with the new interface type. | ||
202 | * No locking or atomic bit operations are needed since the | ||
203 | * data is on the stack of the caller function. | ||
204 | */ | ||
205 | __clear_bit(mvmvif->id, data->available_mac_ids); | ||
206 | |||
207 | /* find a suitable tsf_id */ | ||
208 | iwl_mvm_mac_tsf_id_iter(_data, mac, vif); | ||
209 | } | ||
210 | |||
190 | /* | 211 | /* |
191 | * Get the mask of the queus used by the vif | 212 | * Get the mask of the queus used by the vif |
192 | */ | 213 | */ |
@@ -205,6 +226,29 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, | |||
205 | return qmask; | 226 | return qmask; |
206 | } | 227 | } |
207 | 228 | ||
229 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, | ||
230 | struct ieee80211_vif *vif) | ||
231 | { | ||
232 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
233 | struct iwl_mvm_mac_iface_iterator_data data = { | ||
234 | .mvm = mvm, | ||
235 | .vif = vif, | ||
236 | .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, | ||
237 | /* no preference yet */ | ||
238 | .preferred_tsf = NUM_TSF_IDS, | ||
239 | }; | ||
240 | |||
241 | ieee80211_iterate_active_interfaces_atomic( | ||
242 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
243 | iwl_mvm_mac_tsf_id_iter, &data); | ||
244 | |||
245 | if (data.preferred_tsf != NUM_TSF_IDS) | ||
246 | mvmvif->tsf_id = data.preferred_tsf; | ||
247 | else if (!test_bit(mvmvif->tsf_id, data.available_tsf_ids)) | ||
248 | mvmvif->tsf_id = find_first_bit(data.available_tsf_ids, | ||
249 | NUM_TSF_IDS); | ||
250 | } | ||
251 | |||
208 | static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | 252 | static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, |
209 | struct ieee80211_vif *vif) | 253 | struct ieee80211_vif *vif) |
210 | { | 254 | { |
@@ -586,18 +630,23 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
586 | cpu_to_le32(vif->bss_conf.use_short_slot ? | 630 | cpu_to_le32(vif->bss_conf.use_short_slot ? |
587 | MAC_FLG_SHORT_SLOT : 0); | 631 | MAC_FLG_SHORT_SLOT : 0); |
588 | 632 | ||
589 | for (i = 0; i < AC_NUM; i++) { | 633 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
590 | cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min); | 634 | u8 txf = iwl_mvm_ac_to_tx_fifo[i]; |
591 | cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max); | 635 | |
592 | cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs; | 636 | cmd->ac[txf].cw_min = |
593 | cmd->ac[i].edca_txop = | 637 | cpu_to_le16(mvmvif->queue_params[i].cw_min); |
638 | cmd->ac[txf].cw_max = | ||
639 | cpu_to_le16(mvmvif->queue_params[i].cw_max); | ||
640 | cmd->ac[txf].edca_txop = | ||
594 | cpu_to_le16(mvmvif->queue_params[i].txop * 32); | 641 | cpu_to_le16(mvmvif->queue_params[i].txop * 32); |
595 | cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]); | 642 | cmd->ac[txf].aifsn = mvmvif->queue_params[i].aifs; |
643 | cmd->ac[txf].fifos_mask = BIT(txf); | ||
596 | } | 644 | } |
597 | 645 | ||
598 | /* in AP mode, the MCAST FIFO takes the EDCA params from VO */ | 646 | /* in AP mode, the MCAST FIFO takes the EDCA params from VO */ |
599 | if (vif->type == NL80211_IFTYPE_AP) | 647 | if (vif->type == NL80211_IFTYPE_AP) |
600 | cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST); | 648 | cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |= |
649 | BIT(IWL_MVM_TX_FIFO_MCAST); | ||
601 | 650 | ||
602 | if (vif->bss_conf.qos) | 651 | if (vif->bss_conf.qos) |
603 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); | 652 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); |
@@ -1007,7 +1056,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, | |||
1007 | iwl_mvm_mac_ap_iterator, &data); | 1056 | iwl_mvm_mac_ap_iterator, &data); |
1008 | 1057 | ||
1009 | if (data.beacon_device_ts) { | 1058 | if (data.beacon_device_ts) { |
1010 | u32 rand = (prandom_u32() % (80 - 20)) + 20; | 1059 | u32 rand = (prandom_u32() % (64 - 36)) + 36; |
1011 | mvmvif->ap_beacon_time = data.beacon_device_ts + | 1060 | mvmvif->ap_beacon_time = data.beacon_device_ts + |
1012 | ieee80211_tu_to_usec(data.beacon_int * rand / | 1061 | ieee80211_tu_to_usec(data.beacon_int * rand / |
1013 | 100); | 1062 | 100); |
@@ -1186,10 +1235,18 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
1186 | static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, | 1235 | static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, |
1187 | struct ieee80211_vif *vif) | 1236 | struct ieee80211_vif *vif) |
1188 | { | 1237 | { |
1189 | u16 *id = _data; | 1238 | struct iwl_missed_beacons_notif *missed_beacons = _data; |
1190 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1239 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1191 | 1240 | ||
1192 | if (mvmvif->id == *id) | 1241 | if (mvmvif->id != (u16)le32_to_cpu(missed_beacons->mac_id)) |
1242 | return; | ||
1243 | |||
1244 | /* | ||
1245 | * TODO: the threshold should be adjusted based on latency conditions, | ||
1246 | * and/or in case of a CS flow on one of the other AP vifs. | ||
1247 | */ | ||
1248 | if (le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx) > | ||
1249 | IWL_MVM_MISSED_BEACONS_THRESHOLD) | ||
1193 | ieee80211_beacon_loss(vif); | 1250 | ieee80211_beacon_loss(vif); |
1194 | } | 1251 | } |
1195 | 1252 | ||
@@ -1198,12 +1255,19 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | |||
1198 | struct iwl_device_cmd *cmd) | 1255 | struct iwl_device_cmd *cmd) |
1199 | { | 1256 | { |
1200 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 1257 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
1201 | struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data; | 1258 | struct iwl_missed_beacons_notif *mb = (void *)pkt->data; |
1202 | u16 id = (u16)le32_to_cpu(missed_beacons->mac_id); | 1259 | |
1260 | IWL_DEBUG_INFO(mvm, | ||
1261 | "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", | ||
1262 | le32_to_cpu(mb->mac_id), | ||
1263 | le32_to_cpu(mb->consec_missed_beacons), | ||
1264 | le32_to_cpu(mb->consec_missed_beacons_since_last_rx), | ||
1265 | le32_to_cpu(mb->num_recvd_beacons), | ||
1266 | le32_to_cpu(mb->num_expected_beacons)); | ||
1203 | 1267 | ||
1204 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 1268 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
1205 | IEEE80211_IFACE_ITER_NORMAL, | 1269 | IEEE80211_IFACE_ITER_NORMAL, |
1206 | iwl_mvm_beacon_loss_iterator, | 1270 | iwl_mvm_beacon_loss_iterator, |
1207 | &id); | 1271 | mb); |
1208 | return 0; | 1272 | return 0; |
1209 | } | 1273 | } |