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.c160
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
71const u8 iwl_mvm_ac_to_tx_fifo[] = { 71const 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
78struct iwl_mvm_mac_iface_iterator_data { 78struct 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
88static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, 88static 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
178static 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
229void 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
208static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, 252static 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,
1186static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, 1235static 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}