diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 104 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 |
3 files changed, 91 insertions, 30 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 510cf9f8b95b..3d418299204a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -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 | { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index abe75142edba..4c9448212a97 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -866,6 +866,14 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
866 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 866 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
867 | int ret; | 867 | int ret; |
868 | 868 | ||
869 | /* | ||
870 | * Re-calculate the tsf id, as the master-slave relations depend on the | ||
871 | * beacon interval, which was not known when the station interface was | ||
872 | * added. | ||
873 | */ | ||
874 | if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) | ||
875 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); | ||
876 | |||
869 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif); | 877 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif); |
870 | if (ret) | 878 | if (ret) |
871 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | 879 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); |
@@ -979,6 +987,13 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
979 | if (ret) | 987 | if (ret) |
980 | goto out_unlock; | 988 | goto out_unlock; |
981 | 989 | ||
990 | /* | ||
991 | * Re-calculate the tsf id, as the master-slave relations depend on the | ||
992 | * beacon interval, which was not known when the AP interface was added. | ||
993 | */ | ||
994 | if (vif->type == NL80211_IFTYPE_AP) | ||
995 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); | ||
996 | |||
982 | /* Add the mac context */ | 997 | /* Add the mac context */ |
983 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); | 998 | ret = iwl_mvm_mac_ctxt_add(mvm, vif); |
984 | if (ret) | 999 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ca8a9048383d..f6b096bc9292 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -712,6 +712,8 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
712 | int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | 712 | int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, |
713 | struct iwl_rx_cmd_buffer *rxb, | 713 | struct iwl_rx_cmd_buffer *rxb, |
714 | struct iwl_device_cmd *cmd); | 714 | struct iwl_device_cmd *cmd); |
715 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, | ||
716 | struct ieee80211_vif *vif); | ||
715 | 717 | ||
716 | /* Bindings */ | 718 | /* Bindings */ |
717 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 719 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |