浏览代码

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

David S. Miller 16 年之前
父节点
当前提交
c2da953a46
共有 50 个文件被更改,包括 1166 次插入651 次删除
  1. 5 0
      drivers/net/wireless/ath5k/ath5k.h
  2. 21 17
      drivers/net/wireless/ath5k/base.c
  3. 2 2
      drivers/net/wireless/ath5k/desc.c
  4. 1 0
      drivers/net/wireless/ath9k/core.h
  5. 188 189
      drivers/net/wireless/ath9k/main.c
  6. 2 1
      drivers/net/wireless/ath9k/rc.c
  7. 36 39
      drivers/net/wireless/ath9k/recv.c
  8. 21 1
      drivers/net/wireless/ath9k/xmit.c
  9. 1 0
      drivers/net/wireless/b43/debugfs.c
  10. 1 0
      drivers/net/wireless/b43/debugfs.h
  11. 59 44
      drivers/net/wireless/b43/main.c
  12. 18 0
      drivers/net/wireless/b43/phy_common.c
  13. 6 2
      drivers/net/wireless/b43/phy_g.c
  14. 0 1
      drivers/net/wireless/iwlwifi/iwl-3945.c
  15. 1 8
      drivers/net/wireless/iwlwifi/iwl-3945.h
  16. 3 7
      drivers/net/wireless/iwlwifi/iwl-4965.c
  17. 3 7
      drivers/net/wireless/iwlwifi/iwl-5000.c
  18. 16 10
      drivers/net/wireless/iwlwifi/iwl-agn-rs.c
  19. 21 20
      drivers/net/wireless/iwlwifi/iwl-agn.c
  20. 9 0
      drivers/net/wireless/iwlwifi/iwl-calib.c
  21. 2 0
      drivers/net/wireless/iwlwifi/iwl-commands.h
  22. 1 1
      drivers/net/wireless/iwlwifi/iwl-core.h
  23. 7 10
      drivers/net/wireless/iwlwifi/iwl-debug.h
  24. 3 26
      drivers/net/wireless/iwlwifi/iwl-dev.h
  25. 6 5
      drivers/net/wireless/iwlwifi/iwl-io.h
  26. 1 1
      drivers/net/wireless/iwlwifi/iwl-led.c
  27. 19 10
      drivers/net/wireless/iwlwifi/iwl-rx.c
  28. 3 5
      drivers/net/wireless/iwlwifi/iwl-tx.c
  29. 3 3
      drivers/net/wireless/iwlwifi/iwl3945-base.c
  30. 2 1
      drivers/net/wireless/libertas/if_sdio.c
  31. 2 4
      drivers/net/wireless/mac80211_hwsim.c
  32. 18 5
      drivers/net/wireless/p54/p54.h
  33. 125 73
      drivers/net/wireless/p54/p54common.c
  34. 14 11
      drivers/net/wireless/p54/p54common.h
  35. 5 7
      drivers/net/wireless/p54/p54pci.c
  36. 15 28
      drivers/net/wireless/p54/p54usb.c
  37. 6 10
      drivers/net/wireless/rtl818x/rtl8187_dev.c
  38. 42 11
      include/linux/nl80211.h
  39. 41 1
      include/net/cfg80211.h
  40. 16 10
      include/net/mac80211.h
  41. 37 5
      net/mac80211/cfg.c
  42. 24 11
      net/mac80211/ht.c
  43. 23 2
      net/mac80211/ieee80211_i.h
  44. 21 18
      net/mac80211/main.c
  45. 66 4
      net/mac80211/mlme.c
  46. 48 11
      net/mac80211/rx.c
  47. 13 0
      net/mac80211/tx.c
  48. 81 7
      net/mac80211/util.c
  49. 38 8
      net/mac80211/wext.c
  50. 70 15
      net/wireless/nl80211.c

+ 5 - 0
drivers/net/wireless/ath5k/ath5k.h

@@ -1350,4 +1350,9 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
 	return retval;
 	return retval;
 }
 }
 
 
+static inline int ath5k_pad_size(int hdrlen)
+{
+	return (hdrlen < 24) ? 0 : hdrlen & 3;
+}
+
 #endif
 #endif

+ 21 - 17
drivers/net/wireless/ath5k/base.c

@@ -1668,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data)
 	struct ath5k_desc *ds;
 	struct ath5k_desc *ds;
 	int ret;
 	int ret;
 	int hdrlen;
 	int hdrlen;
-	int pad;
+	int padsize;
 
 
 	spin_lock(&sc->rxbuflock);
 	spin_lock(&sc->rxbuflock);
 	if (list_empty(&sc->rxbuf)) {
 	if (list_empty(&sc->rxbuf)) {
@@ -1753,16 +1753,19 @@ accept:
 
 
 		skb_put(skb, rs.rs_datalen);
 		skb_put(skb, rs.rs_datalen);
 
 
-		/*
-		 * the hardware adds a padding to 4 byte boundaries between
-		 * the header and the payload data if the header length is
-		 * not multiples of 4 - remove it
-		 */
+		/* The MAC header is padded to have 32-bit boundary if the
+		 * packet payload is non-zero. The general calculation for
+		 * padsize would take into account odd header lengths:
+		 * padsize = (4 - hdrlen % 4) % 4; However, since only
+		 * even-length headers are used, padding can only be 0 or 2
+		 * bytes and we can optimize this a bit. In addition, we must
+		 * not try to remove padding from short control frames that do
+		 * not have payload. */
 		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-		if (hdrlen & 3) {
-			pad = hdrlen % 4;
-			memmove(skb->data + pad, skb->data, hdrlen);
-			skb_pull(skb, pad);
+		padsize = ath5k_pad_size(hdrlen);
+		if (padsize) {
+			memmove(skb->data + padsize, skb->data, hdrlen);
+			skb_pull(skb, padsize);
 		}
 		}
 
 
 		/*
 		/*
@@ -2623,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	struct ath5k_buf *bf;
 	struct ath5k_buf *bf;
 	unsigned long flags;
 	unsigned long flags;
 	int hdrlen;
 	int hdrlen;
-	int pad;
+	int padsize;
 
 
 	ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
 	ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
 
 
@@ -2635,15 +2638,16 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	 * if this is not the case we add the padding after the header
 	 * if this is not the case we add the padding after the header
 	 */
 	 */
 	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-	if (hdrlen & 3) {
-		pad = hdrlen % 4;
-		if (skb_headroom(skb) < pad) {
+	padsize = ath5k_pad_size(hdrlen);
+	if (padsize) {
+
+		if (skb_headroom(skb) < padsize) {
 			ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
 			ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
-				" headroom to pad %d\n", hdrlen, pad);
+				  " headroom to pad %d\n", hdrlen, padsize);
 			return -1;
 			return -1;
 		}
 		}
-		skb_push(skb, pad);
-		memmove(skb->data, skb->data+pad, hdrlen);
+		skb_push(skb, padsize);
+		memmove(skb->data, skb->data+padsize, hdrlen);
 	}
 	}
 
 
 	spin_lock_irqsave(&sc->txbuflock, flags);
 	spin_lock_irqsave(&sc->txbuflock, flags);

+ 2 - 2
drivers/net/wireless/ath5k/desc.c

@@ -71,7 +71,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
 	/* Verify and set frame length */
 	/* Verify and set frame length */
 
 
 	/* remove padding we might have added before */
 	/* remove padding we might have added before */
-	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+	frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
 
 
 	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
 	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
 		return -EINVAL;
 		return -EINVAL;
@@ -202,7 +202,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
 	/* Verify and set frame length */
 	/* Verify and set frame length */
 
 
 	/* remove padding we might have added before */
 	/* remove padding we might have added before */
-	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+	frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
 
 
 	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
 	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
 		return -EINVAL;
 		return -EINVAL;

+ 1 - 0
drivers/net/wireless/ath9k/core.h

@@ -701,6 +701,7 @@ struct ath_softc {
 	struct ath_hal *sc_ah;
 	struct ath_hal *sc_ah;
 	void __iomem *mem;
 	void __iomem *mem;
 	spinlock_t sc_resetlock;
 	spinlock_t sc_resetlock;
+	struct mutex mutex;
 
 
 	u8 sc_curbssid[ETH_ALEN];
 	u8 sc_curbssid[ETH_ALEN];
 	u8 sc_myaddr[ETH_ALEN];
 	u8 sc_myaddr[ETH_ALEN];

+ 188 - 189
drivers/net/wireless/ath9k/main.c

@@ -61,8 +61,7 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz)
 
 
 static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
 static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
 {
 {
-	if (!sc->sc_curaid)
-		sc->cur_rate_table = sc->hw_rate_table[mode];
+	sc->cur_rate_table = sc->hw_rate_table[mode];
 	/*
 	/*
 	 * All protection frames are transmited at 2Mb/s for
 	 * All protection frames are transmited at 2Mb/s for
 	 * 11g, otherwise at 1Mb/s.
 	 * 11g, otherwise at 1Mb/s.
@@ -623,37 +622,40 @@ static int ath_get_channel(struct ath_softc *sc,
 	return -1;
 	return -1;
 }
 }
 
 
-/* ext_chan_offset: (-1, 0, 1) (below, none, above) */
-
 static u32 ath_get_extchanmode(struct ath_softc *sc,
 static u32 ath_get_extchanmode(struct ath_softc *sc,
 			       struct ieee80211_channel *chan,
 			       struct ieee80211_channel *chan,
-			       int ext_chan_offset,
-			       enum ath9k_ht_macmode tx_chan_width)
+			       enum nl80211_channel_type channel_type)
 {
 {
 	u32 chanmode = 0;
 	u32 chanmode = 0;
 
 
 	switch (chan->band) {
 	switch (chan->band) {
 	case IEEE80211_BAND_2GHZ:
 	case IEEE80211_BAND_2GHZ:
-		if ((ext_chan_offset == 0) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_20))
+		switch(channel_type) {
+		case NL80211_CHAN_NO_HT:
+		case NL80211_CHAN_HT20:
 			chanmode = CHANNEL_G_HT20;
 			chanmode = CHANNEL_G_HT20;
-		if ((ext_chan_offset == 1) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
+			break;
+		case NL80211_CHAN_HT40PLUS:
 			chanmode = CHANNEL_G_HT40PLUS;
 			chanmode = CHANNEL_G_HT40PLUS;
-		if ((ext_chan_offset == -1) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
+			break;
+		case NL80211_CHAN_HT40MINUS:
 			chanmode = CHANNEL_G_HT40MINUS;
 			chanmode = CHANNEL_G_HT40MINUS;
+			break;
+		}
 		break;
 		break;
 	case IEEE80211_BAND_5GHZ:
 	case IEEE80211_BAND_5GHZ:
-		if ((ext_chan_offset == 0) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_20))
+		switch(channel_type) {
+		case NL80211_CHAN_NO_HT:
+		case NL80211_CHAN_HT20:
 			chanmode = CHANNEL_A_HT20;
 			chanmode = CHANNEL_A_HT20;
-		if ((ext_chan_offset == 1) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
+			break;
+		case NL80211_CHAN_HT40PLUS:
 			chanmode = CHANNEL_A_HT40PLUS;
 			chanmode = CHANNEL_A_HT40PLUS;
-		if ((ext_chan_offset == -1) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
+			break;
+		case NL80211_CHAN_HT40MINUS:
 			chanmode = CHANNEL_A_HT40MINUS;
 			chanmode = CHANNEL_A_HT40MINUS;
+			break;
+		}
 		break;
 		break;
 	default:
 	default:
 		break;
 		break;
@@ -662,13 +664,6 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
 	return chanmode;
 	return chanmode;
 }
 }
 
 
-static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
-{
-	ath9k_hw_keyreset(sc->sc_ah, keyix);
-	if (freeslot)
-		clear_bit(keyix, sc->sc_keymap);
-}
-
 static int ath_keyset(struct ath_softc *sc, u16 keyix,
 static int ath_keyset(struct ath_softc *sc, u16 keyix,
 	       struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
 	       struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
 {
 {
@@ -680,21 +675,20 @@ static int ath_keyset(struct ath_softc *sc, u16 keyix,
 	return status != false;
 	return status != false;
 }
 }
 
 
-static int ath_setkey_tkip(struct ath_softc *sc,
-			   struct ieee80211_key_conf *key,
+static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
 			   struct ath9k_keyval *hk,
 			   struct ath9k_keyval *hk,
 			   const u8 *addr)
 			   const u8 *addr)
 {
 {
-	u8 *key_rxmic = NULL;
-	u8 *key_txmic = NULL;
+	const u8 *key_rxmic;
+	const u8 *key_txmic;
 
 
-	key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
-	key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+	key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+	key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
 
 
 	if (addr == NULL) {
 	if (addr == NULL) {
 		/* Group key installation */
 		/* Group key installation */
-		memcpy(hk->kv_mic,  key_rxmic, sizeof(hk->kv_mic));
-		return ath_keyset(sc, key->keyidx, hk, addr);
+		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+		return ath_keyset(sc, keyix, hk, addr);
 	}
 	}
 	if (!sc->sc_splitmic) {
 	if (!sc->sc_splitmic) {
 		/*
 		/*
@@ -703,14 +697,14 @@ static int ath_setkey_tkip(struct ath_softc *sc,
 		 */
 		 */
 		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
 		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
 		memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
 		memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
-		return ath_keyset(sc, key->keyidx, hk, addr);
+		return ath_keyset(sc, keyix, hk, addr);
 	}
 	}
 	/*
 	/*
 	 * TX key goes at first index, RX key at +32.
 	 * TX key goes at first index, RX key at +32.
 	 * The hal handles the MIC keys at index+64.
 	 * The hal handles the MIC keys at index+64.
 	 */
 	 */
 	memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
 	memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
-	if (!ath_keyset(sc, key->keyidx, hk, NULL)) {
+	if (!ath_keyset(sc, keyix, hk, NULL)) {
 		/* Txmic entry failed. No need to proceed further */
 		/* Txmic entry failed. No need to proceed further */
 		DPRINTF(sc, ATH_DBG_KEYCACHE,
 		DPRINTF(sc, ATH_DBG_KEYCACHE,
 			"Setting TX MIC Key Failed\n");
 			"Setting TX MIC Key Failed\n");
@@ -719,18 +713,97 @@ static int ath_setkey_tkip(struct ath_softc *sc,
 
 
 	memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
 	memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
 	/* XXX delete tx key on failure? */
 	/* XXX delete tx key on failure? */
-	return ath_keyset(sc, key->keyidx+32, hk, addr);
+	return ath_keyset(sc, keyix + 32, hk, addr);
+}
+
+static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
+{
+	int i;
+
+	for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
+		if (test_bit(i, sc->sc_keymap) ||
+		    test_bit(i + 64, sc->sc_keymap))
+			continue; /* At least one part of TKIP key allocated */
+		if (sc->sc_splitmic &&
+		    (test_bit(i + 32, sc->sc_keymap) ||
+		     test_bit(i + 64 + 32, sc->sc_keymap)))
+			continue; /* At least one part of TKIP key allocated */
+
+		/* Found a free slot for a TKIP key */
+		return i;
+	}
+	return -1;
+}
+
+static int ath_reserve_key_cache_slot(struct ath_softc *sc)
+{
+	int i;
+
+	/* First, try to find slots that would not be available for TKIP. */
+	if (sc->sc_splitmic) {
+		for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) {
+			if (!test_bit(i, sc->sc_keymap) &&
+			    (test_bit(i + 32, sc->sc_keymap) ||
+			     test_bit(i + 64, sc->sc_keymap) ||
+			     test_bit(i + 64 + 32, sc->sc_keymap)))
+				return i;
+			if (!test_bit(i + 32, sc->sc_keymap) &&
+			    (test_bit(i, sc->sc_keymap) ||
+			     test_bit(i + 64, sc->sc_keymap) ||
+			     test_bit(i + 64 + 32, sc->sc_keymap)))
+				return i + 32;
+			if (!test_bit(i + 64, sc->sc_keymap) &&
+			    (test_bit(i , sc->sc_keymap) ||
+			     test_bit(i + 32, sc->sc_keymap) ||
+			     test_bit(i + 64 + 32, sc->sc_keymap)))
+				return i + 64;
+			if (!test_bit(i + 64 + 32, sc->sc_keymap) &&
+			    (test_bit(i, sc->sc_keymap) ||
+			     test_bit(i + 32, sc->sc_keymap) ||
+			     test_bit(i + 64, sc->sc_keymap)))
+				return i + 64 + 32;
+		}
+	} else {
+		for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
+			if (!test_bit(i, sc->sc_keymap) &&
+			    test_bit(i + 64, sc->sc_keymap))
+				return i;
+			if (test_bit(i, sc->sc_keymap) &&
+			    !test_bit(i + 64, sc->sc_keymap))
+				return i + 64;
+		}
+	}
+
+	/* No partially used TKIP slots, pick any available slot */
+	for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) {
+		/* Do not allow slots that could be needed for TKIP group keys
+		 * to be used. This limitation could be removed if we know that
+		 * TKIP will not be used. */
+		if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
+			continue;
+		if (sc->sc_splitmic) {
+			if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
+				continue;
+			if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
+				continue;
+		}
+
+		if (!test_bit(i, sc->sc_keymap))
+			return i; /* Found a free slot for a key */
+	}
+
+	/* No free slot found */
+	return -1;
 }
 }
 
 
 static int ath_key_config(struct ath_softc *sc,
 static int ath_key_config(struct ath_softc *sc,
 			  const u8 *addr,
 			  const u8 *addr,
 			  struct ieee80211_key_conf *key)
 			  struct ieee80211_key_conf *key)
 {
 {
-	struct ieee80211_vif *vif;
 	struct ath9k_keyval hk;
 	struct ath9k_keyval hk;
 	const u8 *mac = NULL;
 	const u8 *mac = NULL;
 	int ret = 0;
 	int ret = 0;
-	enum nl80211_iftype opmode;
+	int idx;
 
 
 	memset(&hk, 0, sizeof(hk));
 	memset(&hk, 0, sizeof(hk));
 
 
@@ -748,65 +821,69 @@ static int ath_key_config(struct ath_softc *sc,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	hk.kv_len  = key->keylen;
+	hk.kv_len = key->keylen;
 	memcpy(hk.kv_val, key->key, key->keylen);
 	memcpy(hk.kv_val, key->key, key->keylen);
 
 
-	if (!sc->sc_vaps[0])
-		return -EIO;
-
-	vif = sc->sc_vaps[0];
-	opmode = vif->type;
+	if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+		/* For now, use the default keys for broadcast keys. This may
+		 * need to change with virtual interfaces. */
+		idx = key->keyidx;
+	} else if (key->keyidx) {
+		struct ieee80211_vif *vif;
 
 
-	/*
-	 *  Strategy:
-	 *   For STA mc tx, we will not setup a key at
-	 *   all since we never tx mc.
-	 *
-	 *   For STA mc rx, we will use the keyID.
-	 *
-	 *   For ADHOC mc tx, we will use the keyID, and no macaddr.
-	 *
-	 *   For ADHOC mc rx, we will alloc a slot and plumb the mac of
-	 *   the peer node.
-	 *   BUT we will plumb a cleartext key so that we can do
-	 *   per-Sta default key table lookup in software.
-	 */
-	if (is_broadcast_ether_addr(addr)) {
-		switch (opmode) {
-		case NL80211_IFTYPE_STATION:
-			/* default key:  could be group WPA key
-			 * or could be static WEP key */
-			mac = NULL;
-			break;
-		case NL80211_IFTYPE_ADHOC:
-			break;
-		case NL80211_IFTYPE_AP:
-			break;
-		default:
-			ASSERT(0);
-			break;
-		}
+		mac = addr;
+		vif = sc->sc_vaps[0];
+		if (vif->type != NL80211_IFTYPE_AP) {
+			/* Only keyidx 0 should be used with unicast key, but
+			 * allow this for client mode for now. */
+			idx = key->keyidx;
+		} else
+			return -EIO;
 	} else {
 	} else {
 		mac = addr;
 		mac = addr;
+		if (key->alg == ALG_TKIP)
+			idx = ath_reserve_key_cache_slot_tkip(sc);
+		else
+			idx = ath_reserve_key_cache_slot(sc);
+		if (idx < 0)
+			return -EIO; /* no free key cache entries */
 	}
 	}
 
 
 	if (key->alg == ALG_TKIP)
 	if (key->alg == ALG_TKIP)
-		ret = ath_setkey_tkip(sc, key, &hk, mac);
+		ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
 	else
 	else
-		ret = ath_keyset(sc, key->keyidx, &hk, mac);
+		ret = ath_keyset(sc, idx, &hk, mac);
 
 
 	if (!ret)
 	if (!ret)
 		return -EIO;
 		return -EIO;
 
 
-	return 0;
+	set_bit(idx, sc->sc_keymap);
+	if (key->alg == ALG_TKIP) {
+		set_bit(idx + 64, sc->sc_keymap);
+		if (sc->sc_splitmic) {
+			set_bit(idx + 32, sc->sc_keymap);
+			set_bit(idx + 64 + 32, sc->sc_keymap);
+		}
+	}
+
+	return idx;
 }
 }
 
 
 static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
 static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
 {
 {
-	int freeslot;
+	ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx);
+	if (key->hw_key_idx < IEEE80211_WEP_NKID)
+		return;
+
+	clear_bit(key->hw_key_idx, sc->sc_keymap);
+	if (key->alg != ALG_TKIP)
+		return;
 
 
-	freeslot = (key->keyidx >= 4) ? 1 : 0;
-	ath_key_reset(sc, key->keyidx, freeslot);
+	clear_bit(key->hw_key_idx + 64, sc->sc_keymap);
+	if (sc->sc_splitmic) {
+		clear_bit(key->hw_key_idx + 32, sc->sc_keymap);
+		clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap);
+	}
 }
 }
 
 
 static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
 static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
@@ -829,45 +906,15 @@ static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
 	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 }
 }
 
 
-static void ath9k_ht_conf(struct ath_softc *sc,
-			  struct ieee80211_bss_conf *bss_conf)
-{
-	if (sc->hw->conf.ht.enabled) {
-		if (bss_conf->ht.width_40_ok)
-			sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
-		else
-			sc->tx_chan_width = ATH9K_HT_MACMODE_20;
-
-		ath9k_hw_set11nmac2040(sc->sc_ah, sc->tx_chan_width);
-
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"BSS Changed HT, chanwidth: %d\n", sc->tx_chan_width);
-	}
-}
-
-static inline int ath_sec_offset(u8 ext_offset)
-{
-	if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)
-		return 0;
-	else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
-		return 1;
-	else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
-		return -1;
-
-	return 0;
-}
-
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *bss_conf)
 				 struct ieee80211_bss_conf *bss_conf)
 {
 {
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_channel *curchan = hw->conf.channel;
 	struct ath_vap *avp = (void *)vif->drv_priv;
 	struct ath_vap *avp = (void *)vif->drv_priv;
-	int pos;
 
 
 	if (bss_conf->assoc) {
 	if (bss_conf->assoc) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d\n", bss_conf->aid);
+		DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
+			bss_conf->aid, sc->sc_curbssid);
 
 
 		/* New association, store aid */
 		/* New association, store aid */
 		if (avp->av_opmode == NL80211_IFTYPE_STATION) {
 		if (avp->av_opmode == NL80211_IFTYPE_STATION) {
@@ -886,40 +933,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
 		sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
 		sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
 		sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
 		sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
 
 
-		/* Update chainmask */
-		ath_update_chainmask(sc, hw->conf.ht.enabled);
-
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"bssid %pM aid 0x%x\n",
-			sc->sc_curbssid, sc->sc_curaid);
-
-		pos = ath_get_channel(sc, curchan);
-		if (pos == -1) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"Invalid channel: %d\n", curchan->center_freq);
-			return;
-		}
-
-		if (hw->conf.ht.enabled) {
-			int offset =
-				ath_sec_offset(bss_conf->ht.secondary_channel_offset);
-			sc->tx_chan_width = (bss_conf->ht.width_40_ok) ?
-				ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
-
-			sc->sc_ah->ah_channels[pos].chanmode =
-				ath_get_extchanmode(sc, curchan,
-						    offset, sc->tx_chan_width);
-		} else {
-			sc->sc_ah->ah_channels[pos].chanmode =
-				(curchan->band == IEEE80211_BAND_2GHZ) ?
-				CHANNEL_G : CHANNEL_A;
-		}
-
-		/* set h/w channel */
-		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
-			DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel: %d\n",
-				curchan->center_freq);
-
 		/* Start ANI */
 		/* Start ANI */
 		mod_timer(&sc->sc_ani.timer,
 		mod_timer(&sc->sc_ani.timer,
 			jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
 			jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
@@ -1291,9 +1304,6 @@ static void ath_detach(struct ath_softc *sc)
 	ath_deinit_leds(sc);
 	ath_deinit_leds(sc);
 
 
 	ieee80211_unregister_hw(hw);
 	ieee80211_unregister_hw(hw);
-
-	ath_rate_control_unregister();
-
 	ath_rx_cleanup(sc);
 	ath_rx_cleanup(sc);
 	ath_tx_cleanup(sc);
 	ath_tx_cleanup(sc);
 
 
@@ -1326,6 +1336,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
 		printk(KERN_ERR "Unable to create debugfs files\n");
 		printk(KERN_ERR "Unable to create debugfs files\n");
 
 
 	spin_lock_init(&sc->sc_resetlock);
 	spin_lock_init(&sc->sc_resetlock);
+	mutex_init(&sc->mutex);
 	tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
 	tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
 	tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
 	tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
 		     (unsigned long)sc);
 		     (unsigned long)sc);
@@ -1362,18 +1373,6 @@ static int ath_init(u16 devid, struct ath_softc *sc)
 	 */
 	 */
 	for (i = 0; i < sc->sc_keymax; i++)
 	for (i = 0; i < sc->sc_keymax; i++)
 		ath9k_hw_keyreset(ah, (u16) i);
 		ath9k_hw_keyreset(ah, (u16) i);
-	/*
-	 * Mark key cache slots associated with global keys
-	 * as in use.  If we knew TKIP was not to be used we
-	 * could leave the +32, +64, and +32+64 slots free.
-	 * XXX only for splitmic.
-	 */
-	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
-		set_bit(i, sc->sc_keymap);
-		set_bit(i + 32, sc->sc_keymap);
-		set_bit(i + 64, sc->sc_keymap);
-		set_bit(i + 32 + 64, sc->sc_keymap);
-	}
 
 
 	/* Collect the channel list using the default country code */
 	/* Collect the channel list using the default country code */
 
 
@@ -1574,15 +1573,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
 	hw->sta_data_size = sizeof(struct ath_node);
 	hw->sta_data_size = sizeof(struct ath_node);
 	hw->vif_data_size = sizeof(struct ath_vap);
 	hw->vif_data_size = sizeof(struct ath_vap);
 
 
-	/* Register rate control */
 	hw->rate_control_algorithm = "ath9k_rate_control";
 	hw->rate_control_algorithm = "ath9k_rate_control";
-	error = ath_rate_control_register();
-	if (error != 0) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"Unable to register rate control algorithm: %d\n", error);
-		ath_rate_control_unregister();
-		goto bad;
-	}
 
 
 	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
 	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
 		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
 		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
@@ -1615,10 +1606,6 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
 #endif
 #endif
 
 
 	error = ieee80211_register_hw(hw);
 	error = ieee80211_register_hw(hw);
-	if (error != 0) {
-		ath_rate_control_unregister();
-		goto bad;
-	}
 
 
 	/* Initialize LED control */
 	/* Initialize LED control */
 	ath_init_leds(sc);
 	ath_init_leds(sc);
@@ -1626,7 +1613,6 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
 	return 0;
 	return 0;
 detach:
 detach:
 	ath_detach(sc);
 	ath_detach(sc);
-bad:
 	return error;
 	return error;
 }
 }
 
 
@@ -2146,7 +2132,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 	struct ath_softc *sc = hw->priv;
 	struct ath_softc *sc = hw->priv;
 	struct ieee80211_conf *conf = &hw->conf;
 	struct ieee80211_conf *conf = &hw->conf;
 
 
-	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+	mutex_lock(&sc->mutex);
+	if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
+		       IEEE80211_CONF_CHANGE_HT)) {
 		struct ieee80211_channel *curchan = hw->conf.channel;
 		struct ieee80211_channel *curchan = hw->conf.channel;
 		int pos;
 		int pos;
 
 
@@ -2157,6 +2145,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 		if (pos == -1) {
 		if (pos == -1) {
 			DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
 			DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
 				curchan->center_freq);
 				curchan->center_freq);
+			mutex_unlock(&sc->mutex);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
@@ -2165,29 +2154,29 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 			(curchan->band == IEEE80211_BAND_2GHZ) ?
 			(curchan->band == IEEE80211_BAND_2GHZ) ?
 			CHANNEL_G : CHANNEL_A;
 			CHANNEL_G : CHANNEL_A;
 
 
-		if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) &&
-		    (conf->ht.enabled)) {
-			sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ?
-				ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
+		if (conf->ht.enabled) {
+			if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS ||
+			    conf->ht.channel_type == NL80211_CHAN_HT40MINUS)
+				sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
 
 
 			sc->sc_ah->ah_channels[pos].chanmode =
 			sc->sc_ah->ah_channels[pos].chanmode =
 				ath_get_extchanmode(sc, curchan,
 				ath_get_extchanmode(sc, curchan,
-						    conf->ht.sec_chan_offset,
-						    sc->tx_chan_width);
+						    conf->ht.channel_type);
 		}
 		}
 
 
 		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
 		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
 			DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
 			DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
+			mutex_unlock(&sc->mutex);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
-	}
 
 
-	if (changed & IEEE80211_CONF_CHANGE_HT)
 		ath_update_chainmask(sc, conf->ht.enabled);
 		ath_update_chainmask(sc, conf->ht.enabled);
+	}
 
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER)
 	if (changed & IEEE80211_CONF_CHANGE_POWER)
 		sc->sc_config.txpowlimit = 2 * conf->power_level;
 		sc->sc_config.txpowlimit = 2 * conf->power_level;
 
 
+	mutex_unlock(&sc->mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2371,18 +2360,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
 	switch (cmd) {
 	switch (cmd) {
 	case SET_KEY:
 	case SET_KEY:
 		ret = ath_key_config(sc, addr, key);
 		ret = ath_key_config(sc, addr, key);
-		if (!ret) {
-			set_bit(key->keyidx, sc->sc_keymap);
-			key->hw_key_idx = key->keyidx;
+		if (ret >= 0) {
+			key->hw_key_idx = ret;
 			/* push IV and Michael MIC generation to stack */
 			/* push IV and Michael MIC generation to stack */
 			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 			if (key->alg == ALG_TKIP)
 			if (key->alg == ALG_TKIP)
 				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+			ret = 0;
 		}
 		}
 		break;
 		break;
 	case DISABLE_KEY:
 	case DISABLE_KEY:
 		ath_key_delete(sc, key);
 		ath_key_delete(sc, key);
-		clear_bit(key->keyidx, sc->sc_keymap);
 		break;
 		break;
 	default:
 	default:
 		ret = -EINVAL;
 		ret = -EINVAL;
@@ -2417,9 +2405,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 			sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
 			sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
 	}
 	}
 
 
-	if (changed & BSS_CHANGED_HT)
-		ath9k_ht_conf(sc, bss_conf);
-
 	if (changed & BSS_CHANGED_ASSOC) {
 	if (changed & BSS_CHANGED_ASSOC) {
 		DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
 		DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
 			bss_conf->assoc);
 			bss_conf->assoc);
@@ -2780,11 +2765,24 @@ static struct pci_driver ath_pci_driver = {
 
 
 static int __init init_ath_pci(void)
 static int __init init_ath_pci(void)
 {
 {
+	int error;
+
 	printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION);
 	printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION);
 
 
+	/* Register rate control algorithm */
+	error = ath_rate_control_register();
+	if (error != 0) {
+		printk(KERN_ERR
+			"Unable to register rate control algorithm: %d\n",
+			error);
+		ath_rate_control_unregister();
+		return error;
+	}
+
 	if (pci_register_driver(&ath_pci_driver) < 0) {
 	if (pci_register_driver(&ath_pci_driver) < 0) {
 		printk(KERN_ERR
 		printk(KERN_ERR
 			"ath_pci: No devices found, driver not installed.\n");
 			"ath_pci: No devices found, driver not installed.\n");
+		ath_rate_control_unregister();
 		pci_unregister_driver(&ath_pci_driver);
 		pci_unregister_driver(&ath_pci_driver);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -2795,6 +2793,7 @@ module_init(init_ath_pci);
 
 
 static void __exit exit_ath_pci(void)
 static void __exit exit_ath_pci(void)
 {
 {
+	ath_rate_control_unregister();
 	pci_unregister_driver(&ath_pci_driver);
 	pci_unregister_driver(&ath_pci_driver);
 	printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 	printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 }

+ 2 - 1
drivers/net/wireless/ath9k/rc.c

@@ -1498,7 +1498,8 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	__le16 fc = hdr->frame_control;
 	__le16 fc = hdr->frame_control;
 
 
 	/* lowest rate for management and multicast/broadcast frames */
 	/* lowest rate for management and multicast/broadcast frames */
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
+	    !sta) {
 		tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
 		tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
 		tx_info->control.rates[0].count =
 		tx_info->control.rates[0].count =
 			is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY;
 			is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY;

+ 36 - 39
drivers/net/wireless/ath9k/recv.c

@@ -111,33 +111,6 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
 	return skb;
 	return skb;
 }
 }
 
 
-static int ath_rate2idx(struct ath_softc *sc, int rate)
-{
-	int i = 0, cur_band, n_rates;
-	struct ieee80211_hw *hw = sc->hw;
-
-	cur_band = hw->conf.channel->band;
-	n_rates = sc->sbands[cur_band].n_bitrates;
-
-	for (i = 0; i < n_rates; i++) {
-		if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
-			break;
-	}
-
-	/*
-	 * NB:mac80211 validates rx rate index against the supported legacy rate
-	 * index only (should be done against ht rates also), return the highest
-	 * legacy rate index for rx rate which does not match any one of the
-	 * supported basic and extended rates to make mac80211 happy.
-	 * The following hack will be cleaned up once the issue with
-	 * the rx rate index validation in mac80211 is fixed.
-	 */
-	if (i == n_rates)
-		return n_rates - 1;
-
-	return i;
-}
-
 /*
 /*
  * For Decrypt or Demic errors, we only mark packet status here and always push
  * For Decrypt or Demic errors, we only mark packet status here and always push
  * up the frame up to let mac80211 handle the actual error case, be it no
  * up the frame up to let mac80211 handle the actual error case, be it no
@@ -147,9 +120,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
 			  struct ieee80211_rx_status *rx_status, bool *decrypt_error,
 			  struct ieee80211_rx_status *rx_status, bool *decrypt_error,
 			  struct ath_softc *sc)
 			  struct ath_softc *sc)
 {
 {
-	struct ath_rate_table *rate_table = sc->cur_rate_table;
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_hdr *hdr;
-	int ratekbps, rix;
 	u8 ratecode;
 	u8 ratecode;
 	__le16 fc;
 	__le16 fc;
 
 
@@ -204,15 +175,36 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
 	}
 	}
 
 
 	ratecode = ds->ds_rxstat.rs_rate;
 	ratecode = ds->ds_rxstat.rs_rate;
-	rix = rate_table->rateCodeToIndex[ratecode];
-	ratekbps = rate_table->info[rix].ratekbps;
 
 
-	/* HT rate */
 	if (ratecode & 0x80) {
 	if (ratecode & 0x80) {
+		/* HT rate */
+		rx_status->flag |= RX_FLAG_HT;
 		if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
 		if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
-			ratekbps = (ratekbps * 27) / 13;
+			rx_status->flag |= RX_FLAG_40MHZ;
 		if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
 		if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
-			ratekbps = (ratekbps * 10) / 9;
+			rx_status->flag |= RX_FLAG_SHORT_GI;
+		rx_status->rate_idx = ratecode & 0x7f;
+	} else {
+		int i = 0, cur_band, n_rates;
+		struct ieee80211_hw *hw = sc->hw;
+
+		cur_band = hw->conf.channel->band;
+		n_rates = sc->sbands[cur_band].n_bitrates;
+
+		for (i = 0; i < n_rates; i++) {
+			if (sc->sbands[cur_band].bitrates[i].hw_value ==
+			    ratecode) {
+				rx_status->rate_idx = i;
+				break;
+			}
+
+			if (sc->sbands[cur_band].bitrates[i].hw_value_short ==
+			    ratecode) {
+				rx_status->rate_idx = i;
+				rx_status->flag |= RX_FLAG_SHORTPRE;
+				break;
+			}
+		}
 	}
 	}
 
 
 	rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
 	rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
@@ -220,7 +212,6 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
 	rx_status->freq =  sc->hw->conf.channel->center_freq;
 	rx_status->freq =  sc->hw->conf.channel->center_freq;
 	rx_status->noise = sc->sc_ani.sc_noise_floor;
 	rx_status->noise = sc->sc_ani.sc_noise_floor;
 	rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
 	rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
-	rx_status->rate_idx = ath_rate2idx(sc, (ratekbps / 100));
 	rx_status->antenna = ds->ds_rxstat.rs_antenna;
 	rx_status->antenna = ds->ds_rxstat.rs_antenna;
 
 
 	/* at 45 you will be able to use MCS 15 reliably. A more elaborate
 	/* at 45 you will be able to use MCS 15 reliably. A more elaborate
@@ -528,6 +519,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		if (!skb)
 		if (!skb)
 			continue;
 			continue;
 
 
+		/*
+		 * Synchronize the DMA transfer with CPU before
+		 * 1. accessing the frame
+		 * 2. requeueing the same buffer to h/w
+		 */
+		pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
+				sc->rx.bufsize,
+				PCI_DMA_FROMDEVICE);
+
 		/*
 		/*
 		 * If we're asked to flush receive queue, directly
 		 * If we're asked to flush receive queue, directly
 		 * chain it back at the queue without processing it.
 		 * chain it back at the queue without processing it.
@@ -556,10 +556,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		if (!requeue_skb)
 		if (!requeue_skb)
 			goto requeue;
 			goto requeue;
 
 
-		/* Sync and unmap the frame */
-		pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
-					    sc->rx.bufsize,
-					    PCI_DMA_FROMDEVICE);
+		/* Unmap the frame */
 		pci_unmap_single(sc->pdev, bf->bf_buf_addr,
 		pci_unmap_single(sc->pdev, bf->bf_buf_addr,
 				 sc->rx.bufsize,
 				 sc->rx.bufsize,
 				 PCI_DMA_FROMDEVICE);
 				 PCI_DMA_FROMDEVICE);

+ 21 - 1
drivers/net/wireless/ath9k/xmit.c

@@ -106,6 +106,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 	struct ieee80211_hw *hw = sc->hw;
 	struct ieee80211_hw *hw = sc->hw;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
 	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+	int hdrlen, padsize;
 
 
 	DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
 	DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
 
 
@@ -125,7 +126,26 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 		tx_info->flags |= IEEE80211_TX_STAT_ACK;
 		tx_info->flags |= IEEE80211_TX_STAT_ACK;
 	}
 	}
 
 
-	tx_info->status.rates[0].count = tx_status->retries + 1;
+	tx_info->status.rates[0].count = tx_status->retries;
+	if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
+		/* Change idx from internal table index to MCS index */
+		int idx = tx_info->status.rates[0].idx;
+		struct ath_rate_table *rate_table = sc->cur_rate_table;
+		if (idx >= 0 && idx < rate_table->rate_cnt)
+			tx_info->status.rates[0].idx =
+				rate_table->info[idx].ratecode & 0x7f;
+	}
+
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	padsize = hdrlen & 3;
+	if (padsize && hdrlen >= 24) {
+		/*
+		 * Remove MAC header padding before giving the frame back to
+		 * mac80211.
+		 */
+		memmove(skb->data + padsize, skb->data, hdrlen);
+		skb_pull(skb, padsize);
+	}
 
 
 	ieee80211_tx_status(hw, skb);
 	ieee80211_tx_status(hw, skb);
 }
 }

+ 1 - 0
drivers/net/wireless/b43/debugfs.c

@@ -731,6 +731,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)
 	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
 	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
 	add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
 	add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
 	add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
 	add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
+	add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
 
 
 #undef add_dyn_dbg
 #undef add_dyn_dbg
 }
 }

+ 1 - 0
drivers/net/wireless/b43/debugfs.h

@@ -12,6 +12,7 @@ enum b43_dyndbg {		/* Dynamic debugging features */
 	B43_DBG_PWORK_STOP,
 	B43_DBG_PWORK_STOP,
 	B43_DBG_LO,
 	B43_DBG_LO,
 	B43_DBG_FIRMWARE,
 	B43_DBG_FIRMWARE,
+	B43_DBG_KEYS,
 	__B43_NR_DYNDBG,
 	__B43_NR_DYNDBG,
 };
 };
 
 

+ 59 - 44
drivers/net/wireless/b43/main.c

@@ -992,6 +992,52 @@ static void b43_clear_keys(struct b43_wldev *dev)
 		b43_key_clear(dev, i);
 		b43_key_clear(dev, i);
 }
 }
 
 
+static void b43_dump_keymemory(struct b43_wldev *dev)
+{
+	unsigned int i, index, offset;
+	DECLARE_MAC_BUF(macbuf);
+	u8 mac[ETH_ALEN];
+	u16 algo;
+	u32 rcmta0;
+	u16 rcmta1;
+	u64 hf;
+	struct b43_key *key;
+
+	if (!b43_debug(dev, B43_DBG_KEYS))
+		return;
+
+	hf = b43_hf_read(dev);
+	b43dbg(dev->wl, "Hardware key memory dump:  USEDEFKEYS=%u\n",
+	       !!(hf & B43_HF_USEDEFKEYS));
+	for (index = 0; index < dev->max_nr_keys; index++) {
+		key = &(dev->key[index]);
+		printk(KERN_DEBUG "Key slot %02u: %s",
+		       index, (key->keyconf == NULL) ? " " : "*");
+		offset = dev->ktp + (index * B43_SEC_KEYSIZE);
+		for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
+			u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
+			printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
+		}
+
+		algo = b43_shm_read16(dev, B43_SHM_SHARED,
+				      B43_SHM_SH_KEYIDXBLOCK + (index * 2));
+		printk("   Algo: %04X/%02X", algo, key->algorithm);
+
+		if (index >= 4) {
+			rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
+						((index - 4) * 2) + 0);
+			rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
+						((index - 4) * 2) + 1);
+			*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
+			*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
+			printk("   MAC: %s",
+			       print_mac(macbuf, mac));
+		} else
+			printk("   DEFAULT KEY");
+		printk("\n");
+	}
+}
+
 void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
 void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
 {
 {
 	u32 macctl;
 	u32 macctl;
@@ -3324,7 +3370,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 	unsigned long flags;
 	unsigned long flags;
 	int antenna;
 	int antenna;
 	int err = 0;
 	int err = 0;
-	u32 savedirqs;
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
@@ -3335,24 +3380,14 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 	dev = wl->current_dev;
 	dev = wl->current_dev;
 	phy = &dev->phy;
 	phy = &dev->phy;
 
 
+	b43_mac_suspend(dev);
+
 	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
 		b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
 		b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
 					  conf->long_frame_max_tx_count);
 					  conf->long_frame_max_tx_count);
 	changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
 	changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
 	if (!changed)
 	if (!changed)
-		goto out_unlock_mutex;
-
-	/* Disable IRQs while reconfiguring the device.
-	 * This makes it possible to drop the spinlock throughout
-	 * the reconfiguration process. */
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	if (b43_status(dev) < B43_STAT_STARTED) {
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
-		goto out_unlock_mutex;
-	}
-	savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	b43_synchronize_irq(dev);
+		goto out_mac_enable;
 
 
 	/* Switch to the requested channel.
 	/* Switch to the requested channel.
 	 * The firmware takes care of races with the TX handler. */
 	 * The firmware takes care of races with the TX handler. */
@@ -3399,11 +3434,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 		}
 		}
 	}
 	}
 
 
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43_interrupt_enable(dev, savedirqs);
-	mmiowb();
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-      out_unlock_mutex:
+out_mac_enable:
+	b43_mac_enable(dev);
+out_unlock_mutex:
 	mutex_unlock(&wl->mutex);
 	mutex_unlock(&wl->mutex);
 
 
 	return err;
 	return err;
@@ -3461,27 +3494,12 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
 {
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
 	struct b43_wldev *dev;
-	struct b43_phy *phy;
-	unsigned long flags;
-	u32 savedirqs;
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
 	dev = wl->current_dev;
 	dev = wl->current_dev;
-	phy = &dev->phy;
-
-	/* Disable IRQs while reconfiguring the device.
-	 * This makes it possible to drop the spinlock throughout
-	 * the reconfiguration process. */
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	if (b43_status(dev) < B43_STAT_STARTED) {
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
+	if (!dev || b43_status(dev) < B43_STAT_STARTED)
 		goto out_unlock_mutex;
 		goto out_unlock_mutex;
-	}
-	savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	b43_synchronize_irq(dev);
-
 	b43_mac_suspend(dev);
 	b43_mac_suspend(dev);
 
 
 	if (changed & BSS_CHANGED_BASIC_RATES)
 	if (changed & BSS_CHANGED_BASIC_RATES)
@@ -3495,13 +3513,7 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
 	}
 	}
 
 
 	b43_mac_enable(dev);
 	b43_mac_enable(dev);
-
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43_interrupt_enable(dev, savedirqs);
-	/* XXX: why? */
-	mmiowb();
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
- out_unlock_mutex:
+out_unlock_mutex:
 	mutex_unlock(&wl->mutex);
 	mutex_unlock(&wl->mutex);
 
 
 	return;
 	return;
@@ -3599,15 +3611,18 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	default:
 	default:
 		B43_WARN_ON(1);
 		B43_WARN_ON(1);
 	}
 	}
+
 out_unlock:
 out_unlock:
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	mutex_unlock(&wl->mutex);
 	if (!err) {
 	if (!err) {
 		b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
 		b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
 		       "mac: %pM\n",
 		       "mac: %pM\n",
 		       cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
 		       cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
 		       addr);
 		       addr);
+		b43_dump_keymemory(dev);
 	}
 	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	mutex_unlock(&wl->mutex);
+
 	return err;
 	return err;
 }
 }
 
 

+ 18 - 0
drivers/net/wireless/b43/phy_common.c

@@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev)
 		b43_power_saving_ctl_bits(dev, 0);
 		b43_power_saving_ctl_bits(dev, 0);
 }
 }
 
 
+static inline void assert_mac_suspended(struct b43_wldev *dev)
+{
+	if (!B43_DEBUG)
+		return;
+	if ((b43_status(dev) >= B43_STAT_INITIALIZED) &&
+	    (dev->mac_suspended <= 0)) {
+		b43dbg(dev->wl, "PHY/RADIO register access with "
+		       "enabled MAC.\n");
+		dump_stack();
+	}
+}
+
 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
 {
 {
+	assert_mac_suspended(dev);
 	return dev->phy.ops->radio_read(dev, reg);
 	return dev->phy.ops->radio_read(dev, reg);
 }
 }
 
 
 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
 {
+	assert_mac_suspended(dev);
 	dev->phy.ops->radio_write(dev, reg, value);
 	dev->phy.ops->radio_write(dev, reg, value);
 }
 }
 
 
@@ -208,11 +222,13 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
 
 
 u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
 u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
 {
 {
+	assert_mac_suspended(dev);
 	return dev->phy.ops->phy_read(dev, reg);
 	return dev->phy.ops->phy_read(dev, reg);
 }
 }
 
 
 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
 {
+	assert_mac_suspended(dev);
 	dev->phy.ops->phy_write(dev, reg, value);
 	dev->phy.ops->phy_write(dev, reg, value);
 }
 }
 
 
@@ -280,8 +296,10 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
 		state = RFKILL_STATE_SOFT_BLOCKED;
 		state = RFKILL_STATE_SOFT_BLOCKED;
 	}
 	}
 
 
+	b43_mac_suspend(dev);
 	phy->ops->software_rfkill(dev, state);
 	phy->ops->software_rfkill(dev, state);
 	phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
 	phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
+	b43_mac_enable(dev);
 }
 }
 
 
 /**
 /**

+ 6 - 2
drivers/net/wireless/b43/phy_g.c

@@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
 	int rfatt, bbatt;
 	int rfatt, bbatt;
 	u8 tx_control;
 	u8 tx_control;
 
 
+	b43_mac_suspend(dev);
+
 	spin_lock_irq(&dev->wl->irq_lock);
 	spin_lock_irq(&dev->wl->irq_lock);
 
 
 	/* Calculate the new attenuation values. */
 	/* Calculate the new attenuation values. */
@@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
 			  gphy->tx_control);
 			  gphy->tx_control);
 	b43_radio_unlock(dev);
 	b43_radio_unlock(dev);
 	b43_phy_unlock(dev);
 	b43_phy_unlock(dev);
+
+	b43_mac_enable(dev);
 }
 }
 
 
 static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
 static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
@@ -3215,9 +3219,9 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
 	struct b43_phy *phy = &dev->phy;
 	struct b43_phy *phy = &dev->phy;
 	struct b43_phy_g *gphy = phy->g;
 	struct b43_phy_g *gphy = phy->g;
 
 
+	b43_mac_suspend(dev);
 	//TODO: update_aci_moving_average
 	//TODO: update_aci_moving_average
 	if (gphy->aci_enable && gphy->aci_wlan_automatic) {
 	if (gphy->aci_enable && gphy->aci_wlan_automatic) {
-		b43_mac_suspend(dev);
 		if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
 		if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
 			if (0 /*TODO: bunch of conditions */ ) {
 			if (0 /*TODO: bunch of conditions */ ) {
 				phy->ops->interf_mitigation(dev,
 				phy->ops->interf_mitigation(dev,
@@ -3227,12 +3231,12 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
 			   if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
 			   if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
 				phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
 				phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
 		}
 		}
-		b43_mac_enable(dev);
 	} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
 	} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
 		   phy->rev == 1) {
 		   phy->rev == 1) {
 		//TODO: implement rev1 workaround
 		//TODO: implement rev1 workaround
 	}
 	}
 	b43_lo_g_maintanance_work(dev);
 	b43_lo_g_maintanance_work(dev);
+	b43_mac_enable(dev);
 }
 }
 
 
 static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
 static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)

+ 0 - 1
drivers/net/wireless/iwlwifi/iwl-3945.c

@@ -2482,7 +2482,6 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
 
 
 	frame_size = iwl3945_fill_beacon_frame(priv,
 	frame_size = iwl3945_fill_beacon_frame(priv,
 				tx_beacon_cmd->frame,
 				tx_beacon_cmd->frame,
-				iwl3945_broadcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
 
 	BUG_ON(frame_size > MAX_MPDU_SIZE);
 	BUG_ON(frame_size > MAX_MPDU_SIZE);

+ 1 - 8
drivers/net/wireless/iwlwifi/iwl-3945.h

@@ -405,12 +405,6 @@ struct iwl3945_rx_queue {
 
 
 #define SCAN_INTERVAL 100
 #define SCAN_INTERVAL 100
 
 
-#define MAX_A_CHANNELS  252
-#define MIN_A_CHANNELS  7
-
-#define MAX_B_CHANNELS  14
-#define MIN_B_CHANNELS  1
-
 #define STATUS_HCMD_ACTIVE	0	/* host command in progress */
 #define STATUS_HCMD_ACTIVE	0	/* host command in progress */
 #define STATUS_HCMD_SYNC_ACTIVE	1	/* sync host command in progress */
 #define STATUS_HCMD_SYNC_ACTIVE	1	/* sync host command in progress */
 #define STATUS_INT_ENABLED	2
 #define STATUS_INT_ENABLED	2
@@ -590,8 +584,7 @@ extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len,
 extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv,
 extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv,
 		struct iwl3945_host_cmd *cmd);
 		struct iwl3945_host_cmd *cmd);
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
-					struct ieee80211_hdr *hdr,
-					const u8 *dest, int left);
+					struct ieee80211_hdr *hdr,int left);
 extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
 extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
 					 struct iwl3945_rx_queue *q);
 					 struct iwl3945_rx_queue *q);
 extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);
 extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);

+ 3 - 7
drivers/net/wireless/iwlwifi/iwl-4965.c

@@ -426,7 +426,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
 
 
 static int iwl4965_apm_stop_master(struct iwl_priv *priv)
 static int iwl4965_apm_stop_master(struct iwl_priv *priv)
 {
 {
-	int ret = 0;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&priv->lock, flags);
 	spin_lock_irqsave(&priv->lock, flags);
@@ -434,16 +433,13 @@ static int iwl4965_apm_stop_master(struct iwl_priv *priv)
 	/* set stop master bit */
 	/* set stop master bit */
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
 
-	ret = iwl_poll_direct_bit(priv, CSR_RESET,
+	iwl_poll_direct_bit(priv, CSR_RESET,
 			CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 			CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-	if (ret < 0)
-		goto out;
 
 
-out:
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 	IWL_DEBUG_INFO("stop master\n");
 	IWL_DEBUG_INFO("stop master\n");
 
 
-	return ret;
+	return 0;
 }
 }
 
 
 static void iwl4965_apm_stop(struct iwl_priv *priv)
 static void iwl4965_apm_stop(struct iwl_priv *priv)
@@ -2354,7 +2350,7 @@ module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
 MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
 MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
 module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
 module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
 MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
 MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, int, 0444);
+module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
 MODULE_PARM_DESC(debug, "debug output mask");
 module_param_named(
 module_param_named(
 	disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
 	disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);

+ 3 - 7
drivers/net/wireless/iwlwifi/iwl-5000.c

@@ -73,7 +73,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
 /* FIXME: same implementation as 4965 */
 /* FIXME: same implementation as 4965 */
 static int iwl5000_apm_stop_master(struct iwl_priv *priv)
 static int iwl5000_apm_stop_master(struct iwl_priv *priv)
 {
 {
-	int ret = 0;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&priv->lock, flags);
 	spin_lock_irqsave(&priv->lock, flags);
@@ -81,16 +80,13 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
 	/* set stop master bit */
 	/* set stop master bit */
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
 
-	ret = iwl_poll_direct_bit(priv, CSR_RESET,
+	iwl_poll_direct_bit(priv, CSR_RESET,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-	if (ret < 0)
-		goto out;
 
 
-out:
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 	IWL_DEBUG_INFO("stop master\n");
 	IWL_DEBUG_INFO("stop master\n");
 
 
-	return ret;
+	return 0;
 }
 }
 
 
 
 
@@ -1623,7 +1619,7 @@ MODULE_PARM_DESC(disable50,
 module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
 module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
 MODULE_PARM_DESC(swcrypto50,
 MODULE_PARM_DESC(swcrypto50,
 		  "using software crypto engine (default 0 [hardware])\n");
 		  "using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, int, 0444);
+module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
 MODULE_PARM_DESC(debug50, "50XX debug output mask");
 MODULE_PARM_DESC(debug50, "50XX debug output mask");
 module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
 module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
 MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
 MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");

+ 16 - 10
drivers/net/wireless/iwlwifi/iwl-agn-rs.c

@@ -836,6 +836,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
 	    (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
 	    (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
 	     hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
 	     hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
 		IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
 		IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
+		/* the last LQ command could failed so the LQ in ucode not
+		 * the same in driver sync up
+		 */
+		iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -2167,6 +2171,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
 	struct ieee80211_conf *conf = &priv->hw->conf;
 	struct ieee80211_conf *conf = &priv->hw->conf;
 	struct iwl_lq_sta *lq_sta = priv_sta;
 	struct iwl_lq_sta *lq_sta = priv_sta;
+	u16 mask_bit = 0;
 
 
 	lq_sta->flush_timer = 0;
 	lq_sta->flush_timer = 0;
 	lq_sta->supp_rates = sta->supp_rates[sband->band];
 	lq_sta->supp_rates = sta->supp_rates[sband->band];
@@ -2200,16 +2205,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 		priv->assoc_station_added = 1;
 		priv->assoc_station_added = 1;
 	}
 	}
 
 
-	/* Find highest tx rate supported by hardware and destination station */
-	lq_sta->last_txrate_idx = 3;
-	for (i = 0; i < sband->n_bitrates; i++)
-		if (sta->supp_rates[sband->band] & BIT(i))
-			lq_sta->last_txrate_idx = i;
-
-	/* For MODE_IEEE80211A, skip over cck rates in global rate table */
-	if (sband->band == IEEE80211_BAND_5GHZ)
-		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
-
 	lq_sta->is_dup = 0;
 	lq_sta->is_dup = 0;
 	lq_sta->is_green = rs_use_green(priv, conf);
 	lq_sta->is_green = rs_use_green(priv, conf);
 	lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
 	lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
@@ -2248,6 +2243,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
 	lq_sta->drv = priv;
 	lq_sta->drv = priv;
 
 
+	/* Find highest tx rate supported by hardware and destination station */
+	mask_bit = sta->supp_rates[sband->band] & lq_sta->active_legacy_rate;
+	lq_sta->last_txrate_idx = 3;
+	for (i = 0; i < sband->n_bitrates; i++)
+		if (mask_bit & BIT(i))
+			lq_sta->last_txrate_idx = i;
+
+	/* For MODE_IEEE80211A, skip over cck rates in global rate table */
+	if (sband->band == IEEE80211_BAND_5GHZ)
+		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+
 	rs_initialize_lq(priv, conf, sta, lq_sta);
 	rs_initialize_lq(priv, conf, sta, lq_sta);
 }
 }
 
 

+ 21 - 20
drivers/net/wireless/iwlwifi/iwl-agn.c

@@ -371,7 +371,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
 
 
 static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
 static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
 					  struct ieee80211_hdr *hdr,
 					  struct ieee80211_hdr *hdr,
-					  const u8 *dest, int left)
+					  int left)
 {
 {
 	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
 	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
 	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
 	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
@@ -424,7 +424,6 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
 	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
 
 	frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
 	frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
-				iwl_bcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
 
 	BUG_ON(frame_size > MAX_MPDU_SIZE);
 	BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -515,19 +514,27 @@ static void iwl_ht_conf(struct iwl_priv *priv,
 	iwl_conf->supported_chan_width =
 	iwl_conf->supported_chan_width =
 		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
 		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
 
 
-	iwl_conf->extension_chan_offset = bss_conf->ht.secondary_channel_offset;
+	/*
+	 * XXX: The HT configuration needs to be moved into iwl_mac_config()
+	 *	to be done there correctly.
+	 */
+
+	iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+	if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS)
+		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+	else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS)
+		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+
 	/* If no above or below channel supplied disable FAT channel */
 	/* If no above or below channel supplied disable FAT channel */
 	if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
 	if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
-	    iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) {
-		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+	    iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
 		iwl_conf->supported_chan_width = 0;
 		iwl_conf->supported_chan_width = 0;
-	}
 
 
 	iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
 	iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
 
 
 	memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
 	memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
 
 
-	iwl_conf->tx_chan_width = bss_conf->ht.width_40_ok;
+	iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
 	iwl_conf->ht_protection =
 	iwl_conf->ht_protection =
 		bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
 		bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
 	iwl_conf->non_GF_STA_present =
 	iwl_conf->non_GF_STA_present =
@@ -1103,16 +1110,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
 	priv->cfg->ops->lib->rx_handler_setup(priv);
 	priv->cfg->ops->lib->rx_handler_setup(priv);
 }
 }
 
 
-/*
- * this should be called while priv->lock is locked
-*/
-static void __iwl_rx_replenish(struct iwl_priv *priv)
-{
-	iwl_rx_allocate(priv);
-	iwl_rx_queue_restock(priv);
-}
-
-
 /**
 /**
  * iwl_rx_handle - Main entry function for receiving responses from uCode
  * iwl_rx_handle - Main entry function for receiving responses from uCode
  *
  *
@@ -1221,7 +1218,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
 			count++;
 			count++;
 			if (count >= 8) {
 			if (count >= 8) {
 				priv->rxq.read = i;
 				priv->rxq.read = i;
-				__iwl_rx_replenish(priv);
+				iwl_rx_queue_restock(priv);
 				count = 0;
 				count = 0;
 			}
 			}
 		}
 		}
@@ -3335,7 +3332,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 
 /*
 /*
  * The following adds a new attribute to the sysfs representation
  * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
  * used for controlling the debug level.
  * used for controlling the debug level.
  *
  *
  * See the level definitions in iwl for details.
  * See the level definitions in iwl for details.
@@ -3421,7 +3418,11 @@ static ssize_t show_tx_power(struct device *d,
 			     struct device_attribute *attr, char *buf)
 			     struct device_attribute *attr, char *buf)
 {
 {
 	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
 	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
+
+	if (!iwl_is_ready_rf(priv))
+		return sprintf(buf, "off\n");
+	else
+		return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
 }
 }
 
 
 static ssize_t store_tx_power(struct device *d,
 static ssize_t store_tx_power(struct device *d,

+ 9 - 0
drivers/net/wireless/iwlwifi/iwl-calib.c

@@ -70,6 +70,15 @@
  * INIT calibrations framework
  * INIT calibrations framework
  *****************************************************************************/
  *****************************************************************************/
 
 
+struct statistics_general_data {
+	u32 beacon_silence_rssi_a;
+	u32 beacon_silence_rssi_b;
+	u32 beacon_silence_rssi_c;
+	u32 beacon_energy_a;
+	u32 beacon_energy_b;
+	u32 beacon_energy_c;
+};
+
 int iwl_send_calib_results(struct iwl_priv *priv)
 int iwl_send_calib_results(struct iwl_priv *priv)
 {
 {
 	int ret = 0;
 	int ret = 0;

+ 2 - 0
drivers/net/wireless/iwlwifi/iwl-commands.h

@@ -2418,6 +2418,8 @@ struct statistics_rx_ht_phy {
 	__le32 reserved2;
 	__le32 reserved2;
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
+#define INTERFERENCE_DATA_AVAILABLE      __constant_cpu_to_le32(1)
+
 struct statistics_rx_non_phy {
 struct statistics_rx_non_phy {
 	__le32 bogus_cts;	/* CTS received when not expecting CTS */
 	__le32 bogus_cts;	/* CTS received when not expecting CTS */
 	__le32 bogus_ack;	/* ACK received when not expecting ACK */
 	__le32 bogus_ack;	/* ACK received when not expecting ACK */

+ 1 - 1
drivers/net/wireless/iwlwifi/iwl-core.h

@@ -154,7 +154,7 @@ struct iwl_ops {
 struct iwl_mod_params {
 struct iwl_mod_params {
 	int disable;		/* def: 0 = enable radio */
 	int disable;		/* def: 0 = enable radio */
 	int sw_crypto;		/* def: 0 = using hardware encryption */
 	int sw_crypto;		/* def: 0 = using hardware encryption */
-	int debug;		/* def: 0 = minimal debug log messages */
+	u32 debug;		/* def: 0 = minimal debug log messages */
 	int disable_hw_scan;	/* def: 0 = use h/w scan */
 	int disable_hw_scan;	/* def: 0 = use h/w scan */
 	int num_of_queues;	/* def: HW dependent */
 	int num_of_queues;	/* def: HW dependent */
 	int num_of_ampdu_queues;/* def: HW dependent */
 	int num_of_ampdu_queues;/* def: HW dependent */

+ 7 - 10
drivers/net/wireless/iwlwifi/iwl-debug.h

@@ -96,28 +96,25 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #endif				/* CONFIG_IWLWIFI_DEBUGFS */
 #endif				/* CONFIG_IWLWIFI_DEBUGFS */
 
 
 /*
 /*
- * To use the debug system;
+ * To use the debug system:
  *
  *
  * If you are defining a new debug classification, simply add it to the #define
  * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
+ * list here in the form of
  *
  *
  * #define IWL_DL_xxxx VALUE
  * #define IWL_DL_xxxx VALUE
  *
  *
- * shifting value to the left one bit from the previous entry.  xxxx should be
- * the name of the classification (for example, WEP)
+ * where xxxx should be the name of the classification (for example, WEP).
  *
  *
  * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
  * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
  * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
  * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
  * to send output to that classification.
  * to send output to that classification.
  *
  *
- * To add your debug level to the list of levels seen when you perform
+ * The active debug levels can be accessed via files
  *
  *
- * % cat /sys/class/net/wlanX/device/debug_level
+ * 	/sys/module/iwlagn/parameters/debug{50}
+ * 	/sys/class/net/wlan0/device/debug_level
  *
  *
- * you simply need to add your entry to the iwl_debug_levels array.
- *
- * If you do not see debug_level in  /sys/class/net/wlanX/device/debug_level
- * then you do not have CONFIG_IWLWIFI_DEBUG defined in your kernel config file
+ * when CONFIG_IWLWIFI_DEBUG=y.
  */
  */
 
 
 #define IWL_DL_INFO		(1 << 0)
 #define IWL_DL_INFO		(1 << 0)

+ 3 - 26
drivers/net/wireless/iwlwifi/iwl-dev.h

@@ -323,14 +323,6 @@ struct iwl_rx_queue {
 
 
 #define IWL_SUPPORTED_RATES_IE_LEN         8
 #define IWL_SUPPORTED_RATES_IE_LEN         8
 
 
-#define SCAN_INTERVAL 100
-
-#define MAX_A_CHANNELS  252
-#define MIN_A_CHANNELS  7
-
-#define MAX_B_CHANNELS  14
-#define MIN_B_CHANNELS  1
-
 #define MAX_TID_COUNT        9
 #define MAX_TID_COUNT        9
 
 
 #define IWL_INVALID_RATE     0xFF
 #define IWL_INVALID_RATE     0xFF
@@ -496,8 +488,6 @@ struct iwl_sensitivity_ranges {
 };
 };
 
 
 
 
-#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ)
-
 #define KELVIN_TO_CELSIUS(x) ((x)-273)
 #define KELVIN_TO_CELSIUS(x) ((x)-273)
 #define CELSIUS_TO_KELVIN(x) ((x)+273)
 #define CELSIUS_TO_KELVIN(x) ((x)+273)
 
 
@@ -546,9 +536,6 @@ struct iwl_hw_params {
 	const struct iwl_sensitivity_ranges *sens;
 	const struct iwl_sensitivity_ranges *sens;
 };
 };
 
 
-#define HT_SHORT_GI_20MHZ	(1 << 0)
-#define HT_SHORT_GI_40MHZ	(1 << 1)
-
 
 
 /******************************************************************************
 /******************************************************************************
  *
  *
@@ -590,15 +577,15 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
 }
 }
 
 
 
 
-struct iwl_priv;
-
-
 struct iwl_dma_ptr {
 struct iwl_dma_ptr {
 	dma_addr_t dma;
 	dma_addr_t dma;
 	void *addr;
 	void *addr;
 	size_t size;
 	size_t size;
 };
 };
 
 
+#define HT_SHORT_GI_20MHZ	(1 << 0)
+#define HT_SHORT_GI_40MHZ	(1 << 1)
+
 #define IWL_CHANNEL_WIDTH_20MHZ   0
 #define IWL_CHANNEL_WIDTH_20MHZ   0
 #define IWL_CHANNEL_WIDTH_40MHZ   1
 #define IWL_CHANNEL_WIDTH_40MHZ   1
 
 
@@ -613,7 +600,6 @@ struct iwl_dma_ptr {
 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
 
 
 /* Sensitivity and chain noise calibration */
 /* Sensitivity and chain noise calibration */
-#define INTERFERENCE_DATA_AVAILABLE	__constant_cpu_to_le32(1)
 #define INITIALIZATION_VALUE		0xFFFF
 #define INITIALIZATION_VALUE		0xFFFF
 #define CAL_NUM_OF_BEACONS		20
 #define CAL_NUM_OF_BEACONS		20
 #define MAXIMUM_ALLOWED_PATHLOSS	15
 #define MAXIMUM_ALLOWED_PATHLOSS	15
@@ -666,15 +652,6 @@ enum iwl4965_calib_enabled_state {
 	IWL_CALIB_ENABLED = 1,
 	IWL_CALIB_ENABLED = 1,
 };
 };
 
 
-struct statistics_general_data {
-	u32 beacon_silence_rssi_a;
-	u32 beacon_silence_rssi_b;
-	u32 beacon_silence_rssi_c;
-	u32 beacon_energy_a;
-	u32 beacon_energy_b;
-	u32 beacon_energy_c;
-};
-
 
 
 /*
 /*
  * enum iwl_calib
  * enum iwl_calib

+ 6 - 5
drivers/net/wireless/iwlwifi/iwl-io.h

@@ -87,17 +87,18 @@ static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
 #define iwl_read32(p, o) _iwl_read32(p, o)
 #define iwl_read32(p, o) _iwl_read32(p, o)
 #endif
 #endif
 
 
+#define IWL_POLL_INTERVAL 10	/* microseconds */
 static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
 static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
 				u32 bits, u32 mask, int timeout)
 				u32 bits, u32 mask, int timeout)
 {
 {
-	int i = 0;
+	int t = 0;
 
 
 	do {
 	do {
 		if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
 		if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
-			return i;
-		udelay(10);
-		i += 10;
-	} while (i < timeout);
+			return t;
+		udelay(IWL_POLL_INTERVAL);
+		t += IWL_POLL_INTERVAL;
+	} while (t < timeout);
 
 
 	return -ETIMEDOUT;
 	return -ETIMEDOUT;
 }
 }

+ 1 - 1
drivers/net/wireless/iwlwifi/iwl-led.c

@@ -292,7 +292,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
 			if (tpt  > (blink_tbl[i].tpt * IWL_1MB_RATE))
 			if (tpt  > (blink_tbl[i].tpt * IWL_1MB_RATE))
 				break;
 				break;
 
 
-	IWL_DEBUG_LED("LED BLINK IDX=%d", i);
+	IWL_DEBUG_LED("LED BLINK IDX=%d\n", i);
 	return i;
 	return i;
 }
 }
 
 

+ 19 - 10
drivers/net/wireless/iwlwifi/iwl-rx.c

@@ -244,25 +244,31 @@ void iwl_rx_allocate(struct iwl_priv *priv)
 	struct list_head *element;
 	struct list_head *element;
 	struct iwl_rx_mem_buffer *rxb;
 	struct iwl_rx_mem_buffer *rxb;
 	unsigned long flags;
 	unsigned long flags;
-	spin_lock_irqsave(&rxq->lock, flags);
-	while (!list_empty(&rxq->rx_used)) {
+
+	while (1) {
+		spin_lock_irqsave(&rxq->lock, flags);
+
+		if (list_empty(&rxq->rx_used)) {
+			spin_unlock_irqrestore(&rxq->lock, flags);
+			return;
+		}
 		element = rxq->rx_used.next;
 		element = rxq->rx_used.next;
 		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
 		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		list_del(element);
+
+		spin_unlock_irqrestore(&rxq->lock, flags);
 
 
 		/* Alloc a new receive buffer */
 		/* Alloc a new receive buffer */
 		rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
 		rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
-				__GFP_NOWARN | GFP_ATOMIC);
+				     GFP_KERNEL);
 		if (!rxb->skb) {
 		if (!rxb->skb) {
-			if (net_ratelimit())
-				printk(KERN_CRIT DRV_NAME
-				       ": Can not allocate SKB buffers\n");
+			printk(KERN_CRIT DRV_NAME
+				   "Can not allocate SKB buffers\n");
 			/* We don't reschedule replenish work here -- we will
 			/* We don't reschedule replenish work here -- we will
 			 * call the restock method and if it still needs
 			 * call the restock method and if it still needs
 			 * more buffers it will schedule replenish */
 			 * more buffers it will schedule replenish */
 			break;
 			break;
 		}
 		}
-		priv->alloc_rxb_skb++;
-		list_del(element);
 
 
 		/* Get physical address of RB/SKB */
 		/* Get physical address of RB/SKB */
 		rxb->real_dma_addr = pci_map_single(
 		rxb->real_dma_addr = pci_map_single(
@@ -276,12 +282,15 @@ void iwl_rx_allocate(struct iwl_priv *priv)
 		rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
 		rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
 		skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
 		skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
 
 
+		spin_lock_irqsave(&rxq->lock, flags);
+
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
 		rxq->free_count++;
+		priv->alloc_rxb_skb++;
+
+		spin_unlock_irqrestore(&rxq->lock, flags);
 	}
 	}
-	spin_unlock_irqrestore(&rxq->lock, flags);
 }
 }
-EXPORT_SYMBOL(iwl_rx_allocate);
 
 
 void iwl_rx_replenish(struct iwl_priv *priv)
 void iwl_rx_replenish(struct iwl_priv *priv)
 {
 {

+ 3 - 5
drivers/net/wireless/iwlwifi/iwl-tx.c

@@ -645,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
 				  struct iwl_tx_cmd *tx_cmd,
 				  struct iwl_tx_cmd *tx_cmd,
 				  struct ieee80211_tx_info *info,
 				  struct ieee80211_tx_info *info,
 				  struct ieee80211_hdr *hdr,
 				  struct ieee80211_hdr *hdr,
-				  int is_unicast, u8 std_id)
+				  u8 std_id)
 {
 {
 	__le16 fc = hdr->frame_control;
 	__le16 fc = hdr->frame_control;
 	__le32 tx_flags = tx_cmd->tx_flags;
 	__le32 tx_flags = tx_cmd->tx_flags;
@@ -834,7 +834,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	u16 len, len_org;
 	u16 len, len_org;
 	u16 seq_number = 0;
 	u16 seq_number = 0;
 	__le16 fc;
 	__le16 fc;
-	u8 hdr_len, unicast;
+	u8 hdr_len;
 	u8 sta_id;
 	u8 sta_id;
 	u8 wait_write_ptr = 0;
 	u8 wait_write_ptr = 0;
 	u8 tid = 0;
 	u8 tid = 0;
@@ -854,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 		goto drop_unlock;
 		goto drop_unlock;
 	}
 	}
 
 
-	unicast = !is_multicast_ether_addr(hdr->addr1);
-
 	fc = hdr->frame_control;
 	fc = hdr->frame_control;
 
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -994,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	len = (u16)skb->len;
 	len = (u16)skb->len;
 	tx_cmd->len = cpu_to_le16(len);
 	tx_cmd->len = cpu_to_le16(len);
 	/* TODO need this for burst mode later on */
 	/* TODO need this for burst mode later on */
-	iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id);
+	iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
 
 
 	/* set is_hcca to 0; it probably will never be implemented */
 	/* set is_hcca to 0; it probably will never be implemented */
 	iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
 	iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);

+ 3 - 3
drivers/net/wireless/iwlwifi/iwl3945-base.c

@@ -65,7 +65,7 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
 
 
 /* module parameters */
 /* module parameters */
 static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
 static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
-static int iwl3945_param_debug;    /* def: 0 = minimal debug log messages */
+static u32 iwl3945_param_debug;    /* def: 0 = minimal debug log messages */
 static int iwl3945_param_disable;  /* def: 0 = enable radio */
 static int iwl3945_param_disable;  /* def: 0 = enable radio */
 static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
 static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
 int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
 int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
@@ -1402,7 +1402,7 @@ static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame *
 
 
 unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
 unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
 				struct ieee80211_hdr *hdr,
 				struct ieee80211_hdr *hdr,
-				const u8 *dest, int left)
+				int left)
 {
 {
 
 
 	if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
 	if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
@@ -8343,7 +8343,7 @@ MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
 module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444);
 module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444);
 MODULE_PARM_DESC(hwcrypto,
 MODULE_PARM_DESC(hwcrypto,
 		 "using hardware crypto engine (default 0 [software])\n");
 		 "using hardware crypto engine (default 0 [software])\n");
-module_param_named(debug, iwl3945_param_debug, int, 0444);
+module_param_named(debug, iwl3945_param_debug, uint, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
 MODULE_PARM_DESC(debug, "debug output mask");
 module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
 module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");

+ 2 - 1
drivers/net/wireless/libertas/if_sdio.c

@@ -26,6 +26,7 @@
  * if_sdio_card_to_host() to pad the data.
  * if_sdio_card_to_host() to pad the data.
  */
  */
 
 
+#include <linux/kernel.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/firmware.h>
 #include <linux/netdevice.h>
 #include <linux/netdevice.h>
@@ -581,7 +582,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
 				chunk_size, (chunk_size + 31) / 32 * 32);
 				chunk_size, (chunk_size + 31) / 32 * 32);
 */
 */
 			ret = sdio_writesb(card->func, card->ioport,
 			ret = sdio_writesb(card->func, card->ioport,
-				chunk_buffer, (chunk_size + 31) / 32 * 32);
+				chunk_buffer, roundup(chunk_size, 32));
 			if (ret)
 			if (ret)
 				goto release;
 				goto release;
 
 

+ 2 - 4
drivers/net/wireless/mac80211_hwsim.c

@@ -495,11 +495,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
 	}
 	}
 
 
 	if (changed & BSS_CHANGED_HT) {
 	if (changed & BSS_CHANGED_HT) {
-		printk(KERN_DEBUG "  %s: HT: sec_ch_offs=%d width_40_ok=%d "
-		       "op_mode=%d\n",
+		printk(KERN_DEBUG "  %s: HT: op_mode=0x%x\n",
 		       wiphy_name(hw->wiphy),
 		       wiphy_name(hw->wiphy),
-		       info->ht.secondary_channel_offset,
-		       info->ht.width_40_ok, info->ht.operation_mode);
+		       info->ht.operation_mode);
 	}
 	}
 
 
 	if (changed & BSS_CHANGED_BASIC_RATES) {
 	if (changed & BSS_CHANGED_BASIC_RATES) {

+ 18 - 5
drivers/net/wireless/p54/p54.h

@@ -44,6 +44,9 @@ enum p54_control_frame_types {
 	P54_CONTROL_TYPE_BT_OPTIONS = 35
 	P54_CONTROL_TYPE_BT_OPTIONS = 35
 };
 };
 
 
+#define P54_HDR_FLAG_CONTROL		BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET	(BIT(15) + BIT(0))
+
 struct p54_hdr {
 struct p54_hdr {
 	__le16 flags;
 	__le16 flags;
 	__le16 len;
 	__le16 len;
@@ -54,6 +57,10 @@ struct p54_hdr {
 	u8 data[0];
 	u8 data[0];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
+#define FREE_AFTER_TX(skb)						\
+	((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->		\
+	flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
 struct p54_edcf_queue_param {
 struct p54_edcf_queue_param {
 	__le16 aifs;
 	__le16 aifs;
 	__le16 cwmin;
 	__le16 cwmin;
@@ -61,6 +68,13 @@ struct p54_edcf_queue_param {
 	__le16 txop;
 	__le16 txop;
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
+struct p54_rssi_linear_approximation {
+	s16 mul;
+	s16 add;
+	s16 longbow_unkn;
+	s16 longbow_unk2;
+};
+
 #define EEPROM_READBACK_LEN 0x3fc
 #define EEPROM_READBACK_LEN 0x3fc
 
 
 #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
 #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
@@ -71,11 +85,11 @@ struct p54_edcf_queue_param {
 #define FW_LM20 0x4c4d3230
 #define FW_LM20 0x4c4d3230
 
 
 struct p54_common {
 struct p54_common {
+	struct ieee80211_hw *hw;
 	u32 rx_start;
 	u32 rx_start;
 	u32 rx_end;
 	u32 rx_end;
 	struct sk_buff_head tx_queue;
 	struct sk_buff_head tx_queue;
-	void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb,
-		   int free_on_tx);
+	void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
 	int (*open)(struct ieee80211_hw *dev);
 	int (*open)(struct ieee80211_hw *dev);
 	void (*stop)(struct ieee80211_hw *dev);
 	void (*stop)(struct ieee80211_hw *dev);
 	int mode;
 	int mode;
@@ -90,6 +104,7 @@ struct p54_common {
 	struct pda_channel_output_limit *output_limit;
 	struct pda_channel_output_limit *output_limit;
 	unsigned int output_limit_len;
 	unsigned int output_limit_len;
 	struct pda_pa_curve_data *curve_data;
 	struct pda_pa_curve_data *curve_data;
+	struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
 	unsigned int filter_flags;
 	unsigned int filter_flags;
 	bool use_short_slot;
 	bool use_short_slot;
 	u16 rxhw;
 	u16 rxhw;
@@ -106,9 +121,7 @@ struct p54_common {
 	struct ieee80211_tx_queue_stats tx_stats[8];
 	struct ieee80211_tx_queue_stats tx_stats[8];
 	struct p54_edcf_queue_param qos_params[8];
 	struct p54_edcf_queue_param qos_params[8];
 	struct ieee80211_low_level_stats stats;
 	struct ieee80211_low_level_stats stats;
-	struct timer_list stats_timer;
-	struct completion stats_comp;
-	struct sk_buff *cached_stats;
+	struct delayed_work work;
 	struct sk_buff *cached_beacon;
 	struct sk_buff *cached_beacon;
 	int noise;
 	int noise;
 	void *eeprom;
 	void *eeprom;

+ 125 - 73
drivers/net/wireless/p54/p54common.c

@@ -335,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
                               "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
                               "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
 static int p54_init_xbow_synth(struct ieee80211_hw *dev);
 static int p54_init_xbow_synth(struct ieee80211_hw *dev);
 
 
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+			     u16 type)
+{
+	struct p54_common *priv = dev->priv;
+	int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+	int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+	int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+	int i;
+
+	if (len != (entry_size * num_entries)) {
+		printk(KERN_ERR "%s: unknown rssi calibration data packing "
+				 " type:(%x) len:%d.\n",
+		       wiphy_name(dev->wiphy), type, len);
+
+		print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+				     data, len);
+
+		printk(KERN_ERR "%s: please report this issue.\n",
+			wiphy_name(dev->wiphy));
+		return;
+	}
+
+	for (i = 0; i < num_entries; i++) {
+		struct pda_rssi_cal_entry *cal = data +
+						 (offset + i * entry_size);
+		priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+		priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+	}
+}
+
 static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 {
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
@@ -434,6 +464,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 		case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
 		case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
 			priv->version = *(u8 *)(entry->data + 1);
 			priv->version = *(u8 *)(entry->data + 1);
 			break;
 			break;
+		case PDR_RSSI_LINEAR_APPROXIMATION:
+		case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+		case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+			p54_parse_rssical(dev, entry->data, data_len,
+					  le16_to_cpu(entry->code));
+			break;
 		case PDR_END:
 		case PDR_END:
 			/* make it overrun */
 			/* make it overrun */
 			entry_len = len;
 			entry_len = len;
@@ -453,10 +489,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 		case PDR_DEFAULT_COUNTRY:
 		case PDR_DEFAULT_COUNTRY:
 		case PDR_ANTENNA_GAIN:
 		case PDR_ANTENNA_GAIN:
 		case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
 		case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
-		case PDR_RSSI_LINEAR_APPROXIMATION:
-		case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
 		case PDR_REGULATORY_POWER_LIMITS:
 		case PDR_REGULATORY_POWER_LIMITS:
-		case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
 		case PDR_RADIATED_TRANSMISSION_CORRECTION:
 		case PDR_RADIATED_TRANSMISSION_CORRECTION:
 		case PDR_PRISM_TX_IQ_CALIBRATION:
 		case PDR_PRISM_TX_IQ_CALIBRATION:
 		case PDR_BASEBAND_REGISTERS:
 		case PDR_BASEBAND_REGISTERS:
@@ -527,8 +560,11 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 
 
 static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
 static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
 {
 {
-	/* TODO: get the rssi_add & rssi_mul data from the eeprom */
-	return ((rssi * 0x83) / 64 - 400) / 4;
+	struct p54_common *priv = dev->priv;
+	int band = dev->conf.channel->band;
+
+	return ((rssi * priv->rssical_db[band].mul) / 64 +
+			 priv->rssical_db[band].add) / 4;
 }
 }
 
 
 static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
@@ -589,6 +625,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 
 
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
 
+	queue_delayed_work(dev->workqueue, &priv->work,
+			   msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
 	return -1;
 	return -1;
 }
 }
 
 
@@ -644,7 +683,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
 		freed = priv->rx_end - last_addr;
 		freed = priv->rx_end - last_addr;
 	__skb_unlink(skb, &priv->tx_queue);
 	__skb_unlink(skb, &priv->tx_queue);
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-	kfree_skb(skb);
+	dev_kfree_skb_any(skb);
 
 
 	if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
 	if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
 		     IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
 		     IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
@@ -652,6 +691,27 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
 }
 }
 EXPORT_SYMBOL_GPL(p54_free_skb);
 EXPORT_SYMBOL_GPL(p54_free_skb);
 
 
+static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
+					   __le32 req_id)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *entry = priv->tx_queue.next;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_queue.lock, flags);
+	while (entry != (struct sk_buff *)&priv->tx_queue) {
+		struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+		if (hdr->req_id == req_id) {
+			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+			return entry;
+		}
+		entry = entry->next;
+	}
+	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+	return NULL;
+}
+
 static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
@@ -696,6 +756,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 		entry_hdr = (struct p54_hdr *) entry->data;
 		entry_hdr = (struct p54_hdr *) entry->data;
 		entry_data = (struct p54_tx_data *) entry_hdr->data;
 		entry_data = (struct p54_tx_data *) entry_hdr->data;
 		priv->tx_stats[entry_data->hw_queue].len--;
 		priv->tx_stats[entry_data->hw_queue].len--;
+		priv->stats.dot11ACKFailureCount += payload->tries - 1;
 
 
 		if (unlikely(entry == priv->cached_beacon)) {
 		if (unlikely(entry == priv->cached_beacon)) {
 			kfree_skb(entry);
 			kfree_skb(entry);
@@ -775,8 +836,12 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
 	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
 	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
 	struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
 	struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
-	u32 tsf32 = le32_to_cpu(stats->tsf32);
+	u32 tsf32;
 
 
+	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+		return ;
+
+	tsf32 = le32_to_cpu(stats->tsf32);
 	if (tsf32 < priv->tsf_low32)
 	if (tsf32 < priv->tsf_low32)
 		priv->tsf_high32++;
 		priv->tsf_high32++;
 	priv->tsf_low32 = tsf32;
 	priv->tsf_low32 = tsf32;
@@ -786,9 +851,8 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
 	priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
 	priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
 
 
 	priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
 	priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-	complete(&priv->stats_comp);
 
 
-	mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
+	p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
 }
 }
 
 
 static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
 static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
@@ -897,6 +961,8 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
 		 * have a few spare slots for control frames left.
 		 * have a few spare slots for control frames left.
 		 */
 		 */
 		ieee80211_stop_queues(dev);
 		ieee80211_stop_queues(dev);
+		queue_delayed_work(dev->workqueue, &priv->work,
+				   msecs_to_jiffies(P54_TX_TIMEOUT));
 
 
 		if (unlikely(left == 32)) {
 		if (unlikely(left == 32)) {
 			/*
 			/*
@@ -1022,7 +1088,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
 			eeprom_hdr->v2.magic2 = 0xf;
 			eeprom_hdr->v2.magic2 = 0xf;
 			memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
 			memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
 		}
 		}
-		priv->tx(dev, skb, 0);
+		priv->tx(dev, skb);
 
 
 		if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
 		if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
 			printk(KERN_ERR "%s: device does not respond!\n",
 			printk(KERN_ERR "%s: device does not respond!\n",
@@ -1063,7 +1129,7 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
 	tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
 	tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
 	tim->count = 1;
 	tim->count = 1;
 	tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
 	tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1081,7 +1147,7 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
 
 
 	sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
 	sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
 	memcpy(sta->addr, addr, ETH_ALEN);
 	memcpy(sta->addr, addr, ETH_ALEN);
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1124,7 +1190,7 @@ static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
 	hdr = (void *)entry->data;
 	hdr = (void *)entry->data;
 	cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
 	cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
 	cancel->req_id = hdr->req_id;
 	cancel->req_id = hdr->req_id;
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1353,7 +1419,11 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	/* modifies skb->cb and with it info, so must be last! */
 	/* modifies skb->cb and with it info, so must be last! */
 	if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
 	if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
 		goto err;
 		goto err;
-	priv->tx(dev, skb, 0);
+	priv->tx(dev, skb);
+
+	queue_delayed_work(dev->workqueue, &priv->work,
+			   msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
+
 	return 0;
 	return 0;
 
 
  err:
  err:
@@ -1428,19 +1498,19 @@ static int p54_setup_mac(struct ieee80211_hw *dev)
 		setup->v2.lpf_bandwidth = cpu_to_le16(65535);
 		setup->v2.lpf_bandwidth = cpu_to_le16(65535);
 		setup->v2.osc_start_delay = cpu_to_le16(65535);
 		setup->v2.osc_start_delay = cpu_to_le16(65535);
 	}
 	}
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 }
 }
 
 
-static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell,
-		    u16 frequency)
+static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
 {
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	struct p54_scan *chan;
 	struct p54_scan *chan;
 	unsigned int i;
 	unsigned int i;
 	void *entry;
 	void *entry;
-	__le16 freq = cpu_to_le16(frequency);
+	__le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
+	int band = dev->conf.channel->band;
 
 
 	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
 	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
 			    sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
 			    sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
@@ -1501,15 +1571,15 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell,
 	}
 	}
 
 
 	if (priv->fw_var < 0x500) {
 	if (priv->fw_var < 0x500) {
-		chan->v1.rssical_mul = cpu_to_le16(130);
-		chan->v1.rssical_add = cpu_to_le16(0xfe70);
+		chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+		chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add);
 	} else {
 	} else {
-		chan->v2.rssical_mul = cpu_to_le16(130);
-		chan->v2.rssical_add = cpu_to_le16(0xfe70);
+		chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+		chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add);
 		chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
 		chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
 		memset(chan->v2.rts_rates, 0, 8);
 		memset(chan->v2.rts_rates, 0, 8);
 	}
 	}
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 
 
  err:
  err:
@@ -1535,7 +1605,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
 	led->led_permanent = cpu_to_le16(link);
 	led->led_permanent = cpu_to_le16(link);
 	led->led_temporary = cpu_to_le16(act);
 	led->led_temporary = cpu_to_le16(act);
 	led->duration = cpu_to_le16(1000);
 	led->duration = cpu_to_le16(1000);
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1575,21 +1645,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev)
 	edcf->flags = 0;
 	edcf->flags = 0;
 	memset(edcf->mapping, 0, sizeof(edcf->mapping));
 	memset(edcf->mapping, 0, sizeof(edcf->mapping));
 	memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
 	memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
-	priv->tx(dev, skb, 1);
-	return 0;
-}
-
-static int p54_init_stats(struct ieee80211_hw *dev)
-{
-	struct p54_common *priv = dev->priv;
-
-	priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
-			sizeof(struct p54_hdr) + sizeof(struct p54_statistics),
-			P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
-	if (!priv->cached_stats)
-			return -ENOMEM;
-
-	mod_timer(&priv->stats_timer, jiffies + HZ);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1684,9 +1740,6 @@ static int p54_start(struct ieee80211_hw *dev)
 	P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
 	P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
 	P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
 	P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
 	err = p54_set_edcf(dev);
 	err = p54_set_edcf(dev);
-	if (err)
-		goto out;
-	err = p54_init_stats(dev);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -1698,6 +1751,8 @@ static int p54_start(struct ieee80211_hw *dev)
 		goto out;
 		goto out;
 	}
 	}
 
 
+	queue_delayed_work(dev->workqueue, &priv->work, 0);
+
 out:
 out:
 	mutex_unlock(&priv->conf_mutex);
 	mutex_unlock(&priv->conf_mutex);
 	return err;
 	return err;
@@ -1710,9 +1765,7 @@ static void p54_stop(struct ieee80211_hw *dev)
 
 
 	mutex_lock(&priv->conf_mutex);
 	mutex_lock(&priv->conf_mutex);
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-	del_timer(&priv->stats_timer);
-	p54_free_skb(dev, priv->cached_stats);
-	priv->cached_stats = NULL;
+	cancel_delayed_work_sync(&priv->work);
 	if (priv->cached_beacon)
 	if (priv->cached_beacon)
 		p54_tx_cancel(dev, priv->cached_beacon);
 		p54_tx_cancel(dev, priv->cached_beacon);
 
 
@@ -1784,8 +1837,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
 			goto out;
 			goto out;
 	}
 	}
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-		ret = p54_scan(dev, P54_SCAN_EXIT, 0,
-			       conf->channel->center_freq);
+		ret = p54_scan(dev, P54_SCAN_EXIT, 0);
 		if (ret)
 		if (ret)
 			goto out;
 			goto out;
 	}
 	}
@@ -1811,8 +1863,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
 	}
 	}
 
 
 	if (conf->changed & IEEE80211_IFCC_BEACON) {
 	if (conf->changed & IEEE80211_IFCC_BEACON) {
-		ret = p54_scan(dev, P54_SCAN_EXIT, 0,
-			       dev->conf.channel->center_freq);
+		ret = p54_scan(dev, P54_SCAN_EXIT, 0);
 		if (ret)
 		if (ret)
 			goto out;
 			goto out;
 		ret = p54_setup_mac(dev);
 		ret = p54_setup_mac(dev);
@@ -1885,18 +1936,33 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev)
 	xbow->magic2 = cpu_to_le16(0x2);
 	xbow->magic2 = cpu_to_le16(0x2);
 	xbow->freq = cpu_to_le16(5390);
 	xbow->freq = cpu_to_le16(5390);
 	memset(xbow->padding, 0, sizeof(xbow->padding));
 	memset(xbow->padding, 0, sizeof(xbow->padding));
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	return 0;
 	return 0;
 }
 }
 
 
-static void p54_statistics_timer(unsigned long data)
+static void p54_work(struct work_struct *work)
 {
 {
-	struct ieee80211_hw *dev = (struct ieee80211_hw *) data;
-	struct p54_common *priv = dev->priv;
+	struct p54_common *priv = container_of(work, struct p54_common,
+					       work.work);
+	struct ieee80211_hw *dev = priv->hw;
+	struct sk_buff *skb;
 
 
-	BUG_ON(!priv->cached_stats);
+	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+		return ;
+
+	/*
+	 * TODO: walk through tx_queue and do the following tasks
+	 * 	1. initiate bursts.
+	 *      2. cancel stuck frames / reset the device if necessary.
+	 */
 
 
-	priv->tx(dev, priv->cached_stats, 0);
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) +
+			    sizeof(struct p54_statistics),
+			    P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+	if (!skb)
+		return ;
+
+	priv->tx(dev, skb);
 }
 }
 
 
 static int p54_get_stats(struct ieee80211_hw *dev,
 static int p54_get_stats(struct ieee80211_hw *dev,
@@ -1904,17 +1970,7 @@ static int p54_get_stats(struct ieee80211_hw *dev,
 {
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
 
 
-	del_timer(&priv->stats_timer);
-	p54_statistics_timer((unsigned long)dev);
-
-	if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) {
-		printk(KERN_ERR "%s: device does not respond!\n",
-			wiphy_name(dev->wiphy));
-		return -EBUSY;
-	}
-
 	memcpy(stats, &priv->stats, sizeof(*stats));
 	memcpy(stats, &priv->stats, sizeof(*stats));
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1946,8 +2002,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
 			priv->basic_rate_mask = info->basic_rates;
 			priv->basic_rate_mask = info->basic_rates;
 		p54_setup_mac(dev);
 		p54_setup_mac(dev);
 		if (priv->fw_var >= 0x500)
 		if (priv->fw_var >= 0x500)
-			p54_scan(dev, P54_SCAN_EXIT, 0,
-				 dev->conf.channel->center_freq);
+			p54_scan(dev, P54_SCAN_EXIT, 0);
 	}
 	}
 	if (changed & BSS_CHANGED_ASSOC) {
 	if (changed & BSS_CHANGED_ASSOC) {
 		if (info->assoc) {
 		if (info->assoc) {
@@ -2039,7 +2094,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
 			[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
 			[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
 	}
 	}
 
 
-	priv->tx(dev, skb, 1);
+	priv->tx(dev, skb);
 	mutex_unlock(&priv->conf_mutex);
 	mutex_unlock(&priv->conf_mutex);
 	return 0;
 	return 0;
 }
 }
@@ -2072,6 +2127,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 		return NULL;
 		return NULL;
 
 
 	priv = dev->priv;
 	priv = dev->priv;
+	priv->hw = dev;
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	priv->basic_rate_mask = 0x15f;
 	priv->basic_rate_mask = 0x15f;
 	skb_queue_head_init(&priv->tx_queue);
 	skb_queue_head_init(&priv->tx_queue);
@@ -2107,9 +2163,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 
 
 	mutex_init(&priv->conf_mutex);
 	mutex_init(&priv->conf_mutex);
 	init_completion(&priv->eeprom_comp);
 	init_completion(&priv->eeprom_comp);
-	init_completion(&priv->stats_comp);
-	setup_timer(&priv->stats_timer, p54_statistics_timer,
-		(unsigned long)dev);
+	INIT_DELAYED_WORK(&priv->work, p54_work);
 
 
 	return dev;
 	return dev;
 }
 }
@@ -2118,8 +2172,6 @@ EXPORT_SYMBOL_GPL(p54_init_common);
 void p54_free_common(struct ieee80211_hw *dev)
 void p54_free_common(struct ieee80211_hw *dev)
 {
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
-	del_timer(&priv->stats_timer);
-	kfree_skb(priv->cached_stats);
 	kfree(priv->iq_autocal);
 	kfree(priv->iq_autocal);
 	kfree(priv->output_limit);
 	kfree(priv->output_limit);
 	kfree(priv->curve_data);
 	kfree(priv->curve_data);

+ 14 - 11
drivers/net/wireless/p54/p54common.h

@@ -84,9 +84,6 @@ struct bootrec_desc {
 #define BR_CODE_END_OF_BRA		0xFF0000FF
 #define BR_CODE_END_OF_BRA		0xFF0000FF
 #define LEGACY_BR_CODE_END_OF_BRA	0xFFFFFFFF
 #define LEGACY_BR_CODE_END_OF_BRA	0xFFFFFFFF
 
 
-#define P54_HDR_FLAG_CONTROL		BIT(15)
-#define P54_HDR_FLAG_CONTROL_OPSET	(BIT(15) + BIT(0))
-
 #define P54_HDR_FLAG_DATA_ALIGN		BIT(14)
 #define P54_HDR_FLAG_DATA_ALIGN		BIT(14)
 #define P54_HDR_FLAG_DATA_OUT_PROMISC	BIT(0)
 #define P54_HDR_FLAG_DATA_OUT_PROMISC	BIT(0)
 #define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
 #define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
@@ -178,6 +175,11 @@ struct pda_pa_curve_data {
 	u8 data[0];
 	u8 data[0];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
+struct pda_rssi_cal_entry {
+	__le16 mul;
+	__le16 add;
+} __attribute__ ((packed));
+
 /*
 /*
  * this defines the PDR codes used to build PDAs as defined in document
  * this defines the PDR codes used to build PDAs as defined in document
  * number 553155. The current implementation mirrors version 1.1 of the
  * number 553155. The current implementation mirrors version 1.1 of the
@@ -355,6 +357,11 @@ struct p54_tx_data {
 	u8 align[0];
 	u8 align[0];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
 #define P54_FILTER_TYPE_NONE		0
 #define P54_FILTER_TYPE_NONE		0
 #define P54_FILTER_TYPE_STATION		BIT(0)
 #define P54_FILTER_TYPE_STATION		BIT(0)
 #define P54_FILTER_TYPE_IBSS		BIT(1)
 #define P54_FILTER_TYPE_IBSS		BIT(1)
@@ -424,22 +431,18 @@ struct p54_scan {
 	u8 dup_16qam;
 	u8 dup_16qam;
 	u8 dup_64qam;
 	u8 dup_64qam;
 	union {
 	union {
-		struct {
-			__le16 rssical_mul;
-			__le16 rssical_add;
-		} v1 __attribute__ ((packed));
+		struct pda_rssi_cal_entry v1_rssi;
 
 
 		struct {
 		struct {
 			__le32 basic_rate_mask;
 			__le32 basic_rate_mask;
 			u8 rts_rates[8];
 			u8 rts_rates[8];
-			__le16 rssical_mul;
-			__le16 rssical_add;
+			struct pda_rssi_cal_entry rssi;
 		} v2 __attribute__ ((packed));
 		} v2 __attribute__ ((packed));
 	} __attribute__ ((packed));
 	} __attribute__ ((packed));
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
-#define P54_SCAN_V1_LEN (sizeof(struct p54_scan)-12)
-#define P54_SCAN_V2_LEN (sizeof(struct p54_scan))
+#define P54_SCAN_V1_LEN 0x70
+#define P54_SCAN_V2_LEN 0x7c
 
 
 struct p54_led {
 struct p54_led {
 	__le16 mode;
 	__le16 mode;

+ 5 - 7
drivers/net/wireless/p54/p54pci.c

@@ -227,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
 
 
 	while (i != idx) {
 	while (i != idx) {
 		desc = &ring[i];
 		desc = &ring[i];
-		p54_free_skb(dev, tx_buf[i]);
+		if (tx_buf[i])
+			if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i]))
+				p54_free_skb(dev, tx_buf[i]);
 		tx_buf[i] = NULL;
 		tx_buf[i] = NULL;
 
 
 		pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
 		pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
@@ -298,8 +300,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
 	return reg ? IRQ_HANDLED : IRQ_NONE;
 	return reg ? IRQ_HANDLED : IRQ_NONE;
 }
 }
 
 
-static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
-		    int free_on_tx)
+static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 {
 	struct p54p_priv *priv = dev->priv;
 	struct p54p_priv *priv = dev->priv;
 	struct p54p_ring_control *ring_control = priv->ring_control;
 	struct p54p_ring_control *ring_control = priv->ring_control;
@@ -314,6 +315,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
 	idx = le32_to_cpu(ring_control->host_idx[1]);
 	idx = le32_to_cpu(ring_control->host_idx[1]);
 	i = idx % ARRAY_SIZE(ring_control->tx_data);
 	i = idx % ARRAY_SIZE(ring_control->tx_data);
 
 
+	priv->tx_buf_data[i] = skb;
 	mapping = pci_map_single(priv->pdev, skb->data, skb->len,
 	mapping = pci_map_single(priv->pdev, skb->data, skb->len,
 				 PCI_DMA_TODEVICE);
 				 PCI_DMA_TODEVICE);
 	desc = &ring_control->tx_data[i];
 	desc = &ring_control->tx_data[i];
@@ -324,10 +326,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
 
 
 	wmb();
 	wmb();
 	ring_control->host_idx[1] = cpu_to_le32(idx + 1);
 	ring_control->host_idx[1] = cpu_to_le32(idx + 1);
-
-	if (free_on_tx)
-		priv->tx_buf_data[i] = skb;
-
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 
 	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
 	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));

+ 15 - 28
drivers/net/wireless/p54/p54usb.c

@@ -138,22 +138,16 @@ static void p54u_rx_cb(struct urb *urb)
 	}
 	}
 }
 }
 
 
-static void p54u_tx_reuse_skb_cb(struct urb *urb)
-{
-	struct sk_buff *skb = urb->context;
-	struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *)
-		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv;
-
-	skb_pull(skb, priv->common.tx_hdr_len);
-}
-
-static void p54u_tx_free_skb_cb(struct urb *urb)
+static void p54u_tx_cb(struct urb *urb)
 {
 {
 	struct sk_buff *skb = urb->context;
 	struct sk_buff *skb = urb->context;
 	struct ieee80211_hw *dev = (struct ieee80211_hw *)
 	struct ieee80211_hw *dev = (struct ieee80211_hw *)
 		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+	struct p54u_priv *priv = dev->priv;
 
 
-	p54_free_skb(dev, skb);
+	skb_pull(skb, priv->common.tx_hdr_len);
+	if (FREE_AFTER_TX(skb))
+		p54_free_skb(dev, skb);
 }
 }
 
 
 static void p54u_tx_dummy_cb(struct urb *urb) { }
 static void p54u_tx_dummy_cb(struct urb *urb) { }
@@ -213,8 +207,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
 	return ret;
 	return ret;
 }
 }
 
 
-static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb,
-			 int free_on_tx)
+static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 {
 	struct p54u_priv *priv = dev->priv;
 	struct p54u_priv *priv = dev->priv;
 	struct urb *addr_urb, *data_urb;
 	struct urb *addr_urb, *data_urb;
@@ -236,9 +229,7 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb,
 			  p54u_tx_dummy_cb, dev);
 			  p54u_tx_dummy_cb, dev);
 	usb_fill_bulk_urb(data_urb, priv->udev,
 	usb_fill_bulk_urb(data_urb, priv->udev,
 			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
 			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
-			  skb->data, skb->len,
-			  free_on_tx ? p54u_tx_free_skb_cb :
-				       p54u_tx_reuse_skb_cb, skb);
+			  skb->data, skb->len, p54u_tx_cb, skb);
 
 
 	usb_anchor_urb(addr_urb, &priv->submitted);
 	usb_anchor_urb(addr_urb, &priv->submitted);
 	err = usb_submit_urb(addr_urb, GFP_ATOMIC);
 	err = usb_submit_urb(addr_urb, GFP_ATOMIC);
@@ -273,8 +264,7 @@ static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
 	return cpu_to_le32(chk);
 	return cpu_to_le32(chk);
 }
 }
 
 
-static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb,
-			 int free_on_tx)
+static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 {
 	struct p54u_priv *priv = dev->priv;
 	struct p54u_priv *priv = dev->priv;
 	struct urb *data_urb;
 	struct urb *data_urb;
@@ -293,9 +283,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb,
 
 
 	usb_fill_bulk_urb(data_urb, priv->udev,
 	usb_fill_bulk_urb(data_urb, priv->udev,
 			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
 			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
-			  skb->data, skb->len,
-			  free_on_tx ? p54u_tx_free_skb_cb :
-				       p54u_tx_reuse_skb_cb, skb);
+			  skb->data, skb->len, p54u_tx_cb, skb);
 
 
 	usb_anchor_urb(data_urb, &priv->submitted);
 	usb_anchor_urb(data_urb, &priv->submitted);
 	if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
 	if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
@@ -306,14 +294,15 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb,
 	usb_free_urb(data_urb);
 	usb_free_urb(data_urb);
 }
 }
 
 
-static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb,
-			    int free_on_tx)
+static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 {
 	struct p54u_priv *priv = dev->priv;
 	struct p54u_priv *priv = dev->priv;
 	struct urb *int_urb, *data_urb;
 	struct urb *int_urb, *data_urb;
 	struct net2280_tx_hdr *hdr;
 	struct net2280_tx_hdr *hdr;
 	struct net2280_reg_write *reg;
 	struct net2280_reg_write *reg;
 	int err = 0;
 	int err = 0;
+	__le32 addr = ((struct p54_hdr *) skb->data)->req_id;
+	__le16 len = cpu_to_le16(skb->len);
 
 
 	reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
 	reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
 	if (!reg)
 	if (!reg)
@@ -338,8 +327,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb,
 
 
 	hdr = (void *)skb_push(skb, sizeof(*hdr));
 	hdr = (void *)skb_push(skb, sizeof(*hdr));
 	memset(hdr, 0, sizeof(*hdr));
 	memset(hdr, 0, sizeof(*hdr));
-	hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
-	hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr));
+	hdr->len = len;
+	hdr->device_addr = addr;
 
 
 	usb_fill_bulk_urb(int_urb, priv->udev,
 	usb_fill_bulk_urb(int_urb, priv->udev,
 		usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
 		usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
@@ -354,9 +343,7 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb,
 
 
 	usb_fill_bulk_urb(data_urb, priv->udev,
 	usb_fill_bulk_urb(data_urb, priv->udev,
 			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
 			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
-			  skb->data, skb->len,
-			  free_on_tx ? p54u_tx_free_skb_cb :
-				       p54u_tx_reuse_skb_cb, skb);
+			  skb->data, skb->len, p54u_tx_cb, skb);
 
 
 	usb_anchor_urb(int_urb, &priv->submitted);
 	usb_anchor_urb(int_urb, &priv->submitted);
 	err = usb_submit_urb(int_urb, GFP_ATOMIC);
 	err = usb_submit_urb(int_urb, GFP_ATOMIC);

+ 6 - 10
drivers/net/wireless/rtl818x/rtl8187_dev.c

@@ -213,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 	if (!urb) {
 		kfree_skb(skb);
 		kfree_skb(skb);
-		return 0;
+		return -ENOMEM;
 	}
 	}
 
 
 	flags = skb->len;
 	flags = skb->len;
@@ -281,7 +281,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	}
 	}
 	usb_free_urb(urb);
 	usb_free_urb(urb);
 
 
-	return 0;
+	return rc;
 }
 }
 
 
 static void rtl8187_rx_cb(struct urb *urb)
 static void rtl8187_rx_cb(struct urb *urb)
@@ -294,15 +294,16 @@ static void rtl8187_rx_cb(struct urb *urb)
 	int rate, signal;
 	int rate, signal;
 	u32 flags;
 	u32 flags;
 	u32 quality;
 	u32 quality;
+	unsigned long f;
 
 
-	spin_lock(&priv->rx_queue.lock);
+	spin_lock_irqsave(&priv->rx_queue.lock, f);
 	if (skb->next)
 	if (skb->next)
 		__skb_unlink(skb, &priv->rx_queue);
 		__skb_unlink(skb, &priv->rx_queue);
 	else {
 	else {
-		spin_unlock(&priv->rx_queue.lock);
+		spin_unlock_irqrestore(&priv->rx_queue.lock, f);
 		return;
 		return;
 	}
 	}
-	spin_unlock(&priv->rx_queue.lock);
+	spin_unlock_irqrestore(&priv->rx_queue.lock, f);
 	skb_put(skb, urb->actual_length);
 	skb_put(skb, urb->actual_length);
 
 
 	if (unlikely(urb->status)) {
 	if (unlikely(urb->status)) {
@@ -942,7 +943,6 @@ static int rtl8187_start(struct ieee80211_hw *dev)
 static void rtl8187_stop(struct ieee80211_hw *dev)
 static void rtl8187_stop(struct ieee80211_hw *dev)
 {
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct rtl8187_priv *priv = dev->priv;
-	struct rtl8187_rx_info *info;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	u32 reg;
 	u32 reg;
 
 
@@ -961,10 +961,6 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
 	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
 
-	while ((skb = skb_dequeue(&priv->rx_queue))) {
-		info = (struct rtl8187_rx_info *)skb->cb;
-		kfree_skb(skb);
-	}
 	while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
 	while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
 		dev_kfree_skb_any(skb);
 		dev_kfree_skb_any(skb);
 
 

+ 42 - 11
include/linux/nl80211.h

@@ -201,13 +201,13 @@ enum nl80211_commands {
  * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
  * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
  * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
  * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
  * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
  * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
- * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
  *	if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
  *	if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
- *	NL80211_SEC_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ *	NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
  *		this attribute)
  *		this attribute)
- *	NL80211_SEC_CHAN_DISABLED = HT20 only
- *	NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
- *	NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
+ *	NL80211_CHAN_HT20 = HT20 only
+ *	NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ *	NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
  *
  *
  * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
  * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
  * @NL80211_ATTR_IFNAME: network interface name
  * @NL80211_ATTR_IFNAME: network interface name
@@ -344,7 +344,7 @@ enum nl80211_attrs {
 
 
 	NL80211_ATTR_WIPHY_TXQ_PARAMS,
 	NL80211_ATTR_WIPHY_TXQ_PARAMS,
 	NL80211_ATTR_WIPHY_FREQ,
 	NL80211_ATTR_WIPHY_FREQ,
-	NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
+	NL80211_ATTR_WIPHY_CHANNEL_TYPE,
 
 
 	/* add attributes here, update the policy in nl80211.c */
 	/* add attributes here, update the policy in nl80211.c */
 
 
@@ -424,6 +424,32 @@ enum nl80211_sta_flags {
 	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
 	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
 };
 };
 
 
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+	__NL80211_RATE_INFO_INVALID,
+	NL80211_RATE_INFO_BITRATE,
+	NL80211_RATE_INFO_MCS,
+	NL80211_RATE_INFO_40_MHZ_WIDTH,
+	NL80211_RATE_INFO_SHORT_GI,
+
+	/* keep last */
+	__NL80211_RATE_INFO_AFTER_LAST,
+	NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
 /**
 /**
  * enum nl80211_sta_info - station information
  * enum nl80211_sta_info - station information
  *
  *
@@ -436,6 +462,9 @@ enum nl80211_sta_flags {
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ * 	containing info as possible, see &enum nl80211_sta_info_txrate.
  */
  */
 enum nl80211_sta_info {
 enum nl80211_sta_info {
 	__NL80211_STA_INFO_INVALID,
 	__NL80211_STA_INFO_INVALID,
@@ -445,6 +474,8 @@ enum nl80211_sta_info {
 	NL80211_STA_INFO_LLID,
 	NL80211_STA_INFO_LLID,
 	NL80211_STA_INFO_PLID,
 	NL80211_STA_INFO_PLID,
 	NL80211_STA_INFO_PLINK_STATE,
 	NL80211_STA_INFO_PLINK_STATE,
+	NL80211_STA_INFO_SIGNAL,
+	NL80211_STA_INFO_TX_BITRATE,
 
 
 	/* keep last */
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -774,10 +805,10 @@ enum nl80211_txq_q {
 	NL80211_TXQ_Q_BK
 	NL80211_TXQ_Q_BK
 };
 };
 
 
-enum nl80211_sec_chan_offset {
-	NL80211_SEC_CHAN_NO_HT /* No HT */,
-	NL80211_SEC_CHAN_DISABLED /* HT20 only */,
-	NL80211_SEC_CHAN_BELOW /* HT40- */,
-	NL80211_SEC_CHAN_ABOVE /* HT40+ */
+enum nl80211_channel_type {
+	NL80211_CHAN_NO_HT,
+	NL80211_CHAN_HT20,
+	NL80211_CHAN_HT40MINUS,
+	NL80211_CHAN_HT40PLUS
 };
 };
 #endif /* __LINUX_NL80211_H */
 #endif /* __LINUX_NL80211_H */

+ 41 - 1
include/net/cfg80211.h

@@ -169,6 +169,9 @@ struct station_parameters {
  * @STATION_INFO_LLID: @llid filled
  * @STATION_INFO_LLID: @llid filled
  * @STATION_INFO_PLID: @plid filled
  * @STATION_INFO_PLID: @plid filled
  * @STATION_INFO_PLINK_STATE: @plink_state filled
  * @STATION_INFO_PLINK_STATE: @plink_state filled
+ * @STATION_INFO_SIGNAL: @signal filled
+ * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
+ *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
  */
  */
 enum station_info_flags {
 enum station_info_flags {
 	STATION_INFO_INACTIVE_TIME	= 1<<0,
 	STATION_INFO_INACTIVE_TIME	= 1<<0,
@@ -177,6 +180,39 @@ enum station_info_flags {
 	STATION_INFO_LLID		= 1<<3,
 	STATION_INFO_LLID		= 1<<3,
 	STATION_INFO_PLID		= 1<<4,
 	STATION_INFO_PLID		= 1<<4,
 	STATION_INFO_PLINK_STATE	= 1<<5,
 	STATION_INFO_PLINK_STATE	= 1<<5,
+	STATION_INFO_SIGNAL		= 1<<6,
+	STATION_INFO_TX_BITRATE		= 1<<7,
+};
+
+/**
+ * enum station_info_rate_flags - bitrate info flags
+ *
+ * Used by the driver to indicate the specific rate transmission
+ * type for 802.11n transmissions.
+ *
+ * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
+ */
+enum rate_info_flags {
+	RATE_INFO_FLAGS_MCS		= 1<<0,
+	RATE_INFO_FLAGS_40_MHZ_WIDTH	= 1<<1,
+	RATE_INFO_FLAGS_SHORT_GI	= 1<<2,
+};
+
+/**
+ * struct rate_info - bitrate information
+ *
+ * Information about a receiving or transmitting bitrate
+ *
+ * @flags: bitflag of flags from &enum rate_info_flags
+ * @mcs: mcs index if struct describes a 802.11n bitrate
+ * @legacy: bitrate in 100kbit/s for 802.11abg
+ */
+struct rate_info {
+	u8 flags;
+	u8 mcs;
+	u16 legacy;
 };
 };
 
 
 /**
 /**
@@ -191,6 +227,8 @@ enum station_info_flags {
  * @llid: mesh local link id
  * @llid: mesh local link id
  * @plid: mesh peer link id
  * @plid: mesh peer link id
  * @plink_state: mesh peer link state
  * @plink_state: mesh peer link state
+ * @signal: signal strength of last received packet in dBm
+ * @txrate: current unicast bitrate to this station
  */
  */
 struct station_info {
 struct station_info {
 	u32 filled;
 	u32 filled;
@@ -200,6 +238,8 @@ struct station_info {
 	u16 llid;
 	u16 llid;
 	u16 plid;
 	u16 plid;
 	u8 plink_state;
 	u8 plink_state;
+	s8 signal;
+	struct rate_info txrate;
 };
 };
 
 
 /**
 /**
@@ -523,7 +563,7 @@ struct cfg80211_ops {
 
 
 	int	(*set_channel)(struct wiphy *wiphy,
 	int	(*set_channel)(struct wiphy *wiphy,
 			       struct ieee80211_channel *chan,
 			       struct ieee80211_channel *chan,
-			       enum nl80211_sec_chan_offset);
+			       enum nl80211_channel_type channel_type);
 };
 };
 
 
 /* temporary wext handlers */
 /* temporary wext handlers */

+ 16 - 10
include/net/mac80211.h

@@ -165,14 +165,9 @@ enum ieee80211_bss_change {
 
 
 /**
 /**
  * struct ieee80211_bss_ht_conf - BSS's changing HT configuration
  * struct ieee80211_bss_ht_conf - BSS's changing HT configuration
- * @secondary_channel_offset: secondary channel offset, uses
- *	%IEEE80211_HT_PARAM_CHA_SEC_ values
- * @width_40_ok: indicates that 40 MHz bandwidth may be used for TX
  * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info)
  * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info)
  */
  */
 struct ieee80211_bss_ht_conf {
 struct ieee80211_bss_ht_conf {
-	u8 secondary_channel_offset;
-	bool width_40_ok;
 	u16 operation_mode;
 	u16 operation_mode;
 };
 };
 
 
@@ -441,6 +436,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  *	is valid. This is useful in monitor mode and necessary for beacon frames
  *	is valid. This is useful in monitor mode and necessary for beacon frames
  *	to enable IBSS merging.
  *	to enable IBSS merging.
  * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
  * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
+ * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
+ * @RX_FLAG_40MHZ: HT40 (40 MHz) was used
+ * @RX_FLAG_SHORT_GI: Short guard interval was used
  */
  */
 enum mac80211_rx_flags {
 enum mac80211_rx_flags {
 	RX_FLAG_MMIC_ERROR	= 1<<0,
 	RX_FLAG_MMIC_ERROR	= 1<<0,
@@ -451,7 +449,10 @@ enum mac80211_rx_flags {
 	RX_FLAG_FAILED_FCS_CRC	= 1<<5,
 	RX_FLAG_FAILED_FCS_CRC	= 1<<5,
 	RX_FLAG_FAILED_PLCP_CRC = 1<<6,
 	RX_FLAG_FAILED_PLCP_CRC = 1<<6,
 	RX_FLAG_TSFT		= 1<<7,
 	RX_FLAG_TSFT		= 1<<7,
-	RX_FLAG_SHORTPRE	= 1<<8
+	RX_FLAG_SHORTPRE	= 1<<8,
+	RX_FLAG_HT		= 1<<9,
+	RX_FLAG_40MHZ		= 1<<10,
+	RX_FLAG_SHORT_GI	= 1<<11,
 };
 };
 
 
 /**
 /**
@@ -471,7 +472,8 @@ enum mac80211_rx_flags {
  * @noise: noise when receiving this frame, in dBm.
  * @noise: noise when receiving this frame, in dBm.
  * @qual: overall signal quality indication, in percent (0-100).
  * @qual: overall signal quality indication, in percent (0-100).
  * @antenna: antenna used
  * @antenna: antenna used
- * @rate_idx: index of data rate into band's supported rates
+ * @rate_idx: index of data rate into band's supported rates or MCS index if
+ *	HT rates are use (RX_FLAG_HT)
  * @flag: %RX_FLAG_*
  * @flag: %RX_FLAG_*
  */
  */
 struct ieee80211_rx_status {
 struct ieee80211_rx_status {
@@ -508,9 +510,7 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void)
 
 
 struct ieee80211_ht_conf {
 struct ieee80211_ht_conf {
 	bool enabled;
 	bool enabled;
-	int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary
-			      * channel below primary; 1 = HT40 enabled,
-			      * secondary channel above primary */
+	enum nl80211_channel_type channel_type;
 };
 };
 
 
 /**
 /**
@@ -854,6 +854,11 @@ enum ieee80211_tkip_key_type {
  *
  *
  * @IEEE80211_HW_AMPDU_AGGREGATION:
  * @IEEE80211_HW_AMPDU_AGGREGATION:
  *	Hardware supports 11n A-MPDU aggregation.
  *	Hardware supports 11n A-MPDU aggregation.
+ *
+ * @IEEE80211_HW_NO_STACK_DYNAMIC_PS:
+ *	Hardware which has dynamic power save support, meaning
+ *	that power save is enabled in idle periods, and don't need support
+ *	from stack.
  */
  */
 enum ieee80211_hw_flags {
 enum ieee80211_hw_flags {
 	IEEE80211_HW_RX_INCLUDES_FCS			= 1<<1,
 	IEEE80211_HW_RX_INCLUDES_FCS			= 1<<1,
@@ -866,6 +871,7 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_NOISE_DBM				= 1<<8,
 	IEEE80211_HW_NOISE_DBM				= 1<<8,
 	IEEE80211_HW_SPECTRUM_MGMT			= 1<<9,
 	IEEE80211_HW_SPECTRUM_MGMT			= 1<<9,
 	IEEE80211_HW_AMPDU_AGGREGATION			= 1<<10,
 	IEEE80211_HW_AMPDU_AGGREGATION			= 1<<10,
+	IEEE80211_HW_NO_STACK_DYNAMIC_PS		= 1<<11,
 };
 };
 
 
 /**
 /**

+ 37 - 5
net/mac80211/cfg.c

@@ -310,12 +310,35 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 
 
 	sinfo->filled = STATION_INFO_INACTIVE_TIME |
 	sinfo->filled = STATION_INFO_INACTIVE_TIME |
 			STATION_INFO_RX_BYTES |
 			STATION_INFO_RX_BYTES |
-			STATION_INFO_TX_BYTES;
+			STATION_INFO_TX_BYTES |
+			STATION_INFO_TX_BITRATE;
 
 
 	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
 	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
 	sinfo->rx_bytes = sta->rx_bytes;
 	sinfo->rx_bytes = sta->rx_bytes;
 	sinfo->tx_bytes = sta->tx_bytes;
 	sinfo->tx_bytes = sta->tx_bytes;
 
 
+	if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+		sinfo->filled |= STATION_INFO_SIGNAL;
+		sinfo->signal = (s8)sta->last_signal;
+	}
+
+	sinfo->txrate.flags = 0;
+	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+	if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
+		struct ieee80211_supported_band *sband;
+		sband = sta->local->hw.wiphy->bands[
+				sta->local->hw.conf.channel->band];
+		sinfo->txrate.legacy =
+			sband->bitrates[sta->last_tx_rate.idx].bitrate;
+	} else
+		sinfo->txrate.mcs = sta->last_tx_rate.idx;
+
 	if (ieee80211_vif_is_mesh(&sdata->vif)) {
 	if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
 #ifdef CONFIG_MAC80211_MESH
 		sinfo->filled |= STATION_INFO_LLID |
 		sinfo->filled |= STATION_INFO_LLID |
@@ -663,6 +686,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 	struct sta_info *sta;
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
 	int err;
 	int err;
+	int layer2_update;
 
 
 	/* Prevent a race with changing the rate control algorithm */
 	/* Prevent a race with changing the rate control algorithm */
 	if (!netif_running(dev))
 	if (!netif_running(dev))
@@ -693,17 +717,25 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 
 
 	rate_control_rate_init(sta);
 	rate_control_rate_init(sta);
 
 
+	layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+		sdata->vif.type == NL80211_IFTYPE_AP;
+
 	rcu_read_lock();
 	rcu_read_lock();
 
 
 	err = sta_info_insert(sta);
 	err = sta_info_insert(sta);
 	if (err) {
 	if (err) {
 		/* STA has been freed */
 		/* STA has been freed */
+		if (err == -EEXIST && layer2_update) {
+			/* Need to update layer 2 devices on reassociation */
+			sta = sta_info_get(local, mac);
+			if (sta)
+				ieee80211_send_layer2_update(sta);
+		}
 		rcu_read_unlock();
 		rcu_read_unlock();
 		return err;
 		return err;
 	}
 	}
 
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-	    sdata->vif.type == NL80211_IFTYPE_AP)
+	if (layer2_update)
 		ieee80211_send_layer2_update(sta);
 		ieee80211_send_layer2_update(sta);
 
 
 	rcu_read_unlock();
 	rcu_read_unlock();
@@ -1099,12 +1131,12 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
 
 
 static int ieee80211_set_channel(struct wiphy *wiphy,
 static int ieee80211_set_channel(struct wiphy *wiphy,
 				 struct ieee80211_channel *chan,
 				 struct ieee80211_channel *chan,
-				 enum nl80211_sec_chan_offset sec_chan_offset)
+				 enum nl80211_channel_type channel_type)
 {
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 
 
 	local->oper_channel = chan;
 	local->oper_channel = chan;
-	local->oper_sec_chan_offset = sec_chan_offset;
+	local->oper_channel_type = channel_type;
 
 
 	return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 	return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 }
 }

+ 24 - 11
net/mac80211/ht.c

@@ -98,6 +98,7 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_bss_ht_conf ht;
 	struct ieee80211_bss_ht_conf ht;
 	u32 changed = 0;
 	u32 changed = 0;
 	bool enable_ht = true, ht_changed;
 	bool enable_ht = true, ht_changed;
+	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 
@@ -112,24 +113,36 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 	    ieee80211_channel_to_frequency(hti->control_chan))
 	    ieee80211_channel_to_frequency(hti->control_chan))
 		enable_ht = false;
 		enable_ht = false;
 
 
-	/*
-	 * XXX: This is totally incorrect when there are multiple virtual
-	 *	interfaces, needs to be fixed later.
-	 */
-	ht_changed = local->hw.conf.ht.enabled != enable_ht;
+	if (enable_ht) {
+		channel_type = NL80211_CHAN_HT20;
+
+		if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+		    (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
+		    (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
+			switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+				channel_type = NL80211_CHAN_HT40PLUS;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+				channel_type = NL80211_CHAN_HT40MINUS;
+				break;
+			}
+		}
+	}
+
+	ht_changed = local->hw.conf.ht.enabled != enable_ht ||
+		     channel_type != local->hw.conf.ht.channel_type;
+
+	local->oper_channel_type = channel_type;
 	local->hw.conf.ht.enabled = enable_ht;
 	local->hw.conf.ht.enabled = enable_ht;
+
 	if (ht_changed)
 	if (ht_changed)
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
 
 
 	/* disable HT */
 	/* disable HT */
 	if (!enable_ht)
 	if (!enable_ht)
 		return 0;
 		return 0;
-	ht.secondary_channel_offset =
-		hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
-	ht.width_40_ok =
-		!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
-		(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
-		(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
+
 	ht.operation_mode = le16_to_cpu(hti->operation_mode);
 	ht.operation_mode = le16_to_cpu(hti->operation_mode);
 
 
 	/* if bss configuration changed store the new one */
 	/* if bss configuration changed store the new one */

+ 23 - 2
net/mac80211/ieee80211_i.h

@@ -538,6 +538,11 @@ enum {
 	IEEE80211_ADDBA_MSG	= 4,
 	IEEE80211_ADDBA_MSG	= 4,
 };
 };
 
 
+enum queue_stop_reason {
+	IEEE80211_QUEUE_STOP_REASON_DRIVER,
+	IEEE80211_QUEUE_STOP_REASON_PS,
+};
+
 /* maximum number of hardware queues we support. */
 /* maximum number of hardware queues we support. */
 #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
 #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
 
 
@@ -554,7 +559,8 @@ struct ieee80211_local {
 	const struct ieee80211_ops *ops;
 	const struct ieee80211_ops *ops;
 
 
 	unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
 	unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
-
+	unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
+	spinlock_t queue_stop_reason_lock;
 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
 	int open_count;
 	int open_count;
 	int monitors, cooked_mntrs;
 	int monitors, cooked_mntrs;
@@ -625,7 +631,7 @@ struct ieee80211_local {
 	struct delayed_work scan_work;
 	struct delayed_work scan_work;
 	struct ieee80211_sub_if_data *scan_sdata;
 	struct ieee80211_sub_if_data *scan_sdata;
 	struct ieee80211_channel *oper_channel, *scan_channel;
 	struct ieee80211_channel *oper_channel, *scan_channel;
-	enum nl80211_sec_chan_offset oper_sec_chan_offset;
+	enum nl80211_channel_type oper_channel_type;
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	size_t scan_ssid_len;
 	size_t scan_ssid_len;
 	struct list_head bss_list;
 	struct list_head bss_list;
@@ -689,6 +695,12 @@ struct ieee80211_local {
 	int wifi_wme_noack_test;
 	int wifi_wme_noack_test;
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
 
+	bool powersave;
+	int dynamic_ps_timeout;
+	struct work_struct dynamic_ps_enable_work;
+	struct work_struct dynamic_ps_disable_work;
+	struct timer_list dynamic_ps_timer;
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct local_debugfsdentries {
 	struct local_debugfsdentries {
 		struct dentry *rcdir;
 		struct dentry *rcdir;
@@ -971,6 +983,15 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
 u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
 u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
 			      enum ieee80211_band band);
 			      enum ieee80211_band band);
 
 
+void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
+void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
+void ieee80211_dynamic_ps_timer(unsigned long data);
+
+void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+				     enum queue_stop_reason reason);
+void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
+				     enum queue_stop_reason reason);
+
 #ifdef CONFIG_MAC80211_NOINLINE
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
 #define debug_noinline noinline
 #else
 #else

+ 21 - 18
net/mac80211/main.c

@@ -195,37 +195,30 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 	struct ieee80211_channel *chan;
 	struct ieee80211_channel *chan;
 	int ret = 0;
 	int ret = 0;
 	int power;
 	int power;
-	enum nl80211_sec_chan_offset sec_chan_offset;
+	enum nl80211_channel_type channel_type;
 
 
 	might_sleep();
 	might_sleep();
 
 
 	if (local->sw_scanning) {
 	if (local->sw_scanning) {
 		chan = local->scan_channel;
 		chan = local->scan_channel;
-		sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
+		channel_type = NL80211_CHAN_NO_HT;
 	} else {
 	} else {
 		chan = local->oper_channel;
 		chan = local->oper_channel;
-		sec_chan_offset = local->oper_sec_chan_offset;
+		channel_type = local->oper_channel_type;
 	}
 	}
 
 
 	if (chan != local->hw.conf.channel ||
 	if (chan != local->hw.conf.channel ||
-	    sec_chan_offset != local->hw.conf.ht.sec_chan_offset) {
+	    channel_type != local->hw.conf.ht.channel_type) {
 		local->hw.conf.channel = chan;
 		local->hw.conf.channel = chan;
-		switch (sec_chan_offset) {
-		case NL80211_SEC_CHAN_NO_HT:
+		local->hw.conf.ht.channel_type = channel_type;
+		switch (channel_type) {
+		case NL80211_CHAN_NO_HT:
 			local->hw.conf.ht.enabled = false;
 			local->hw.conf.ht.enabled = false;
-			local->hw.conf.ht.sec_chan_offset = 0;
 			break;
 			break;
-		case NL80211_SEC_CHAN_DISABLED:
+		case NL80211_CHAN_HT20:
+		case NL80211_CHAN_HT40MINUS:
+		case NL80211_CHAN_HT40PLUS:
 			local->hw.conf.ht.enabled = true;
 			local->hw.conf.ht.enabled = true;
-			local->hw.conf.ht.sec_chan_offset = 0;
-			break;
-		case NL80211_SEC_CHAN_BELOW:
-			local->hw.conf.ht.enabled = true;
-			local->hw.conf.ht.sec_chan_offset = -1;
-			break;
-		case NL80211_SEC_CHAN_ABOVE:
-			local->hw.conf.ht.enabled = true;
-			local->hw.conf.ht.sec_chan_offset = 1;
 			break;
 			break;
 		}
 		}
 		changed |= IEEE80211_CONF_CHANGE_CHANNEL;
 		changed |= IEEE80211_CONF_CHANGE_CHANNEL;
@@ -348,7 +341,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
 			dev_kfree_skb(skb);
 			dev_kfree_skb(skb);
 			break ;
 			break ;
 		default:
 		default:
-			WARN_ON(1);
+			WARN(1, "mac80211: Packet is of unknown type %d\n",
+			     skb->pkt_type);
 			dev_kfree_skb(skb);
 			dev_kfree_skb(skb);
 			break;
 			break;
 		}
 		}
@@ -731,8 +725,17 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
 
 	spin_lock_init(&local->key_lock);
 	spin_lock_init(&local->key_lock);
 
 
+	spin_lock_init(&local->queue_stop_reason_lock);
+
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
 
+	INIT_WORK(&local->dynamic_ps_enable_work,
+		  ieee80211_dynamic_ps_enable_work);
+	INIT_WORK(&local->dynamic_ps_disable_work,
+		  ieee80211_dynamic_ps_disable_work);
+	setup_timer(&local->dynamic_ps_timer,
+		    ieee80211_dynamic_ps_timer, (unsigned long) local);
+
 	sta_info_init(local);
 	sta_info_init(local);
 
 
 	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
 	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,

+ 66 - 4
net/mac80211/mlme.c

@@ -309,7 +309,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 						  IEEE80211_STYPE_ASSOC_REQ);
 						  IEEE80211_STYPE_ASSOC_REQ);
 		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
 		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
-		mgmt->u.reassoc_req.listen_interval =
+		mgmt->u.assoc_req.listen_interval =
 				cpu_to_le16(local->hw.conf.listen_interval);
 				cpu_to_le16(local->hw.conf.listen_interval);
 	}
 	}
 
 
@@ -744,6 +744,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 	bss_info_changed |= BSS_CHANGED_BASIC_RATES;
 	bss_info_changed |= BSS_CHANGED_BASIC_RATES;
 	ieee80211_bss_info_change_notify(sdata, bss_info_changed);
 	ieee80211_bss_info_change_notify(sdata, bss_info_changed);
 
 
+	if (local->powersave) {
+		if (local->dynamic_ps_timeout > 0)
+			mod_timer(&local->dynamic_ps_timer, jiffies +
+				  msecs_to_jiffies(local->dynamic_ps_timeout));
+		else {
+			conf->flags |= IEEE80211_CONF_PS;
+			ieee80211_hw_config(local,
+					    IEEE80211_CONF_CHANGE_PS);
+		}
+	}
+
 	netif_tx_start_all_queues(sdata->dev);
 	netif_tx_start_all_queues(sdata->dev);
 	netif_carrier_on(sdata->dev);
 	netif_carrier_on(sdata->dev);
 
 
@@ -812,7 +823,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 {
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	struct sta_info *sta;
-	u32 changed = 0;
+	u32 changed = 0, config_changed = 0;
 
 
 	rcu_read_lock();
 	rcu_read_lock();
 
 
@@ -858,8 +869,18 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	rcu_read_unlock();
 	rcu_read_unlock();
 
 
 	local->hw.conf.ht.enabled = false;
 	local->hw.conf.ht.enabled = false;
-	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
+	local->oper_channel_type = NL80211_CHAN_NO_HT;
+	config_changed |= IEEE80211_CONF_CHANGE_HT;
+
+	del_timer_sync(&local->dynamic_ps_timer);
+	cancel_work_sync(&local->dynamic_ps_enable_work);
 
 
+	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+		config_changed |= IEEE80211_CONF_CHANGE_PS;
+	}
+
+	ieee80211_hw_config(local, config_changed);
 	ieee80211_bss_info_change_notify(sdata, changed);
 	ieee80211_bss_info_change_notify(sdata, changed);
 
 
 	rcu_read_lock();
 	rcu_read_lock();
@@ -1612,8 +1633,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 			 * e.g: at 1 MBit that means mactime is 192 usec earlier
 			 * e.g: at 1 MBit that means mactime is 192 usec earlier
 			 * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
 			 * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
 			 */
 			 */
-			int rate = local->hw.wiphy->bands[band]->
+			int rate;
+			if (rx_status->flag & RX_FLAG_HT) {
+				rate = 65; /* TODO: HT rates */
+			} else {
+				rate = local->hw.wiphy->bands[band]->
 					bitrates[rx_status->rate_idx].bitrate;
 					bitrates[rx_status->rate_idx].bitrate;
+			}
 			rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
 			rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
 		} else if (local && local->ops && local->ops->get_tsf)
 		} else if (local && local->ops && local->ops->get_tsf)
 			/* second best option: get current TSF */
 			/* second best option: get current TSF */
@@ -2576,3 +2602,39 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
 		ieee80211_restart_sta_timer(sdata);
 		ieee80211_restart_sta_timer(sdata);
 	rcu_read_unlock();
 	rcu_read_unlock();
 }
 }
+
+void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local,
+			     dynamic_ps_disable_work);
+
+	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+	}
+
+	ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_QUEUE_STOP_REASON_PS);
+}
+
+void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local,
+			     dynamic_ps_enable_work);
+
+	if (local->hw.conf.flags & IEEE80211_CONF_PS)
+		return;
+
+	local->hw.conf.flags |= IEEE80211_CONF_PS;
+
+	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+}
+
+void ieee80211_dynamic_ps_timer(unsigned long data)
+{
+	struct ieee80211_local *local = (void *) data;
+
+	queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
+}

+ 48 - 11
net/mac80211/rx.c

@@ -123,7 +123,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 	/* radiotap header, set always present flags */
 	/* radiotap header, set always present flags */
 	rthdr->it_present =
 	rthdr->it_present =
 		cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
 		cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-			    (1 << IEEE80211_RADIOTAP_RATE) |
 			    (1 << IEEE80211_RADIOTAP_CHANNEL) |
 			    (1 << IEEE80211_RADIOTAP_CHANNEL) |
 			    (1 << IEEE80211_RADIOTAP_ANTENNA) |
 			    (1 << IEEE80211_RADIOTAP_ANTENNA) |
 			    (1 << IEEE80211_RADIOTAP_RX_FLAGS));
 			    (1 << IEEE80211_RADIOTAP_RX_FLAGS));
@@ -149,7 +148,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 	pos++;
 	pos++;
 
 
 	/* IEEE80211_RADIOTAP_RATE */
 	/* IEEE80211_RADIOTAP_RATE */
-	*pos = rate->bitrate / 5;
+	if (status->flag & RX_FLAG_HT) {
+		/*
+		 * TODO: add following information into radiotap header once
+		 * suitable fields are defined for it:
+		 * - MCS index (status->rate_idx)
+		 * - HT40 (status->flag & RX_FLAG_40MHZ)
+		 * - short-GI (status->flag & RX_FLAG_SHORT_GI)
+		 */
+		*pos = 0;
+	} else {
+		rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE);
+		*pos = rate->bitrate / 5;
+	}
 	pos++;
 	pos++;
 
 
 	/* IEEE80211_RADIOTAP_CHANNEL */
 	/* IEEE80211_RADIOTAP_CHANNEL */
