diff options
author | David S. Miller <davem@davemloft.net> | 2010-02-14 20:45:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-14 20:45:59 -0500 |
commit | f6f223039c0d0683bdea1eabd35b309e10311a60 (patch) | |
tree | 890e07acf8c18ddc2994ebc0a0bdcdda38b0dcc6 | |
parent | b3b3f04fb587ecb61b5baa6c1c5f0e666fd12d73 (diff) | |
parent | 42c4568a4ace0adc27a9d6f02936e2047ba6fc7e (diff) |
Merge branch 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
79 files changed, 1458 insertions, 1088 deletions
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index 971d1c0c83e..affb15a344a 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl | |||
@@ -234,7 +234,6 @@ usage should require reading the full document. | |||
234 | <title>Multiple queues and QoS support</title> | 234 | <title>Multiple queues and QoS support</title> |
235 | <para>TBD</para> | 235 | <para>TBD</para> |
236 | !Finclude/net/mac80211.h ieee80211_tx_queue_params | 236 | !Finclude/net/mac80211.h ieee80211_tx_queue_params |
237 | !Finclude/net/mac80211.h ieee80211_tx_queue_stats | ||
238 | </chapter> | 237 | </chapter> |
239 | 238 | ||
240 | <chapter id="AP"> | 239 | <chapter id="AP"> |
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index e6ca3eb4c0d..547912e6843 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c | |||
@@ -302,18 +302,6 @@ static int adm8211_get_stats(struct ieee80211_hw *dev, | |||
302 | return 0; | 302 | return 0; |
303 | } | 303 | } |
304 | 304 | ||
305 | static int adm8211_get_tx_stats(struct ieee80211_hw *dev, | ||
306 | struct ieee80211_tx_queue_stats *stats) | ||
307 | { | ||
308 | struct adm8211_priv *priv = dev->priv; | ||
309 | |||
310 | stats[0].len = priv->cur_tx - priv->dirty_tx; | ||
311 | stats[0].limit = priv->tx_ring_size - 2; | ||
312 | stats[0].count = priv->dirty_tx; | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static void adm8211_interrupt_tci(struct ieee80211_hw *dev) | 305 | static void adm8211_interrupt_tci(struct ieee80211_hw *dev) |
318 | { | 306 | { |
319 | struct adm8211_priv *priv = dev->priv; | 307 | struct adm8211_priv *priv = dev->priv; |
@@ -1773,7 +1761,6 @@ static const struct ieee80211_ops adm8211_ops = { | |||
1773 | .prepare_multicast = adm8211_prepare_multicast, | 1761 | .prepare_multicast = adm8211_prepare_multicast, |
1774 | .configure_filter = adm8211_configure_filter, | 1762 | .configure_filter = adm8211_configure_filter, |
1775 | .get_stats = adm8211_get_stats, | 1763 | .get_stats = adm8211_get_stats, |
1776 | .get_tx_stats = adm8211_get_tx_stats, | ||
1777 | .get_tsf = adm8211_get_tsft | 1764 | .get_tsf = adm8211_get_tsft |
1778 | }; | 1765 | }; |
1779 | 1766 | ||
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index b99a8c2053d..8c8ce67971e 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h | |||
@@ -144,6 +144,12 @@ struct ar9170_sta_tid { | |||
144 | bool active; | 144 | bool active; |
145 | }; | 145 | }; |
146 | 146 | ||
147 | struct ar9170_tx_queue_stats { | ||
148 | unsigned int len; | ||
149 | unsigned int limit; | ||
150 | unsigned int count; | ||
151 | }; | ||
152 | |||
147 | #define AR9170_QUEUE_TIMEOUT 64 | 153 | #define AR9170_QUEUE_TIMEOUT 64 |
148 | #define AR9170_TX_TIMEOUT 8 | 154 | #define AR9170_TX_TIMEOUT 8 |
149 | #define AR9170_BA_TIMEOUT 4 | 155 | #define AR9170_BA_TIMEOUT 4 |
@@ -211,7 +217,7 @@ struct ar9170 { | |||
211 | 217 | ||
212 | /* qos queue settings */ | 218 | /* qos queue settings */ |
213 | spinlock_t tx_stats_lock; | 219 | spinlock_t tx_stats_lock; |
214 | struct ieee80211_tx_queue_stats tx_stats[5]; | 220 | struct ar9170_tx_queue_stats tx_stats[5]; |
215 | struct ieee80211_tx_queue_params edcf[5]; | 221 | struct ieee80211_tx_queue_params edcf[5]; |
216 | 222 | ||
217 | spinlock_t cmdlock; | 223 | spinlock_t cmdlock; |
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 4d27f7f67c7..91797cb6e0e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c | |||
@@ -2396,18 +2396,6 @@ static int ar9170_get_stats(struct ieee80211_hw *hw, | |||
2396 | return 0; | 2396 | return 0; |
2397 | } | 2397 | } |
2398 | 2398 | ||
2399 | static int ar9170_get_tx_stats(struct ieee80211_hw *hw, | ||
2400 | struct ieee80211_tx_queue_stats *tx_stats) | ||
2401 | { | ||
2402 | struct ar9170 *ar = hw->priv; | ||
2403 | |||
2404 | spin_lock_bh(&ar->tx_stats_lock); | ||
2405 | memcpy(tx_stats, ar->tx_stats, sizeof(tx_stats[0]) * hw->queues); | ||
2406 | spin_unlock_bh(&ar->tx_stats_lock); | ||
2407 | |||
2408 | return 0; | ||
2409 | } | ||
2410 | |||
2411 | static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, | 2399 | static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, |
2412 | const struct ieee80211_tx_queue_params *param) | 2400 | const struct ieee80211_tx_queue_params *param) |
2413 | { | 2401 | { |
@@ -2509,7 +2497,6 @@ static const struct ieee80211_ops ar9170_ops = { | |||
2509 | .set_key = ar9170_set_key, | 2497 | .set_key = ar9170_set_key, |
2510 | .sta_notify = ar9170_sta_notify, | 2498 | .sta_notify = ar9170_sta_notify, |
2511 | .get_stats = ar9170_get_stats, | 2499 | .get_stats = ar9170_get_stats, |
2512 | .get_tx_stats = ar9170_get_tx_stats, | ||
2513 | .ampdu_action = ar9170_ampdu_action, | 2500 | .ampdu_action = ar9170_ampdu_action, |
2514 | }; | 2501 | }; |
2515 | 2502 | ||
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index ad4d446f026..ac67f02e26d 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -541,7 +541,6 @@ struct ath5k_txq_info { | |||
541 | /* | 541 | /* |
542 | * Transmit packet types. | 542 | * Transmit packet types. |
543 | * used on tx control descriptor | 543 | * used on tx control descriptor |
544 | * TODO: Use them inside base.c corectly | ||
545 | */ | 544 | */ |
546 | enum ath5k_pkt_type { | 545 | enum ath5k_pkt_type { |
547 | AR5K_PKT_TYPE_NORMAL = 0, | 546 | AR5K_PKT_TYPE_NORMAL = 0, |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index edb6c90e376..8dce0077b02 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -241,8 +241,6 @@ static int ath5k_set_key(struct ieee80211_hw *hw, | |||
241 | struct ieee80211_key_conf *key); | 241 | struct ieee80211_key_conf *key); |
242 | static int ath5k_get_stats(struct ieee80211_hw *hw, | 242 | static int ath5k_get_stats(struct ieee80211_hw *hw, |
243 | struct ieee80211_low_level_stats *stats); | 243 | struct ieee80211_low_level_stats *stats); |
244 | static int ath5k_get_tx_stats(struct ieee80211_hw *hw, | ||
245 | struct ieee80211_tx_queue_stats *stats); | ||
246 | static u64 ath5k_get_tsf(struct ieee80211_hw *hw); | 244 | static u64 ath5k_get_tsf(struct ieee80211_hw *hw); |
247 | static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); | 245 | static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); |
248 | static void ath5k_reset_tsf(struct ieee80211_hw *hw); | 246 | static void ath5k_reset_tsf(struct ieee80211_hw *hw); |
@@ -269,7 +267,6 @@ static const struct ieee80211_ops ath5k_hw_ops = { | |||
269 | .set_key = ath5k_set_key, | 267 | .set_key = ath5k_set_key, |
270 | .get_stats = ath5k_get_stats, | 268 | .get_stats = ath5k_get_stats, |
271 | .conf_tx = NULL, | 269 | .conf_tx = NULL, |
272 | .get_tx_stats = ath5k_get_tx_stats, | ||
273 | .get_tsf = ath5k_get_tsf, | 270 | .get_tsf = ath5k_get_tsf, |
274 | .set_tsf = ath5k_set_tsf, | 271 | .set_tsf = ath5k_set_tsf, |
275 | .reset_tsf = ath5k_reset_tsf, | 272 | .reset_tsf = ath5k_reset_tsf, |
@@ -1249,6 +1246,29 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1249 | return 0; | 1246 | return 0; |
1250 | } | 1247 | } |
1251 | 1248 | ||
1249 | static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) | ||
1250 | { | ||
1251 | struct ieee80211_hdr *hdr; | ||
1252 | enum ath5k_pkt_type htype; | ||
1253 | __le16 fc; | ||
1254 | |||
1255 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1256 | fc = hdr->frame_control; | ||
1257 | |||
1258 | if (ieee80211_is_beacon(fc)) | ||
1259 | htype = AR5K_PKT_TYPE_BEACON; | ||
1260 | else if (ieee80211_is_probe_resp(fc)) | ||
1261 | htype = AR5K_PKT_TYPE_PROBE_RESP; | ||
1262 | else if (ieee80211_is_atim(fc)) | ||
1263 | htype = AR5K_PKT_TYPE_ATIM; | ||
1264 | else if (ieee80211_is_pspoll(fc)) | ||
1265 | htype = AR5K_PKT_TYPE_PSPOLL; | ||
1266 | else | ||
1267 | htype = AR5K_PKT_TYPE_NORMAL; | ||
1268 | |||
1269 | return htype; | ||
1270 | } | ||
1271 | |||
1252 | static int | 1272 | static int |
1253 | ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, | 1273 | ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, |
1254 | struct ath5k_txq *txq) | 1274 | struct ath5k_txq *txq) |
@@ -1303,7 +1323,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, | |||
1303 | sc->vif, pktlen, info)); | 1323 | sc->vif, pktlen, info)); |
1304 | } | 1324 | } |
1305 | ret = ah->ah_setup_tx_desc(ah, ds, pktlen, | 1325 | ret = ah->ah_setup_tx_desc(ah, ds, pktlen, |
1306 | ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, | 1326 | ieee80211_get_hdrlen_from_skb(skb), |
1327 | get_hw_packet_type(skb), | ||
1307 | (sc->power_level * 2), | 1328 | (sc->power_level * 2), |
1308 | hw_rate, | 1329 | hw_rate, |
1309 | info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, | 1330 | info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, |
@@ -1332,7 +1353,6 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, | |||
1332 | 1353 | ||
1333 | spin_lock_bh(&txq->lock); | 1354 | spin_lock_bh(&txq->lock); |
1334 | list_add_tail(&bf->list, &txq->q); | 1355 | list_add_tail(&bf->list, &txq->q); |
1335 | sc->tx_stats[txq->qnum].len++; | ||
1336 | if (txq->link == NULL) /* is this first packet? */ | 1356 | if (txq->link == NULL) /* is this first packet? */ |
1337 | ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); | 1357 | ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); |
1338 | else /* no, so only link it */ | 1358 | else /* no, so only link it */ |
@@ -1581,7 +1601,6 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1581 | ath5k_txbuf_free(sc, bf); | 1601 | ath5k_txbuf_free(sc, bf); |
1582 | 1602 | ||
1583 | spin_lock_bh(&sc->txbuflock); | 1603 | spin_lock_bh(&sc->txbuflock); |
1584 | sc->tx_stats[txq->qnum].len--; | ||
1585 | list_move_tail(&bf->list, &sc->txbuf); | 1604 | list_move_tail(&bf->list, &sc->txbuf); |
1586 | sc->txbuf_len++; | 1605 | sc->txbuf_len++; |
1587 | spin_unlock_bh(&sc->txbuflock); | 1606 | spin_unlock_bh(&sc->txbuflock); |
@@ -2011,10 +2030,8 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
2011 | } | 2030 | } |
2012 | 2031 | ||
2013 | ieee80211_tx_status(sc->hw, skb); | 2032 | ieee80211_tx_status(sc->hw, skb); |
2014 | sc->tx_stats[txq->qnum].count++; | ||
2015 | 2033 | ||
2016 | spin_lock(&sc->txbuflock); | 2034 | spin_lock(&sc->txbuflock); |
2017 | sc->tx_stats[txq->qnum].len--; | ||
2018 | list_move_tail(&bf->list, &sc->txbuf); | 2035 | list_move_tail(&bf->list, &sc->txbuf); |
2019 | sc->txbuf_len++; | 2036 | sc->txbuf_len++; |
2020 | spin_unlock(&sc->txbuflock); | 2037 | spin_unlock(&sc->txbuflock); |
@@ -3116,17 +3133,6 @@ ath5k_get_stats(struct ieee80211_hw *hw, | |||
3116 | return 0; | 3133 | return 0; |
3117 | } | 3134 | } |
3118 | 3135 | ||
3119 | static int | ||
3120 | ath5k_get_tx_stats(struct ieee80211_hw *hw, | ||
3121 | struct ieee80211_tx_queue_stats *stats) | ||
3122 | { | ||
3123 | struct ath5k_softc *sc = hw->priv; | ||
3124 | |||
3125 | memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats)); | ||
3126 | |||
3127 | return 0; | ||
3128 | } | ||
3129 | |||
3130 | static u64 | 3136 | static u64 |
3131 | ath5k_get_tsf(struct ieee80211_hw *hw) | 3137 | ath5k_get_tsf(struct ieee80211_hw *hw) |
3132 | { | 3138 | { |
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 952b3a21bbc..7e1a88a5abd 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h | |||
@@ -117,7 +117,6 @@ struct ath5k_softc { | |||
117 | struct pci_dev *pdev; /* for dma mapping */ | 117 | struct pci_dev *pdev; /* for dma mapping */ |
118 | void __iomem *iobase; /* address of the device */ | 118 | void __iomem *iobase; /* address of the device */ |
119 | struct mutex lock; /* dev-level lock */ | 119 | struct mutex lock; /* dev-level lock */ |
120 | struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; | ||
121 | struct ieee80211_low_level_stats ll_stats; | 120 | struct ieee80211_low_level_stats ll_stats; |
122 | struct ieee80211_hw *hw; /* IEEE 802.11 common */ | 121 | struct ieee80211_hw *hw; /* IEEE 802.11 common */ |
123 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; | 122 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0ea340fd071..83c7ea4c007 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -267,6 +267,7 @@ void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
267 | u16 tid, u16 *ssn); | 267 | u16 tid, u16 *ssn); |
268 | void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | 268 | void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); |
269 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | 269 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); |
270 | void ath9k_enable_ps(struct ath_softc *sc); | ||
270 | 271 | ||
271 | /********/ | 272 | /********/ |
272 | /* VIFs */ | 273 | /* VIFs */ |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 422454fe4ff..d088ebfe63a 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -577,6 +577,13 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
577 | u64 tsf; | 577 | u64 tsf; |
578 | int num_beacons, offset, dtim_dec_count, cfp_dec_count; | 578 | int num_beacons, offset, dtim_dec_count, cfp_dec_count; |
579 | 579 | ||
580 | /* No need to configure beacon if we are not associated */ | ||
581 | if (!common->curaid) { | ||
582 | ath_print(common, ATH_DBG_BEACON, | ||
583 | "STA is not yet associated..skipping beacon config\n"); | ||
584 | return; | ||
585 | } | ||
586 | |||
580 | memset(&bs, 0, sizeof(bs)); | 587 | memset(&bs, 0, sizeof(bs)); |
581 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 588 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; |
582 | 589 | ||
@@ -739,7 +746,6 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
739 | enum nl80211_iftype iftype; | 746 | enum nl80211_iftype iftype; |
740 | 747 | ||
741 | /* Setup the beacon configuration parameters */ | 748 | /* Setup the beacon configuration parameters */ |
742 | |||
743 | if (vif) { | 749 | if (vif) { |
744 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 750 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
745 | 751 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f15fee76a4e..f00f5c744f4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -1217,6 +1217,17 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) | |||
1217 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ | 1217 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ |
1218 | slottime = ah->slottime + 3 * ah->coverage_class; | 1218 | slottime = ah->slottime + 3 * ah->coverage_class; |
1219 | acktimeout = slottime + sifstime; | 1219 | acktimeout = slottime + sifstime; |
1220 | |||
1221 | /* | ||
1222 | * Workaround for early ACK timeouts, add an offset to match the | ||
1223 | * initval's 64us ack timeout value. | ||
1224 | * This was initially only meant to work around an issue with delayed | ||
1225 | * BA frames in some implementations, but it has been found to fix ACK | ||
1226 | * timeout issues in other cases as well. | ||
1227 | */ | ||
1228 | if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) | ||
1229 | acktimeout += 64 - sifstime - ah->slottime; | ||
1230 | |||
1220 | ath9k_hw_setslottime(ah, slottime); | 1231 | ath9k_hw_setslottime(ah, slottime); |
1221 | ath9k_hw_set_ack_timeout(ah, acktimeout); | 1232 | ath9k_hw_set_ack_timeout(ah, acktimeout); |
1222 | ath9k_hw_set_cts_timeout(ah, acktimeout); | 1233 | ath9k_hw_set_cts_timeout(ah, acktimeout); |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4b5e5484868..623c2f88498 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -622,7 +622,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
622 | IEEE80211_HW_SIGNAL_DBM | | 622 | IEEE80211_HW_SIGNAL_DBM | |
623 | IEEE80211_HW_SUPPORTS_PS | | 623 | IEEE80211_HW_SUPPORTS_PS | |
624 | IEEE80211_HW_PS_NULLFUNC_STACK | | 624 | IEEE80211_HW_PS_NULLFUNC_STACK | |
625 | IEEE80211_HW_SPECTRUM_MGMT; | 625 | IEEE80211_HW_SPECTRUM_MGMT | |
626 | IEEE80211_HW_REPORTS_TX_ACK_STATUS; | ||
626 | 627 | ||
627 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) | 628 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) |
628 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; | 629 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6796d5cdc29..9c8f925c209 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -809,6 +809,7 @@ static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf | |||
809 | 809 | ||
810 | clear_bit(key->hw_key_idx + 64, common->keymap); | 810 | clear_bit(key->hw_key_idx + 64, common->keymap); |
811 | if (common->splitmic) { | 811 | if (common->splitmic) { |
812 | ath9k_hw_keyreset(ah, key->hw_key_idx + 32); | ||
812 | clear_bit(key->hw_key_idx + 32, common->keymap); | 813 | clear_bit(key->hw_key_idx + 32, common->keymap); |
813 | clear_bit(key->hw_key_idx + 64 + 32, common->keymap); | 814 | clear_bit(key->hw_key_idx + 64 + 32, common->keymap); |
814 | } | 815 | } |
@@ -1492,6 +1493,19 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
1492 | mutex_unlock(&sc->mutex); | 1493 | mutex_unlock(&sc->mutex); |
1493 | } | 1494 | } |
1494 | 1495 | ||
1496 | void ath9k_enable_ps(struct ath_softc *sc) | ||
1497 | { | ||
1498 | sc->ps_enabled = true; | ||
1499 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { | ||
1500 | if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { | ||
1501 | sc->imask |= ATH9K_INT_TIM_TIMER; | ||
1502 | ath9k_hw_set_interrupts(sc->sc_ah, | ||
1503 | sc->imask); | ||
1504 | } | ||
1505 | } | ||
1506 | ath9k_hw_setrxabort(sc->sc_ah, 1); | ||
1507 | } | ||
1508 | |||
1495 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | 1509 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) |
1496 | { | 1510 | { |
1497 | struct ath_wiphy *aphy = hw->priv; | 1511 | struct ath_wiphy *aphy = hw->priv; |
@@ -1546,22 +1560,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
1546 | if (changed & IEEE80211_CONF_CHANGE_PS) { | 1560 | if (changed & IEEE80211_CONF_CHANGE_PS) { |
1547 | if (conf->flags & IEEE80211_CONF_PS) { | 1561 | if (conf->flags & IEEE80211_CONF_PS) { |
1548 | sc->ps_flags |= PS_ENABLED; | 1562 | sc->ps_flags |= PS_ENABLED; |
1549 | if (!(ah->caps.hw_caps & | ||
1550 | ATH9K_HW_CAP_AUTOSLEEP)) { | ||
1551 | if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { | ||
1552 | sc->imask |= ATH9K_INT_TIM_TIMER; | ||
1553 | ath9k_hw_set_interrupts(sc->sc_ah, | ||
1554 | sc->imask); | ||
1555 | } | ||
1556 | } | ||
1557 | /* | 1563 | /* |
1558 | * At this point we know hardware has received an ACK | 1564 | * At this point we know hardware has received an ACK |
1559 | * of a previously sent null data frame. | 1565 | * of a previously sent null data frame. |
1560 | */ | 1566 | */ |
1561 | if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) { | 1567 | if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) { |
1562 | sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; | 1568 | sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; |
1563 | sc->ps_enabled = true; | 1569 | ath9k_enable_ps(sc); |
1564 | ath9k_hw_setrxabort(sc->sc_ah, 1); | ||
1565 | } | 1570 | } |
1566 | } else { | 1571 | } else { |
1567 | sc->ps_enabled = false; | 1572 | sc->ps_enabled = false; |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3c790a4f38f..f5cbbcb9a4a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -2048,10 +2048,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2048 | */ | 2048 | */ |
2049 | if (bf->bf_isnullfunc && | 2049 | if (bf->bf_isnullfunc && |
2050 | (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { | 2050 | (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { |
2051 | if ((sc->ps_flags & PS_ENABLED)) { | 2051 | if ((sc->ps_flags & PS_ENABLED)) |
2052 | sc->ps_enabled = true; | 2052 | ath9k_enable_ps(sc); |
2053 | ath9k_hw_setrxabort(sc->sc_ah, 1); | 2053 | else |
2054 | } else | ||
2055 | sc->ps_flags |= PS_NULLFUNC_COMPLETED; | 2054 | sc->ps_flags |= PS_NULLFUNC_COMPLETED; |
2056 | } | 2055 | } |
2057 | 2056 | ||
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 039ac490465..04abd1f556b 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c | |||
@@ -110,8 +110,9 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { | |||
110 | 110 | ||
111 | static inline bool is_wwr_sku(u16 regd) | 111 | static inline bool is_wwr_sku(u16 regd) |
112 | { | 112 | { |
113 | return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || | 113 | return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && |
114 | (regd == WORLD); | 114 | (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || |
115 | (regd == WORLD)); | ||
115 | } | 116 | } |
116 | 117 | ||
117 | static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) | 118 | static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) |
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 54d6085a887..6a6ab0f630e 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -115,6 +115,7 @@ | |||
115 | #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ | 115 | #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ |
116 | #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ | 116 | #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ |
117 | #define B43_MMIO_RNG 0x65A | 117 | #define B43_MMIO_RNG 0x65A |
118 | #define B43_MMIO_IFSSLOT 0x684 /* Interframe slot time */ | ||
118 | #define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ | 119 | #define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ |
119 | #define B43_MMIO_IFSCTL_USE_EDCF 0x0004 | 120 | #define B43_MMIO_IFSCTL_USE_EDCF 0x0004 |
120 | #define B43_MMIO_POWERUP_DELAY 0x6A8 | 121 | #define B43_MMIO_POWERUP_DELAY 0x6A8 |
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 615af22c49f..be7abf8916a 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -1369,7 +1369,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1369 | b43err(dev->wl, "DMA tx mapping failure\n"); | 1369 | b43err(dev->wl, "DMA tx mapping failure\n"); |
1370 | goto out; | 1370 | goto out; |
1371 | } | 1371 | } |
1372 | ring->nr_tx_packets++; | ||
1373 | if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || | 1372 | if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || |
1374 | should_inject_overflow(ring)) { | 1373 | should_inject_overflow(ring)) { |
1375 | /* This TX ring is full. */ | 1374 | /* This TX ring is full. */ |
@@ -1500,22 +1499,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1500 | } | 1499 | } |
1501 | } | 1500 | } |
1502 | 1501 | ||
1503 | void b43_dma_get_tx_stats(struct b43_wldev *dev, | ||
1504 | struct ieee80211_tx_queue_stats *stats) | ||
1505 | { | ||
1506 | const int nr_queues = dev->wl->hw->queues; | ||
1507 | struct b43_dmaring *ring; | ||
1508 | int i; | ||
1509 | |||
1510 | for (i = 0; i < nr_queues; i++) { | ||
1511 | ring = select_ring_by_priority(dev, i); | ||
1512 | |||
1513 | stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; | ||
1514 | stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; | ||
1515 | stats[i].count = ring->nr_tx_packets; | ||
1516 | } | ||
1517 | } | ||
1518 | |||
1519 | static void dma_rx(struct b43_dmaring *ring, int *slot) | 1502 | static void dma_rx(struct b43_dmaring *ring, int *slot) |
1520 | { | 1503 | { |
1521 | const struct b43_dma_ops *ops = ring->ops; | 1504 | const struct b43_dma_ops *ops = ring->ops; |
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index f7ab37c4cdb..dc91944d602 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h | |||
@@ -228,8 +228,6 @@ struct b43_dmaring { | |||
228 | int used_slots; | 228 | int used_slots; |
229 | /* Currently used slot in the ring. */ | 229 | /* Currently used slot in the ring. */ |
230 | int current_slot; | 230 | int current_slot; |
231 | /* Total number of packets sent. Statistics only. */ | ||
232 | unsigned int nr_tx_packets; | ||
233 | /* Frameoffset in octets. */ | 231 | /* Frameoffset in octets. */ |
234 | u32 frameoffset; | 232 | u32 frameoffset; |
235 | /* Descriptor buffer size. */ | 233 | /* Descriptor buffer size. */ |
@@ -278,9 +276,6 @@ void b43_dma_free(struct b43_wldev *dev); | |||
278 | void b43_dma_tx_suspend(struct b43_wldev *dev); | 276 | void b43_dma_tx_suspend(struct b43_wldev *dev); |
279 | void b43_dma_tx_resume(struct b43_wldev *dev); | 277 | void b43_dma_tx_resume(struct b43_wldev *dev); |
280 | 278 | ||
281 | void b43_dma_get_tx_stats(struct b43_wldev *dev, | ||
282 | struct ieee80211_tx_queue_stats *stats); | ||
283 | |||
284 | int b43_dma_tx(struct b43_wldev *dev, | 279 | int b43_dma_tx(struct b43_wldev *dev, |
285 | struct sk_buff *skb); | 280 | struct sk_buff *skb); |
286 | void b43_dma_handle_txstatus(struct b43_wldev *dev, | 281 | void b43_dma_handle_txstatus(struct b43_wldev *dev, |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 316a913860d..aa33d741e5e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -637,10 +637,17 @@ static void b43_upload_card_macaddress(struct b43_wldev *dev) | |||
637 | static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) | 637 | static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) |
638 | { | 638 | { |
639 | /* slot_time is in usec. */ | 639 | /* slot_time is in usec. */ |
640 | if (dev->phy.type != B43_PHYTYPE_G) | 640 | /* This test used to exit for all but a G PHY. */ |
641 | if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) | ||
641 | return; | 642 | return; |
642 | b43_write16(dev, 0x684, 510 + slot_time); | 643 | b43_write16(dev, B43_MMIO_IFSSLOT, 510 + slot_time); |
643 | b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time); | 644 | /* Shared memory location 0x0010 is the slot time and should be |
645 | * set to slot_time; however, this register is initially 0 and changing | ||
646 | * the value adversely affects the transmit rate for BCM4311 | ||
647 | * devices. Until this behavior is unterstood, delete this step | ||
648 | * | ||
649 | * b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time); | ||
650 | */ | ||
644 | } | 651 | } |
645 | 652 | ||
646 | static void b43_short_slot_timing_enable(struct b43_wldev *dev) | 653 | static void b43_short_slot_timing_enable(struct b43_wldev *dev) |
@@ -3349,27 +3356,6 @@ out_unlock: | |||
3349 | return err; | 3356 | return err; |
3350 | } | 3357 | } |
3351 | 3358 | ||
3352 | static int b43_op_get_tx_stats(struct ieee80211_hw *hw, | ||
3353 | struct ieee80211_tx_queue_stats *stats) | ||
3354 | { | ||
3355 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
3356 | struct b43_wldev *dev; | ||
3357 | int err = -ENODEV; | ||
3358 | |||
3359 | mutex_lock(&wl->mutex); | ||
3360 | dev = wl->current_dev; | ||
3361 | if (dev && b43_status(dev) >= B43_STAT_STARTED) { | ||
3362 | if (b43_using_pio_transfers(dev)) | ||
3363 | b43_pio_get_tx_stats(dev, stats); | ||
3364 | else | ||
3365 | b43_dma_get_tx_stats(dev, stats); | ||
3366 | err = 0; | ||
3367 | } | ||
3368 | mutex_unlock(&wl->mutex); | ||
3369 | |||
3370 | return err; | ||
3371 | } | ||
3372 | |||
3373 | static int b43_op_get_stats(struct ieee80211_hw *hw, | 3359 | static int b43_op_get_stats(struct ieee80211_hw *hw, |
3374 | struct ieee80211_low_level_stats *stats) | 3360 | struct ieee80211_low_level_stats *stats) |
3375 | { | 3361 | { |
@@ -3980,6 +3966,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev) | |||
3980 | } | 3966 | } |
3981 | 3967 | ||
3982 | /* We are ready to run. */ | 3968 | /* We are ready to run. */ |
3969 | ieee80211_wake_queues(dev->wl->hw); | ||
3983 | b43_set_status(dev, B43_STAT_STARTED); | 3970 | b43_set_status(dev, B43_STAT_STARTED); |
3984 | 3971 | ||
3985 | /* Start data flow (TX/RX). */ | 3972 | /* Start data flow (TX/RX). */ |
@@ -4389,8 +4376,6 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | |||
4389 | 4376 | ||
4390 | ieee80211_wake_queues(dev->wl->hw); | 4377 | ieee80211_wake_queues(dev->wl->hw); |
4391 | 4378 | ||
4392 | ieee80211_wake_queues(dev->wl->hw); | ||
4393 | |||
4394 | b43_set_status(dev, B43_STAT_INITIALIZED); | 4379 | b43_set_status(dev, B43_STAT_INITIALIZED); |
4395 | 4380 | ||
4396 | out: | 4381 | out: |
@@ -4596,7 +4581,6 @@ static const struct ieee80211_ops b43_hw_ops = { | |||
4596 | .set_key = b43_op_set_key, | 4581 | .set_key = b43_op_set_key, |
4597 | .update_tkip_key = b43_op_update_tkip_key, | 4582 | .update_tkip_key = b43_op_update_tkip_key, |
4598 | .get_stats = b43_op_get_stats, | 4583 | .get_stats = b43_op_get_stats, |
4599 | .get_tx_stats = b43_op_get_tx_stats, | ||
4600 | .get_tsf = b43_op_get_tsf, | 4584 | .get_tsf = b43_op_get_tsf, |
4601 | .set_tsf = b43_op_set_tsf, | 4585 | .set_tsf = b43_op_set_tsf, |
4602 | .start = b43_op_start, | 4586 | .start = b43_op_start, |
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 6392da25efe..795bb1e3345 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c | |||
@@ -68,6 +68,10 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, | |||
68 | u8 *events, u8 *delays, u8 length); | 68 | u8 *events, u8 *delays, u8 length); |
69 | static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, | 69 | static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, |
70 | enum b43_nphy_rf_sequence seq); | 70 | enum b43_nphy_rf_sequence seq); |
71 | static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, | ||
72 | u16 value, u8 core, bool off); | ||
73 | static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, | ||
74 | u16 value, u8 core); | ||
71 | 75 | ||
72 | void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) | 76 | void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) |
73 | {//TODO | 77 | {//TODO |
@@ -498,8 +502,8 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) | |||
498 | b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007); | 502 | b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007); |
499 | } | 503 | } |
500 | 504 | ||
501 | /* TODO: Call N PHY RF Ctrl Intc Override with 2, 0, 3 as arguments */ | 505 | b43_nphy_rf_control_intc_override(dev, 2, 0, 3); |
502 | /* TODO: Call N PHY RF Intc Override with 8, 0, 3, 0 as arguments */ | 506 | b43_nphy_rf_control_override(dev, 8, 0, 3, false); |
503 | b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); | 507 | b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); |
504 | 508 | ||
505 | if (core == 0) { | 509 | if (core == 0) { |
@@ -509,9 +513,8 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) | |||
509 | rxval = 4; | 513 | rxval = 4; |
510 | txval = 2; | 514 | txval = 2; |
511 | } | 515 | } |
512 | 516 | b43_nphy_rf_control_intc_override(dev, 1, rxval, (core + 1)); | |
513 | /* TODO: Call N PHY RF Ctrl Intc Override with 1, rxval, (core + 1) */ | 517 | b43_nphy_rf_control_intc_override(dev, 1, txval, (2 - core)); |
514 | /* TODO: Call N PHY RF Ctrl Intc Override with 1, txval, (2 - core) */ | ||
515 | } | 518 | } |
516 | 519 | ||
517 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ | 520 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ |
@@ -714,6 +717,67 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) | |||
714 | b43_nphy_stay_in_carrier_search(dev, 0); | 717 | b43_nphy_stay_in_carrier_search(dev, 0); |
715 | } | 718 | } |
716 | 719 | ||
720 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */ | ||
721 | static void b43_nphy_spur_workaround(struct b43_wldev *dev) | ||
722 | { | ||
723 | struct b43_phy_n *nphy = dev->phy.n; | ||
724 | |||
725 | unsigned int channel; | ||
726 | int tone[2] = { 57, 58 }; | ||
727 | u32 noise[2] = { 0x3FF, 0x3FF }; | ||
728 | |||
729 | B43_WARN_ON(dev->phy.rev < 3); | ||
730 | |||
731 | if (nphy->hang_avoid) | ||
732 | b43_nphy_stay_in_carrier_search(dev, 1); | ||
733 | |||
734 | /* FIXME: channel = radio_chanspec */ | ||
735 | |||
736 | if (nphy->gband_spurwar_en) { | ||
737 | /* TODO: N PHY Adjust Analog Pfbw (7) */ | ||
738 | if (channel == 11 && dev->phy.is_40mhz) | ||
739 | ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/ | ||
740 | else | ||
741 | ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ | ||
742 | /* TODO: N PHY Adjust CRS Min Power (0x1E) */ | ||
743 | } | ||
744 | |||
745 | if (nphy->aband_spurwar_en) { | ||
746 | if (channel == 54) { | ||
747 | tone[0] = 0x20; | ||
748 | noise[0] = 0x25F; | ||
749 | } else if (channel == 38 || channel == 102 || channel == 118) { | ||
750 | if (0 /* FIXME */) { | ||
751 | tone[0] = 0x20; | ||
752 | noise[0] = 0x21F; | ||
753 | } else { | ||
754 | tone[0] = 0; | ||
755 | noise[0] = 0; | ||
756 | } | ||
757 | } else if (channel == 134) { | ||
758 | tone[0] = 0x20; | ||
759 | noise[0] = 0x21F; | ||
760 | } else if (channel == 151) { | ||
761 | tone[0] = 0x10; | ||
762 | noise[0] = 0x23F; | ||
763 | } else if (channel == 153 || channel == 161) { | ||
764 | tone[0] = 0x30; | ||
765 | noise[0] = 0x23F; | ||
766 | } else { | ||
767 | tone[0] = 0; | ||
768 | noise[0] = 0; | ||
769 | } | ||
770 | |||
771 | if (!tone[0] && !noise[0]) | ||
772 | ; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/ | ||
773 | else | ||
774 | ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ | ||
775 | } | ||
776 | |||
777 | if (nphy->hang_avoid) | ||
778 | b43_nphy_stay_in_carrier_search(dev, 0); | ||
779 | } | ||
780 | |||
717 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ | 781 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ |
718 | static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev) | 782 | static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev) |
719 | { | 783 | { |
@@ -953,6 +1017,33 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) | |||
953 | b43_nphy_stay_in_carrier_search(dev, 0); | 1017 | b43_nphy_stay_in_carrier_search(dev, 0); |
954 | } | 1018 | } |
955 | 1019 | ||
1020 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */ | ||
1021 | static int b43_nphy_load_samples(struct b43_wldev *dev, | ||
1022 | struct b43_c32 *samples, u16 len) { | ||
1023 | struct b43_phy_n *nphy = dev->phy.n; | ||
1024 | u16 i; | ||
1025 | u32 *data; | ||
1026 | |||
1027 | data = kzalloc(len * sizeof(u32), GFP_KERNEL); | ||
1028 | if (!data) { | ||
1029 | b43err(dev->wl, "allocation for samples loading failed\n"); | ||
1030 | return -ENOMEM; | ||
1031 | } | ||
1032 | if (nphy->hang_avoid) | ||
1033 | b43_nphy_stay_in_carrier_search(dev, 1); | ||
1034 | |||
1035 | for (i = 0; i < len; i++) { | ||
1036 | data[i] = (samples[i].i & 0x3FF << 10); | ||
1037 | data[i] |= samples[i].q & 0x3FF; | ||
1038 | } | ||
1039 | b43_ntab_write_bulk(dev, B43_NTAB32(17, 0), len, data); | ||
1040 | |||
1041 | kfree(data); | ||
1042 | if (nphy->hang_avoid) | ||
1043 | b43_nphy_stay_in_carrier_search(dev, 0); | ||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
956 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ | 1047 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ |
957 | static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, | 1048 | static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, |
958 | bool test) | 1049 | bool test) |
@@ -978,6 +1069,10 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, | |||
978 | } | 1069 | } |
979 | 1070 | ||
980 | samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL); | 1071 | samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL); |
1072 | if (!samples) { | ||
1073 | b43err(dev->wl, "allocation for samples generation failed\n"); | ||
1074 | return 0; | ||
1075 | } | ||
981 | rot = (((freq * 36) / bw) << 16) / 100; | 1076 | rot = (((freq * 36) / bw) << 16) / 100; |
982 | angle = 0; | 1077 | angle = 0; |
983 | 1078 | ||
@@ -988,9 +1083,9 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, | |||
988 | samples[i].i = CORDIC_CONVERT(samples[i].i * max); | 1083 | samples[i].i = CORDIC_CONVERT(samples[i].i * max); |
989 | } | 1084 | } |
990 | 1085 | ||
991 | /* TODO: Call N PHY Load Sample Table with buffer, len as arguments */ | 1086 | i = b43_nphy_load_samples(dev, samples, len); |
992 | kfree(samples); | 1087 | kfree(samples); |
993 | return len; | 1088 | return (i < 0) ? 0 : len; |
994 | } | 1089 | } |
995 | 1090 | ||
996 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ | 1091 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ |
@@ -1264,6 +1359,104 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, | |||
1264 | } | 1359 | } |
1265 | } | 1360 | } |
1266 | 1361 | ||
1362 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */ | ||
1363 | static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, | ||
1364 | u16 value, u8 core) | ||
1365 | { | ||
1366 | u8 i, j; | ||
1367 | u16 reg, tmp, val; | ||
1368 | |||
1369 | B43_WARN_ON(dev->phy.rev < 3); | ||
1370 | B43_WARN_ON(field > 4); | ||
1371 | |||
1372 | for (i = 0; i < 2; i++) { | ||
1373 | if ((core == 1 && i == 1) || (core == 2 && !i)) | ||
1374 | continue; | ||
1375 | |||
1376 | reg = (i == 0) ? | ||
1377 | B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2; | ||
1378 | b43_phy_mask(dev, reg, 0xFBFF); | ||
1379 | |||
1380 | switch (field) { | ||
1381 | case 0: | ||
1382 | b43_phy_write(dev, reg, 0); | ||
1383 | b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); | ||
1384 | break; | ||
1385 | case 1: | ||
1386 | if (!i) { | ||
1387 | b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC1, | ||
1388 | 0xFC3F, (value << 6)); | ||
1389 | b43_phy_maskset(dev, B43_NPHY_TXF_40CO_B1S1, | ||
1390 | 0xFFFE, 1); | ||
1391 | b43_phy_set(dev, B43_NPHY_RFCTL_CMD, | ||
1392 | B43_NPHY_RFCTL_CMD_START); | ||
1393 | for (j = 0; j < 100; j++) { | ||
1394 | if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_START) { | ||
1395 | j = 0; | ||
1396 | break; | ||
1397 | } | ||
1398 | udelay(10); | ||
1399 | } | ||
1400 | if (j) | ||
1401 | b43err(dev->wl, | ||
1402 | "intc override timeout\n"); | ||
1403 | b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1, | ||
1404 | 0xFFFE); | ||
1405 | } else { | ||
1406 | b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC2, | ||
1407 | 0xFC3F, (value << 6)); | ||
1408 | b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, | ||
1409 | 0xFFFE, 1); | ||
1410 | b43_phy_set(dev, B43_NPHY_RFCTL_CMD, | ||
1411 | B43_NPHY_RFCTL_CMD_RXTX); | ||
1412 | for (j = 0; j < 100; j++) { | ||
1413 | if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_RXTX) { | ||
1414 | j = 0; | ||
1415 | break; | ||
1416 | } | ||
1417 | udelay(10); | ||
1418 | } | ||
1419 | if (j) | ||
1420 | b43err(dev->wl, | ||
1421 | "intc override timeout\n"); | ||
1422 | b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, | ||
1423 | 0xFFFE); | ||
1424 | } | ||
1425 | break; | ||
1426 | case 2: | ||
1427 | if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { | ||
1428 | tmp = 0x0020; | ||
1429 | val = value << 5; | ||
1430 | } else { | ||
1431 | tmp = 0x0010; | ||
1432 | val = value << 4; | ||
1433 | } | ||
1434 | b43_phy_maskset(dev, reg, ~tmp, val); | ||
1435 | break; | ||
1436 | case 3: | ||
1437 | if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { | ||
1438 | tmp = 0x0001; | ||
1439 | val = value; | ||
1440 | } else { | ||
1441 | tmp = 0x0004; | ||
1442 | val = value << 2; | ||
1443 | } | ||
1444 | b43_phy_maskset(dev, reg, ~tmp, val); | ||
1445 | break; | ||
1446 | case 4: | ||
1447 | if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { | ||
1448 | tmp = 0x0002; | ||
1449 | val = value << 1; | ||
1450 | } else { | ||
1451 | tmp = 0x0008; | ||
1452 | val = value << 3; | ||
1453 | } | ||
1454 | b43_phy_maskset(dev, reg, ~tmp, val); | ||
1455 | break; | ||
1456 | } | ||
1457 | } | ||
1458 | } | ||
1459 | |||
1267 | static void b43_nphy_bphy_init(struct b43_wldev *dev) | 1460 | static void b43_nphy_bphy_init(struct b43_wldev *dev) |
1268 | { | 1461 | { |
1269 | unsigned int i; | 1462 | unsigned int i; |
@@ -2161,9 +2354,9 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) | |||
2161 | regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); | 2354 | regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); |
2162 | regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); | 2355 | regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); |
2163 | 2356 | ||
2164 | /* TODO: Call N PHY RF Ctrl Intc Override with 2, 1, 3 */ | 2357 | b43_nphy_rf_control_intc_override(dev, 2, 1, 3); |
2165 | /* TODO: Call N PHY RF Ctrl Intc Override with 1, 2, 1 */ | 2358 | b43_nphy_rf_control_intc_override(dev, 1, 2, 1); |
2166 | /* TODO: Call N PHY RF Ctrl Intc Override with 1, 8, 2 */ | 2359 | b43_nphy_rf_control_intc_override(dev, 1, 8, 2); |
2167 | 2360 | ||
2168 | regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0); | 2361 | regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0); |
2169 | regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1); | 2362 | regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1); |
@@ -2194,6 +2387,55 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) | |||
2194 | } | 2387 | } |
2195 | } | 2388 | } |
2196 | 2389 | ||
2390 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */ | ||
2391 | static void b43_nphy_save_cal(struct b43_wldev *dev) | ||
2392 | { | ||
2393 | struct b43_phy_n *nphy = dev->phy.n; | ||
2394 | |||
2395 | struct b43_phy_n_iq_comp *rxcal_coeffs = NULL; | ||
2396 | u16 *txcal_radio_regs = NULL; | ||
2397 | u8 *iqcal_chanspec; | ||
2398 | u16 *table = NULL; | ||
2399 | |||
2400 | if (nphy->hang_avoid) | ||
2401 | b43_nphy_stay_in_carrier_search(dev, 1); | ||
2402 | |||
2403 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
2404 | rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G; | ||
2405 | txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G; | ||
2406 | iqcal_chanspec = &nphy->iqcal_chanspec_2G; | ||
2407 | table = nphy->cal_cache.txcal_coeffs_2G; | ||
2408 | } else { | ||
2409 | rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G; | ||
2410 | txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G; | ||
2411 | iqcal_chanspec = &nphy->iqcal_chanspec_5G; | ||
2412 | table = nphy->cal_cache.txcal_coeffs_5G; | ||
2413 | } | ||
2414 | |||
2415 | b43_nphy_rx_iq_coeffs(dev, false, rxcal_coeffs); | ||
2416 | /* TODO use some definitions */ | ||
2417 | if (dev->phy.rev >= 3) { | ||
2418 | txcal_radio_regs[0] = b43_radio_read(dev, 0x2021); | ||
2419 | txcal_radio_regs[1] = b43_radio_read(dev, 0x2022); | ||
2420 | txcal_radio_regs[2] = b43_radio_read(dev, 0x3021); | ||
2421 | txcal_radio_regs[3] = b43_radio_read(dev, 0x3022); | ||
2422 | txcal_radio_regs[4] = b43_radio_read(dev, 0x2023); | ||
2423 | txcal_radio_regs[5] = b43_radio_read(dev, 0x2024); | ||
2424 | txcal_radio_regs[6] = b43_radio_read(dev, 0x3023); | ||
2425 | txcal_radio_regs[7] = b43_radio_read(dev, 0x3024); | ||
2426 | } else { | ||
2427 | txcal_radio_regs[0] = b43_radio_read(dev, 0x8B); | ||
2428 | txcal_radio_regs[1] = b43_radio_read(dev, 0xBA); | ||
2429 | txcal_radio_regs[2] = b43_radio_read(dev, 0x8D); | ||
2430 | txcal_radio_regs[3] = b43_radio_read(dev, 0xBC); | ||
2431 | } | ||
2432 | *iqcal_chanspec = nphy->radio_chanspec; | ||
2433 | b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 8, table); | ||
2434 | |||
2435 | if (nphy->hang_avoid) | ||
2436 | b43_nphy_stay_in_carrier_search(dev, 0); | ||
2437 | } | ||
2438 | |||
2197 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ | 2439 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ |
2198 | static void b43_nphy_restore_cal(struct b43_wldev *dev) | 2440 | static void b43_nphy_restore_cal(struct b43_wldev *dev) |
2199 | { | 2441 | { |
@@ -2486,6 +2728,39 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, | |||
2486 | return error; | 2728 | return error; |
2487 | } | 2729 | } |
2488 | 2730 | ||
2731 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */ | ||
2732 | static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) | ||
2733 | { | ||
2734 | struct b43_phy_n *nphy = dev->phy.n; | ||
2735 | u8 i; | ||
2736 | u16 buffer[7]; | ||
2737 | bool equal = true; | ||
2738 | |||
2739 | if (!nphy->txiqlocal_coeffsvalid || 1 /* FIXME */) | ||
2740 | return; | ||
2741 | |||
2742 | b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer); | ||
2743 | for (i = 0; i < 4; i++) { | ||
2744 | if (buffer[i] != nphy->txiqlocal_bestc[i]) { | ||
2745 | equal = false; | ||
2746 | break; | ||
2747 | } | ||
2748 | } | ||
2749 | |||
2750 | if (!equal) { | ||
2751 | b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4, | ||
2752 | nphy->txiqlocal_bestc); | ||
2753 | for (i = 0; i < 4; i++) | ||
2754 | buffer[i] = 0; | ||
2755 | b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, | ||
2756 | buffer); | ||
2757 | b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, | ||
2758 | &nphy->txiqlocal_bestc[5]); | ||
2759 | b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, | ||
2760 | &nphy->txiqlocal_bestc[5]); | ||
2761 | } | ||
2762 | } | ||
2763 | |||
2489 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ | 2764 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ |
2490 | static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, | 2765 | static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, |
2491 | struct nphy_txgains target, u8 type, bool debug) | 2766 | struct nphy_txgains target, u8 type, bool debug) |
@@ -2516,7 +2791,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, | |||
2516 | b43_nphy_stay_in_carrier_search(dev, 1); | 2791 | b43_nphy_stay_in_carrier_search(dev, 1); |
2517 | 2792 | ||
2518 | if (dev->phy.rev < 2) | 2793 | if (dev->phy.rev < 2) |
2519 | ;/* TODO: Call N PHY Reapply TX Cal Coeffs */ | 2794 | b43_nphy_reapply_tx_cal_coeffs(dev); |
2520 | b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save); | 2795 | b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save); |
2521 | for (i = 0; i < 2; i++) { | 2796 | for (i = 0; i < 2; i++) { |
2522 | b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]); | 2797 | b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]); |
@@ -2858,7 +3133,7 @@ int b43_phy_initn(struct b43_wldev *dev) | |||
2858 | 3133 | ||
2859 | if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) { | 3134 | if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) { |
2860 | if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0) | 3135 | if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0) |
2861 | ;/* Call N PHY Save Cal */ | 3136 | b43_nphy_save_cal(dev); |
2862 | else if (nphy->mphase_cal_phase_id == 0) | 3137 | else if (nphy->mphase_cal_phase_id == 0) |
2863 | ;/* N PHY Periodic Calibration with argument 3 */ | 3138 | ;/* N PHY Periodic Calibration with argument 3 */ |
2864 | } else { | 3139 | } else { |
@@ -2872,7 +3147,8 @@ int b43_phy_initn(struct b43_wldev *dev) | |||
2872 | if (phy->rev >= 3 && phy->rev <= 6) | 3147 | if (phy->rev >= 3 && phy->rev <= 6) |
2873 | b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014); | 3148 | b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014); |
2874 | b43_nphy_tx_lp_fbw(dev); | 3149 | b43_nphy_tx_lp_fbw(dev); |
2875 | /* TODO N PHY Spur Workaround */ | 3150 | if (phy->rev >= 3) |
3151 | b43_nphy_spur_workaround(dev); | ||
2876 | 3152 | ||
2877 | b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); | 3153 | b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); |
2878 | return 0; | 3154 | return 0; |
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index ae82f0fc209..403aad3f894 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h | |||
@@ -975,6 +975,7 @@ struct b43_phy_n { | |||
975 | u16 papd_epsilon_offset[2]; | 975 | u16 papd_epsilon_offset[2]; |
976 | s32 preamble_override; | 976 | s32 preamble_override; |
977 | u32 bb_mult_save; | 977 | u32 bb_mult_save; |
978 | u16 radio_chanspec; | ||
978 | 979 | ||
979 | bool gain_boost; | 980 | bool gain_boost; |
980 | bool elna_gain_config; | 981 | bool elna_gain_config; |
@@ -1001,6 +1002,9 @@ struct b43_phy_n { | |||
1001 | u16 classifier_state; | 1002 | u16 classifier_state; |
1002 | u16 clip_state[2]; | 1003 | u16 clip_state[2]; |
1003 | 1004 | ||
1005 | bool aband_spurwar_en; | ||
1006 | bool gband_spurwar_en; | ||
1007 | |||
1004 | bool ipa2g_on; | 1008 | bool ipa2g_on; |
1005 | u8 iqcal_chanspec_2G; | 1009 | u8 iqcal_chanspec_2G; |
1006 | u8 rssical_chanspec_2G; | 1010 | u8 rssical_chanspec_2G; |
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index c01b8e02412..a6062c3e89a 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c | |||
@@ -559,7 +559,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
559 | b43err(dev->wl, "PIO transmission failure\n"); | 559 | b43err(dev->wl, "PIO transmission failure\n"); |
560 | goto out; | 560 | goto out; |
561 | } | 561 | } |
562 | q->nr_tx_packets++; | ||
563 | 562 | ||
564 | B43_WARN_ON(q->buffer_used > q->buffer_size); | 563 | B43_WARN_ON(q->buffer_used > q->buffer_size); |
565 | if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || | 564 | if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || |
@@ -605,22 +604,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, | |||
605 | } | 604 | } |
606 | } | 605 | } |
607 | 606 | ||
608 | void b43_pio_get_tx_stats(struct b43_wldev *dev, | ||
609 | struct ieee80211_tx_queue_stats *stats) | ||
610 | { | ||
611 | const int nr_queues = dev->wl->hw->queues; | ||
612 | struct b43_pio_txqueue *q; | ||
613 | int i; | ||
614 | |||
615 | for (i = 0; i < nr_queues; i++) { | ||
616 | q = select_queue_by_priority(dev, i); | ||
617 | |||
618 | stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; | ||
619 | stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; | ||
620 | stats[i].count = q->nr_tx_packets; | ||
621 | } | ||
622 | } | ||
623 | |||
624 | /* Returns whether we should fetch another frame. */ | 607 | /* Returns whether we should fetch another frame. */ |
625 | static bool pio_rx_frame(struct b43_pio_rxqueue *q) | 608 | static bool pio_rx_frame(struct b43_pio_rxqueue *q) |
626 | { | 609 | { |
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 7b3c42f93a1..1e516147424 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h | |||
@@ -90,9 +90,6 @@ struct b43_pio_txqueue { | |||
90 | struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS]; | 90 | struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS]; |
91 | struct list_head packets_list; | 91 | struct list_head packets_list; |
92 | 92 | ||
93 | /* Total number of transmitted packets. */ | ||
94 | unsigned int nr_tx_packets; | ||
95 | |||
96 | /* Shortcut to the 802.11 core revision. This is to | 93 | /* Shortcut to the 802.11 core revision. This is to |
97 | * avoid horrible pointer dereferencing in the fastpaths. */ | 94 | * avoid horrible pointer dereferencing in the fastpaths. */ |
98 | u8 rev; | 95 | u8 rev; |
@@ -160,8 +157,6 @@ void b43_pio_free(struct b43_wldev *dev); | |||
160 | int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); | 157 | int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); |
161 | void b43_pio_handle_txstatus(struct b43_wldev *dev, | 158 | void b43_pio_handle_txstatus(struct b43_wldev *dev, |
162 | const struct b43_txstatus *status); | 159 | const struct b43_txstatus *status); |
163 | void b43_pio_get_tx_stats(struct b43_wldev *dev, | ||
164 | struct ieee80211_tx_queue_stats *stats); | ||
165 | void b43_pio_rx(struct b43_pio_rxqueue *q); | 160 | void b43_pio_rx(struct b43_pio_rxqueue *q); |
166 | 161 | ||
167 | void b43_pio_tx_suspend(struct b43_wldev *dev); | 162 | void b43_pio_tx_suspend(struct b43_wldev *dev); |
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 0a86bdf5315..8b9387c6ff3 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c | |||
@@ -1411,7 +1411,6 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, | |||
1411 | b43legacyerr(dev->wl, "DMA tx mapping failure\n"); | 1411 | b43legacyerr(dev->wl, "DMA tx mapping failure\n"); |
1412 | goto out_unlock; | 1412 | goto out_unlock; |
1413 | } | 1413 | } |
1414 | ring->nr_tx_packets++; | ||
1415 | if ((free_slots(ring) < SLOTS_PER_PACKET) || | 1414 | if ((free_slots(ring) < SLOTS_PER_PACKET) || |
1416 | should_inject_overflow(ring)) { | 1415 | should_inject_overflow(ring)) { |
1417 | /* This TX ring is full. */ | 1416 | /* This TX ring is full. */ |
@@ -1527,25 +1526,6 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, | |||
1527 | spin_unlock(&ring->lock); | 1526 | spin_unlock(&ring->lock); |
1528 | } | 1527 | } |
1529 | 1528 | ||
1530 | void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, | ||
1531 | struct ieee80211_tx_queue_stats *stats) | ||
1532 | { | ||
1533 | const int nr_queues = dev->wl->hw->queues; | ||
1534 | struct b43legacy_dmaring *ring; | ||
1535 | unsigned long flags; | ||
1536 | int i; | ||
1537 | |||
1538 | for (i = 0; i < nr_queues; i++) { | ||
1539 | ring = priority_to_txring(dev, i); | ||
1540 | |||
1541 | spin_lock_irqsave(&ring->lock, flags); | ||
1542 | stats[i].len = ring->used_slots / SLOTS_PER_PACKET; | ||
1543 | stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; | ||
1544 | stats[i].count = ring->nr_tx_packets; | ||
1545 | spin_unlock_irqrestore(&ring->lock, flags); | ||
1546 | } | ||
1547 | } | ||
1548 | |||
1549 | static void dma_rx(struct b43legacy_dmaring *ring, | 1529 | static void dma_rx(struct b43legacy_dmaring *ring, |
1550 | int *slot) | 1530 | int *slot) |
1551 | { | 1531 | { |
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 2f186003c31..f9681041c2d 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h | |||
@@ -243,8 +243,6 @@ struct b43legacy_dmaring { | |||
243 | int used_slots; | 243 | int used_slots; |
244 | /* Currently used slot in the ring. */ | 244 | /* Currently used slot in the ring. */ |
245 | int current_slot; | 245 | int current_slot; |
246 | /* Total number of packets sent. Statistics only. */ | ||
247 | unsigned int nr_tx_packets; | ||
248 | /* Frameoffset in octets. */ | 246 | /* Frameoffset in octets. */ |
249 | u32 frameoffset; | 247 | u32 frameoffset; |
250 | /* Descriptor buffer size. */ | 248 | /* Descriptor buffer size. */ |
@@ -292,9 +290,6 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev); | |||
292 | void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev); | 290 | void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev); |
293 | void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev); | 291 | void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev); |
294 | 292 | ||
295 | void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, | ||
296 | struct ieee80211_tx_queue_stats *stats); | ||
297 | |||
298 | int b43legacy_dma_tx(struct b43legacy_wldev *dev, | 293 | int b43legacy_dma_tx(struct b43legacy_wldev *dev, |
299 | struct sk_buff *skb); | 294 | struct sk_buff *skb); |
300 | void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, | 295 | void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, |
@@ -315,11 +310,6 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev) | |||
315 | { | 310 | { |
316 | } | 311 | } |
317 | static inline | 312 | static inline |
318 | void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, | ||
319 | struct ieee80211_tx_queue_stats *stats) | ||
320 | { | ||
321 | } | ||
322 | static inline | ||
323 | int b43legacy_dma_tx(struct b43legacy_wldev *dev, | 313 | int b43legacy_dma_tx(struct b43legacy_wldev *dev, |
324 | struct sk_buff *skb) | 314 | struct sk_buff *skb) |
325 | { | 315 | { |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 874a64a6c61..1d070be5a67 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -2446,29 +2446,6 @@ static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
2446 | return 0; | 2446 | return 0; |
2447 | } | 2447 | } |
2448 | 2448 | ||
2449 | static int b43legacy_op_get_tx_stats(struct ieee80211_hw *hw, | ||
2450 | struct ieee80211_tx_queue_stats *stats) | ||
2451 | { | ||
2452 | struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); | ||
2453 | struct b43legacy_wldev *dev = wl->current_dev; | ||
2454 | unsigned long flags; | ||
2455 | int err = -ENODEV; | ||
2456 | |||
2457 | if (!dev) | ||
2458 | goto out; | ||
2459 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
2460 | if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) { | ||
2461 | if (b43legacy_using_pio(dev)) | ||
2462 | b43legacy_pio_get_tx_stats(dev, stats); | ||
2463 | else | ||
2464 | b43legacy_dma_get_tx_stats(dev, stats); | ||
2465 | err = 0; | ||
2466 | } | ||
2467 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2468 | out: | ||
2469 | return err; | ||
2470 | } | ||
2471 | |||
2472 | static int b43legacy_op_get_stats(struct ieee80211_hw *hw, | 2449 | static int b43legacy_op_get_stats(struct ieee80211_hw *hw, |
2473 | struct ieee80211_low_level_stats *stats) | 2450 | struct ieee80211_low_level_stats *stats) |
2474 | { | 2451 | { |
@@ -2923,6 +2900,7 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) | |||
2923 | goto out; | 2900 | goto out; |
2924 | } | 2901 | } |
2925 | /* We are ready to run. */ | 2902 | /* We are ready to run. */ |
2903 | ieee80211_wake_queues(dev->wl->hw); | ||
2926 | b43legacy_set_status(dev, B43legacy_STAT_STARTED); | 2904 | b43legacy_set_status(dev, B43legacy_STAT_STARTED); |
2927 | 2905 | ||
2928 | /* Start data flow (TX/RX) */ | 2906 | /* Start data flow (TX/RX) */ |
@@ -3343,6 +3321,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) | |||
3343 | b43legacy_security_init(dev); | 3321 | b43legacy_security_init(dev); |
3344 | b43legacy_rng_init(wl); | 3322 | b43legacy_rng_init(wl); |
3345 | 3323 | ||
3324 | ieee80211_wake_queues(dev->wl->hw); | ||
3346 | b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); | 3325 | b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); |
3347 | 3326 | ||
3348 | b43legacy_leds_init(dev); | 3327 | b43legacy_leds_init(dev); |
@@ -3511,7 +3490,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = { | |||
3511 | .bss_info_changed = b43legacy_op_bss_info_changed, | 3490 | .bss_info_changed = b43legacy_op_bss_info_changed, |
3512 | .configure_filter = b43legacy_op_configure_filter, | 3491 | .configure_filter = b43legacy_op_configure_filter, |
3513 | .get_stats = b43legacy_op_get_stats, | 3492 | .get_stats = b43legacy_op_get_stats, |
3514 | .get_tx_stats = b43legacy_op_get_tx_stats, | ||
3515 | .start = b43legacy_op_start, | 3493 | .start = b43legacy_op_start, |
3516 | .stop = b43legacy_op_stop, | 3494 | .stop = b43legacy_op_stop, |
3517 | .set_tim = b43legacy_op_beacon_set_tim, | 3495 | .set_tim = b43legacy_op_beacon_set_tim, |
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 51866c9a276..017c0e9c37e 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c | |||
@@ -477,7 +477,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev, | |||
477 | 477 | ||
478 | list_move_tail(&packet->list, &queue->txqueue); | 478 | list_move_tail(&packet->list, &queue->txqueue); |
479 | queue->nr_txfree--; | 479 | queue->nr_txfree--; |
480 | queue->nr_tx_packets++; | ||
481 | B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS); | 480 | B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS); |
482 | 481 | ||
483 | tasklet_schedule(&queue->txtask); | 482 | tasklet_schedule(&queue->txtask); |
@@ -546,18 +545,6 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, | |||
546 | tasklet_schedule(&queue->txtask); | 545 | tasklet_schedule(&queue->txtask); |
547 | } | 546 | } |
548 | 547 | ||
549 | void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, | ||
550 | struct ieee80211_tx_queue_stats *stats) | ||
551 | { | ||
552 | struct b43legacy_pio *pio = &dev->pio; | ||
553 | struct b43legacy_pioqueue *queue; | ||
554 | |||
555 | queue = pio->queue1; | ||
556 | stats[0].len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; | ||
557 | stats[0].limit = B43legacy_PIO_MAXTXPACKETS; | ||
558 | stats[0].count = queue->nr_tx_packets; | ||
559 | } | ||
560 | |||
561 | static void pio_rx_error(struct b43legacy_pioqueue *queue, | 548 | static void pio_rx_error(struct b43legacy_pioqueue *queue, |
562 | int clear_buffers, | 549 | int clear_buffers, |
563 | const char *error) | 550 | const char *error) |
diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h index 464fec05a06..8e6773ea6e7 100644 --- a/drivers/net/wireless/b43legacy/pio.h +++ b/drivers/net/wireless/b43legacy/pio.h | |||
@@ -74,10 +74,6 @@ struct b43legacy_pioqueue { | |||
74 | * posted to the device. We are waiting for the txstatus. | 74 | * posted to the device. We are waiting for the txstatus. |
75 | */ | 75 | */ |
76 | struct list_head txrunning; | 76 | struct list_head txrunning; |
77 | /* Total number or packets sent. | ||
78 | * (This counter can obviously wrap). | ||
79 | */ | ||
80 | unsigned int nr_tx_packets; | ||
81 | struct tasklet_struct txtask; | 77 | struct tasklet_struct txtask; |
82 | struct b43legacy_pio_txpacket | 78 | struct b43legacy_pio_txpacket |
83 | tx_packets_cache[B43legacy_PIO_MAXTXPACKETS]; | 79 | tx_packets_cache[B43legacy_PIO_MAXTXPACKETS]; |
@@ -106,8 +102,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev, | |||
106 | struct sk_buff *skb); | 102 | struct sk_buff *skb); |
107 | void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, | 103 | void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, |
108 | const struct b43legacy_txstatus *status); | 104 | const struct b43legacy_txstatus *status); |
109 | void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, | ||
110 | struct ieee80211_tx_queue_stats *stats); | ||
111 | void b43legacy_pio_rx(struct b43legacy_pioqueue *queue); | 105 | void b43legacy_pio_rx(struct b43legacy_pioqueue *queue); |
112 | 106 | ||
113 | /* Suspend TX queue in hardware. */ | 107 | /* Suspend TX queue in hardware. */ |
@@ -140,11 +134,6 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, | |||
140 | { | 134 | { |
141 | } | 135 | } |
142 | static inline | 136 | static inline |
143 | void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, | ||
144 | struct ieee80211_tx_queue_stats *stats) | ||
145 | { | ||
146 | } | ||
147 | static inline | ||
148 | void b43legacy_pio_rx(struct b43legacy_pioqueue *queue) | 137 | void b43legacy_pio_rx(struct b43legacy_pioqueue *queue) |
149 | { | 138 | { |
150 | } | 139 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 9d1820676f3..694ceef8859 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -247,6 +247,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { | |||
247 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 247 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
248 | .support_ct_kill_exit = true, | 248 | .support_ct_kill_exit = true, |
249 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 249 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
250 | .chain_noise_scale = 1000, | ||
250 | }; | 251 | }; |
251 | 252 | ||
252 | struct iwl_cfg iwl1000_bg_cfg = { | 253 | struct iwl_cfg iwl1000_bg_cfg = { |
@@ -274,6 +275,7 @@ struct iwl_cfg iwl1000_bg_cfg = { | |||
274 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 275 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
275 | .support_ct_kill_exit = true, | 276 | .support_ct_kill_exit = true, |
276 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 277 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
278 | .chain_noise_scale = 1000, | ||
277 | }; | 279 | }; |
278 | 280 | ||
279 | MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); | 281 | MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6d598890134..f3d662c8cbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -179,14 +179,24 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, | |||
179 | data->delta_gain_code[i] = 0; | 179 | data->delta_gain_code[i] = 0; |
180 | continue; | 180 | continue; |
181 | } | 181 | } |
182 | delta_g = (1000 * ((s32)average_noise[default_chain] - | 182 | |
183 | delta_g = (priv->cfg->chain_noise_scale * | ||
184 | ((s32)average_noise[default_chain] - | ||
183 | (s32)average_noise[i])) / 1500; | 185 | (s32)average_noise[i])) / 1500; |
186 | |||
184 | /* bound gain by 2 bits value max, 3rd bit is sign */ | 187 | /* bound gain by 2 bits value max, 3rd bit is sign */ |
185 | data->delta_gain_code[i] = | 188 | data->delta_gain_code[i] = |
186 | min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE); | 189 | min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE); |
187 | 190 | ||
188 | if (delta_g < 0) | 191 | if (delta_g < 0) |
189 | /* set negative sign */ | 192 | /* |
193 | * set negative sign ... | ||
194 | * note to Intel developers: This is uCode API format, | ||
195 | * not the format of any internal device registers. | ||
196 | * Do not change this format for e.g. 6050 or similar | ||
197 | * devices. Change format only if more resolution | ||
198 | * (i.e. more than 2 bits magnitude) is needed. | ||
199 | */ | ||
190 | data->delta_gain_code[i] |= (1 << 2); | 200 | data->delta_gain_code[i] |= (1 << 2); |
191 | } | 201 | } |
192 | 202 | ||
@@ -1587,6 +1597,7 @@ struct iwl_cfg iwl5300_agn_cfg = { | |||
1587 | .use_rts_for_ht = true, /* use rts/cts protection */ | 1597 | .use_rts_for_ht = true, /* use rts/cts protection */ |
1588 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1598 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1589 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1599 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1600 | .chain_noise_scale = 1000, | ||
1590 | }; | 1601 | }; |
1591 | 1602 | ||
1592 | struct iwl_cfg iwl5100_bgn_cfg = { | 1603 | struct iwl_cfg iwl5100_bgn_cfg = { |
@@ -1612,6 +1623,7 @@ struct iwl_cfg iwl5100_bgn_cfg = { | |||
1612 | .use_rts_for_ht = true, /* use rts/cts protection */ | 1623 | .use_rts_for_ht = true, /* use rts/cts protection */ |
1613 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1624 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1614 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1625 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1626 | .chain_noise_scale = 1000, | ||
1615 | }; | 1627 | }; |
1616 | 1628 | ||
1617 | struct iwl_cfg iwl5100_abg_cfg = { | 1629 | struct iwl_cfg iwl5100_abg_cfg = { |
@@ -1635,6 +1647,7 @@ struct iwl_cfg iwl5100_abg_cfg = { | |||
1635 | .led_compensation = 51, | 1647 | .led_compensation = 51, |
1636 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1648 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1637 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1649 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1650 | .chain_noise_scale = 1000, | ||
1638 | }; | 1651 | }; |
1639 | 1652 | ||
1640 | struct iwl_cfg iwl5100_agn_cfg = { | 1653 | struct iwl_cfg iwl5100_agn_cfg = { |
@@ -1660,6 +1673,7 @@ struct iwl_cfg iwl5100_agn_cfg = { | |||
1660 | .use_rts_for_ht = true, /* use rts/cts protection */ | 1673 | .use_rts_for_ht = true, /* use rts/cts protection */ |
1661 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1674 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1662 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1675 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1676 | .chain_noise_scale = 1000, | ||
1663 | }; | 1677 | }; |
1664 | 1678 | ||
1665 | struct iwl_cfg iwl5350_agn_cfg = { | 1679 | struct iwl_cfg iwl5350_agn_cfg = { |
@@ -1685,6 +1699,7 @@ struct iwl_cfg iwl5350_agn_cfg = { | |||
1685 | .use_rts_for_ht = true, /* use rts/cts protection */ | 1699 | .use_rts_for_ht = true, /* use rts/cts protection */ |
1686 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1700 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1687 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1701 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1702 | .chain_noise_scale = 1000, | ||
1688 | }; | 1703 | }; |
1689 | 1704 | ||
1690 | struct iwl_cfg iwl5150_agn_cfg = { | 1705 | struct iwl_cfg iwl5150_agn_cfg = { |
@@ -1710,6 +1725,7 @@ struct iwl_cfg iwl5150_agn_cfg = { | |||
1710 | .use_rts_for_ht = true, /* use rts/cts protection */ | 1725 | .use_rts_for_ht = true, /* use rts/cts protection */ |
1711 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1726 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1712 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1727 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1728 | .chain_noise_scale = 1000, | ||
1713 | }; | 1729 | }; |
1714 | 1730 | ||
1715 | struct iwl_cfg iwl5150_abg_cfg = { | 1731 | struct iwl_cfg iwl5150_abg_cfg = { |
@@ -1733,6 +1749,7 @@ struct iwl_cfg iwl5150_abg_cfg = { | |||
1733 | .led_compensation = 51, | 1749 | .led_compensation = 51, |
1734 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1750 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1735 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1751 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1752 | .chain_noise_scale = 1000, | ||
1736 | }; | 1753 | }; |
1737 | 1754 | ||
1738 | MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); | 1755 | MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a9f8551e0e4..782e23a2698 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -277,21 +277,6 @@ static const struct iwl_ops iwl6000_ops = { | |||
277 | .led = &iwlagn_led_ops, | 277 | .led = &iwlagn_led_ops, |
278 | }; | 278 | }; |
279 | 279 | ||
280 | static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = { | ||
281 | .get_hcmd_size = iwl5000_get_hcmd_size, | ||
282 | .build_addsta_hcmd = iwl5000_build_addsta_hcmd, | ||
283 | .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, | ||
284 | .calc_rssi = iwl5000_calc_rssi, | ||
285 | }; | ||
286 | |||
287 | static const struct iwl_ops iwl6050_ops = { | ||
288 | .ucode = &iwl5000_ucode, | ||
289 | .lib = &iwl6000_lib, | ||
290 | .hcmd = &iwl5000_hcmd, | ||
291 | .utils = &iwl6050_hcmd_utils, | ||
292 | .led = &iwlagn_led_ops, | ||
293 | }; | ||
294 | |||
295 | /* | 280 | /* |
296 | * "i": Internal configuration, use internal Power Amplifier | 281 | * "i": Internal configuration, use internal Power Amplifier |
297 | */ | 282 | */ |
@@ -324,6 +309,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { | |||
324 | .adv_thermal_throttle = true, | 309 | .adv_thermal_throttle = true, |
325 | .support_ct_kill_exit = true, | 310 | .support_ct_kill_exit = true, |
326 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 311 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
312 | .chain_noise_scale = 1000, | ||
327 | }; | 313 | }; |
328 | 314 | ||
329 | struct iwl_cfg iwl6000i_2abg_cfg = { | 315 | struct iwl_cfg iwl6000i_2abg_cfg = { |
@@ -354,6 +340,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { | |||
354 | .adv_thermal_throttle = true, | 340 | .adv_thermal_throttle = true, |
355 | .support_ct_kill_exit = true, | 341 | .support_ct_kill_exit = true, |
356 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 342 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
343 | .chain_noise_scale = 1000, | ||
357 | }; | 344 | }; |
358 | 345 | ||
359 | struct iwl_cfg iwl6000i_2bg_cfg = { | 346 | struct iwl_cfg iwl6000i_2bg_cfg = { |
@@ -384,6 +371,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { | |||
384 | .adv_thermal_throttle = true, | 371 | .adv_thermal_throttle = true, |
385 | .support_ct_kill_exit = true, | 372 | .support_ct_kill_exit = true, |
386 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 373 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
374 | .chain_noise_scale = 1000, | ||
387 | }; | 375 | }; |
388 | 376 | ||
389 | struct iwl_cfg iwl6050_2agn_cfg = { | 377 | struct iwl_cfg iwl6050_2agn_cfg = { |
@@ -392,7 +380,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { | |||
392 | .ucode_api_max = IWL6050_UCODE_API_MAX, | 380 | .ucode_api_max = IWL6050_UCODE_API_MAX, |
393 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 381 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
394 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 382 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
395 | .ops = &iwl6050_ops, | 383 | .ops = &iwl6000_ops, |
396 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | 384 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
397 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, | 385 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, |
398 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 386 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
@@ -415,6 +403,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { | |||
415 | .adv_thermal_throttle = true, | 403 | .adv_thermal_throttle = true, |
416 | .support_ct_kill_exit = true, | 404 | .support_ct_kill_exit = true, |
417 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 405 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
406 | .chain_noise_scale = 1500, | ||
418 | }; | 407 | }; |
419 | 408 | ||
420 | struct iwl_cfg iwl6050_2abg_cfg = { | 409 | struct iwl_cfg iwl6050_2abg_cfg = { |
@@ -423,7 +412,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { | |||
423 | .ucode_api_max = IWL6050_UCODE_API_MAX, | 412 | .ucode_api_max = IWL6050_UCODE_API_MAX, |
424 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 413 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
425 | .sku = IWL_SKU_A|IWL_SKU_G, | 414 | .sku = IWL_SKU_A|IWL_SKU_G, |
426 | .ops = &iwl6050_ops, | 415 | .ops = &iwl6000_ops, |
427 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | 416 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
428 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, | 417 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, |
429 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | 418 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, |
@@ -445,6 +434,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { | |||
445 | .adv_thermal_throttle = true, | 434 | .adv_thermal_throttle = true, |
446 | .support_ct_kill_exit = true, | 435 | .support_ct_kill_exit = true, |
447 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 436 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
437 | .chain_noise_scale = 1500, | ||
448 | }; | 438 | }; |
449 | 439 | ||
450 | struct iwl_cfg iwl6000_3agn_cfg = { | 440 | struct iwl_cfg iwl6000_3agn_cfg = { |
@@ -476,6 +466,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { | |||
476 | .adv_thermal_throttle = true, | 466 | .adv_thermal_throttle = true, |
477 | .support_ct_kill_exit = true, | 467 | .support_ct_kill_exit = true, |
478 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 468 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
469 | .chain_noise_scale = 1000, | ||
479 | }; | 470 | }; |
480 | 471 | ||
481 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); | 472 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d0268280d67..1854c720b5e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -2631,7 +2631,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv) | |||
2631 | */ | 2631 | */ |
2632 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 2632 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; |
2633 | 2633 | ||
2634 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; | 2634 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX + 1; |
2635 | /* we create the 802.11 header and a zero-length SSID element */ | 2635 | /* we create the 802.11 header and a zero-length SSID element */ |
2636 | hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; | 2636 | hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; |
2637 | 2637 | ||
@@ -3440,7 +3440,6 @@ static struct ieee80211_ops iwl_hw_ops = { | |||
3440 | .set_key = iwl_mac_set_key, | 3440 | .set_key = iwl_mac_set_key, |
3441 | .update_tkip_key = iwl_mac_update_tkip_key, | 3441 | .update_tkip_key = iwl_mac_update_tkip_key, |
3442 | .get_stats = iwl_mac_get_stats, | 3442 | .get_stats = iwl_mac_get_stats, |
3443 | .get_tx_stats = iwl_mac_get_tx_stats, | ||
3444 | .conf_tx = iwl_mac_conf_tx, | 3443 | .conf_tx = iwl_mac_conf_tx, |
3445 | .reset_tsf = iwl_mac_reset_tsf, | 3444 | .reset_tsf = iwl_mac_reset_tsf, |
3446 | .bss_info_changed = iwl_bss_info_changed, | 3445 | .bss_info_changed = iwl_bss_info_changed, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 02bf17ecaf5..d390eef2efe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -2787,6 +2787,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
2787 | if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) | 2787 | if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) |
2788 | priv->staging_rxon.flags = 0; | 2788 | priv->staging_rxon.flags = 0; |
2789 | 2789 | ||
2790 | iwl_set_rxon_ht(priv, ht_conf); | ||
2790 | iwl_set_rxon_channel(priv, conf->channel); | 2791 | iwl_set_rxon_channel(priv, conf->channel); |
2791 | 2792 | ||
2792 | iwl_set_flags_for_band(priv, conf->channel->band); | 2793 | iwl_set_flags_for_band(priv, conf->channel->band); |
@@ -2850,42 +2851,6 @@ out: | |||
2850 | } | 2851 | } |
2851 | EXPORT_SYMBOL(iwl_mac_config); | 2852 | EXPORT_SYMBOL(iwl_mac_config); |
2852 | 2853 | ||
2853 | int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, | ||
2854 | struct ieee80211_tx_queue_stats *stats) | ||
2855 | { | ||
2856 | struct iwl_priv *priv = hw->priv; | ||
2857 | int i, avail; | ||
2858 | struct iwl_tx_queue *txq; | ||
2859 | struct iwl_queue *q; | ||
2860 | unsigned long flags; | ||
2861 | |||
2862 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
2863 | |||
2864 | if (!iwl_is_ready_rf(priv)) { | ||
2865 | IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); | ||
2866 | return -EIO; | ||
2867 | } | ||
2868 | |||
2869 | spin_lock_irqsave(&priv->lock, flags); | ||
2870 | |||
2871 | for (i = 0; i < AC_NUM; i++) { | ||
2872 | txq = &priv->txq[i]; | ||
2873 | q = &txq->q; | ||
2874 | avail = iwl_queue_space(q); | ||
2875 | |||
2876 | stats[i].len = q->n_window - avail; | ||
2877 | stats[i].limit = q->n_window - q->high_mark; | ||
2878 | stats[i].count = q->n_window; | ||
2879 | |||
2880 | } | ||
2881 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2882 | |||
2883 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
2884 | |||
2885 | return 0; | ||
2886 | } | ||
2887 | EXPORT_SYMBOL(iwl_mac_get_tx_stats); | ||
2888 | |||
2889 | void iwl_mac_reset_tsf(struct ieee80211_hw *hw) | 2854 | void iwl_mac_reset_tsf(struct ieee80211_hw *hw) |
2890 | { | 2855 | { |
2891 | struct iwl_priv *priv = hw->priv; | 2856 | struct iwl_priv *priv = hw->priv; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ec1fe1d7cc9..8f0c564e68b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -293,6 +293,7 @@ struct iwl_cfg { | |||
293 | bool support_ct_kill_exit; | 293 | bool support_ct_kill_exit; |
294 | const bool support_wimax_coexist; | 294 | const bool support_wimax_coexist; |
295 | u8 plcp_delta_threshold; | 295 | u8 plcp_delta_threshold; |
296 | s32 chain_noise_scale; | ||
296 | }; | 297 | }; |
297 | 298 | ||
298 | /*************************** | 299 | /*************************** |
@@ -341,8 +342,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, | |||
341 | struct ieee80211_vif *vif); | 342 | struct ieee80211_vif *vif); |
342 | int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); | 343 | int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); |
343 | void iwl_config_ap(struct iwl_priv *priv); | 344 | void iwl_config_ap(struct iwl_priv *priv); |
344 | int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, | ||
345 | struct ieee80211_tx_queue_stats *stats); | ||
346 | void iwl_mac_reset_tsf(struct ieee80211_hw *hw); | 345 | void iwl_mac_reset_tsf(struct ieee80211_hw *hw); |
347 | int iwl_alloc_txq_mem(struct iwl_priv *priv); | 346 | int iwl_alloc_txq_mem(struct iwl_priv *priv); |
348 | void iwl_free_txq_mem(struct iwl_priv *priv); | 347 | void iwl_free_txq_mem(struct iwl_priv *priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 08faafae849..f786a407638 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -651,9 +651,20 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, | |||
651 | if (left < 0) | 651 | if (left < 0) |
652 | return 0; | 652 | return 0; |
653 | *pos++ = WLAN_EID_SSID; | 653 | *pos++ = WLAN_EID_SSID; |
654 | *pos++ = 0; | 654 | if (!priv->is_internal_short_scan && |
655 | 655 | priv->scan_request->n_ssids) { | |
656 | len += 2; | 656 | struct cfg80211_ssid *ssid = |
657 | priv->scan_request->ssids; | ||
658 | |||
659 | /* Broadcast if ssid_len is 0 */ | ||
660 | *pos++ = ssid->ssid_len; | ||
661 | memcpy(pos, ssid->ssid, ssid->ssid_len); | ||
662 | pos += ssid->ssid_len; | ||
663 | len += 2 + ssid->ssid_len; | ||
664 | } else { | ||
665 | *pos++ = 0; | ||
666 | len += 2; | ||
667 | } | ||
657 | 668 | ||
658 | if (WARN_ON(left < ie_len)) | 669 | if (WARN_ON(left < ie_len)) |
659 | return len; | 670 | return len; |
@@ -782,20 +793,26 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
782 | if (priv->is_internal_short_scan) { | 793 | if (priv->is_internal_short_scan) { |
783 | IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); | 794 | IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); |
784 | } else if (priv->scan_request->n_ssids) { | 795 | } else if (priv->scan_request->n_ssids) { |
785 | int i, p = 0; | ||
786 | IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); | 796 | IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); |
787 | for (i = 0; i < priv->scan_request->n_ssids; i++) { | 797 | /* |
788 | /* always does wildcard anyway */ | 798 | * The first SSID to scan is stuffed into the probe request |
789 | if (!priv->scan_request->ssids[i].ssid_len) | 799 | * template and the remaining ones are handled through the |
790 | continue; | 800 | * direct_scan array. |
791 | scan->direct_scan[p].id = WLAN_EID_SSID; | 801 | */ |
792 | scan->direct_scan[p].len = | 802 | if (priv->scan_request->n_ssids > 1) { |
793 | priv->scan_request->ssids[i].ssid_len; | 803 | int i, p = 0; |
794 | memcpy(scan->direct_scan[p].ssid, | 804 | for (i = 1; i < priv->scan_request->n_ssids; i++) { |
795 | priv->scan_request->ssids[i].ssid, | 805 | if (!priv->scan_request->ssids[i].ssid_len) |
796 | priv->scan_request->ssids[i].ssid_len); | 806 | continue; |
797 | n_probes++; | 807 | scan->direct_scan[p].id = WLAN_EID_SSID; |
798 | p++; | 808 | scan->direct_scan[p].len = |
809 | priv->scan_request->ssids[i].ssid_len; | ||
810 | memcpy(scan->direct_scan[p].ssid, | ||
811 | priv->scan_request->ssids[i].ssid, | ||
812 | priv->scan_request->ssids[i].ssid_len); | ||
813 | n_probes++; | ||
814 | p++; | ||
815 | } | ||
799 | } | 816 | } |
800 | is_active = true; | 817 | is_active = true; |
801 | } else | 818 | } else |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 119da54116d..eac2b9a9571 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -3835,7 +3835,6 @@ static struct ieee80211_ops iwl3945_hw_ops = { | |||
3835 | .config = iwl_mac_config, | 3835 | .config = iwl_mac_config, |
3836 | .configure_filter = iwl_configure_filter, | 3836 | .configure_filter = iwl_configure_filter, |
3837 | .set_key = iwl3945_mac_set_key, | 3837 | .set_key = iwl3945_mac_set_key, |
3838 | .get_tx_stats = iwl_mac_get_tx_stats, | ||
3839 | .conf_tx = iwl_mac_conf_tx, | 3838 | .conf_tx = iwl_mac_conf_tx, |
3840 | .reset_tsf = iwl_mac_reset_tsf, | 3839 | .reset_tsf = iwl_mac_reset_tsf, |
3841 | .bss_info_changed = iwl_bss_info_changed, | 3840 | .bss_info_changed = iwl_bss_info_changed, |
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 0334a58820e..e7470442f76 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c | |||
@@ -240,11 +240,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) | |||
240 | /* Now we got response from FW, cancel the command timer */ | 240 | /* Now we got response from FW, cancel the command timer */ |
241 | del_timer(&priv->command_timer); | 241 | del_timer(&priv->command_timer); |
242 | priv->cmd_timed_out = 0; | 242 | priv->cmd_timed_out = 0; |
243 | if (priv->nr_retries) { | ||
244 | lbs_pr_info("Received result %x to command %x after %d retries\n", | ||
245 | result, curcmd, priv->nr_retries); | ||
246 | priv->nr_retries = 0; | ||
247 | } | ||
248 | 243 | ||
249 | /* Store the response code to cur_cmd_retcode. */ | 244 | /* Store the response code to cur_cmd_retcode. */ |
250 | priv->cur_cmd_retcode = result; | 245 | priv->cur_cmd_retcode = result; |
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index c348aff8f30..6977ee82021 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -109,7 +109,6 @@ struct lbs_private { | |||
109 | struct list_head cmdpendingq; /* pending command buffers */ | 109 | struct list_head cmdpendingq; /* pending command buffers */ |
110 | wait_queue_head_t cmd_pending; | 110 | wait_queue_head_t cmd_pending; |
111 | struct timer_list command_timer; | 111 | struct timer_list command_timer; |
112 | int nr_retries; | ||
113 | int cmd_timed_out; | 112 | int cmd_timed_out; |
114 | 113 | ||
115 | /* Command responses sent from the hardware to the driver */ | 114 | /* Command responses sent from the hardware to the driver */ |
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index bf4bfbae622..3ea03f259ee 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kthread.h> | 23 | #include <linux/kthread.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/netdevice.h> | 25 | #include <linux/netdevice.h> |
26 | #include <linux/semaphore.h> | ||
26 | #include <linux/spi/libertas_spi.h> | 27 | #include <linux/spi/libertas_spi.h> |
27 | #include <linux/spi/spi.h> | 28 | #include <linux/spi/spi.h> |
28 | 29 | ||
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 60bde1233a3..cd8ed7fdafa 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -536,31 +536,14 @@ static int lbs_thread(void *data) | |||
536 | if (priv->cmd_timed_out && priv->cur_cmd) { | 536 | if (priv->cmd_timed_out && priv->cur_cmd) { |
537 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; | 537 | struct cmd_ctrl_node *cmdnode = priv->cur_cmd; |
538 | 538 | ||
539 | if (++priv->nr_retries > 3) { | 539 | lbs_pr_info("Timeout submitting command 0x%04x\n", |
540 | lbs_pr_info("Excessive timeouts submitting " | 540 | le16_to_cpu(cmdnode->cmdbuf->command)); |
541 | "command 0x%04x\n", | 541 | lbs_complete_command(priv, cmdnode, -ETIMEDOUT); |
542 | le16_to_cpu(cmdnode->cmdbuf->command)); | 542 | if (priv->reset_card) |
543 | lbs_complete_command(priv, cmdnode, -ETIMEDOUT); | 543 | priv->reset_card(priv); |
544 | priv->nr_retries = 0; | ||
545 | if (priv->reset_card) | ||
546 | priv->reset_card(priv); | ||
547 | } else { | ||
548 | priv->cur_cmd = NULL; | ||
549 | priv->dnld_sent = DNLD_RES_RECEIVED; | ||
550 | lbs_pr_info("requeueing command 0x%04x due " | ||
551 | "to timeout (#%d)\n", | ||
552 | le16_to_cpu(cmdnode->cmdbuf->command), | ||
553 | priv->nr_retries); | ||
554 | |||
555 | /* Stick it back at the _top_ of the pending queue | ||
556 | for immediate resubmission */ | ||
557 | list_add(&cmdnode->list, &priv->cmdpendingq); | ||
558 | } | ||
559 | } | 544 | } |
560 | priv->cmd_timed_out = 0; | 545 | priv->cmd_timed_out = 0; |
561 | 546 | ||
562 | |||
563 | |||
564 | if (!priv->fw_ready) | 547 | if (!priv->fw_ready) |
565 | continue; | 548 | continue; |
566 | 549 | ||
@@ -732,7 +715,7 @@ done: | |||
732 | * This function handles the timeout of command sending. | 715 | * This function handles the timeout of command sending. |
733 | * It will re-send the same command again. | 716 | * It will re-send the same command again. |
734 | */ | 717 | */ |
735 | static void command_timer_fn(unsigned long data) | 718 | static void lbs_cmd_timeout_handler(unsigned long data) |
736 | { | 719 | { |
737 | struct lbs_private *priv = (struct lbs_private *)data; | 720 | struct lbs_private *priv = (struct lbs_private *)data; |
738 | unsigned long flags; | 721 | unsigned long flags; |
@@ -851,7 +834,7 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
851 | 834 | ||
852 | mutex_init(&priv->lock); | 835 | mutex_init(&priv->lock); |
853 | 836 | ||
854 | setup_timer(&priv->command_timer, command_timer_fn, | 837 | setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, |
855 | (unsigned long)priv); | 838 | (unsigned long)priv); |
856 | setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, | 839 | setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, |
857 | (unsigned long)priv); | 840 | (unsigned long)priv); |
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index ba3eb0101d5..6ab30033c26 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c | |||
@@ -555,6 +555,9 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) | |||
555 | priv->band.n_channels = ARRAY_SIZE(lbtf_channels); | 555 | priv->band.n_channels = ARRAY_SIZE(lbtf_channels); |
556 | priv->band.channels = priv->channels; | 556 | priv->band.channels = priv->channels; |
557 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; | 557 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; |
558 | hw->wiphy->interface_modes = | ||
559 | BIT(NL80211_IFTYPE_STATION) | | ||
560 | BIT(NL80211_IFTYPE_ADHOC); | ||
558 | skb_queue_head_init(&priv->bc_ps_buf); | 561 | skb_queue_head_init(&priv->bc_ps_buf); |
559 | 562 | ||
560 | SET_IEEE80211_DEV(hw, dmdev); | 563 | SET_IEEE80211_DEV(hw, dmdev); |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 0dbda8dfbd9..00ffe6dd435 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -32,6 +32,10 @@ static int radios = 2; | |||
32 | module_param(radios, int, 0444); | 32 | module_param(radios, int, 0444); |
33 | MODULE_PARM_DESC(radios, "Number of simulated radios"); | 33 | MODULE_PARM_DESC(radios, "Number of simulated radios"); |
34 | 34 | ||
35 | static bool fake_hw_scan; | ||
36 | module_param(fake_hw_scan, bool, 0444); | ||
37 | MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); | ||
38 | |||
35 | /** | 39 | /** |
36 | * enum hwsim_regtest - the type of regulatory tests we offer | 40 | * enum hwsim_regtest - the type of regulatory tests we offer |
37 | * | 41 | * |
@@ -908,8 +912,43 @@ static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) | |||
908 | */ | 912 | */ |
909 | } | 913 | } |
910 | 914 | ||
915 | struct hw_scan_done { | ||
916 | struct delayed_work w; | ||
917 | struct ieee80211_hw *hw; | ||
918 | }; | ||
911 | 919 | ||
912 | static const struct ieee80211_ops mac80211_hwsim_ops = | 920 | static void hw_scan_done(struct work_struct *work) |
921 | { | ||
922 | struct hw_scan_done *hsd = | ||
923 | container_of(work, struct hw_scan_done, w.work); | ||
924 | |||
925 | ieee80211_scan_completed(hsd->hw, false); | ||
926 | kfree(hsd); | ||
927 | } | ||
928 | |||
929 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, | ||
930 | struct cfg80211_scan_request *req) | ||
931 | { | ||
932 | struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL); | ||
933 | int i; | ||
934 | |||
935 | if (!hsd) | ||
936 | return -ENOMEM; | ||
937 | |||
938 | hsd->hw = hw; | ||
939 | INIT_DELAYED_WORK(&hsd->w, hw_scan_done); | ||
940 | |||
941 | printk(KERN_DEBUG "hwsim scan request\n"); | ||
942 | for (i = 0; i < req->n_channels; i++) | ||
943 | printk(KERN_DEBUG "hwsim scan freq %d\n", | ||
944 | req->channels[i]->center_freq); | ||
945 | |||
946 | ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static struct ieee80211_ops mac80211_hwsim_ops = | ||
913 | { | 952 | { |
914 | .tx = mac80211_hwsim_tx, | 953 | .tx = mac80211_hwsim_tx, |
915 | .start = mac80211_hwsim_start, | 954 | .start = mac80211_hwsim_start, |
@@ -1119,6 +1158,9 @@ static int __init init_mac80211_hwsim(void) | |||
1119 | if (radios < 1 || radios > 100) | 1158 | if (radios < 1 || radios > 100) |
1120 | return -EINVAL; | 1159 | return -EINVAL; |
1121 | 1160 | ||
1161 | if (fake_hw_scan) | ||
1162 | mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; | ||
1163 | |||
1122 | spin_lock_init(&hwsim_radio_lock); | 1164 | spin_lock_init(&hwsim_radio_lock); |
1123 | INIT_LIST_HEAD(&hwsim_radios); | 1165 | INIT_LIST_HEAD(&hwsim_radios); |
1124 | 1166 | ||
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f0f08f3919c..0cfdb9db66f 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -119,7 +119,7 @@ struct mwl8k_tx_queue { | |||
119 | /* sw appends here */ | 119 | /* sw appends here */ |
120 | int tail; | 120 | int tail; |
121 | 121 | ||
122 | struct ieee80211_tx_queue_stats stats; | 122 | unsigned int len; |
123 | struct mwl8k_tx_desc *txd; | 123 | struct mwl8k_tx_desc *txd; |
124 | dma_addr_t txd_dma; | 124 | dma_addr_t txd_dma; |
125 | struct sk_buff **skb; | 125 | struct sk_buff **skb; |
@@ -1136,8 +1136,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) | |||
1136 | int size; | 1136 | int size; |
1137 | int i; | 1137 | int i; |
1138 | 1138 | ||
1139 | memset(&txq->stats, 0, sizeof(struct ieee80211_tx_queue_stats)); | 1139 | txq->len = 0; |
1140 | txq->stats.limit = MWL8K_TX_DESCS; | ||
1141 | txq->head = 0; | 1140 | txq->head = 0; |
1142 | txq->tail = 0; | 1141 | txq->tail = 0; |
1143 | 1142 | ||
@@ -1213,7 +1212,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) | |||
1213 | printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d " | 1212 | printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d " |
1214 | "fw_owned=%d drv_owned=%d unused=%d\n", | 1213 | "fw_owned=%d drv_owned=%d unused=%d\n", |
1215 | wiphy_name(hw->wiphy), i, | 1214 | wiphy_name(hw->wiphy), i, |
1216 | txq->stats.len, txq->head, txq->tail, | 1215 | txq->len, txq->head, txq->tail, |
1217 | fw_owned, drv_owned, unused); | 1216 | fw_owned, drv_owned, unused); |
1218 | } | 1217 | } |
1219 | } | 1218 | } |
@@ -1299,7 +1298,7 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1299 | int processed; | 1298 | int processed; |
1300 | 1299 | ||
1301 | processed = 0; | 1300 | processed = 0; |
1302 | while (txq->stats.len > 0 && limit--) { | 1301 | while (txq->len > 0 && limit--) { |
1303 | int tx; | 1302 | int tx; |
1304 | struct mwl8k_tx_desc *tx_desc; | 1303 | struct mwl8k_tx_desc *tx_desc; |
1305 | unsigned long addr; | 1304 | unsigned long addr; |
@@ -1321,8 +1320,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1321 | } | 1320 | } |
1322 | 1321 | ||
1323 | txq->head = (tx + 1) % MWL8K_TX_DESCS; | 1322 | txq->head = (tx + 1) % MWL8K_TX_DESCS; |
1324 | BUG_ON(txq->stats.len == 0); | 1323 | BUG_ON(txq->len == 0); |
1325 | txq->stats.len--; | 1324 | txq->len--; |
1326 | priv->pending_tx_pkts--; | 1325 | priv->pending_tx_pkts--; |
1327 | 1326 | ||
1328 | addr = le32_to_cpu(tx_desc->pkt_phys_addr); | 1327 | addr = le32_to_cpu(tx_desc->pkt_phys_addr); |
@@ -1454,8 +1453,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1454 | wmb(); | 1453 | wmb(); |
1455 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); | 1454 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); |
1456 | 1455 | ||
1457 | txq->stats.count++; | 1456 | txq->len++; |
1458 | txq->stats.len++; | ||
1459 | priv->pending_tx_pkts++; | 1457 | priv->pending_tx_pkts++; |
1460 | 1458 | ||
1461 | txq->tail++; | 1459 | txq->tail++; |
@@ -3818,24 +3816,6 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
3818 | return rc; | 3816 | return rc; |
3819 | } | 3817 | } |
3820 | 3818 | ||
3821 | static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, | ||
3822 | struct ieee80211_tx_queue_stats *stats) | ||
3823 | { | ||
3824 | struct mwl8k_priv *priv = hw->priv; | ||
3825 | struct mwl8k_tx_queue *txq; | ||
3826 | int index; | ||
3827 | |||
3828 | spin_lock_bh(&priv->tx_lock); | ||
3829 | for (index = 0; index < MWL8K_TX_QUEUES; index++) { | ||
3830 | txq = priv->txq + index; | ||
3831 | memcpy(&stats[index], &txq->stats, | ||
3832 | sizeof(struct ieee80211_tx_queue_stats)); | ||
3833 | } | ||
3834 | spin_unlock_bh(&priv->tx_lock); | ||
3835 | |||
3836 | return 0; | ||
3837 | } | ||
3838 | |||
3839 | static int mwl8k_get_stats(struct ieee80211_hw *hw, | 3819 | static int mwl8k_get_stats(struct ieee80211_hw *hw, |
3840 | struct ieee80211_low_level_stats *stats) | 3820 | struct ieee80211_low_level_stats *stats) |
3841 | { | 3821 | { |
@@ -3871,7 +3851,6 @@ static const struct ieee80211_ops mwl8k_ops = { | |||
3871 | .set_rts_threshold = mwl8k_set_rts_threshold, | 3851 | .set_rts_threshold = mwl8k_set_rts_threshold, |
3872 | .sta_notify = mwl8k_sta_notify, | 3852 | .sta_notify = mwl8k_sta_notify, |
3873 | .conf_tx = mwl8k_conf_tx, | 3853 | .conf_tx = mwl8k_conf_tx, |
3874 | .get_tx_stats = mwl8k_get_tx_stats, | ||
3875 | .get_stats = mwl8k_get_stats, | 3854 | .get_stats = mwl8k_get_stats, |
3876 | .ampdu_action = mwl8k_ampdu_action, | 3855 | .ampdu_action = mwl8k_ampdu_action, |
3877 | }; | 3856 | }; |
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 26428e4c9c6..3fe6366e567 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c | |||
@@ -358,16 +358,6 @@ static int p54_get_stats(struct ieee80211_hw *dev, | |||
358 | return 0; | 358 | return 0; |
359 | } | 359 | } |
360 | 360 | ||
361 | static int p54_get_tx_stats(struct ieee80211_hw *dev, | ||
362 | struct ieee80211_tx_queue_stats *stats) | ||
363 | { | ||
364 | struct p54_common *priv = dev->priv; | ||
365 | |||
366 | memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA], | ||
367 | sizeof(stats[0]) * dev->queues); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static void p54_bss_info_changed(struct ieee80211_hw *dev, | 361 | static void p54_bss_info_changed(struct ieee80211_hw *dev, |
372 | struct ieee80211_vif *vif, | 362 | struct ieee80211_vif *vif, |
373 | struct ieee80211_bss_conf *info, | 363 | struct ieee80211_bss_conf *info, |
@@ -522,7 +512,6 @@ static const struct ieee80211_ops p54_ops = { | |||
522 | .configure_filter = p54_configure_filter, | 512 | .configure_filter = p54_configure_filter, |
523 | .conf_tx = p54_conf_tx, | 513 | .conf_tx = p54_conf_tx, |
524 | .get_stats = p54_get_stats, | 514 | .get_stats = p54_get_stats, |
525 | .get_tx_stats = p54_get_tx_stats | ||
526 | }; | 515 | }; |
527 | 516 | ||
528 | struct ieee80211_hw *p54_init_common(size_t priv_data_len) | 517 | struct ieee80211_hw *p54_init_common(size_t priv_data_len) |
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1afc39410e8..43a3b2ead81 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h | |||
@@ -157,6 +157,12 @@ struct p54_led_dev { | |||
157 | 157 | ||
158 | #endif /* CONFIG_P54_LEDS */ | 158 | #endif /* CONFIG_P54_LEDS */ |
159 | 159 | ||
160 | struct p54_tx_queue_stats { | ||
161 | unsigned int len; | ||
162 | unsigned int limit; | ||
163 | unsigned int count; | ||
164 | }; | ||
165 | |||
160 | struct p54_common { | 166 | struct p54_common { |
161 | struct ieee80211_hw *hw; | 167 | struct ieee80211_hw *hw; |
162 | struct ieee80211_vif *vif; | 168 | struct ieee80211_vif *vif; |
@@ -183,7 +189,7 @@ struct p54_common { | |||
183 | /* (e)DCF / QOS state */ | 189 | /* (e)DCF / QOS state */ |
184 | bool use_short_slot; | 190 | bool use_short_slot; |
185 | spinlock_t tx_stats_lock; | 191 | spinlock_t tx_stats_lock; |
186 | struct ieee80211_tx_queue_stats tx_stats[8]; | 192 | struct p54_tx_queue_stats tx_stats[8]; |
187 | struct p54_edcf_queue_param qos_params[8]; | 193 | struct p54_edcf_queue_param qos_params[8]; |
188 | 194 | ||
189 | /* Radio data */ | 195 | /* Radio data */ |
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index b6dda2b27fb..0e8f69461ff 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c | |||
@@ -183,7 +183,7 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv, | |||
183 | struct sk_buff *skb, | 183 | struct sk_buff *skb, |
184 | const u16 p54_queue) | 184 | const u16 p54_queue) |
185 | { | 185 | { |
186 | struct ieee80211_tx_queue_stats *queue; | 186 | struct p54_tx_queue_stats *queue; |
187 | unsigned long flags; | 187 | unsigned long flags; |
188 | 188 | ||
189 | if (WARN_ON(p54_queue > P54_QUEUE_NUM)) | 189 | if (WARN_ON(p54_queue > P54_QUEUE_NUM)) |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index aa579eb8723..108982762d4 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1561,7 +1561,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { | |||
1561 | .get_stats = rt2x00mac_get_stats, | 1561 | .get_stats = rt2x00mac_get_stats, |
1562 | .bss_info_changed = rt2x00mac_bss_info_changed, | 1562 | .bss_info_changed = rt2x00mac_bss_info_changed, |
1563 | .conf_tx = rt2400pci_conf_tx, | 1563 | .conf_tx = rt2400pci_conf_tx, |
1564 | .get_tx_stats = rt2x00mac_get_tx_stats, | ||
1565 | .get_tsf = rt2400pci_get_tsf, | 1564 | .get_tsf = rt2400pci_get_tsf, |
1566 | .tx_last_beacon = rt2400pci_tx_last_beacon, | 1565 | .tx_last_beacon = rt2400pci_tx_last_beacon, |
1567 | .rfkill_poll = rt2x00mac_rfkill_poll, | 1566 | .rfkill_poll = rt2x00mac_rfkill_poll, |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 77ee1df7933..f6440bb0e5f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1859,7 +1859,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { | |||
1859 | .get_stats = rt2x00mac_get_stats, | 1859 | .get_stats = rt2x00mac_get_stats, |
1860 | .bss_info_changed = rt2x00mac_bss_info_changed, | 1860 | .bss_info_changed = rt2x00mac_bss_info_changed, |
1861 | .conf_tx = rt2x00mac_conf_tx, | 1861 | .conf_tx = rt2x00mac_conf_tx, |
1862 | .get_tx_stats = rt2x00mac_get_tx_stats, | ||
1863 | .get_tsf = rt2500pci_get_tsf, | 1862 | .get_tsf = rt2500pci_get_tsf, |
1864 | .tx_last_beacon = rt2500pci_tx_last_beacon, | 1863 | .tx_last_beacon = rt2500pci_tx_last_beacon, |
1865 | .rfkill_poll = rt2x00mac_rfkill_poll, | 1864 | .rfkill_poll = rt2x00mac_rfkill_poll, |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 9e6f865c57f..81ca4ec068d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1761,7 +1761,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { | |||
1761 | .get_stats = rt2x00mac_get_stats, | 1761 | .get_stats = rt2x00mac_get_stats, |
1762 | .bss_info_changed = rt2x00mac_bss_info_changed, | 1762 | .bss_info_changed = rt2x00mac_bss_info_changed, |
1763 | .conf_tx = rt2x00mac_conf_tx, | 1763 | .conf_tx = rt2x00mac_conf_tx, |
1764 | .get_tx_stats = rt2x00mac_get_tx_stats, | ||
1765 | .rfkill_poll = rt2x00mac_rfkill_poll, | 1764 | .rfkill_poll = rt2x00mac_rfkill_poll, |
1766 | }; | 1765 | }; |
1767 | 1766 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 529a37364eb..a45e027f2d1 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -2297,7 +2297,6 @@ const struct ieee80211_ops rt2800_mac80211_ops = { | |||
2297 | .set_rts_threshold = rt2800_set_rts_threshold, | 2297 | .set_rts_threshold = rt2800_set_rts_threshold, |
2298 | .bss_info_changed = rt2x00mac_bss_info_changed, | 2298 | .bss_info_changed = rt2x00mac_bss_info_changed, |
2299 | .conf_tx = rt2800_conf_tx, | 2299 | .conf_tx = rt2800_conf_tx, |
2300 | .get_tx_stats = rt2x00mac_get_tx_stats, | ||
2301 | .get_tsf = rt2800_get_tsf, | 2300 | .get_tsf = rt2800_get_tsf, |
2302 | .rfkill_poll = rt2x00mac_rfkill_poll, | 2301 | .rfkill_poll = rt2x00mac_rfkill_poll, |
2303 | }; | 2302 | }; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 096da85a66f..43b70c6e4e9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1044,8 +1044,6 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
1044 | #endif /* CONFIG_RT2X00_LIB_CRYPTO */ | 1044 | #endif /* CONFIG_RT2X00_LIB_CRYPTO */ |
1045 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, | 1045 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, |
1046 | struct ieee80211_low_level_stats *stats); | 1046 | struct ieee80211_low_level_stats *stats); |
1047 | int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, | ||
1048 | struct ieee80211_tx_queue_stats *stats); | ||
1049 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | 1047 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, |
1050 | struct ieee80211_vif *vif, | 1048 | struct ieee80211_vif *vif, |
1051 | struct ieee80211_bss_conf *bss_conf, | 1049 | struct ieee80211_bss_conf *bss_conf, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 00f1f939f1b..abbd857ec75 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -555,22 +555,6 @@ int rt2x00mac_get_stats(struct ieee80211_hw *hw, | |||
555 | } | 555 | } |
556 | EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); | 556 | EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); |
557 | 557 | ||
558 | int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, | ||
559 | struct ieee80211_tx_queue_stats *stats) | ||
560 | { | ||
561 | struct rt2x00_dev *rt2x00dev = hw->priv; | ||
562 | unsigned int i; | ||
563 | |||
564 | for (i = 0; i < rt2x00dev->ops->tx_queues; i++) { | ||
565 | stats[i].len = rt2x00dev->tx[i].length; | ||
566 | stats[i].limit = rt2x00dev->tx[i].limit; | ||
567 | stats[i].count = rt2x00dev->tx[i].count; | ||
568 | } | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); | ||
573 | |||
574 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | 558 | void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, |
575 | struct ieee80211_vif *vif, | 559 | struct ieee80211_vif *vif, |
576 | struct ieee80211_bss_conf *bss_conf, | 560 | struct ieee80211_bss_conf *bss_conf, |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 1f97a797bc4..74de53e68b4 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -2730,7 +2730,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { | |||
2730 | .get_stats = rt2x00mac_get_stats, | 2730 | .get_stats = rt2x00mac_get_stats, |
2731 | .bss_info_changed = rt2x00mac_bss_info_changed, | 2731 | .bss_info_changed = rt2x00mac_bss_info_changed, |
2732 | .conf_tx = rt61pci_conf_tx, | 2732 | .conf_tx = rt61pci_conf_tx, |
2733 | .get_tx_stats = rt2x00mac_get_tx_stats, | ||
2734 | .get_tsf = rt61pci_get_tsf, | 2733 | .get_tsf = rt61pci_get_tsf, |
2735 | .rfkill_poll = rt2x00mac_rfkill_poll, | 2734 | .rfkill_poll = rt2x00mac_rfkill_poll, |
2736 | }; | 2735 | }; |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a0269129439..3781eb7b4aa 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -2245,7 +2245,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { | |||
2245 | .get_stats = rt2x00mac_get_stats, | 2245 | .get_stats = rt2x00mac_get_stats, |
2246 | .bss_info_changed = rt2x00mac_bss_info_changed, | 2246 | .bss_info_changed = rt2x00mac_bss_info_changed, |
2247 | .conf_tx = rt73usb_conf_tx, | 2247 | .conf_tx = rt73usb_conf_tx, |
2248 | .get_tx_stats = rt2x00mac_get_tx_stats, | ||
2249 | .get_tsf = rt73usb_get_tsf, | 2248 | .get_tsf = rt73usb_get_tsf, |
2250 | .rfkill_poll = rt2x00mac_rfkill_poll, | 2249 | .rfkill_poll = rt2x00mac_rfkill_poll, |
2251 | }; | 2250 | }; |
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index a717dde4822..24ae6a360ac 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -1144,9 +1144,10 @@ static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1144 | if (ret < 0) | 1144 | if (ret < 0) |
1145 | goto out; | 1145 | goto out; |
1146 | 1146 | ||
1147 | /* mac80211 uses units of 32 usec */ | ||
1147 | ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), | 1148 | ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), |
1148 | params->cw_min, params->cw_max, | 1149 | params->cw_min, params->cw_max, |
1149 | params->aifs, params->txop); | 1150 | params->aifs, params->txop * 32); |
1150 | if (ret < 0) | 1151 | if (ret < 0) |
1151 | goto out_sleep; | 1152 | goto out_sleep; |
1152 | 1153 | ||
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 3c6feed46f6..97efce184a8 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c | |||
@@ -270,7 +270,6 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) | |||
270 | set_irq(dev, irq++); | 270 | set_irq(dev, irq++); |
271 | } | 271 | } |
272 | break; | 272 | break; |
273 | /* fallthrough */ | ||
274 | case SSB_DEV_PCI: | 273 | case SSB_DEV_PCI: |
275 | case SSB_DEV_ETHERNET: | 274 | case SSB_DEV_ETHERNET: |
276 | case SSB_DEV_ETHERNET_GBIT: | 275 | case SSB_DEV_ETHERNET_GBIT: |
@@ -281,6 +280,10 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) | |||
281 | set_irq(dev, irq++); | 280 | set_irq(dev, irq++); |
282 | break; | 281 | break; |
283 | } | 282 | } |
283 | /* fallthrough */ | ||
284 | case SSB_DEV_EXTIF: | ||
285 | set_irq(dev, 0); | ||
286 | break; | ||
284 | } | 287 | } |
285 | } | 288 | } |
286 | ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n"); | 289 | ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n"); |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 5681ebed9c6..03dfd27c4bf 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -494,8 +494,7 @@ static int ssb_devices_register(struct ssb_bus *bus) | |||
494 | #endif | 494 | #endif |
495 | break; | 495 | break; |
496 | case SSB_BUSTYPE_SDIO: | 496 | case SSB_BUSTYPE_SDIO: |
497 | #ifdef CONFIG_SSB_SDIO | 497 | #ifdef CONFIG_SSB_SDIOHOST |
498 | sdev->irq = bus->host_sdio->dev.irq; | ||
499 | dev->parent = &bus->host_sdio->dev; | 498 | dev->parent = &bus->host_sdio->dev; |
500 | #endif | 499 | #endif |
501 | break; | 500 | break; |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a3f0a7ed31a..5b3569b2a74 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1561,37 +1561,82 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | |||
1561 | * Documentation in Documentation/networking/radiotap-headers.txt | 1561 | * Documentation in Documentation/networking/radiotap-headers.txt |
1562 | */ | 1562 | */ |
1563 | 1563 | ||
1564 | struct radiotap_align_size { | ||
1565 | uint8_t align:4, size:4; | ||
1566 | }; | ||
1567 | |||
1568 | struct ieee80211_radiotap_namespace { | ||
1569 | const struct radiotap_align_size *align_size; | ||
1570 | int n_bits; | ||
1571 | uint32_t oui; | ||
1572 | uint8_t subns; | ||
1573 | }; | ||
1574 | |||
1575 | struct ieee80211_radiotap_vendor_namespaces { | ||
1576 | const struct ieee80211_radiotap_namespace *ns; | ||
1577 | int n_ns; | ||
1578 | }; | ||
1579 | |||
1564 | /** | 1580 | /** |
1565 | * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args | 1581 | * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args |
1566 | * @rtheader: pointer to the radiotap header we are walking through | 1582 | * @this_arg_index: index of current arg, valid after each successful call |
1567 | * @max_length: length of radiotap header in cpu byte ordering | 1583 | * to ieee80211_radiotap_iterator_next() |
1568 | * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg | 1584 | * @this_arg: pointer to current radiotap arg; it is valid after each |
1569 | * @this_arg: pointer to current radiotap arg | 1585 | * call to ieee80211_radiotap_iterator_next() but also after |
1570 | * @arg_index: internal next argument index | 1586 | * ieee80211_radiotap_iterator_init() where it will point to |
1571 | * @arg: internal next argument pointer | 1587 | * the beginning of the actual data portion |
1572 | * @next_bitmap: internal pointer to next present u32 | 1588 | * @this_arg_size: length of the current arg, for convenience |
1573 | * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present | 1589 | * @current_namespace: pointer to the current namespace definition |
1590 | * (or internally %NULL if the current namespace is unknown) | ||
1591 | * @is_radiotap_ns: indicates whether the current namespace is the default | ||
1592 | * radiotap namespace or not | ||
1593 | * | ||
1594 | * @overrides: override standard radiotap fields | ||
1595 | * @n_overrides: number of overrides | ||
1596 | * | ||
1597 | * @_rtheader: pointer to the radiotap header we are walking through | ||
1598 | * @_max_length: length of radiotap header in cpu byte ordering | ||
1599 | * @_arg_index: next argument index | ||
1600 | * @_arg: next argument pointer | ||
1601 | * @_next_bitmap: internal pointer to next present u32 | ||
1602 | * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present | ||
1603 | * @_vns: vendor namespace definitions | ||
1604 | * @_next_ns_data: beginning of the next namespace's data | ||
1605 | * @_reset_on_ext: internal; reset the arg index to 0 when going to the | ||
1606 | * next bitmap word | ||
1607 | * | ||
1608 | * Describes the radiotap parser state. Fields prefixed with an underscore | ||
1609 | * must not be used by users of the parser, only by the parser internally. | ||
1574 | */ | 1610 | */ |
1575 | 1611 | ||
1576 | struct ieee80211_radiotap_iterator { | 1612 | struct ieee80211_radiotap_iterator { |
1577 | struct ieee80211_radiotap_header *rtheader; | 1613 | struct ieee80211_radiotap_header *_rtheader; |
1578 | int max_length; | 1614 | const struct ieee80211_radiotap_vendor_namespaces *_vns; |
1615 | const struct ieee80211_radiotap_namespace *current_namespace; | ||
1616 | |||
1617 | unsigned char *_arg, *_next_ns_data; | ||
1618 | uint32_t *_next_bitmap; | ||
1619 | |||
1620 | unsigned char *this_arg; | ||
1579 | int this_arg_index; | 1621 | int this_arg_index; |
1580 | u8 *this_arg; | 1622 | int this_arg_size; |
1581 | 1623 | ||
1582 | int arg_index; | 1624 | int is_radiotap_ns; |
1583 | u8 *arg; | 1625 | |
1584 | __le32 *next_bitmap; | 1626 | int _max_length; |
1585 | u32 bitmap_shifter; | 1627 | int _arg_index; |
1628 | uint32_t _bitmap_shifter; | ||
1629 | int _reset_on_ext; | ||
1586 | }; | 1630 | }; |
1587 | 1631 | ||
1588 | extern int ieee80211_radiotap_iterator_init( | 1632 | extern int ieee80211_radiotap_iterator_init( |
1589 | struct ieee80211_radiotap_iterator *iterator, | 1633 | struct ieee80211_radiotap_iterator *iterator, |
1590 | struct ieee80211_radiotap_header *radiotap_header, | 1634 | struct ieee80211_radiotap_header *radiotap_header, |
1591 | int max_length); | 1635 | int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns); |
1592 | 1636 | ||
1593 | extern int ieee80211_radiotap_iterator_next( | 1637 | extern int ieee80211_radiotap_iterator_next( |
1594 | struct ieee80211_radiotap_iterator *iterator); | 1638 | struct ieee80211_radiotap_iterator *iterator); |
1639 | |||
1595 | 1640 | ||
1596 | extern const unsigned char rfc1042_header[6]; | 1641 | extern const unsigned char rfc1042_header[6]; |
1597 | extern const unsigned char bridge_tunnel_header[6]; | 1642 | extern const unsigned char bridge_tunnel_header[6]; |
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index 9d3d86aaccb..af49f8ab7f8 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h | |||
@@ -198,6 +198,10 @@ enum ieee80211_radiotap_type { | |||
198 | IEEE80211_RADIOTAP_TX_FLAGS = 15, | 198 | IEEE80211_RADIOTAP_TX_FLAGS = 15, |
199 | IEEE80211_RADIOTAP_RTS_RETRIES = 16, | 199 | IEEE80211_RADIOTAP_RTS_RETRIES = 16, |
200 | IEEE80211_RADIOTAP_DATA_RETRIES = 17, | 200 | IEEE80211_RADIOTAP_DATA_RETRIES = 17, |
201 | |||
202 | /* valid in every it_present bitmap, even vendor namespaces */ | ||
203 | IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, | ||
204 | IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, | ||
201 | IEEE80211_RADIOTAP_EXT = 31 | 205 | IEEE80211_RADIOTAP_EXT = 31 |
202 | }; | 206 | }; |
203 | 207 | ||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 74ccf30fdf8..314e9817316 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -117,19 +117,6 @@ struct ieee80211_tx_queue_params { | |||
117 | bool uapsd; | 117 | bool uapsd; |
118 | }; | 118 | }; |
119 | 119 | ||
120 | /** | ||
121 | * struct ieee80211_tx_queue_stats - transmit queue statistics | ||
122 | * | ||
123 | * @len: number of packets in queue | ||
124 | * @limit: queue length limit | ||
125 | * @count: number of frames sent | ||
126 | */ | ||
127 | struct ieee80211_tx_queue_stats { | ||
128 | unsigned int len; | ||
129 | unsigned int limit; | ||
130 | unsigned int count; | ||
131 | }; | ||
132 | |||
133 | struct ieee80211_low_level_stats { | 120 | struct ieee80211_low_level_stats { |
134 | unsigned int dot11ACKFailureCount; | 121 | unsigned int dot11ACKFailureCount; |
135 | unsigned int dot11RTSFailureCount; | 122 | unsigned int dot11RTSFailureCount; |
@@ -814,7 +801,7 @@ enum set_key_cmd { | |||
814 | * mac80211, any ieee80211_sta pointer you get access to must | 801 | * mac80211, any ieee80211_sta pointer you get access to must |
815 | * either be protected by rcu_read_lock() explicitly or implicitly, | 802 | * either be protected by rcu_read_lock() explicitly or implicitly, |
816 | * or you must take good care to not use such a pointer after a | 803 | * or you must take good care to not use such a pointer after a |
817 | * call to your sta_notify callback that removed it. | 804 | * call to your sta_remove callback that removed it. |
818 | * | 805 | * |
819 | * @addr: MAC address | 806 | * @addr: MAC address |
820 | * @aid: AID we assigned to the station if we're an AP | 807 | * @aid: AID we assigned to the station if we're an AP |
@@ -840,8 +827,8 @@ struct ieee80211_sta { | |||
840 | * indicates addition and removal of a station to station table, | 827 | * indicates addition and removal of a station to station table, |
841 | * or if a associated station made a power state transition. | 828 | * or if a associated station made a power state transition. |
842 | * | 829 | * |
843 | * @STA_NOTIFY_ADD: a station was added to the station table | 830 | * @STA_NOTIFY_ADD: (DEPRECATED) a station was added to the station table |
844 | * @STA_NOTIFY_REMOVE: a station being removed from the station table | 831 | * @STA_NOTIFY_REMOVE: (DEPRECATED) a station being removed from the station table |
845 | * @STA_NOTIFY_SLEEP: a station is now sleeping | 832 | * @STA_NOTIFY_SLEEP: a station is now sleeping |
846 | * @STA_NOTIFY_AWAKE: a sleeping station woke up | 833 | * @STA_NOTIFY_AWAKE: a sleeping station woke up |
847 | */ | 834 | */ |
@@ -958,6 +945,11 @@ enum ieee80211_tkip_key_type { | |||
958 | * Hardware supports Unscheduled Automatic Power Save Delivery | 945 | * Hardware supports Unscheduled Automatic Power Save Delivery |
959 | * (U-APSD) in managed mode. The mode is configured with | 946 | * (U-APSD) in managed mode. The mode is configured with |
960 | * conf_tx() operation. | 947 | * conf_tx() operation. |
948 | * | ||
949 | * @IEEE80211_HW_REPORTS_TX_ACK_STATUS: | ||
950 | * Hardware can provide ack status reports of Tx frames to | ||
951 | * the stack. | ||
952 | * | ||
961 | */ | 953 | */ |
962 | enum ieee80211_hw_flags { | 954 | enum ieee80211_hw_flags { |
963 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, | 955 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, |
@@ -978,6 +970,7 @@ enum ieee80211_hw_flags { | |||
978 | IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, | 970 | IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, |
979 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, | 971 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, |
980 | IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, | 972 | IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, |
973 | IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, | ||
981 | }; | 974 | }; |
982 | 975 | ||
983 | /** | 976 | /** |
@@ -1534,22 +1527,20 @@ enum ieee80211_ampdu_mlme_action { | |||
1534 | * @set_rts_threshold: Configuration of RTS threshold (if device needs it) | 1527 | * @set_rts_threshold: Configuration of RTS threshold (if device needs it) |
1535 | * The callback can sleep. | 1528 | * The callback can sleep. |
1536 | * | 1529 | * |
1537 | * @sta_notify: Notifies low level driver about addition, removal or power | 1530 | * @sta_add: Notifies low level driver about addition of an associated station, |
1538 | * state transition of an associated station, AP, IBSS/WDS/mesh peer etc. | 1531 | * AP, IBSS/WDS/mesh peer etc. This callback can sleep. |
1539 | * Must be atomic. | 1532 | * |
1533 | * @sta_remove: Notifies low level driver about removal of an associated | ||
1534 | * station, AP, IBSS/WDS/mesh peer etc. This callback can sleep. | ||
1535 | * | ||
1536 | * @sta_notify: Notifies low level driver about power state transition of an | ||
1537 | * associated station, AP, IBSS/WDS/mesh peer etc. Must be atomic. | ||
1540 | * | 1538 | * |
1541 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), | 1539 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), |
1542 | * bursting) for a hardware TX queue. | 1540 | * bursting) for a hardware TX queue. |
1543 | * Returns a negative error code on failure. | 1541 | * Returns a negative error code on failure. |
1544 | * The callback can sleep. | 1542 | * The callback can sleep. |
1545 | * | 1543 | * |
1546 | * @get_tx_stats: Get statistics of the current TX queue status. This is used | ||
1547 | * to get number of currently queued packets (queue length), maximum queue | ||
1548 | * size (limit), and total number of packets sent using each TX queue | ||
1549 | * (count). The 'stats' pointer points to an array that has hw->queues | ||
1550 | * items. | ||
1551 | * The callback must be atomic. | ||
1552 | * | ||
1553 | * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, | 1544 | * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, |
1554 | * this is only used for IBSS mode BSSID merging and debugging. Is not a | 1545 | * this is only used for IBSS mode BSSID merging and debugging. Is not a |
1555 | * required function. | 1546 | * required function. |
@@ -1635,12 +1626,14 @@ struct ieee80211_ops { | |||
1635 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, | 1626 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, |
1636 | u32 *iv32, u16 *iv16); | 1627 | u32 *iv32, u16 *iv16); |
1637 | int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); | 1628 | int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); |
1629 | int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
1630 | struct ieee80211_sta *sta); | ||
1631 | int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
1632 | struct ieee80211_sta *sta); | ||
1638 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1633 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1639 | enum sta_notify_cmd, struct ieee80211_sta *sta); | 1634 | enum sta_notify_cmd, struct ieee80211_sta *sta); |
1640 | int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, | 1635 | int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, |
1641 | const struct ieee80211_tx_queue_params *params); | 1636 | const struct ieee80211_tx_queue_params *params); |
1642 | int (*get_tx_stats)(struct ieee80211_hw *hw, | ||
1643 | struct ieee80211_tx_queue_stats *stats); | ||
1644 | u64 (*get_tsf)(struct ieee80211_hw *hw); | 1637 | u64 (*get_tsf)(struct ieee80211_hw *hw); |
1645 | void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf); | 1638 | void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf); |
1646 | void (*reset_tsf)(struct ieee80211_hw *hw); | 1639 | void (*reset_tsf)(struct ieee80211_hw *hw); |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 718fbcff84d..5538e1b4a69 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -237,6 +237,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
237 | sdata->vif.type != NL80211_IFTYPE_AP) | 237 | sdata->vif.type != NL80211_IFTYPE_AP) |
238 | return -EINVAL; | 238 | return -EINVAL; |
239 | 239 | ||
240 | if (test_sta_flags(sta, WLAN_STA_DISASSOC)) { | ||
241 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
242 | printk(KERN_DEBUG "Disassociation is in progress. " | ||
243 | "Denying BA session request\n"); | ||
244 | #endif | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
240 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { | 248 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { |
241 | #ifdef CONFIG_MAC80211_HT_DEBUG | 249 | #ifdef CONFIG_MAC80211_HT_DEBUG |
242 | printk(KERN_DEBUG "Suspend in progress. " | 250 | printk(KERN_DEBUG "Suspend in progress. " |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index facf233843e..e1731b7c252 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -515,6 +515,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
515 | if (old) | 515 | if (old) |
516 | memcpy(new->tail, old->tail, new_tail_len); | 516 | memcpy(new->tail, old->tail, new_tail_len); |
517 | 517 | ||
518 | sdata->vif.bss_conf.dtim_period = new->dtim_period; | ||
519 | |||
518 | rcu_assign_pointer(sdata->u.ap.beacon, new); | 520 | rcu_assign_pointer(sdata->u.ap.beacon, new); |
519 | 521 | ||
520 | synchronize_rcu(); | 522 | synchronize_rcu(); |
@@ -747,9 +749,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
747 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 749 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
748 | sdata->vif.type == NL80211_IFTYPE_AP; | 750 | sdata->vif.type == NL80211_IFTYPE_AP; |
749 | 751 | ||
750 | rcu_read_lock(); | 752 | err = sta_info_insert_rcu(sta); |
751 | |||
752 | err = sta_info_insert(sta); | ||
753 | if (err) { | 753 | if (err) { |
754 | rcu_read_unlock(); | 754 | rcu_read_unlock(); |
755 | return err; | 755 | return err; |
@@ -768,26 +768,13 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
768 | { | 768 | { |
769 | struct ieee80211_local *local = wiphy_priv(wiphy); | 769 | struct ieee80211_local *local = wiphy_priv(wiphy); |
770 | struct ieee80211_sub_if_data *sdata; | 770 | struct ieee80211_sub_if_data *sdata; |
771 | struct sta_info *sta; | ||
772 | 771 | ||
773 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 772 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
774 | 773 | ||
775 | if (mac) { | 774 | if (mac) |
776 | rcu_read_lock(); | 775 | return sta_info_destroy_addr_bss(sdata, mac); |
777 | |||
778 | sta = sta_info_get_bss(sdata, mac); | ||
779 | if (!sta) { | ||
780 | rcu_read_unlock(); | ||
781 | return -ENOENT; | ||
782 | } | ||
783 | |||
784 | sta_info_unlink(&sta); | ||
785 | rcu_read_unlock(); | ||
786 | |||
787 | sta_info_destroy(sta); | ||
788 | } else | ||
789 | sta_info_flush(local, sdata); | ||
790 | 776 | ||
777 | sta_info_flush(local, sdata); | ||
791 | return 0; | 778 | return 0; |
792 | } | 779 | } |
793 | 780 | ||
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index b3bc32b62a5..637929b65cc 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -250,6 +250,38 @@ static const struct file_operations uapsd_max_sp_len_ops = { | |||
250 | .open = mac80211_open_file_generic | 250 | .open = mac80211_open_file_generic |
251 | }; | 251 | }; |
252 | 252 | ||
253 | static ssize_t channel_type_read(struct file *file, char __user *user_buf, | ||
254 | size_t count, loff_t *ppos) | ||
255 | { | ||
256 | struct ieee80211_local *local = file->private_data; | ||
257 | const char *buf; | ||
258 | |||
259 | switch (local->hw.conf.channel_type) { | ||
260 | case NL80211_CHAN_NO_HT: | ||
261 | buf = "no ht\n"; | ||
262 | break; | ||
263 | case NL80211_CHAN_HT20: | ||
264 | buf = "ht20\n"; | ||
265 | break; | ||
266 | case NL80211_CHAN_HT40MINUS: | ||
267 | buf = "ht40-\n"; | ||
268 | break; | ||
269 | case NL80211_CHAN_HT40PLUS: | ||
270 | buf = "ht40+\n"; | ||
271 | break; | ||
272 | default: | ||
273 | buf = "???"; | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | ||
278 | } | ||
279 | |||
280 | static const struct file_operations channel_type_ops = { | ||
281 | .read = channel_type_read, | ||
282 | .open = mac80211_open_file_generic | ||
283 | }; | ||
284 | |||
253 | static ssize_t queues_read(struct file *file, char __user *user_buf, | 285 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
254 | size_t count, loff_t *ppos) | 286 | size_t count, loff_t *ppos) |
255 | { | 287 | { |
@@ -408,6 +440,7 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
408 | DEBUGFS_ADD(noack); | 440 | DEBUGFS_ADD(noack); |
409 | DEBUGFS_ADD(uapsd_queues); | 441 | DEBUGFS_ADD(uapsd_queues); |
410 | DEBUGFS_ADD(uapsd_max_sp_len); | 442 | DEBUGFS_ADD(uapsd_max_sp_len); |
443 | DEBUGFS_ADD(channel_type); | ||
411 | 444 | ||
412 | statsd = debugfs_create_dir("statistics", phyd); | 445 | statsd = debugfs_create_dir("statistics", phyd); |
413 | 446 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 6c31f38ac7f..c3d844093a2 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -243,6 +243,40 @@ static inline void drv_sta_notify(struct ieee80211_local *local, | |||
243 | trace_drv_sta_notify(local, sdata, cmd, sta); | 243 | trace_drv_sta_notify(local, sdata, cmd, sta); |
244 | } | 244 | } |
245 | 245 | ||
246 | static inline int drv_sta_add(struct ieee80211_local *local, | ||
247 | struct ieee80211_sub_if_data *sdata, | ||
248 | struct ieee80211_sta *sta) | ||
249 | { | ||
250 | int ret = 0; | ||
251 | |||
252 | might_sleep(); | ||
253 | |||
254 | if (local->ops->sta_add) | ||
255 | ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); | ||
256 | else if (local->ops->sta_notify) | ||
257 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
258 | STA_NOTIFY_ADD, sta); | ||
259 | |||
260 | trace_drv_sta_add(local, sdata, sta, ret); | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | static inline void drv_sta_remove(struct ieee80211_local *local, | ||
266 | struct ieee80211_sub_if_data *sdata, | ||
267 | struct ieee80211_sta *sta) | ||
268 | { | ||
269 | might_sleep(); | ||
270 | |||
271 | if (local->ops->sta_remove) | ||
272 | local->ops->sta_remove(&local->hw, &sdata->vif, sta); | ||
273 | else if (local->ops->sta_notify) | ||
274 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
275 | STA_NOTIFY_REMOVE, sta); | ||
276 | |||
277 | trace_drv_sta_remove(local, sdata, sta); | ||
278 | } | ||
279 | |||
246 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | 280 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, |
247 | const struct ieee80211_tx_queue_params *params) | 281 | const struct ieee80211_tx_queue_params *params) |
248 | { | 282 | { |
@@ -256,14 +290,6 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | |||
256 | return ret; | 290 | return ret; |
257 | } | 291 | } |
258 | 292 | ||
259 | static inline int drv_get_tx_stats(struct ieee80211_local *local, | ||
260 | struct ieee80211_tx_queue_stats *stats) | ||
261 | { | ||
262 | int ret = local->ops->get_tx_stats(&local->hw, stats); | ||
263 | trace_drv_get_tx_stats(local, stats, ret); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static inline u64 drv_get_tsf(struct ieee80211_local *local) | 293 | static inline u64 drv_get_tsf(struct ieee80211_local *local) |
268 | { | 294 | { |
269 | u64 ret = -1ULL; | 295 | u64 ret = -1ULL; |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 502424b2538..41baf730a5c 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -545,59 +545,88 @@ TRACE_EVENT(drv_sta_notify, | |||
545 | ) | 545 | ) |
546 | ); | 546 | ); |
547 | 547 | ||
548 | TRACE_EVENT(drv_conf_tx, | 548 | TRACE_EVENT(drv_sta_add, |
549 | TP_PROTO(struct ieee80211_local *local, u16 queue, | 549 | TP_PROTO(struct ieee80211_local *local, |
550 | const struct ieee80211_tx_queue_params *params, | 550 | struct ieee80211_sub_if_data *sdata, |
551 | int ret), | 551 | struct ieee80211_sta *sta, int ret), |
552 | 552 | ||
553 | TP_ARGS(local, queue, params, ret), | 553 | TP_ARGS(local, sdata, sta, ret), |
554 | 554 | ||
555 | TP_STRUCT__entry( | 555 | TP_STRUCT__entry( |
556 | LOCAL_ENTRY | 556 | LOCAL_ENTRY |
557 | __field(u16, queue) | 557 | VIF_ENTRY |
558 | __field(u16, txop) | 558 | STA_ENTRY |
559 | __field(u16, cw_min) | ||
560 | __field(u16, cw_max) | ||
561 | __field(u8, aifs) | ||
562 | __field(int, ret) | 559 | __field(int, ret) |
563 | ), | 560 | ), |
564 | 561 | ||
565 | TP_fast_assign( | 562 | TP_fast_assign( |
566 | LOCAL_ASSIGN; | 563 | LOCAL_ASSIGN; |
567 | __entry->queue = queue; | 564 | VIF_ASSIGN; |
565 | STA_ASSIGN; | ||
568 | __entry->ret = ret; | 566 | __entry->ret = ret; |
569 | __entry->txop = params->txop; | ||
570 | __entry->cw_max = params->cw_max; | ||
571 | __entry->cw_min = params->cw_min; | ||
572 | __entry->aifs = params->aifs; | ||
573 | ), | 567 | ), |
574 | 568 | ||
575 | TP_printk( | 569 | TP_printk( |
576 | LOCAL_PR_FMT " queue:%d ret:%d", | 570 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d", |
577 | LOCAL_PR_ARG, __entry->queue, __entry->ret | 571 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret |
578 | ) | 572 | ) |
579 | ); | 573 | ); |
580 | 574 | ||
581 | TRACE_EVENT(drv_get_tx_stats, | 575 | TRACE_EVENT(drv_sta_remove, |
582 | TP_PROTO(struct ieee80211_local *local, | 576 | TP_PROTO(struct ieee80211_local *local, |
583 | struct ieee80211_tx_queue_stats *stats, | 577 | struct ieee80211_sub_if_data *sdata, |
578 | struct ieee80211_sta *sta), | ||
579 | |||
580 | TP_ARGS(local, sdata, sta), | ||
581 | |||
582 | TP_STRUCT__entry( | ||
583 | LOCAL_ENTRY | ||
584 | VIF_ENTRY | ||
585 | STA_ENTRY | ||
586 | ), | ||
587 | |||
588 | TP_fast_assign( | ||
589 | LOCAL_ASSIGN; | ||
590 | VIF_ASSIGN; | ||
591 | STA_ASSIGN; | ||
592 | ), | ||
593 | |||
594 | TP_printk( | ||
595 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT, | ||
596 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | ||
597 | ) | ||
598 | ); | ||
599 | |||
600 | TRACE_EVENT(drv_conf_tx, | ||
601 | TP_PROTO(struct ieee80211_local *local, u16 queue, | ||
602 | const struct ieee80211_tx_queue_params *params, | ||
584 | int ret), | 603 | int ret), |
585 | 604 | ||
586 | TP_ARGS(local, stats, ret), | 605 | TP_ARGS(local, queue, params, ret), |
587 | 606 | ||
588 | TP_STRUCT__entry( | 607 | TP_STRUCT__entry( |
589 | LOCAL_ENTRY | 608 | LOCAL_ENTRY |
609 | __field(u16, queue) | ||
610 | __field(u16, txop) | ||
611 | __field(u16, cw_min) | ||
612 | __field(u16, cw_max) | ||
613 | __field(u8, aifs) | ||
590 | __field(int, ret) | 614 | __field(int, ret) |
591 | ), | 615 | ), |
592 | 616 | ||
593 | TP_fast_assign( | 617 | TP_fast_assign( |
594 | LOCAL_ASSIGN; | 618 | LOCAL_ASSIGN; |
619 | __entry->queue = queue; | ||
595 | __entry->ret = ret; | 620 | __entry->ret = ret; |
621 | __entry->txop = params->txop; | ||
622 | __entry->cw_max = params->cw_max; | ||
623 | __entry->cw_min = params->cw_min; | ||
624 | __entry->aifs = params->aifs; | ||
596 | ), | 625 | ), |
597 | 626 | ||
598 | TP_printk( | 627 | TP_printk( |
599 | LOCAL_PR_FMT " ret:%d", | 628 | LOCAL_PR_FMT " queue:%d ret:%d", |
600 | LOCAL_PR_ARG, __entry->ret | 629 | LOCAL_PR_ARG, __entry->queue, __entry->ret |
601 | ) | 630 | ) |
602 | ); | 631 | ); |
603 | 632 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f95750b423e..f3e94248674 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -275,10 +275,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
275 | (unsigned long long) supp_rates, | 275 | (unsigned long long) supp_rates, |
276 | (unsigned long long) sta->sta.supp_rates[band]); | 276 | (unsigned long long) sta->sta.supp_rates[band]); |
277 | #endif | 277 | #endif |
278 | } else | 278 | rcu_read_unlock(); |
279 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 279 | } else { |
280 | 280 | rcu_read_unlock(); | |
281 | rcu_read_unlock(); | 281 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
282 | supp_rates, GFP_KERNEL); | ||
283 | } | ||
282 | } | 284 | } |
283 | 285 | ||
284 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 286 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
@@ -368,7 +370,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
368 | sdata->name, mgmt->bssid); | 370 | sdata->name, mgmt->bssid); |
369 | #endif | 371 | #endif |
370 | ieee80211_sta_join_ibss(sdata, bss); | 372 | ieee80211_sta_join_ibss(sdata, bss); |
371 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 373 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
374 | supp_rates, GFP_KERNEL); | ||
372 | } | 375 | } |
373 | 376 | ||
374 | put_bss: | 377 | put_bss: |
@@ -381,7 +384,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
381 | * must be callable in atomic context. | 384 | * must be callable in atomic context. |
382 | */ | 385 | */ |
383 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 386 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
384 | u8 *bssid,u8 *addr, u32 supp_rates) | 387 | u8 *bssid,u8 *addr, u32 supp_rates, |
388 | gfp_t gfp) | ||
385 | { | 389 | { |
386 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 390 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
387 | struct ieee80211_local *local = sdata->local; | 391 | struct ieee80211_local *local = sdata->local; |
@@ -410,7 +414,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
410 | wiphy_name(local->hw.wiphy), addr, sdata->name); | 414 | wiphy_name(local->hw.wiphy), addr, sdata->name); |
411 | #endif | 415 | #endif |
412 | 416 | ||
413 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 417 | sta = sta_info_alloc(sdata, addr, gfp); |
414 | if (!sta) | 418 | if (!sta) |
415 | return NULL; | 419 | return NULL; |
416 | 420 | ||
@@ -422,9 +426,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
422 | 426 | ||
423 | rate_control_rate_init(sta); | 427 | rate_control_rate_init(sta); |
424 | 428 | ||
429 | /* If it fails, maybe we raced another insertion? */ | ||
425 | if (sta_info_insert(sta)) | 430 | if (sta_info_insert(sta)) |
426 | return NULL; | 431 | return sta_info_get(sdata, addr); |
427 | |||
428 | return sta; | 432 | return sta; |
429 | } | 433 | } |
430 | 434 | ||
@@ -652,7 +656,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
652 | } | 656 | } |
653 | if (pos[1] != 0 && | 657 | if (pos[1] != 0 && |
654 | (pos[1] != ifibss->ssid_len || | 658 | (pos[1] != ifibss->ssid_len || |
655 | !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { | 659 | memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { |
656 | /* Ignore ProbeReq for foreign SSID */ | 660 | /* Ignore ProbeReq for foreign SSID */ |
657 | return; | 661 | return; |
658 | } | 662 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3067fbd69d6..9dd98b674cb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -316,6 +316,7 @@ enum ieee80211_sta_flags { | |||
316 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 316 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
317 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 317 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
318 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 318 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
319 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), | ||
319 | }; | 320 | }; |
320 | 321 | ||
321 | struct ieee80211_if_managed { | 322 | struct ieee80211_if_managed { |
@@ -688,15 +689,18 @@ struct ieee80211_local { | |||
688 | 689 | ||
689 | /* Station data */ | 690 | /* Station data */ |
690 | /* | 691 | /* |
691 | * The lock only protects the list, hash, timer and counter | 692 | * The mutex only protects the list and counter, |
692 | * against manipulation, reads are done in RCU. Additionally, | 693 | * reads are done in RCU. |
693 | * the lock protects each BSS's TIM bitmap. | 694 | * Additionally, the lock protects the hash table, |
695 | * the pending list and each BSS's TIM bitmap. | ||
694 | */ | 696 | */ |
697 | struct mutex sta_mtx; | ||
695 | spinlock_t sta_lock; | 698 | spinlock_t sta_lock; |
696 | unsigned long num_sta; | 699 | unsigned long num_sta; |
697 | struct list_head sta_list; | 700 | struct list_head sta_list, sta_pending_list; |
698 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 701 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
699 | struct timer_list sta_cleanup; | 702 | struct timer_list sta_cleanup; |
703 | struct work_struct sta_finish_work; | ||
700 | int sta_generation; | 704 | int sta_generation; |
701 | 705 | ||
702 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 706 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
@@ -770,10 +774,6 @@ struct ieee80211_local { | |||
770 | assoc_led_name[32], radio_led_name[32]; | 774 | assoc_led_name[32], radio_led_name[32]; |
771 | #endif | 775 | #endif |
772 | 776 | ||
773 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
774 | struct work_struct sta_debugfs_add; | ||
775 | #endif | ||
776 | |||
777 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 777 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
778 | /* TX/RX handler statistics */ | 778 | /* TX/RX handler statistics */ |
779 | unsigned int tx_handlers_drop; | 779 | unsigned int tx_handlers_drop; |
@@ -985,7 +985,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); | |||
985 | ieee80211_rx_result | 985 | ieee80211_rx_result |
986 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 986 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
987 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 987 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
988 | u8 *bssid, u8 *addr, u32 supp_rates); | 988 | u8 *bssid, u8 *addr, u32 supp_rates, |
989 | gfp_t gfp); | ||
989 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 990 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
990 | struct cfg80211_ibss_params *params); | 991 | struct cfg80211_ibss_params *params); |
991 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 992 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 7985e515089..bc4e20e57ff 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -102,7 +102,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
102 | if (local->num_sta >= MESH_MAX_PLINKS) | 102 | if (local->num_sta >= MESH_MAX_PLINKS) |
103 | return NULL; | 103 | return NULL; |
104 | 104 | ||
105 | sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); | 105 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); |
106 | if (!sta) | 106 | if (!sta) |
107 | return NULL; | 107 | return NULL; |
108 | 108 | ||
@@ -236,12 +236,12 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
236 | 236 | ||
237 | sta = sta_info_get(sdata, hw_addr); | 237 | sta = sta_info_get(sdata, hw_addr); |
238 | if (!sta) { | 238 | if (!sta) { |
239 | rcu_read_unlock(); | ||
240 | |||
239 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | 241 | sta = mesh_plink_alloc(sdata, hw_addr, rates); |
240 | if (!sta) { | 242 | if (!sta) |
241 | rcu_read_unlock(); | ||
242 | return; | 243 | return; |
243 | } | 244 | if (sta_info_insert_rcu(sta)) { |
244 | if (sta_info_insert(sta)) { | ||
245 | rcu_read_unlock(); | 245 | rcu_read_unlock(); |
246 | return; | 246 | return; |
247 | } | 247 | } |
@@ -485,9 +485,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
485 | } else if (!sta) { | 485 | } else if (!sta) { |
486 | /* ftype == PLINK_OPEN */ | 486 | /* ftype == PLINK_OPEN */ |
487 | u32 rates; | 487 | u32 rates; |
488 | |||
489 | rcu_read_unlock(); | ||
490 | |||
488 | if (!mesh_plink_free_count(sdata)) { | 491 | if (!mesh_plink_free_count(sdata)) { |
489 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 492 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
490 | rcu_read_unlock(); | ||
491 | return; | 493 | return; |
492 | } | 494 | } |
493 | 495 | ||
@@ -495,10 +497,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
495 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); | 497 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); |
496 | if (!sta) { | 498 | if (!sta) { |
497 | mpl_dbg("Mesh plink error: plink table full\n"); | 499 | mpl_dbg("Mesh plink error: plink table full\n"); |
498 | rcu_read_unlock(); | ||
499 | return; | 500 | return; |
500 | } | 501 | } |
501 | if (sta_info_insert(sta)) { | 502 | if (sta_info_insert_rcu(sta)) { |
502 | rcu_read_unlock(); | 503 | rcu_read_unlock(); |
503 | return; | 504 | return; |
504 | } | 505 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86c6ad1b058..bfc4a507001 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -27,10 +27,6 @@ | |||
27 | #include "rate.h" | 27 | #include "rate.h" |
28 | #include "led.h" | 28 | #include "led.h" |
29 | 29 | ||
30 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
31 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
33 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
34 | #define IEEE80211_MAX_PROBE_TRIES 5 | 30 | #define IEEE80211_MAX_PROBE_TRIES 5 |
35 | 31 | ||
36 | /* | 32 | /* |
@@ -438,8 +434,11 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, | |||
438 | } else { | 434 | } else { |
439 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 435 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
440 | ieee80211_send_nullfunc(local, sdata, 1); | 436 | ieee80211_send_nullfunc(local, sdata, 1); |
441 | conf->flags |= IEEE80211_CONF_PS; | 437 | |
442 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 438 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
439 | conf->flags |= IEEE80211_CONF_PS; | ||
440 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
441 | } | ||
443 | } | 442 | } |
444 | } | 443 | } |
445 | 444 | ||
@@ -545,6 +544,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
545 | container_of(work, struct ieee80211_local, | 544 | container_of(work, struct ieee80211_local, |
546 | dynamic_ps_enable_work); | 545 | dynamic_ps_enable_work); |
547 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 546 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
547 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
548 | 548 | ||
549 | /* can only happen when PS was just disabled anyway */ | 549 | /* can only happen when PS was just disabled anyway */ |
550 | if (!sdata) | 550 | if (!sdata) |
@@ -553,11 +553,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
553 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 553 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
554 | return; | 554 | return; |
555 | 555 | ||
556 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 556 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
557 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) | ||
557 | ieee80211_send_nullfunc(local, sdata, 1); | 558 | ieee80211_send_nullfunc(local, sdata, 1); |
558 | 559 | ||
559 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 560 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) || |
560 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 561 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { |
562 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
563 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
564 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
565 | } | ||
561 | } | 566 | } |
562 | 567 | ||
563 | void ieee80211_dynamic_ps_timer(unsigned long data) | 568 | void ieee80211_dynamic_ps_timer(unsigned long data) |
@@ -792,8 +797,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
792 | 797 | ||
793 | rcu_read_lock(); | 798 | rcu_read_lock(); |
794 | sta = sta_info_get(sdata, bssid); | 799 | sta = sta_info_get(sdata, bssid); |
795 | if (sta) | 800 | if (sta) { |
801 | set_sta_flags(sta, WLAN_STA_DISASSOC); | ||
796 | ieee80211_sta_tear_down_BA_sessions(sta); | 802 | ieee80211_sta_tear_down_BA_sessions(sta); |
803 | } | ||
797 | rcu_read_unlock(); | 804 | rcu_read_unlock(); |
798 | 805 | ||
799 | changed |= ieee80211_reset_erp_info(sdata); | 806 | changed |= ieee80211_reset_erp_info(sdata); |
@@ -826,19 +833,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
826 | changed |= BSS_CHANGED_BSSID; | 833 | changed |= BSS_CHANGED_BSSID; |
827 | ieee80211_bss_info_change_notify(sdata, changed); | 834 | ieee80211_bss_info_change_notify(sdata, changed); |
828 | 835 | ||
829 | rcu_read_lock(); | 836 | sta_info_destroy_addr(sdata, bssid); |
830 | |||
831 | sta = sta_info_get(sdata, bssid); | ||
832 | if (!sta) { | ||
833 | rcu_read_unlock(); | ||
834 | return; | ||
835 | } | ||
836 | |||
837 | sta_info_unlink(&sta); | ||
838 | |||
839 | rcu_read_unlock(); | ||
840 | |||
841 | sta_info_destroy(sta); | ||
842 | } | 837 | } |
843 | 838 | ||
844 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 839 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -1844,7 +1839,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
1844 | wk->probe_auth.algorithm = auth_alg; | 1839 | wk->probe_auth.algorithm = auth_alg; |
1845 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; | 1840 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; |
1846 | 1841 | ||
1847 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | 1842 | /* if we already have a probe, don't probe again */ |
1843 | if (req->bss->proberesp_ies) | ||
1844 | wk->type = IEEE80211_WORK_AUTH; | ||
1845 | else | ||
1846 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | ||
1848 | wk->chan = req->bss->channel; | 1847 | wk->chan = req->bss->channel; |
1849 | wk->sdata = sdata; | 1848 | wk->sdata = sdata; |
1850 | wk->done = ieee80211_probe_auth_done; | 1849 | wk->done = ieee80211_probe_auth_done; |
@@ -1904,6 +1903,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
1904 | return -ENOMEM; | 1903 | return -ENOMEM; |
1905 | 1904 | ||
1906 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 1905 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
1906 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
1907 | 1907 | ||
1908 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | 1908 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) |
1909 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 1909 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
@@ -2007,12 +2007,18 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2007 | 2007 | ||
2008 | mutex_lock(&local->work_mtx); | 2008 | mutex_lock(&local->work_mtx); |
2009 | list_for_each_entry(wk, &local->work_list, list) { | 2009 | list_for_each_entry(wk, &local->work_list, list) { |
2010 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | 2010 | if (wk->sdata != sdata) |
2011 | continue; | ||
2012 | |||
2013 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && | ||
2014 | wk->type != IEEE80211_WORK_AUTH) | ||
2011 | continue; | 2015 | continue; |
2016 | |||
2012 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | 2017 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) |
2013 | continue; | 2018 | continue; |
2014 | not_auth_yet = true; | 2019 | |
2015 | list_del(&wk->list); | 2020 | not_auth_yet = wk->type == IEEE80211_WORK_DIRECT_PROBE; |
2021 | list_del_rcu(&wk->list); | ||
2016 | free_work(wk); | 2022 | free_work(wk); |
2017 | break; | 2023 | break; |
2018 | } | 2024 | } |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 47f818959ad..0e64484e861 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -11,7 +11,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
11 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
13 | struct sta_info *sta; | 13 | struct sta_info *sta; |
14 | unsigned long flags; | ||
15 | 14 | ||
16 | ieee80211_scan_cancel(local); | 15 | ieee80211_scan_cancel(local); |
17 | 16 | ||
@@ -55,22 +54,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
55 | rcu_read_unlock(); | 54 | rcu_read_unlock(); |
56 | 55 | ||
57 | /* remove STAs */ | 56 | /* remove STAs */ |
58 | spin_lock_irqsave(&local->sta_lock, flags); | 57 | mutex_lock(&local->sta_mtx); |
59 | list_for_each_entry(sta, &local->sta_list, list) { | 58 | list_for_each_entry(sta, &local->sta_list, list) { |
60 | if (local->ops->sta_notify) { | 59 | if (sta->uploaded) { |
61 | sdata = sta->sdata; | 60 | sdata = sta->sdata; |
62 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 61 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
63 | sdata = container_of(sdata->bss, | 62 | sdata = container_of(sdata->bss, |
64 | struct ieee80211_sub_if_data, | 63 | struct ieee80211_sub_if_data, |
65 | u.ap); | 64 | u.ap); |
66 | 65 | ||
67 | drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, | 66 | drv_sta_remove(local, sdata, &sta->sta); |
68 | &sta->sta); | ||
69 | } | 67 | } |
70 | 68 | ||
71 | mesh_plink_quiesce(sta); | 69 | mesh_plink_quiesce(sta); |
72 | } | 70 | } |
73 | spin_unlock_irqrestore(&local->sta_lock, flags); | 71 | mutex_unlock(&local->sta_mtx); |
74 | 72 | ||
75 | /* remove all interfaces */ | 73 | /* remove all interfaces */ |
76 | list_for_each_entry(sdata, &local->interfaces, list) { | 74 | list_for_each_entry(sdata, &local->interfaces, list) { |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index c74b7c85403..99ab24cc978 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -145,7 +145,7 @@ static const struct file_operations rcname_ops = { | |||
145 | }; | 145 | }; |
146 | #endif | 146 | #endif |
147 | 147 | ||
148 | struct rate_control_ref *rate_control_alloc(const char *name, | 148 | static struct rate_control_ref *rate_control_alloc(const char *name, |
149 | struct ieee80211_local *local) | 149 | struct ieee80211_local *local) |
150 | { | 150 | { |
151 | struct dentry *debugfsdir = NULL; | 151 | struct dentry *debugfsdir = NULL; |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 998cf7a935b..b6108bca96d 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -26,10 +26,6 @@ struct rate_control_ref { | |||
26 | struct kref kref; | 26 | struct kref kref; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the | ||
30 | * first available algorithm. */ | ||
31 | struct rate_control_ref *rate_control_alloc(const char *name, | ||
32 | struct ieee80211_local *local); | ||
33 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 29 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
34 | struct sta_info *sta, | 30 | struct sta_info *sta, |
35 | struct ieee80211_tx_rate_control *txrc); | 31 | struct ieee80211_tx_rate_control *txrc); |
@@ -116,7 +112,8 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) | |||
116 | #endif | 112 | #endif |
117 | } | 113 | } |
118 | 114 | ||
119 | /* functions for rate control related to a device */ | 115 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the |
116 | * first available algorithm. */ | ||
120 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | 117 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
121 | const char *name); | 118 | const char *name); |
122 | void rate_control_deinitialize(struct ieee80211_local *local); | 119 | void rate_control_deinitialize(struct ieee80211_local *local); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5709307fcb9..c9755f3d986 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1719,6 +1719,7 @@ static ieee80211_rx_result debug_noinline | |||
1719 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | 1719 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) |
1720 | { | 1720 | { |
1721 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1721 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1722 | struct ieee80211_local *local = rx->local; | ||
1722 | struct net_device *dev = sdata->dev; | 1723 | struct net_device *dev = sdata->dev; |
1723 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1724 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1724 | __le16 fc = hdr->frame_control; | 1725 | __le16 fc = hdr->frame_control; |
@@ -1750,6 +1751,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1750 | dev->stats.rx_packets++; | 1751 | dev->stats.rx_packets++; |
1751 | dev->stats.rx_bytes += rx->skb->len; | 1752 | dev->stats.rx_bytes += rx->skb->len; |
1752 | 1753 | ||
1754 | if (ieee80211_is_data(hdr->frame_control) && | ||
1755 | !is_multicast_ether_addr(hdr->addr1) && | ||
1756 | local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) { | ||
1757 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1758 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
1759 | } | ||
1760 | |||
1753 | ieee80211_deliver_skb(rx); | 1761 | ieee80211_deliver_skb(rx); |
1754 | 1762 | ||
1755 | return RX_QUEUED; | 1763 | return RX_QUEUED; |
@@ -2244,8 +2252,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2244 | rate_idx = 0; /* TODO: HT rates */ | 2252 | rate_idx = 0; /* TODO: HT rates */ |
2245 | else | 2253 | else |
2246 | rate_idx = status->rate_idx; | 2254 | rate_idx = status->rate_idx; |
2247 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, | 2255 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, |
2248 | BIT(rate_idx)); | 2256 | hdr->addr2, BIT(rate_idx), GFP_ATOMIC); |
2249 | } | 2257 | } |
2250 | break; | 2258 | break; |
2251 | case NL80211_IFTYPE_MESH_POINT: | 2259 | case NL80211_IFTYPE_MESH_POINT: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index bc061f62967..b822dce9786 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -345,6 +345,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
345 | if (local->scan_req) | 345 | if (local->scan_req) |
346 | return -EBUSY; | 346 | return -EBUSY; |
347 | 347 | ||
348 | if (!list_empty(&local->work_list)) { | ||
349 | /* wait for the work to finish/time out */ | ||
350 | local->scan_req = req; | ||
351 | local->scan_sdata = sdata; | ||
352 | return 0; | ||
353 | } | ||
354 | |||
348 | if (local->ops->hw_scan) { | 355 | if (local->ops->hw_scan) { |
349 | u8 *ies; | 356 | u8 *ies; |
350 | 357 | ||
@@ -364,29 +371,33 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
364 | local->hw_scan_req->ie = ies; | 371 | local->hw_scan_req->ie = ies; |
365 | 372 | ||
366 | local->hw_scan_band = 0; | 373 | local->hw_scan_band = 0; |
374 | |||
375 | /* | ||
376 | * After allocating local->hw_scan_req, we must | ||
377 | * go through until ieee80211_prep_hw_scan(), so | ||
378 | * anything that might be changed here and leave | ||
379 | * this function early must not go after this | ||
380 | * allocation. | ||
381 | */ | ||
367 | } | 382 | } |
368 | 383 | ||
369 | local->scan_req = req; | 384 | local->scan_req = req; |
370 | local->scan_sdata = sdata; | 385 | local->scan_sdata = sdata; |
371 | 386 | ||
372 | if (!list_empty(&local->work_list)) { | ||
373 | /* wait for the work to finish/time out */ | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | if (local->ops->hw_scan) | 387 | if (local->ops->hw_scan) |
378 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 388 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
379 | else | 389 | else |
380 | __set_bit(SCAN_SW_SCANNING, &local->scanning); | 390 | __set_bit(SCAN_SW_SCANNING, &local->scanning); |
391 | |||
381 | /* | 392 | /* |
382 | * Kicking off the scan need not be protected, | 393 | * Kicking off the scan need not be protected, |
383 | * only the scan variable stuff, since now | 394 | * only the scan variable stuff, since now |
384 | * local->scan_req is assigned and other callers | 395 | * local->scan_req is assigned and other callers |
385 | * will abort their scan attempts. | 396 | * will abort their scan attempts. |
386 | * | 397 | * |
387 | * This avoids getting a scan_mtx -> iflist_mtx | 398 | * This avoids too many locking dependencies |
388 | * dependency, so that the scan completed calls | 399 | * so that the scan completed calls have more |
389 | * have more locking freedom. | 400 | * locking freedom. |
390 | */ | 401 | */ |
391 | 402 | ||
392 | ieee80211_recalc_idle(local); | 403 | ieee80211_recalc_idle(local); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f735826f055..211c475f73c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -32,49 +32,33 @@ | |||
32 | * for faster lookup and a list for iteration. They are managed using | 32 | * for faster lookup and a list for iteration. They are managed using |
33 | * RCU, i.e. access to the list and hash table is protected by RCU. | 33 | * RCU, i.e. access to the list and hash table is protected by RCU. |
34 | * | 34 | * |
35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller owns | 35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller |
36 | * that structure. It must then either destroy it using sta_info_destroy() | 36 | * owns that structure. It must then insert it into the hash table using |
37 | * (which is pretty useless) or insert it into the hash table using | 37 | * either sta_info_insert() or sta_info_insert_rcu(); only in the latter |
38 | * sta_info_insert() which demotes the reference from ownership to a regular | 38 | * case (which acquires an rcu read section but must not be called from |
39 | * RCU-protected reference; if the function is called without protection by an | 39 | * within one) will the pointer still be valid after the call. Note that |
40 | * RCU critical section the reference is instantly invalidated. Note that the | 40 | * the caller may not do much with the STA info before inserting it, in |
41 | * caller may not do much with the STA info before inserting it, in particular, | 41 | * particular, it may not start any mesh peer link management or add |
42 | * it may not start any mesh peer link management or add encryption keys. | 42 | * encryption keys. |
43 | * | 43 | * |
44 | * When the insertion fails (sta_info_insert()) returns non-zero), the | 44 | * When the insertion fails (sta_info_insert()) returns non-zero), the |
45 | * structure will have been freed by sta_info_insert()! | 45 | * structure will have been freed by sta_info_insert()! |
46 | * | 46 | * |
47 | * sta entries are added by mac80211 when you establish a link with a | 47 | * Station entries are added by mac80211 when you establish a link with a |
48 | * peer. This means different things for the different type of interfaces | 48 | * peer. This means different things for the different type of interfaces |
49 | * we support. For a regular station this mean we add the AP sta when we | 49 | * we support. For a regular station this mean we add the AP sta when we |
50 | * receive an assocation response from the AP. For IBSS this occurs when | 50 | * receive an assocation response from the AP. For IBSS this occurs when |
51 | * we receive a probe response or a beacon from target IBSS network. For | 51 | * get to know about a peer on the same IBSS. For WDS we add the sta for |
52 | * WDS we add the sta for the peer imediately upon device open. When using | 52 | * the peer imediately upon device open. When using AP mode we add stations |
53 | * AP mode we add stations for each respective station upon request from | 53 | * for each respective station upon request from userspace through nl80211. |
54 | * userspace through nl80211. | ||
55 | * | 54 | * |
56 | * Because there are debugfs entries for each station, and adding those | 55 | * In order to remove a STA info structure, various sta_info_destroy_*() |
57 | * must be able to sleep, it is also possible to "pin" a station entry, | 56 | * calls are available. |
58 | * that means it can be removed from the hash table but not be freed. | ||
59 | * See the comment in __sta_info_unlink() for more information, this is | ||
60 | * an internal capability only. | ||
61 | * | 57 | * |
62 | * In order to remove a STA info structure, the caller needs to first | 58 | * There is no concept of ownership on a STA entry, each structure is |
63 | * unlink it (sta_info_unlink()) from the list and hash tables and | 59 | * owned by the global hash table/list until it is removed. All users of |
64 | * then destroy it; sta_info_destroy() will wait for an RCU grace period | 60 | * the structure need to be RCU protected so that the structure won't be |
65 | * to elapse before actually freeing it. Due to the pinning and the | 61 | * freed before they are done using it. |
66 | * possibility of multiple callers trying to remove the same STA info at | ||
67 | * the same time, sta_info_unlink() can clear the STA info pointer it is | ||
68 | * passed to indicate that the STA info is owned by somebody else now. | ||
69 | * | ||
70 | * If sta_info_unlink() did not clear the pointer then the caller owns | ||
71 | * the STA info structure now and is responsible of destroying it with | ||
72 | * a call to sta_info_destroy(). | ||
73 | * | ||
74 | * In all other cases, there is no concept of ownership on a STA entry, | ||
75 | * each structure is owned by the global hash table/list until it is | ||
76 | * removed. All users of the structure need to be RCU protected so that | ||
77 | * the structure won't be freed before they are done using it. | ||
78 | */ | 62 | */ |
79 | 63 | ||
80 | /* Caller must hold local->sta_lock */ | 64 | /* Caller must hold local->sta_lock */ |
@@ -185,101 +169,6 @@ static void __sta_info_free(struct ieee80211_local *local, | |||
185 | kfree(sta); | 169 | kfree(sta); |
186 | } | 170 | } |
187 | 171 | ||
188 | void sta_info_destroy(struct sta_info *sta) | ||
189 | { | ||
190 | struct ieee80211_local *local; | ||
191 | struct sk_buff *skb; | ||
192 | int i; | ||
193 | |||
194 | might_sleep(); | ||
195 | |||
196 | if (!sta) | ||
197 | return; | ||
198 | |||
199 | local = sta->local; | ||
200 | |||
201 | cancel_work_sync(&sta->drv_unblock_wk); | ||
202 | |||
203 | rate_control_remove_sta_debugfs(sta); | ||
204 | ieee80211_sta_debugfs_remove(sta); | ||
205 | |||
206 | #ifdef CONFIG_MAC80211_MESH | ||
207 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
208 | mesh_plink_deactivate(sta); | ||
209 | #endif | ||
210 | |||
211 | /* | ||
212 | * We have only unlinked the key, and actually destroying it | ||
213 | * may mean it is removed from hardware which requires that | ||
214 | * the key->sta pointer is still valid, so flush the key todo | ||
215 | * list here. | ||
216 | * | ||
217 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
218 | * nothing can reference this sta struct any more. | ||
219 | */ | ||
220 | ieee80211_key_todo(); | ||
221 | |||
222 | #ifdef CONFIG_MAC80211_MESH | ||
223 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
224 | del_timer_sync(&sta->plink_timer); | ||
225 | #endif | ||
226 | |||
227 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
228 | local->total_ps_buffered--; | ||
229 | dev_kfree_skb_any(skb); | ||
230 | } | ||
231 | |||
232 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
233 | dev_kfree_skb_any(skb); | ||
234 | |||
235 | for (i = 0; i < STA_TID_NUM; i++) { | ||
236 | struct tid_ampdu_rx *tid_rx; | ||
237 | struct tid_ampdu_tx *tid_tx; | ||
238 | |||
239 | spin_lock_bh(&sta->lock); | ||
240 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
241 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
242 | if (tid_rx) | ||
243 | tid_rx->shutdown = true; | ||
244 | |||
245 | spin_unlock_bh(&sta->lock); | ||
246 | |||
247 | /* | ||
248 | * Outside spinlock - shutdown is true now so that the timer | ||
249 | * won't free tid_rx, we have to do that now. Can't let the | ||
250 | * timer do it because we have to sync the timer outside the | ||
251 | * lock that it takes itself. | ||
252 | */ | ||
253 | if (tid_rx) { | ||
254 | del_timer_sync(&tid_rx->session_timer); | ||
255 | kfree(tid_rx); | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * No need to do such complications for TX agg sessions, the | ||
260 | * path leading to freeing the tid_tx struct goes via a call | ||
261 | * from the driver, and thus needs to look up the sta struct | ||
262 | * again, which cannot be found when we get here. Hence, we | ||
263 | * just need to delete the timer and free the aggregation | ||
264 | * info; we won't be telling the peer about it then but that | ||
265 | * doesn't matter if we're not talking to it again anyway. | ||
266 | */ | ||
267 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
268 | if (tid_tx) { | ||
269 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
270 | /* | ||
271 | * STA removed while aggregation session being | ||
272 | * started? Bit odd, but purge frames anyway. | ||
273 | */ | ||
274 | skb_queue_purge(&tid_tx->pending); | ||
275 | kfree(tid_tx); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | __sta_info_free(local, sta); | ||
280 | } | ||
281 | |||
282 | |||
283 | /* Caller must hold local->sta_lock */ | 172 | /* Caller must hold local->sta_lock */ |
284 | static void sta_info_hash_add(struct ieee80211_local *local, | 173 | static void sta_info_hash_add(struct ieee80211_local *local, |
285 | struct sta_info *sta) | 174 | struct sta_info *sta) |
@@ -376,7 +265,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
376 | return sta; | 265 | return sta; |
377 | } | 266 | } |
378 | 267 | ||
379 | int sta_info_insert(struct sta_info *sta) | 268 | static int sta_info_finish_insert(struct sta_info *sta, bool async) |
380 | { | 269 | { |
381 | struct ieee80211_local *local = sta->local; | 270 | struct ieee80211_local *local = sta->local; |
382 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 271 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -384,6 +273,91 @@ int sta_info_insert(struct sta_info *sta) | |||
384 | unsigned long flags; | 273 | unsigned long flags; |
385 | int err = 0; | 274 | int err = 0; |
386 | 275 | ||
276 | WARN_ON(!mutex_is_locked(&local->sta_mtx)); | ||
277 | |||
278 | /* notify driver */ | ||
279 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
280 | sdata = container_of(sdata->bss, | ||
281 | struct ieee80211_sub_if_data, | ||
282 | u.ap); | ||
283 | err = drv_sta_add(local, sdata, &sta->sta); | ||
284 | if (err) { | ||
285 | if (!async) | ||
286 | return err; | ||
287 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" | ||
288 | " - keeping it anyway.\n", | ||
289 | sdata->name, sta->sta.addr, err); | ||
290 | } else { | ||
291 | sta->uploaded = true; | ||
292 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
293 | if (async) | ||
294 | printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n", | ||
295 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
296 | #endif | ||
297 | } | ||
298 | |||
299 | sdata = sta->sdata; | ||
300 | |||
301 | if (!async) { | ||
302 | local->num_sta++; | ||
303 | local->sta_generation++; | ||
304 | smp_mb(); | ||
305 | |||
306 | /* make the station visible */ | ||
307 | spin_lock_irqsave(&local->sta_lock, flags); | ||
308 | sta_info_hash_add(local, sta); | ||
309 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
310 | } | ||
311 | |||
312 | list_add(&sta->list, &local->sta_list); | ||
313 | |||
314 | ieee80211_sta_debugfs_add(sta); | ||
315 | rate_control_add_sta_debugfs(sta); | ||
316 | |||
317 | sinfo.filled = 0; | ||
318 | sinfo.generation = local->sta_generation; | ||
319 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
320 | |||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static void sta_info_finish_pending(struct ieee80211_local *local) | ||
326 | { | ||
327 | struct sta_info *sta; | ||
328 | unsigned long flags; | ||
329 | |||
330 | spin_lock_irqsave(&local->sta_lock, flags); | ||
331 | while (!list_empty(&local->sta_pending_list)) { | ||
332 | sta = list_first_entry(&local->sta_pending_list, | ||
333 | struct sta_info, list); | ||
334 | list_del(&sta->list); | ||
335 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
336 | |||
337 | sta_info_finish_insert(sta, true); | ||
338 | |||
339 | spin_lock_irqsave(&local->sta_lock, flags); | ||
340 | } | ||
341 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
342 | } | ||
343 | |||
344 | static void sta_info_finish_work(struct work_struct *work) | ||
345 | { | ||
346 | struct ieee80211_local *local = | ||
347 | container_of(work, struct ieee80211_local, sta_finish_work); | ||
348 | |||
349 | mutex_lock(&local->sta_mtx); | ||
350 | sta_info_finish_pending(local); | ||
351 | mutex_unlock(&local->sta_mtx); | ||
352 | } | ||
353 | |||
354 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | ||
355 | { | ||
356 | struct ieee80211_local *local = sta->local; | ||
357 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
358 | unsigned long flags; | ||
359 | int err = 0; | ||
360 | |||
387 | /* | 361 | /* |
388 | * Can't be a WARN_ON because it can be triggered through a race: | 362 | * Can't be a WARN_ON because it can be triggered through a race: |
389 | * something inserts a STA (on one CPU) without holding the RTNL | 363 | * something inserts a STA (on one CPU) without holding the RTNL |
@@ -391,36 +365,87 @@ int sta_info_insert(struct sta_info *sta) | |||
391 | */ | 365 | */ |
392 | if (unlikely(!ieee80211_sdata_running(sdata))) { | 366 | if (unlikely(!ieee80211_sdata_running(sdata))) { |
393 | err = -ENETDOWN; | 367 | err = -ENETDOWN; |
368 | rcu_read_lock(); | ||
394 | goto out_free; | 369 | goto out_free; |
395 | } | 370 | } |
396 | 371 | ||
397 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || | 372 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || |
398 | is_multicast_ether_addr(sta->sta.addr))) { | 373 | is_multicast_ether_addr(sta->sta.addr))) { |
399 | err = -EINVAL; | 374 | err = -EINVAL; |
375 | rcu_read_lock(); | ||
400 | goto out_free; | 376 | goto out_free; |
401 | } | 377 | } |
402 | 378 | ||
379 | /* | ||
380 | * In ad-hoc mode, we sometimes need to insert stations | ||
381 | * from tasklet context from the RX path. To avoid races, | ||
382 | * always do so in that case -- see the comment below. | ||
383 | */ | ||
384 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
385 | spin_lock_irqsave(&local->sta_lock, flags); | ||
386 | /* check if STA exists already */ | ||
387 | if (sta_info_get_bss(sdata, sta->sta.addr)) { | ||
388 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
389 | rcu_read_lock(); | ||
390 | err = -EEXIST; | ||
391 | goto out_free; | ||
392 | } | ||
393 | |||
394 | local->num_sta++; | ||
395 | local->sta_generation++; | ||
396 | smp_mb(); | ||
397 | sta_info_hash_add(local, sta); | ||
398 | |||
399 | list_add_tail(&sta->list, &local->sta_pending_list); | ||
400 | |||
401 | rcu_read_lock(); | ||
402 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
403 | |||
404 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
405 | printk(KERN_DEBUG "%s: Added IBSS STA %pM\n", | ||
406 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
407 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
408 | |||
409 | ieee80211_queue_work(&local->hw, &local->sta_finish_work); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * On first glance, this will look racy, because the code | ||
416 | * below this point, which inserts a station with sleeping, | ||
417 | * unlocks the sta_lock between checking existence in the | ||
418 | * hash table and inserting into it. | ||
419 | * | ||
420 | * However, it is not racy against itself because it keeps | ||
421 | * the mutex locked. It still seems to race against the | ||
422 | * above code that atomically inserts the station... That, | ||
423 | * however, is not true because the above code can only | ||
424 | * be invoked for IBSS interfaces, and the below code will | ||
425 | * not be -- and the two do not race against each other as | ||
426 | * the hash table also keys off the interface. | ||
427 | */ | ||
428 | |||
429 | might_sleep(); | ||
430 | |||
431 | mutex_lock(&local->sta_mtx); | ||
432 | |||
403 | spin_lock_irqsave(&local->sta_lock, flags); | 433 | spin_lock_irqsave(&local->sta_lock, flags); |
404 | /* check if STA exists already */ | 434 | /* check if STA exists already */ |
405 | if (sta_info_get(sdata, sta->sta.addr)) { | 435 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
406 | spin_unlock_irqrestore(&local->sta_lock, flags); | 436 | spin_unlock_irqrestore(&local->sta_lock, flags); |
437 | rcu_read_lock(); | ||
407 | err = -EEXIST; | 438 | err = -EEXIST; |
408 | goto out_free; | 439 | goto out_free; |
409 | } | 440 | } |
410 | list_add(&sta->list, &local->sta_list); | ||
411 | local->sta_generation++; | ||
412 | local->num_sta++; | ||
413 | sta_info_hash_add(local, sta); | ||
414 | 441 | ||
415 | /* notify driver */ | 442 | spin_unlock_irqrestore(&local->sta_lock, flags); |
416 | if (local->ops->sta_notify) { | ||
417 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
418 | sdata = container_of(sdata->bss, | ||
419 | struct ieee80211_sub_if_data, | ||
420 | u.ap); | ||
421 | 443 | ||
422 | drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta); | 444 | err = sta_info_finish_insert(sta, false); |
423 | sdata = sta->sdata; | 445 | if (err) { |
446 | mutex_unlock(&local->sta_mtx); | ||
447 | rcu_read_lock(); | ||
448 | goto out_free; | ||
424 | } | 449 | } |
425 | 450 | ||
426 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 451 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -428,22 +453,9 @@ int sta_info_insert(struct sta_info *sta) | |||
428 | wiphy_name(local->hw.wiphy), sta->sta.addr); | 453 | wiphy_name(local->hw.wiphy), sta->sta.addr); |
429 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 454 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
430 | 455 | ||
431 | spin_unlock_irqrestore(&local->sta_lock, flags); | 456 | /* move reference to rcu-protected */ |
432 | 457 | rcu_read_lock(); | |
433 | sinfo.filled = 0; | 458 | mutex_unlock(&local->sta_mtx); |
434 | sinfo.generation = local->sta_generation; | ||
435 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC); | ||
436 | |||
437 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
438 | /* | ||
439 | * Debugfs entry adding might sleep, so schedule process | ||
440 | * context task for adding entry for STAs that do not yet | ||
441 | * have one. | ||
442 | * NOTE: due to auto-freeing semantics this may only be done | ||
443 | * if the insertion is successful! | ||
444 | */ | ||
445 | schedule_work(&local->sta_debugfs_add); | ||
446 | #endif | ||
447 | 459 | ||
448 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 460 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
449 | mesh_accept_plinks_update(sdata); | 461 | mesh_accept_plinks_update(sdata); |
@@ -455,6 +467,15 @@ int sta_info_insert(struct sta_info *sta) | |||
455 | return err; | 467 | return err; |
456 | } | 468 | } |
457 | 469 | ||
470 | int sta_info_insert(struct sta_info *sta) | ||
471 | { | ||
472 | int err = sta_info_insert_rcu(sta); | ||
473 | |||
474 | rcu_read_unlock(); | ||
475 | |||
476 | return err; | ||
477 | } | ||
478 | |||
458 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 479 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
459 | { | 480 | { |
460 | /* | 481 | /* |
@@ -523,108 +544,6 @@ void sta_info_clear_tim_bit(struct sta_info *sta) | |||
523 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | 544 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
524 | } | 545 | } |
525 | 546 | ||
526 | static void __sta_info_unlink(struct sta_info **sta) | ||
527 | { | ||
528 | struct ieee80211_local *local = (*sta)->local; | ||
529 | struct ieee80211_sub_if_data *sdata = (*sta)->sdata; | ||
530 | /* | ||
531 | * pull caller's reference if we're already gone. | ||
532 | */ | ||
533 | if (sta_info_hash_del(local, *sta)) { | ||
534 | *sta = NULL; | ||
535 | return; | ||
536 | } | ||
537 | |||
538 | if ((*sta)->key) { | ||
539 | ieee80211_key_free((*sta)->key); | ||
540 | WARN_ON((*sta)->key); | ||
541 | } | ||
542 | |||
543 | list_del(&(*sta)->list); | ||
544 | (*sta)->dead = true; | ||
545 | |||
546 | if (test_and_clear_sta_flags(*sta, | ||
547 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
548 | BUG_ON(!sdata->bss); | ||
549 | |||
550 | atomic_dec(&sdata->bss->num_sta_ps); | ||
551 | __sta_info_clear_tim_bit(sdata->bss, *sta); | ||
552 | } | ||
553 | |||
554 | local->num_sta--; | ||
555 | local->sta_generation++; | ||
556 | |||
557 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
558 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
559 | |||
560 | if (local->ops->sta_notify) { | ||
561 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
562 | sdata = container_of(sdata->bss, | ||
563 | struct ieee80211_sub_if_data, | ||
564 | u.ap); | ||
565 | |||
566 | drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, | ||
567 | &(*sta)->sta); | ||
568 | sdata = (*sta)->sdata; | ||
569 | } | ||
570 | |||
571 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
572 | mesh_accept_plinks_update(sdata); | ||
573 | #ifdef CONFIG_MAC80211_MESH | ||
574 | del_timer(&(*sta)->plink_timer); | ||
575 | #endif | ||
576 | } | ||
577 | |||
578 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
579 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
580 | wiphy_name(local->hw.wiphy), (*sta)->sta.addr); | ||
581 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
582 | |||
583 | /* | ||
584 | * Finally, pull caller's reference if the STA is pinned by the | ||
585 | * task that is adding the debugfs entries. In that case, we | ||
586 | * leave the STA "to be freed". | ||
587 | * | ||
588 | * The rules are not trivial, but not too complex either: | ||
589 | * (1) pin_status is only modified under the sta_lock | ||
590 | * (2) STAs may only be pinned under the RTNL so that | ||
591 | * sta_info_flush() is guaranteed to actually destroy | ||
592 | * all STAs that are active for a given interface, this | ||
593 | * is required for correctness because otherwise we | ||
594 | * could notify a driver that an interface is going | ||
595 | * away and only after that (!) notify it about a STA | ||
596 | * on that interface going away. | ||
597 | * (3) sta_info_debugfs_add_work() will set the status | ||
598 | * to PINNED when it found an item that needs a new | ||
599 | * debugfs directory created. In that case, that item | ||
600 | * must not be freed although all *RCU* users are done | ||
601 | * with it. Hence, we tell the caller of _unlink() | ||
602 | * that the item is already gone (as can happen when | ||
603 | * two tasks try to unlink/destroy at the same time) | ||
604 | * (4) We set the pin_status to DESTROY here when we | ||
605 | * find such an item. | ||
606 | * (5) sta_info_debugfs_add_work() will reset the pin_status | ||
607 | * from PINNED to NORMAL when it is done with the item, | ||
608 | * but will check for DESTROY before resetting it in | ||
609 | * which case it will free the item. | ||
610 | */ | ||
611 | if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { | ||
612 | (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; | ||
613 | *sta = NULL; | ||
614 | return; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | void sta_info_unlink(struct sta_info **sta) | ||
619 | { | ||
620 | struct ieee80211_local *local = (*sta)->local; | ||
621 | unsigned long flags; | ||
622 | |||
623 | spin_lock_irqsave(&local->sta_lock, flags); | ||
624 | __sta_info_unlink(sta); | ||
625 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
626 | } | ||
627 | |||
628 | static int sta_info_buffer_expired(struct sta_info *sta, | 547 | static int sta_info_buffer_expired(struct sta_info *sta, |
629 | struct sk_buff *skb) | 548 | struct sk_buff *skb) |
630 | { | 549 | { |
@@ -681,109 +600,209 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
681 | } | 600 | } |
682 | } | 601 | } |
683 | 602 | ||
684 | 603 | static int __must_check __sta_info_destroy(struct sta_info *sta) | |
685 | static void sta_info_cleanup(unsigned long data) | ||
686 | { | 604 | { |
687 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 605 | struct ieee80211_local *local; |
688 | struct sta_info *sta; | 606 | struct ieee80211_sub_if_data *sdata; |
607 | struct sk_buff *skb; | ||
608 | unsigned long flags; | ||
609 | int ret, i; | ||
689 | 610 | ||
690 | rcu_read_lock(); | 611 | might_sleep(); |
691 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
692 | sta_info_cleanup_expire_buffered(local, sta); | ||
693 | rcu_read_unlock(); | ||
694 | 612 | ||
695 | if (local->quiescing) | 613 | if (!sta) |
696 | return; | 614 | return -ENOENT; |
697 | 615 | ||
698 | local->sta_cleanup.expires = | 616 | local = sta->local; |
699 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 617 | sdata = sta->sdata; |
700 | add_timer(&local->sta_cleanup); | ||
701 | } | ||
702 | 618 | ||
703 | #ifdef CONFIG_MAC80211_DEBUGFS | 619 | spin_lock_irqsave(&local->sta_lock, flags); |
704 | /* | 620 | ret = sta_info_hash_del(local, sta); |
705 | * See comment in __sta_info_unlink, | 621 | /* this might still be the pending list ... which is fine */ |
706 | * caller must hold local->sta_lock. | 622 | if (!ret) |
707 | */ | 623 | list_del(&sta->list); |
708 | static void __sta_info_pin(struct sta_info *sta) | 624 | spin_unlock_irqrestore(&local->sta_lock, flags); |
709 | { | 625 | if (ret) |
710 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); | 626 | return ret; |
711 | sta->pin_status = STA_INFO_PIN_STAT_PINNED; | 627 | |
628 | if (sta->key) { | ||
629 | ieee80211_key_free(sta->key); | ||
630 | /* | ||
631 | * We have only unlinked the key, and actually destroying it | ||
632 | * may mean it is removed from hardware which requires that | ||
633 | * the key->sta pointer is still valid, so flush the key todo | ||
634 | * list here. | ||
635 | * | ||
636 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
637 | * nothing can reference this sta struct any more. | ||
638 | */ | ||
639 | ieee80211_key_todo(); | ||
640 | |||
641 | WARN_ON(sta->key); | ||
642 | } | ||
643 | |||
644 | sta->dead = true; | ||
645 | |||
646 | if (test_and_clear_sta_flags(sta, | ||
647 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
648 | BUG_ON(!sdata->bss); | ||
649 | |||
650 | atomic_dec(&sdata->bss->num_sta_ps); | ||
651 | __sta_info_clear_tim_bit(sdata->bss, sta); | ||
652 | } | ||
653 | |||
654 | local->num_sta--; | ||
655 | local->sta_generation++; | ||
656 | |||
657 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
658 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
659 | |||
660 | if (sta->uploaded) { | ||
661 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
662 | sdata = container_of(sdata->bss, | ||
663 | struct ieee80211_sub_if_data, | ||
664 | u.ap); | ||
665 | drv_sta_remove(local, sdata, &sta->sta); | ||
666 | sdata = sta->sdata; | ||
667 | } | ||
668 | |||
669 | #ifdef CONFIG_MAC80211_MESH | ||
670 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
671 | mesh_accept_plinks_update(sdata); | ||
672 | del_timer(&sta->plink_timer); | ||
673 | } | ||
674 | #endif | ||
675 | |||
676 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
677 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
678 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
679 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
680 | cancel_work_sync(&sta->drv_unblock_wk); | ||
681 | |||
682 | rate_control_remove_sta_debugfs(sta); | ||
683 | ieee80211_sta_debugfs_remove(sta); | ||
684 | |||
685 | #ifdef CONFIG_MAC80211_MESH | ||
686 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | ||
687 | mesh_plink_deactivate(sta); | ||
688 | del_timer_sync(&sta->plink_timer); | ||
689 | } | ||
690 | #endif | ||
691 | |||
692 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
693 | local->total_ps_buffered--; | ||
694 | dev_kfree_skb_any(skb); | ||
695 | } | ||
696 | |||
697 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
698 | dev_kfree_skb_any(skb); | ||
699 | |||
700 | for (i = 0; i < STA_TID_NUM; i++) { | ||
701 | struct tid_ampdu_rx *tid_rx; | ||
702 | struct tid_ampdu_tx *tid_tx; | ||
703 | |||
704 | spin_lock_bh(&sta->lock); | ||
705 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
706 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
707 | if (tid_rx) | ||
708 | tid_rx->shutdown = true; | ||
709 | |||
710 | spin_unlock_bh(&sta->lock); | ||
711 | |||
712 | /* | ||
713 | * Outside spinlock - shutdown is true now so that the timer | ||
714 | * won't free tid_rx, we have to do that now. Can't let the | ||
715 | * timer do it because we have to sync the timer outside the | ||
716 | * lock that it takes itself. | ||
717 | */ | ||
718 | if (tid_rx) { | ||
719 | del_timer_sync(&tid_rx->session_timer); | ||
720 | kfree(tid_rx); | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * No need to do such complications for TX agg sessions, the | ||
725 | * path leading to freeing the tid_tx struct goes via a call | ||
726 | * from the driver, and thus needs to look up the sta struct | ||
727 | * again, which cannot be found when we get here. Hence, we | ||
728 | * just need to delete the timer and free the aggregation | ||
729 | * info; we won't be telling the peer about it then but that | ||
730 | * doesn't matter if we're not talking to it again anyway. | ||
731 | */ | ||
732 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
733 | if (tid_tx) { | ||
734 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
735 | /* | ||
736 | * STA removed while aggregation session being | ||
737 | * started? Bit odd, but purge frames anyway. | ||
738 | */ | ||
739 | skb_queue_purge(&tid_tx->pending); | ||
740 | kfree(tid_tx); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | __sta_info_free(local, sta); | ||
745 | |||
746 | return 0; | ||
712 | } | 747 | } |
713 | 748 | ||
714 | /* | 749 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) |
715 | * See comment in __sta_info_unlink, returns sta if it | ||
716 | * needs to be destroyed. | ||
717 | */ | ||
718 | static struct sta_info *__sta_info_unpin(struct sta_info *sta) | ||
719 | { | 750 | { |
720 | struct sta_info *ret = NULL; | 751 | struct sta_info *sta; |
721 | unsigned long flags; | 752 | int ret; |
722 | 753 | ||
723 | spin_lock_irqsave(&sta->local->sta_lock, flags); | 754 | mutex_lock(&sdata->local->sta_mtx); |
724 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && | 755 | sta = sta_info_get(sdata, addr); |
725 | sta->pin_status != STA_INFO_PIN_STAT_PINNED); | 756 | ret = __sta_info_destroy(sta); |
726 | if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) | 757 | mutex_unlock(&sdata->local->sta_mtx); |
727 | ret = sta; | ||
728 | sta->pin_status = STA_INFO_PIN_STAT_NORMAL; | ||
729 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | ||
730 | 758 | ||
731 | return ret; | 759 | return ret; |
732 | } | 760 | } |
733 | 761 | ||
734 | static void sta_info_debugfs_add_work(struct work_struct *work) | 762 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
763 | const u8 *addr) | ||
735 | { | 764 | { |
736 | struct ieee80211_local *local = | 765 | struct sta_info *sta; |
737 | container_of(work, struct ieee80211_local, sta_debugfs_add); | 766 | int ret; |
738 | struct sta_info *sta, *tmp; | ||
739 | unsigned long flags; | ||
740 | 767 | ||
741 | /* We need to keep the RTNL across the whole pinned status. */ | 768 | mutex_lock(&sdata->local->sta_mtx); |
742 | rtnl_lock(); | 769 | sta = sta_info_get_bss(sdata, addr); |
743 | while (1) { | 770 | ret = __sta_info_destroy(sta); |
744 | sta = NULL; | 771 | mutex_unlock(&sdata->local->sta_mtx); |
745 | 772 | ||
746 | spin_lock_irqsave(&local->sta_lock, flags); | 773 | return ret; |
747 | list_for_each_entry(tmp, &local->sta_list, list) { | 774 | } |
748 | /* | ||
749 | * debugfs.add_has_run will be set by | ||
750 | * ieee80211_sta_debugfs_add regardless | ||
751 | * of what else it does. | ||
752 | */ | ||
753 | if (!tmp->debugfs.add_has_run) { | ||
754 | sta = tmp; | ||
755 | __sta_info_pin(sta); | ||
756 | break; | ||
757 | } | ||
758 | } | ||
759 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
760 | 775 | ||
761 | if (!sta) | 776 | static void sta_info_cleanup(unsigned long data) |
762 | break; | 777 | { |
778 | struct ieee80211_local *local = (struct ieee80211_local *) data; | ||
779 | struct sta_info *sta; | ||
780 | |||
781 | rcu_read_lock(); | ||
782 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
783 | sta_info_cleanup_expire_buffered(local, sta); | ||
784 | rcu_read_unlock(); | ||
763 | 785 | ||
764 | ieee80211_sta_debugfs_add(sta); | 786 | if (local->quiescing) |
765 | rate_control_add_sta_debugfs(sta); | 787 | return; |
766 | 788 | ||
767 | sta = __sta_info_unpin(sta); | 789 | local->sta_cleanup.expires = |
768 | sta_info_destroy(sta); | 790 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
769 | } | 791 | add_timer(&local->sta_cleanup); |
770 | rtnl_unlock(); | ||
771 | } | 792 | } |
772 | #endif | ||
773 | 793 | ||
774 | void sta_info_init(struct ieee80211_local *local) | 794 | void sta_info_init(struct ieee80211_local *local) |
775 | { | 795 | { |
776 | spin_lock_init(&local->sta_lock); | 796 | spin_lock_init(&local->sta_lock); |
797 | mutex_init(&local->sta_mtx); | ||
777 | INIT_LIST_HEAD(&local->sta_list); | 798 | INIT_LIST_HEAD(&local->sta_list); |
799 | INIT_LIST_HEAD(&local->sta_pending_list); | ||
800 | INIT_WORK(&local->sta_finish_work, sta_info_finish_work); | ||
778 | 801 | ||
779 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 802 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
780 | (unsigned long)local); | 803 | (unsigned long)local); |
781 | local->sta_cleanup.expires = | 804 | local->sta_cleanup.expires = |
782 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 805 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
783 | |||
784 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
785 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); | ||
786 | #endif | ||
787 | } | 806 | } |
788 | 807 | ||
789 | int sta_info_start(struct ieee80211_local *local) | 808 | int sta_info_start(struct ieee80211_local *local) |
@@ -795,16 +814,6 @@ int sta_info_start(struct ieee80211_local *local) | |||
795 | void sta_info_stop(struct ieee80211_local *local) | 814 | void sta_info_stop(struct ieee80211_local *local) |
796 | { | 815 | { |
797 | del_timer(&local->sta_cleanup); | 816 | del_timer(&local->sta_cleanup); |
798 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
799 | /* | ||
800 | * Make sure the debugfs adding work isn't pending after this | ||
801 | * because we're about to be destroyed. It doesn't matter | ||
802 | * whether it ran or not since we're going to flush all STAs | ||
803 | * anyway. | ||
804 | */ | ||
805 | cancel_work_sync(&local->sta_debugfs_add); | ||
806 | #endif | ||
807 | |||
808 | sta_info_flush(local, NULL); | 817 | sta_info_flush(local, NULL); |
809 | } | 818 | } |
810 | 819 | ||
@@ -820,26 +829,19 @@ int sta_info_flush(struct ieee80211_local *local, | |||
820 | struct ieee80211_sub_if_data *sdata) | 829 | struct ieee80211_sub_if_data *sdata) |
821 | { | 830 | { |
822 | struct sta_info *sta, *tmp; | 831 | struct sta_info *sta, *tmp; |
823 | LIST_HEAD(tmp_list); | ||
824 | int ret = 0; | 832 | int ret = 0; |
825 | unsigned long flags; | ||
826 | 833 | ||
827 | might_sleep(); | 834 | might_sleep(); |
828 | 835 | ||
829 | spin_lock_irqsave(&local->sta_lock, flags); | 836 | mutex_lock(&local->sta_mtx); |
837 | |||
838 | sta_info_finish_pending(local); | ||
839 | |||
830 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 840 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
831 | if (!sdata || sdata == sta->sdata) { | 841 | if (!sdata || sdata == sta->sdata) |
832 | __sta_info_unlink(&sta); | 842 | WARN_ON(__sta_info_destroy(sta)); |
833 | if (sta) { | ||
834 | list_add_tail(&sta->list, &tmp_list); | ||
835 | ret++; | ||
836 | } | ||
837 | } | ||
838 | } | 843 | } |
839 | spin_unlock_irqrestore(&local->sta_lock, flags); | 844 | mutex_unlock(&local->sta_mtx); |
840 | |||
841 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
842 | sta_info_destroy(sta); | ||
843 | 845 | ||
844 | return ret; | 846 | return ret; |
845 | } | 847 | } |
@@ -849,24 +851,17 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
849 | { | 851 | { |
850 | struct ieee80211_local *local = sdata->local; | 852 | struct ieee80211_local *local = sdata->local; |
851 | struct sta_info *sta, *tmp; | 853 | struct sta_info *sta, *tmp; |
852 | LIST_HEAD(tmp_list); | ||
853 | unsigned long flags; | ||
854 | 854 | ||
855 | spin_lock_irqsave(&local->sta_lock, flags); | 855 | mutex_lock(&local->sta_mtx); |
856 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 856 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
857 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 857 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
858 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 858 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
859 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", | 859 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", |
860 | sdata->name, sta->sta.addr); | 860 | sdata->name, sta->sta.addr); |
861 | #endif | 861 | #endif |
862 | __sta_info_unlink(&sta); | 862 | WARN_ON(__sta_info_destroy(sta)); |
863 | if (sta) | ||
864 | list_add(&sta->list, &tmp_list); | ||
865 | } | 863 | } |
866 | spin_unlock_irqrestore(&local->sta_lock, flags); | 864 | mutex_unlock(&local->sta_mtx); |
867 | |||
868 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
869 | sta_info_destroy(sta); | ||
870 | } | 865 | } |
871 | 866 | ||
872 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | 867 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6f79bba5706..822d8452293 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -42,6 +42,9 @@ | |||
42 | * be in the queues | 42 | * be in the queues |
43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping | 43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping |
44 | * station in power-save mode, reply when the driver unblocks. | 44 | * station in power-save mode, reply when the driver unblocks. |
45 | * @WLAN_STA_DISASSOC: Disassociation in progress. | ||
46 | * This is used to reject TX BA session requests when disassociation | ||
47 | * is in progress. | ||
45 | */ | 48 | */ |
46 | enum ieee80211_sta_info_flags { | 49 | enum ieee80211_sta_info_flags { |
47 | WLAN_STA_AUTH = 1<<0, | 50 | WLAN_STA_AUTH = 1<<0, |
@@ -57,6 +60,7 @@ enum ieee80211_sta_info_flags { | |||
57 | WLAN_STA_SUSPEND = 1<<11, | 60 | WLAN_STA_SUSPEND = 1<<11, |
58 | WLAN_STA_PS_DRIVER = 1<<12, | 61 | WLAN_STA_PS_DRIVER = 1<<12, |
59 | WLAN_STA_PSPOLL = 1<<13, | 62 | WLAN_STA_PSPOLL = 1<<13, |
63 | WLAN_STA_DISASSOC = 1<<14, | ||
60 | }; | 64 | }; |
61 | 65 | ||
62 | #define STA_TID_NUM 16 | 66 | #define STA_TID_NUM 16 |
@@ -162,11 +166,6 @@ struct sta_ampdu_mlme { | |||
162 | }; | 166 | }; |
163 | 167 | ||
164 | 168 | ||
165 | /* see __sta_info_unlink */ | ||
166 | #define STA_INFO_PIN_STAT_NORMAL 0 | ||
167 | #define STA_INFO_PIN_STAT_PINNED 1 | ||
168 | #define STA_INFO_PIN_STAT_DESTROY 2 | ||
169 | |||
170 | /** | 169 | /** |
171 | * struct sta_info - STA information | 170 | * struct sta_info - STA information |
172 | * | 171 | * |
@@ -187,7 +186,6 @@ struct sta_ampdu_mlme { | |||
187 | * @flaglock: spinlock for flags accesses | 186 | * @flaglock: spinlock for flags accesses |
188 | * @drv_unblock_wk: used for driver PS unblocking | 187 | * @drv_unblock_wk: used for driver PS unblocking |
189 | * @listen_interval: listen interval of this station, when we're acting as AP | 188 | * @listen_interval: listen interval of this station, when we're acting as AP |
190 | * @pin_status: used internally for pinning a STA struct into memory | ||
191 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | 189 | * @flags: STA flags, see &enum ieee80211_sta_info_flags |
192 | * @ps_tx_buf: buffer of frames to transmit to this station | 190 | * @ps_tx_buf: buffer of frames to transmit to this station |
193 | * when it leaves power saving state | 191 | * when it leaves power saving state |
@@ -226,6 +224,7 @@ struct sta_ampdu_mlme { | |||
226 | * @debugfs: debug filesystem info | 224 | * @debugfs: debug filesystem info |
227 | * @sta: station information we share with the driver | 225 | * @sta: station information we share with the driver |
228 | * @dead: set to true when sta is unlinked | 226 | * @dead: set to true when sta is unlinked |
227 | * @uploaded: set to true when sta is uploaded to the driver | ||
229 | */ | 228 | */ |
230 | struct sta_info { | 229 | struct sta_info { |
231 | /* General information, mostly static */ | 230 | /* General information, mostly static */ |
@@ -245,11 +244,7 @@ struct sta_info { | |||
245 | 244 | ||
246 | bool dead; | 245 | bool dead; |
247 | 246 | ||
248 | /* | 247 | bool uploaded; |
249 | * for use by the internal lifetime management, | ||
250 | * see __sta_info_unlink | ||
251 | */ | ||
252 | u8 pin_status; | ||
253 | 248 | ||
254 | /* | 249 | /* |
255 | * frequently updated, locked with own spinlock (flaglock), | 250 | * frequently updated, locked with own spinlock (flaglock), |
@@ -449,18 +444,19 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
449 | * Insert STA info into hash table/list, returns zero or a | 444 | * Insert STA info into hash table/list, returns zero or a |
450 | * -EEXIST if (if the same MAC address is already present). | 445 | * -EEXIST if (if the same MAC address is already present). |
451 | * | 446 | * |
452 | * Calling this without RCU protection makes the caller | 447 | * Calling the non-rcu version makes the caller relinquish, |
453 | * relinquish its reference to @sta. | 448 | * the _rcu version calls read_lock_rcu() and must be called |
449 | * without it held. | ||
454 | */ | 450 | */ |
455 | int sta_info_insert(struct sta_info *sta); | 451 | int sta_info_insert(struct sta_info *sta); |
456 | /* | 452 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); |
457 | * Unlink a STA info from the hash table/list. | 453 | int sta_info_insert_atomic(struct sta_info *sta); |
458 | * This can NULL the STA pointer if somebody else | 454 | |
459 | * has already unlinked it. | 455 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, |
460 | */ | 456 | const u8 *addr); |
461 | void sta_info_unlink(struct sta_info **sta); | 457 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
458 | const u8 *addr); | ||
462 | 459 | ||
463 | void sta_info_destroy(struct sta_info *sta); | ||
464 | void sta_info_set_tim_bit(struct sta_info *sta); | 460 | void sta_info_set_tim_bit(struct sta_info *sta); |
465 | void sta_info_clear_tim_bit(struct sta_info *sta); | 461 | void sta_info_clear_tim_bit(struct sta_info *sta); |
466 | 462 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index e57ad6b1d7e..ded98730c11 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -188,6 +188,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
188 | rcu_read_lock(); | 188 | rcu_read_lock(); |
189 | 189 | ||
190 | sband = local->hw.wiphy->bands[info->band]; | 190 | sband = local->hw.wiphy->bands[info->band]; |
191 | fc = hdr->frame_control; | ||
191 | 192 | ||
192 | for_each_sta_info(local, hdr->addr1, sta, tmp) { | 193 | for_each_sta_info(local, hdr->addr1, sta, tmp) { |
193 | /* skip wrong virtual interface */ | 194 | /* skip wrong virtual interface */ |
@@ -205,8 +206,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
205 | return; | 206 | return; |
206 | } | 207 | } |
207 | 208 | ||
208 | fc = hdr->frame_control; | ||
209 | |||
210 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && | 209 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && |
211 | (ieee80211_is_data_qos(fc))) { | 210 | (ieee80211_is_data_qos(fc))) { |
212 | u16 tid, ssn; | 211 | u16 tid, ssn; |
@@ -275,6 +274,20 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
275 | local->dot11FailedCount++; | 274 | local->dot11FailedCount++; |
276 | } | 275 | } |
277 | 276 | ||
277 | if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) && | ||
278 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && | ||
279 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && | ||
280 | local->ps_sdata && !(local->scanning)) { | ||
281 | if (info->flags & IEEE80211_TX_STAT_ACK) { | ||
282 | local->ps_sdata->u.mgd.flags |= | ||
283 | IEEE80211_STA_NULLFUNC_ACKED; | ||
284 | ieee80211_queue_work(&local->hw, | ||
285 | &local->dynamic_ps_enable_work); | ||
286 | } else | ||
287 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
288 | msecs_to_jiffies(10)); | ||
289 | } | ||
290 | |||
278 | /* this was a transmitted frame, but now we want to reuse it */ | 291 | /* this was a transmitted frame, but now we want to reuse it */ |
279 | skb_orphan(skb); | 292 | skb_orphan(skb); |
280 | 293 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 85e382aa894..cbe53ed4fb0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -571,7 +571,7 @@ ieee80211_tx_h_sta(struct ieee80211_tx_data *tx) | |||
571 | { | 571 | { |
572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
573 | 573 | ||
574 | if (tx->sta) | 574 | if (tx->sta && tx->sta->uploaded) |
575 | info->control.sta = &tx->sta->sta; | 575 | info->control.sta = &tx->sta->sta; |
576 | 576 | ||
577 | return TX_CONTINUE; | 577 | return TX_CONTINUE; |
@@ -1010,7 +1010,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1010 | (struct ieee80211_radiotap_header *) skb->data; | 1010 | (struct ieee80211_radiotap_header *) skb->data; |
1011 | struct ieee80211_supported_band *sband; | 1011 | struct ieee80211_supported_band *sband; |
1012 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1012 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1013 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); | 1013 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
1014 | NULL); | ||
1014 | 1015 | ||
1015 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; | 1016 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; |
1016 | 1017 | ||
@@ -1046,7 +1047,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1046 | * because it will be recomputed and added | 1047 | * because it will be recomputed and added |
1047 | * on transmission | 1048 | * on transmission |
1048 | */ | 1049 | */ |
1049 | if (skb->len < (iterator.max_length + FCS_LEN)) | 1050 | if (skb->len < (iterator._max_length + FCS_LEN)) |
1050 | return false; | 1051 | return false; |
1051 | 1052 | ||
1052 | skb_trim(skb, skb->len - FCS_LEN); | 1053 | skb_trim(skb, skb->len - FCS_LEN); |
@@ -1073,10 +1074,10 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1073 | 1074 | ||
1074 | /* | 1075 | /* |
1075 | * remove the radiotap header | 1076 | * remove the radiotap header |
1076 | * iterator->max_length was sanity-checked against | 1077 | * iterator->_max_length was sanity-checked against |
1077 | * skb->len by iterator init | 1078 | * skb->len by iterator init |
1078 | */ | 1079 | */ |
1079 | skb_pull(skb, iterator.max_length); | 1080 | skb_pull(skb, iterator._max_length); |
1080 | 1081 | ||
1081 | return true; | 1082 | return true; |
1082 | } | 1083 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ca170b417da..c453226f06b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1082,7 +1082,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1082 | struct ieee80211_hw *hw = &local->hw; | 1082 | struct ieee80211_hw *hw = &local->hw; |
1083 | struct ieee80211_sub_if_data *sdata; | 1083 | struct ieee80211_sub_if_data *sdata; |
1084 | struct sta_info *sta; | 1084 | struct sta_info *sta; |
1085 | unsigned long flags; | ||
1086 | int res; | 1085 | int res; |
1087 | 1086 | ||
1088 | if (local->suspended) | 1087 | if (local->suspended) |
@@ -1116,20 +1115,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1116 | } | 1115 | } |
1117 | 1116 | ||
1118 | /* add STAs back */ | 1117 | /* add STAs back */ |
1119 | if (local->ops->sta_notify) { | 1118 | mutex_lock(&local->sta_mtx); |
1120 | spin_lock_irqsave(&local->sta_lock, flags); | 1119 | list_for_each_entry(sta, &local->sta_list, list) { |
1121 | list_for_each_entry(sta, &local->sta_list, list) { | 1120 | if (sta->uploaded) { |
1122 | sdata = sta->sdata; | 1121 | sdata = sta->sdata; |
1123 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1122 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1124 | sdata = container_of(sdata->bss, | 1123 | sdata = container_of(sdata->bss, |
1125 | struct ieee80211_sub_if_data, | 1124 | struct ieee80211_sub_if_data, |
1126 | u.ap); | 1125 | u.ap); |
1127 | 1126 | ||
1128 | drv_sta_notify(local, sdata, STA_NOTIFY_ADD, | 1127 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
1129 | &sta->sta); | ||
1130 | } | 1128 | } |
1131 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1132 | } | 1129 | } |
1130 | mutex_unlock(&local->sta_mtx); | ||
1133 | 1131 | ||
1134 | /* Clear Suspend state so that ADDBA requests can be processed */ | 1132 | /* Clear Suspend state so that ADDBA requests can be processed */ |
1135 | 1133 | ||
@@ -1180,6 +1178,14 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1180 | } | 1178 | } |
1181 | } | 1179 | } |
1182 | 1180 | ||
1181 | rcu_read_lock(); | ||
1182 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
1183 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
1184 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
1185 | } | ||
1186 | } | ||
1187 | rcu_read_unlock(); | ||
1188 | |||
1183 | /* add back keys */ | 1189 | /* add back keys */ |
1184 | list_for_each_entry(sdata, &local->interfaces, list) | 1190 | list_for_each_entry(sdata, &local->interfaces, list) |
1185 | if (ieee80211_sdata_running(sdata)) | 1191 | if (ieee80211_sdata_running(sdata)) |
@@ -1219,10 +1225,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1219 | 1225 | ||
1220 | add_timer(&local->sta_cleanup); | 1226 | add_timer(&local->sta_cleanup); |
1221 | 1227 | ||
1222 | spin_lock_irqsave(&local->sta_lock, flags); | 1228 | mutex_lock(&local->sta_mtx); |
1223 | list_for_each_entry(sta, &local->sta_list, list) | 1229 | list_for_each_entry(sta, &local->sta_list, list) |
1224 | mesh_plink_restart(sta); | 1230 | mesh_plink_restart(sta); |
1225 | spin_unlock_irqrestore(&local->sta_lock, flags); | 1231 | mutex_unlock(&local->sta_mtx); |
1226 | #else | 1232 | #else |
1227 | WARN_ON(1); | 1233 | WARN_ON(1); |
1228 | #endif | 1234 | #endif |
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index f591871a7b4..1332c445d1c 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c | |||
@@ -2,6 +2,16 @@ | |||
2 | * Radiotap parser | 2 | * Radiotap parser |
3 | * | 3 | * |
4 | * Copyright 2007 Andy Green <andy@warmcat.com> | 4 | * Copyright 2007 Andy Green <andy@warmcat.com> |
5 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Alternatively, this software may be distributed under the terms of BSD | ||
12 | * license. | ||
13 | * | ||
14 | * See COPYING for more details. | ||
5 | */ | 15 | */ |
6 | 16 | ||
7 | #include <net/cfg80211.h> | 17 | #include <net/cfg80211.h> |
@@ -10,6 +20,35 @@ | |||
10 | 20 | ||
11 | /* function prototypes and related defs are in include/net/cfg80211.h */ | 21 | /* function prototypes and related defs are in include/net/cfg80211.h */ |
12 | 22 | ||
23 | static const struct radiotap_align_size rtap_namespace_sizes[] = { | ||
24 | [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, | ||
25 | [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, | ||
26 | [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, | ||
27 | [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, | ||
28 | [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, | ||
29 | [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, | ||
30 | [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, | ||
31 | [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, | ||
32 | [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, | ||
33 | [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, | ||
34 | [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, | ||
35 | [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, | ||
36 | [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, | ||
37 | [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, | ||
38 | [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, | ||
39 | [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, | ||
40 | [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, | ||
41 | [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, | ||
42 | /* | ||
43 | * add more here as they are defined in radiotap.h | ||
44 | */ | ||
45 | }; | ||
46 | |||
47 | static const struct ieee80211_radiotap_namespace radiotap_ns = { | ||
48 | .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), | ||
49 | .align_size = rtap_namespace_sizes, | ||
50 | }; | ||
51 | |||
13 | /** | 52 | /** |
14 | * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization | 53 | * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization |
15 | * @iterator: radiotap_iterator to initialize | 54 | * @iterator: radiotap_iterator to initialize |
@@ -50,9 +89,9 @@ | |||
50 | */ | 89 | */ |
51 | 90 | ||
52 | int ieee80211_radiotap_iterator_init( | 91 | int ieee80211_radiotap_iterator_init( |
53 | struct ieee80211_radiotap_iterator *iterator, | 92 | struct ieee80211_radiotap_iterator *iterator, |
54 | struct ieee80211_radiotap_header *radiotap_header, | 93 | struct ieee80211_radiotap_header *radiotap_header, |
55 | int max_length) | 94 | int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) |
56 | { | 95 | { |
57 | /* Linux only supports version 0 radiotap format */ | 96 | /* Linux only supports version 0 radiotap format */ |
58 | if (radiotap_header->it_version) | 97 | if (radiotap_header->it_version) |
@@ -62,19 +101,24 @@ int ieee80211_radiotap_iterator_init( | |||
62 | if (max_length < get_unaligned_le16(&radiotap_header->it_len)) | 101 | if (max_length < get_unaligned_le16(&radiotap_header->it_len)) |
63 | return -EINVAL; | 102 | return -EINVAL; |
64 | 103 | ||
65 | iterator->rtheader = radiotap_header; | 104 | iterator->_rtheader = radiotap_header; |
66 | iterator->max_length = get_unaligned_le16(&radiotap_header->it_len); | 105 | iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); |
67 | iterator->arg_index = 0; | 106 | iterator->_arg_index = 0; |
68 | iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); | 107 | iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); |
69 | iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); | 108 | iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); |
70 | iterator->this_arg = NULL; | 109 | iterator->_reset_on_ext = 0; |
110 | iterator->_next_bitmap = &radiotap_header->it_present; | ||
111 | iterator->_next_bitmap++; | ||
112 | iterator->_vns = vns; | ||
113 | iterator->current_namespace = &radiotap_ns; | ||
114 | iterator->is_radiotap_ns = 1; | ||
71 | 115 | ||
72 | /* find payload start allowing for extended bitmap(s) */ | 116 | /* find payload start allowing for extended bitmap(s) */ |
73 | 117 | ||
74 | if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { | 118 | if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) { |
75 | while (get_unaligned_le32(iterator->arg) & | 119 | while (get_unaligned_le32(iterator->_arg) & |
76 | (1 << IEEE80211_RADIOTAP_EXT)) { | 120 | (1 << IEEE80211_RADIOTAP_EXT)) { |
77 | iterator->arg += sizeof(u32); | 121 | iterator->_arg += sizeof(uint32_t); |
78 | 122 | ||
79 | /* | 123 | /* |
80 | * check for insanity where the present bitmaps | 124 | * check for insanity where the present bitmaps |
@@ -82,12 +126,13 @@ int ieee80211_radiotap_iterator_init( | |||
82 | * stated radiotap header length | 126 | * stated radiotap header length |
83 | */ | 127 | */ |
84 | 128 | ||
85 | if (((ulong)iterator->arg - | 129 | if ((unsigned long)iterator->_arg - |
86 | (ulong)iterator->rtheader) > iterator->max_length) | 130 | (unsigned long)iterator->_rtheader > |
131 | (unsigned long)iterator->_max_length) | ||
87 | return -EINVAL; | 132 | return -EINVAL; |
88 | } | 133 | } |
89 | 134 | ||
90 | iterator->arg += sizeof(u32); | 135 | iterator->_arg += sizeof(uint32_t); |
91 | 136 | ||
92 | /* | 137 | /* |
93 | * no need to check again for blowing past stated radiotap | 138 | * no need to check again for blowing past stated radiotap |
@@ -96,12 +141,36 @@ int ieee80211_radiotap_iterator_init( | |||
96 | */ | 141 | */ |
97 | } | 142 | } |
98 | 143 | ||
144 | iterator->this_arg = iterator->_arg; | ||
145 | |||
99 | /* we are all initialized happily */ | 146 | /* we are all initialized happily */ |
100 | 147 | ||
101 | return 0; | 148 | return 0; |
102 | } | 149 | } |
103 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); | 150 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); |
104 | 151 | ||
152 | static void find_ns(struct ieee80211_radiotap_iterator *iterator, | ||
153 | uint32_t oui, uint8_t subns) | ||
154 | { | ||
155 | int i; | ||
156 | |||
157 | iterator->current_namespace = NULL; | ||
158 | |||
159 | if (!iterator->_vns) | ||
160 | return; | ||
161 | |||
162 | for (i = 0; i < iterator->_vns->n_ns; i++) { | ||
163 | if (iterator->_vns->ns[i].oui != oui) | ||
164 | continue; | ||
165 | if (iterator->_vns->ns[i].subns != subns) | ||
166 | continue; | ||
167 | |||
168 | iterator->current_namespace = &iterator->_vns->ns[i]; | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
105 | 174 | ||
106 | /** | 175 | /** |
107 | * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg | 176 | * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg |
@@ -127,99 +196,80 @@ EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); | |||
127 | */ | 196 | */ |
128 | 197 | ||
129 | int ieee80211_radiotap_iterator_next( | 198 | int ieee80211_radiotap_iterator_next( |
130 | struct ieee80211_radiotap_iterator *iterator) | 199 | struct ieee80211_radiotap_iterator *iterator) |
131 | { | 200 | { |
132 | 201 | while (1) { | |
133 | /* | ||
134 | * small length lookup table for all radiotap types we heard of | ||
135 | * starting from b0 in the bitmap, so we can walk the payload | ||
136 | * area of the radiotap header | ||
137 | * | ||
138 | * There is a requirement to pad args, so that args | ||
139 | * of a given length must begin at a boundary of that length | ||
140 | * -- but note that compound args are allowed (eg, 2 x u16 | ||
141 | * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not | ||
142 | * a reliable indicator of alignment requirement. | ||
143 | * | ||
144 | * upper nybble: content alignment for arg | ||
145 | * lower nybble: content length for arg | ||
146 | */ | ||
147 | |||
148 | static const u8 rt_sizes[] = { | ||
149 | [IEEE80211_RADIOTAP_TSFT] = 0x88, | ||
150 | [IEEE80211_RADIOTAP_FLAGS] = 0x11, | ||
151 | [IEEE80211_RADIOTAP_RATE] = 0x11, | ||
152 | [IEEE80211_RADIOTAP_CHANNEL] = 0x24, | ||
153 | [IEEE80211_RADIOTAP_FHSS] = 0x22, | ||
154 | [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, | ||
155 | [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, | ||
156 | [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, | ||
157 | [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, | ||
158 | [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, | ||
159 | [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, | ||
160 | [IEEE80211_RADIOTAP_ANTENNA] = 0x11, | ||
161 | [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, | ||
162 | [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, | ||
163 | [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, | ||
164 | [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, | ||
165 | [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, | ||
166 | [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, | ||
167 | /* | ||
168 | * add more here as they are defined in | ||
169 | * include/net/ieee80211_radiotap.h | ||
170 | */ | ||
171 | }; | ||
172 | |||
173 | /* | ||
174 | * for every radiotap entry we can at | ||
175 | * least skip (by knowing the length)... | ||
176 | */ | ||
177 | |||
178 | while (iterator->arg_index < sizeof(rt_sizes)) { | ||
179 | int hit = 0; | 202 | int hit = 0; |
180 | int pad; | 203 | int pad, align, size, subns, vnslen; |
204 | uint32_t oui; | ||
181 | 205 | ||
182 | if (!(iterator->bitmap_shifter & 1)) | 206 | /* if no more EXT bits, that's it */ |
207 | if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && | ||
208 | !(iterator->_bitmap_shifter & 1)) | ||
209 | return -ENOENT; | ||
210 | |||
211 | if (!(iterator->_bitmap_shifter & 1)) | ||
183 | goto next_entry; /* arg not present */ | 212 | goto next_entry; /* arg not present */ |
184 | 213 | ||
214 | /* get alignment/size of data */ | ||
215 | switch (iterator->_arg_index % 32) { | ||
216 | case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: | ||
217 | case IEEE80211_RADIOTAP_EXT: | ||
218 | align = 1; | ||
219 | size = 0; | ||
220 | break; | ||
221 | case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: | ||
222 | align = 2; | ||
223 | size = 6; | ||
224 | break; | ||
225 | default: | ||
226 | if (!iterator->current_namespace || | ||
227 | iterator->_arg_index >= iterator->current_namespace->n_bits) { | ||
228 | if (iterator->current_namespace == &radiotap_ns) | ||
229 | return -ENOENT; | ||
230 | align = 0; | ||
231 | } else { | ||
232 | align = iterator->current_namespace->align_size[iterator->_arg_index].align; | ||
233 | size = iterator->current_namespace->align_size[iterator->_arg_index].size; | ||
234 | } | ||
235 | if (!align) { | ||
236 | /* skip all subsequent data */ | ||
237 | iterator->_arg = iterator->_next_ns_data; | ||
238 | /* give up on this namespace */ | ||
239 | iterator->current_namespace = NULL; | ||
240 | goto next_entry; | ||
241 | } | ||
242 | break; | ||
243 | } | ||
244 | |||
185 | /* | 245 | /* |
186 | * arg is present, account for alignment padding | 246 | * arg is present, account for alignment padding |
187 | * 8-bit args can be at any alignment | ||
188 | * 16-bit args must start on 16-bit boundary | ||
189 | * 32-bit args must start on 32-bit boundary | ||
190 | * 64-bit args must start on 64-bit boundary | ||
191 | * | 247 | * |
192 | * note that total arg size can differ from alignment of | 248 | * Note that these alignments are relative to the start |
193 | * elements inside arg, so we use upper nybble of length | 249 | * of the radiotap header. There is no guarantee |
194 | * table to base alignment on | ||
195 | * | ||
196 | * also note: these alignments are ** relative to the | ||
197 | * start of the radiotap header **. There is no guarantee | ||
198 | * that the radiotap header itself is aligned on any | 250 | * that the radiotap header itself is aligned on any |
199 | * kind of boundary. | 251 | * kind of boundary. |
200 | * | 252 | * |
201 | * the above is why get_unaligned() is used to dereference | 253 | * The above is why get_unaligned() is used to dereference |
202 | * multibyte elements from the radiotap area | 254 | * multibyte elements from the radiotap area. |
203 | */ | 255 | */ |
204 | 256 | ||
205 | pad = (((ulong)iterator->arg) - | 257 | pad = ((unsigned long)iterator->_arg - |
206 | ((ulong)iterator->rtheader)) & | 258 | (unsigned long)iterator->_rtheader) & (align - 1); |
207 | ((rt_sizes[iterator->arg_index] >> 4) - 1); | ||
208 | 259 | ||
209 | if (pad) | 260 | if (pad) |
210 | iterator->arg += | 261 | iterator->_arg += align - pad; |
211 | (rt_sizes[iterator->arg_index] >> 4) - pad; | ||
212 | 262 | ||
213 | /* | 263 | /* |
214 | * this is what we will return to user, but we need to | 264 | * this is what we will return to user, but we need to |
215 | * move on first so next call has something fresh to test | 265 | * move on first so next call has something fresh to test |
216 | */ | 266 | */ |
217 | iterator->this_arg_index = iterator->arg_index; | 267 | iterator->this_arg_index = iterator->_arg_index; |
218 | iterator->this_arg = iterator->arg; | 268 | iterator->this_arg = iterator->_arg; |
219 | hit = 1; | 269 | iterator->this_arg_size = size; |
220 | 270 | ||
221 | /* internally move on the size of this arg */ | 271 | /* internally move on the size of this arg */ |
222 | iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; | 272 | iterator->_arg += size; |
223 | 273 | ||
224 | /* | 274 | /* |
225 | * check for insanity where we are given a bitmap that | 275 | * check for insanity where we are given a bitmap that |
@@ -228,32 +278,73 @@ int ieee80211_radiotap_iterator_next( | |||
228 | * max_length on the last arg, never exceeding it. | 278 | * max_length on the last arg, never exceeding it. |
229 | */ | 279 | */ |
230 | 280 | ||
231 | if (((ulong)iterator->arg - (ulong)iterator->rtheader) > | 281 | if ((unsigned long)iterator->_arg - |
232 | iterator->max_length) | 282 | (unsigned long)iterator->_rtheader > |
283 | (unsigned long)iterator->_max_length) | ||
233 | return -EINVAL; | 284 | return -EINVAL; |
234 | 285 | ||
235 | next_entry: | 286 | /* these special ones are valid in each bitmap word */ |
236 | iterator->arg_index++; | 287 | switch (iterator->_arg_index % 32) { |
237 | if (unlikely((iterator->arg_index & 31) == 0)) { | 288 | case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: |
238 | /* completed current u32 bitmap */ | 289 | iterator->_bitmap_shifter >>= 1; |
239 | if (iterator->bitmap_shifter & 1) { | 290 | iterator->_arg_index++; |
240 | /* b31 was set, there is more */ | 291 | |
241 | /* move to next u32 bitmap */ | 292 | iterator->_reset_on_ext = 1; |
242 | iterator->bitmap_shifter = | 293 | |
243 | get_unaligned_le32(iterator->next_bitmap); | 294 | vnslen = get_unaligned_le16(iterator->this_arg + 4); |
244 | iterator->next_bitmap++; | 295 | iterator->_next_ns_data = iterator->_arg + vnslen; |
245 | } else | 296 | oui = (*iterator->this_arg << 16) | |
246 | /* no more bitmaps: end */ | 297 | (*(iterator->this_arg + 1) << 8) | |
247 | iterator->arg_index = sizeof(rt_sizes); | 298 | *(iterator->this_arg + 2); |
248 | } else /* just try the next bit */ | 299 | subns = *(iterator->this_arg + 3); |
249 | iterator->bitmap_shifter >>= 1; | 300 | |
301 | find_ns(iterator, oui, subns); | ||
302 | |||
303 | iterator->is_radiotap_ns = 0; | ||
304 | /* allow parsers to show this information */ | ||
305 | iterator->this_arg_index = | ||
306 | IEEE80211_RADIOTAP_VENDOR_NAMESPACE; | ||
307 | iterator->this_arg_size += vnslen; | ||
308 | if ((unsigned long)iterator->this_arg + | ||
309 | iterator->this_arg_size - | ||
310 | (unsigned long)iterator->_rtheader > | ||
311 | (unsigned long)(unsigned long)iterator->_max_length) | ||
312 | return -EINVAL; | ||
313 | hit = 1; | ||
314 | break; | ||
315 | case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: | ||
316 | iterator->_bitmap_shifter >>= 1; | ||
317 | iterator->_arg_index++; | ||
318 | |||
319 | iterator->_reset_on_ext = 1; | ||
320 | iterator->current_namespace = &radiotap_ns; | ||
321 | iterator->is_radiotap_ns = 1; | ||
322 | break; | ||
323 | case IEEE80211_RADIOTAP_EXT: | ||
324 | /* | ||
325 | * bit 31 was set, there is more | ||
326 | * -- move to next u32 bitmap | ||
327 | */ | ||
328 | iterator->_bitmap_shifter = | ||
329 | get_unaligned_le32(iterator->_next_bitmap); | ||
330 | iterator->_next_bitmap++; | ||
331 | if (iterator->_reset_on_ext) | ||
332 | iterator->_arg_index = 0; | ||
333 | else | ||
334 | iterator->_arg_index++; | ||
335 | iterator->_reset_on_ext = 0; | ||
336 | break; | ||
337 | default: | ||
338 | /* we've got a hit! */ | ||
339 | hit = 1; | ||
340 | next_entry: | ||
341 | iterator->_bitmap_shifter >>= 1; | ||
342 | iterator->_arg_index++; | ||
343 | } | ||
250 | 344 | ||
251 | /* if we found a valid arg earlier, return it now */ | 345 | /* if we found a valid arg earlier, return it now */ |
252 | if (hit) | 346 | if (hit) |
253 | return 0; | 347 | return 0; |
254 | } | 348 | } |
255 | |||
256 | /* we don't know how to handle any more args, we're done */ | ||
257 | return -ENOENT; | ||
258 | } | 349 | } |
259 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_next); | 350 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_next); |