@@ -1849,9 +1860,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 			if (!(sdata->dev->flags & IFF_PROMISC))
 			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
 				return 0;
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
-		} else if (!rx->sta)
+		} else if (!rx->sta) {
+			int rate_idx;
+			if (rx->status->flag & RX_FLAG_HT)
+				rate_idx = 0; /* TODO: HT rates */
+			else
+				rate_idx = rx->status->rate_idx;
 			rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2,
 			rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2,
-				BIT(rx->status->rate_idx));
+				BIT(rate_idx));
+		}
 		break;
 		break;
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_MESH_POINT:
 		if (!multicast &&
 		if (!multicast &&
@@ -2057,7 +2074,13 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 					tid_agg_rx->reorder_buf[index]->cb,
 					tid_agg_rx->reorder_buf[index]->cb,
 					sizeof(status));
 					sizeof(status));
 				sband = local->hw.wiphy->bands[status.band];
 				sband = local->hw.wiphy->bands[status.band];
-				rate = &sband->bitrates[status.rate_idx];
+				if (status.flag & RX_FLAG_HT) {
+					/* TODO: HT rates */
+					rate = sband->bitrates;
+				} else {
+					rate = &sband->bitrates
+						[status.rate_idx];
+				}
 				__ieee80211_rx_handle_packet(hw,
 				__ieee80211_rx_handle_packet(hw,
 					tid_agg_rx->reorder_buf[index],
 					tid_agg_rx->reorder_buf[index],
 					&status, rate);
 					&status, rate);
@@ -2101,7 +2124,10 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 		memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
 		memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
 			sizeof(status));
 			sizeof(status));
 		sband = local->hw.wiphy->bands[status.band];
 		sband = local->hw.wiphy->bands[status.band];
-		rate = &sband->bitrates[status.rate_idx];
+		if (status.flag & RX_FLAG_HT)
+			rate = sband->bitrates; /* TODO: HT rates */
+		else
+			rate = &sband->bitrates[status.rate_idx];
 		__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
 		__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
 					     &status, rate);
 					     &status, rate);
 		tid_agg_rx->stored_mpdu_num--;
 		tid_agg_rx->stored_mpdu_num--;
@@ -2189,15 +2215,26 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	}
 	}
 
 
 	sband = local->hw.wiphy->bands[status->band];
 	sband = local->hw.wiphy->bands[status->band];
-
-	if (!sband ||
-	    status->rate_idx < 0 ||
-	    status->rate_idx >= sband->n_bitrates) {
+	if (!sband) {
 		WARN_ON(1);
 		WARN_ON(1);
 		return;
 		return;
 	}
 	}
 
 
-	rate = &sband->bitrates[status->rate_idx];
+	if (status->flag & RX_FLAG_HT) {
+		/* rate_idx is MCS index */
+		if (WARN_ON(status->rate_idx < 0 ||
+			    status->rate_idx >= 76))
+			return;
+		/* HT rates are not in the table - use the highest legacy rate
+		 * for now since other parts of mac80211 may not yet be fully
+		 * MCS aware. */
+		rate = &sband->bitrates[sband->n_bitrates - 1];
+	} else {
+		if (WARN_ON(status->rate_idx < 0 ||
+			    status->rate_idx >= sband->n_bitrates))
+			return;
+		rate = &sband->bitrates[status->rate_idx];
+	}
 
 
 	/*
 	/*
 	 * key references and virtual interfaces are protected using RCU
 	 * key references and virtual interfaces are protected using RCU

+ 13 - 0
net/mac80211/tx.c

@@ -1473,6 +1473,19 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		goto fail;
 		goto fail;
 	}
 	}
 
 
+	if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
+	    local->dynamic_ps_timeout > 0) {
+		if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+			ieee80211_stop_queues_by_reason(&local->hw,
+							IEEE80211_QUEUE_STOP_REASON_PS);
+			queue_work(local->hw.workqueue,
+				   &local->dynamic_ps_disable_work);
+		}
+
+		mod_timer(&local->dynamic_ps_timer, jiffies +
+			  msecs_to_jiffies(local->dynamic_ps_timeout));
+	}
+
 	nh_pos = skb_network_header(skb) - skb->data;
 	nh_pos = skb_network_header(skb) - skb->data;
 	h_pos = skb_transport_header(skb) - skb->data;
 	h_pos = skb_transport_header(skb) - skb->data;
 
 

+ 81 - 7
net/mac80211/util.c

@@ -330,10 +330,20 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
 }
 }
 EXPORT_SYMBOL(ieee80211_ctstoself_duration);
 EXPORT_SYMBOL(ieee80211_ctstoself_duration);
 
 
-void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
+				   enum queue_stop_reason reason)
 {
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_local *local = hw_to_local(hw);
 
 
+	/* we don't need to track ampdu queues */
+	if (queue < ieee80211_num_regular_queues(hw)) {
+		__clear_bit(reason, &local->queue_stop_reasons[queue]);
+
+		if (local->queue_stop_reasons[queue] != 0)
+			/* someone still has this queue stopped */
+			return;
+	}
+
 	if (test_bit(queue, local->queues_pending)) {
 	if (test_bit(queue, local->queues_pending)) {
 		set_bit(queue, local->queues_pending_run);
 		set_bit(queue, local->queues_pending_run);
 		tasklet_schedule(&local->tx_pending_tasklet);
 		tasklet_schedule(&local->tx_pending_tasklet);
@@ -341,22 +351,74 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
 		netif_wake_subqueue(local->mdev, queue);
 		netif_wake_subqueue(local->mdev, queue);
 	}
 	}
 }
 }
+
+void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
+				    enum queue_stop_reason reason)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+	__ieee80211_wake_queue(hw, queue, reason);
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+{
+	ieee80211_wake_queue_by_reason(hw, queue,
+				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
+}
 EXPORT_SYMBOL(ieee80211_wake_queue);
 EXPORT_SYMBOL(ieee80211_wake_queue);
 
 
-void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
+				   enum queue_stop_reason reason)
 {
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_local *local = hw_to_local(hw);
 
 
+	/* we don't need to track ampdu queues */
+	if (queue < ieee80211_num_regular_queues(hw))
+		__set_bit(reason, &local->queue_stop_reasons[queue]);
+
 	netif_stop_subqueue(local->mdev, queue);
 	netif_stop_subqueue(local->mdev, queue);
 }
 }
+
+void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
+				    enum queue_stop_reason reason)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+	__ieee80211_stop_queue(hw, queue, reason);
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+{
+	ieee80211_stop_queue_by_reason(hw, queue,
+				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
+}
 EXPORT_SYMBOL(ieee80211_stop_queue);
 EXPORT_SYMBOL(ieee80211_stop_queue);
 
 
-void ieee80211_stop_queues(struct ieee80211_hw *hw)
+void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
+				    enum queue_stop_reason reason)
 {
 {
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
 	int i;
 	int i;
 
 
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+
 	for (i = 0; i < ieee80211_num_queues(hw); i++)
 	for (i = 0; i < ieee80211_num_queues(hw); i++)
-		ieee80211_stop_queue(hw, i);
+		__ieee80211_stop_queue(hw, i, reason);
+
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+	ieee80211_stop_queues_by_reason(hw,
+					IEEE80211_QUEUE_STOP_REASON_DRIVER);
 }
 }
 EXPORT_SYMBOL(ieee80211_stop_queues);
 EXPORT_SYMBOL(ieee80211_stop_queues);
 
 
@@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
 }
 }
 EXPORT_SYMBOL(ieee80211_queue_stopped);
 EXPORT_SYMBOL(ieee80211_queue_stopped);
 
 
-void ieee80211_wake_queues(struct ieee80211_hw *hw)
+void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+				     enum queue_stop_reason reason)
 {
 {
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
 	int i;
 	int i;
 
 
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+
 	for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
 	for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
-		ieee80211_wake_queue(hw, i);
+		__ieee80211_wake_queue(hw, i, reason);
+
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+	ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
 }
 }
 EXPORT_SYMBOL(ieee80211_wake_queues);
 EXPORT_SYMBOL(ieee80211_wake_queues);
 
 
@@ -641,7 +715,7 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
 		    chan->flags & IEEE80211_CHAN_NO_IBSS)
 		    chan->flags & IEEE80211_CHAN_NO_IBSS)
 			return ret;
 			return ret;
 		local->oper_channel = chan;
 		local->oper_channel = chan;
-		local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
+		local->oper_channel_type = NL80211_CHAN_NO_HT;
 
 
 		if (local->sw_scanning || local->hw_scanning)
 		if (local->sw_scanning || local->hw_scanning)
 			ret = 0;
 			ret = 0;

+ 38 - 8
net/mac80211/wext.c

@@ -830,25 +830,56 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
 				    struct iw_param *wrq,
 				    struct iw_param *wrq,
 				    char *extra)
 				    char *extra)
 {
 {
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_conf *conf = &local->hw.conf;
 	struct ieee80211_conf *conf = &local->hw.conf;
+	int ret = 0, timeout = 0;
+	bool ps;
+
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
+		return -EINVAL;
 
 
 	if (wrq->disabled) {
 	if (wrq->disabled) {
-		conf->flags &= ~IEEE80211_CONF_PS;
-		return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+		ps = false;
+		timeout = 0;
+		goto set;
 	}
 	}
 
 
 	switch (wrq->flags & IW_POWER_MODE) {
 	switch (wrq->flags & IW_POWER_MODE) {
 	case IW_POWER_ON:       /* If not specified */
 	case IW_POWER_ON:       /* If not specified */
 	case IW_POWER_MODE:     /* If set all mask */
 	case IW_POWER_MODE:     /* If set all mask */
 	case IW_POWER_ALL_R:    /* If explicitely state all */
 	case IW_POWER_ALL_R:    /* If explicitely state all */
-		conf->flags |= IEEE80211_CONF_PS;
+		ps = true;
+		break;
+	default:                /* Otherwise we ignore */
 		break;
 		break;
-	default:                /* Otherwise we don't support it */
-		return -EINVAL;
 	}
 	}
 
 
-	return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+	if (wrq->flags & IW_POWER_TIMEOUT)
+		timeout = wrq->value / 1000;
+
+set:
+	if (ps == local->powersave && timeout == local->dynamic_ps_timeout)
+		return ret;
+
+	local->powersave = ps;
+	local->dynamic_ps_timeout = timeout;
+
+	if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+		if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
+		    local->dynamic_ps_timeout > 0)
+			mod_timer(&local->dynamic_ps_timer, jiffies +
+				  msecs_to_jiffies(local->dynamic_ps_timeout));
+		else {
+			if (local->powersave)
+				conf->flags |= IEEE80211_CONF_PS;
+			else
+				conf->flags &= ~IEEE80211_CONF_PS;
+		}
+		ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+	}
+
+	return ret;
 }
 }
 
 
 static int ieee80211_ioctl_giwpower(struct net_device *dev,
 static int ieee80211_ioctl_giwpower(struct net_device *dev,
@@ -857,9 +888,8 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev,
 				    char *extra)
 				    char *extra)
 {
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_conf *conf = &local->hw.conf;
 
 
-	wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS);
+	wrqu->power.disabled = !local->powersave;
 
 
 	return 0;
 	return 0;
 }
 }

+ 70 - 15
net/wireless/nl80211.c

@@ -60,7 +60,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
 				      .len = BUS_ID_SIZE-1 },
 				      .len = BUS_ID_SIZE-1 },
 	[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
 	[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
 	[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
 	[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
-	[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 },
+	[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
 
 
 	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -362,8 +362,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 	}
 	}
 
 
 	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
 	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-		enum nl80211_sec_chan_offset sec_chan_offset =
-			NL80211_SEC_CHAN_NO_HT;
+		enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 		struct ieee80211_channel *chan;
 		struct ieee80211_channel *chan;
 		struct ieee80211_sta_ht_cap *ht_cap;
 		struct ieee80211_sta_ht_cap *ht_cap;
 		u32 freq, sec_freq;
 		u32 freq, sec_freq;
@@ -375,13 +374,13 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
 
 		result = -EINVAL;
 		result = -EINVAL;
 
 
-		if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
-			sec_chan_offset = nla_get_u32(info->attrs[
-					NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
-			if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT &&
-			    sec_chan_offset != NL80211_SEC_CHAN_DISABLED &&
-			    sec_chan_offset != NL80211_SEC_CHAN_BELOW &&
-			    sec_chan_offset != NL80211_SEC_CHAN_ABOVE)
+		if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+			channel_type = nla_get_u32(info->attrs[
+					   NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+			if (channel_type != NL80211_CHAN_NO_HT &&
+			    channel_type != NL80211_CHAN_HT20 &&
+			    channel_type != NL80211_CHAN_HT40PLUS &&
+			    channel_type != NL80211_CHAN_HT40MINUS)
 				goto bad_res;
 				goto bad_res;
 		}
 		}
 
 
@@ -392,9 +391,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 		if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
 		if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
 			goto bad_res;
 			goto bad_res;
 
 
-		if (sec_chan_offset == NL80211_SEC_CHAN_BELOW)
+		if (channel_type == NL80211_CHAN_HT40MINUS)
 			sec_freq = freq - 20;
 			sec_freq = freq - 20;
-		else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE)
+		else if (channel_type == NL80211_CHAN_HT40PLUS)
 			sec_freq = freq + 20;
 			sec_freq = freq + 20;
 		else
 		else
 			sec_freq = 0;
 			sec_freq = 0;
@@ -402,7 +401,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 		ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
 		ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
 
 
 		/* no HT capabilities */
 		/* no HT capabilities */
-		if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT &&
+		if (channel_type != NL80211_CHAN_NO_HT &&
 		    !ht_cap->ht_supported)
 		    !ht_cap->ht_supported)
 			goto bad_res;
 			goto bad_res;
 
 
@@ -422,7 +421,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 		}
 		}
 
 
 		result = rdev->ops->set_channel(&rdev->wiphy, chan,
 		result = rdev->ops->set_channel(&rdev->wiphy, chan,
-						sec_chan_offset);
+						channel_type);
 		if (result)
 		if (result)
 			goto bad_res;
 			goto bad_res;
 	}
 	}
@@ -1091,12 +1090,46 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
 	return 0;
 	return 0;
 }
 }
 
 
+static u16 nl80211_calculate_bitrate(struct rate_info *rate)
+{
+	int modulation, streams, bitrate;
+
+	if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+		return rate->legacy;
+
+	/* the formula below does only work for MCS values smaller than 32 */
+	if (rate->mcs >= 32)
+		return 0;
+
+	modulation = rate->mcs & 7;
+	streams = (rate->mcs >> 3) + 1;
+
+	bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
+			13500000 : 6500000;
+
+	if (modulation < 4)
+		bitrate *= (modulation + 1);
+	else if (modulation == 4)
+		bitrate *= (modulation + 2);
+	else
+		bitrate *= (modulation + 3);
+
+	bitrate *= streams;
+
+	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+		bitrate = (bitrate / 9) * 10;
+
+	/* do NOT round down here */
+	return (bitrate + 50000) / 100000;
+}
+
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 				int flags, struct net_device *dev,
 				int flags, struct net_device *dev,
 				u8 *mac_addr, struct station_info *sinfo)
 				u8 *mac_addr, struct station_info *sinfo)
 {
 {
 	void *hdr;
 	void *hdr;
-	struct nlattr *sinfoattr;
+	struct nlattr *sinfoattr, *txrate;
+	u16 bitrate;
 
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
 	if (!hdr)
 	if (!hdr)
@@ -1126,7 +1159,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 	if (sinfo->filled & STATION_INFO_PLINK_STATE)
 	if (sinfo->filled & STATION_INFO_PLINK_STATE)
 		NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
 		NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
 			    sinfo->plink_state);
 			    sinfo->plink_state);
+	if (sinfo->filled & STATION_INFO_SIGNAL)
+		NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL,
+			   sinfo->signal);
+	if (sinfo->filled & STATION_INFO_TX_BITRATE) {
+		txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE);
+		if (!txrate)
+			goto nla_put_failure;
+
+		/* nl80211_calculate_bitrate will return 0 for mcs >= 32 */
+		bitrate = nl80211_calculate_bitrate(&sinfo->txrate);
+		if (bitrate > 0)
+			NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
 
 
+		if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)
+			NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS,
+				    sinfo->txrate.mcs);
+		if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
+			NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
+		if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
+			NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
+
+		nla_nest_end(msg, txrate);
+	}
 	nla_nest_end(msg, sinfoattr);
 	nla_nest_end(msg, sinfoattr);
 
 
 	return genlmsg_end(msg, hdr);
 	return genlmsg_end(msg, hdr);