Browse Source

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

David S. Miller 16 years ago
parent
commit
2377989754
100 changed files with 7717 additions and 4562 deletions
  1. 9 8
      drivers/net/ps3_gelic_wireless.c
  2. 2 2
      drivers/net/ps3_gelic_wireless.h
  3. 1 8
      drivers/net/wireless/Makefile
  4. 0 23
      drivers/net/wireless/adm8211.c
  5. 0 2
      drivers/net/wireless/adm8211.h
  6. 24 26
      drivers/net/wireless/airo.c
  7. 2 1
      drivers/net/wireless/ath5k/ath5k.h
  8. 9 3
      drivers/net/wireless/ath5k/base.c
  9. 158 26
      drivers/net/wireless/ath5k/pcu.c
  10. 9 3
      drivers/net/wireless/ath5k/reg.h
  11. 4 0
      drivers/net/wireless/ath9k/Makefile
  12. 854 0
      drivers/net/wireless/ath9k/ani.c
  13. 216 160
      drivers/net/wireless/ath9k/ath9k.h
  14. 28 14
      drivers/net/wireless/ath9k/beacon.c
  15. 930 0
      drivers/net/wireless/ath9k/calib.c
  16. 126 357
      drivers/net/wireless/ath9k/core.c
  17. 24 133
      drivers/net/wireless/ath9k/core.h
  18. 1605 0
      drivers/net/wireless/ath9k/eeprom.c
  19. 311 1029
      drivers/net/wireless/ath9k/hw.c
  20. 1 1
      drivers/net/wireless/ath9k/hw.h
  21. 1031 0
      drivers/net/wireless/ath9k/mac.c
  22. 135 302
      drivers/net/wireless/ath9k/main.c
  23. 5 5
      drivers/net/wireless/ath9k/phy.c
  24. 13 77
      drivers/net/wireless/ath9k/rc.c
  25. 0 536
      drivers/net/wireless/ath9k/recv.c
  26. 298 389
      drivers/net/wireless/ath9k/xmit.c
  27. 35 35
      drivers/net/wireless/atmel.c
  28. 0 1
      drivers/net/wireless/b43/b43.h
  29. 99 33
      drivers/net/wireless/b43/main.c
  30. 1 1
      drivers/net/wireless/b43legacy/dma.c
  31. 0 24
      drivers/net/wireless/b43legacy/main.c
  32. 0 2
      drivers/net/wireless/iwlwifi/iwl-3945.h
  33. 2 2
      drivers/net/wireless/iwlwifi/iwl-4965.c
  34. 6 6
      drivers/net/wireless/iwlwifi/iwl-5000.c
  35. 2 4
      drivers/net/wireless/iwlwifi/iwl-agn-rs.c
  36. 4 4
      drivers/net/wireless/iwlwifi/iwl-agn-rs.h
  37. 129 126
      drivers/net/wireless/iwlwifi/iwl-agn.c
  38. 3 3
      drivers/net/wireless/iwlwifi/iwl-commands.h
  39. 2 4
      drivers/net/wireless/iwlwifi/iwl-dev.h
  40. 29 23
      drivers/net/wireless/iwlwifi/iwl-fh.h
  41. 0 7
      drivers/net/wireless/iwlwifi/iwl-scan.c
  42. 1 1
      drivers/net/wireless/iwlwifi/iwl-sta.c
  43. 2 2
      drivers/net/wireless/iwlwifi/iwl-tx.c
  44. 11 54
      drivers/net/wireless/iwlwifi/iwl3945-base.c
  45. 10 8
      drivers/net/wireless/libertas/assoc.c
  46. 2 3
      drivers/net/wireless/libertas/cmd.c
  47. 6 1
      drivers/net/wireless/libertas/dev.h
  48. 19 20
      drivers/net/wireless/libertas/main.c
  49. 1 1
      drivers/net/wireless/libertas/persistcfg.c
  50. 39 38
      drivers/net/wireless/libertas/scan.c
  51. 4 0
      drivers/net/wireless/libertas/scan.h
  52. 2 3
      drivers/net/wireless/libertas/types.h
  53. 0 1
      drivers/net/wireless/libertas/wext.c
  54. 1 1
      drivers/net/wireless/libertas_tf/if_usb.c
  55. 234 0
      drivers/net/wireless/mac80211_hwsim.c
  56. 12 0
      drivers/net/wireless/orinoco/Makefile
  57. 0 0
      drivers/net/wireless/orinoco/airport.c
  58. 0 0
      drivers/net/wireless/orinoco/hermes.c
  59. 0 0
      drivers/net/wireless/orinoco/hermes.h
  60. 0 0
      drivers/net/wireless/orinoco/hermes_dld.c
  61. 0 0
      drivers/net/wireless/orinoco/hermes_dld.h
  62. 0 0
      drivers/net/wireless/orinoco/hermes_rid.h
  63. 16 14
      drivers/net/wireless/orinoco/orinoco.c
  64. 0 0
      drivers/net/wireless/orinoco/orinoco.h
  65. 0 0
      drivers/net/wireless/orinoco/orinoco_cs.c
  66. 0 0
      drivers/net/wireless/orinoco/orinoco_nortel.c
  67. 0 0
      drivers/net/wireless/orinoco/orinoco_pci.c
  68. 0 0
      drivers/net/wireless/orinoco/orinoco_pci.h
  69. 0 0
      drivers/net/wireless/orinoco/orinoco_plx.c
  70. 0 0
      drivers/net/wireless/orinoco/orinoco_tmd.c
  71. 0 0
      drivers/net/wireless/orinoco/spectrum_cs.c
  72. 1 0
      drivers/net/wireless/p54/p54.h
  73. 396 56
      drivers/net/wireless/p54/p54common.c
  74. 30 1
      drivers/net/wireless/p54/p54common.h
  75. 6 3
      drivers/net/wireless/p54/p54pci.c
  76. 16 7
      drivers/net/wireless/p54/p54usb.c
  77. 12 12
      drivers/net/wireless/rndis_wlan.c
  78. 87 103
      drivers/net/wireless/rt2x00/rt2400pci.c
  79. 2 0
      drivers/net/wireless/rt2x00/rt2400pci.h
  80. 107 122
      drivers/net/wireless/rt2x00/rt2500pci.c
  81. 2 0
      drivers/net/wireless/rt2x00/rt2500pci.h
  82. 67 68
      drivers/net/wireless/rt2x00/rt2500usb.c
  83. 2 0
      drivers/net/wireless/rt2x00/rt2500usb.h
  84. 13 31
      drivers/net/wireless/rt2x00/rt2x00.h
  85. 24 140
      drivers/net/wireless/rt2x00/rt2x00config.c
  86. 16 6
      drivers/net/wireless/rt2x00/rt2x00debug.c
  87. 13 0
      drivers/net/wireless/rt2x00/rt2x00debug.h
  88. 11 5
      drivers/net/wireless/rt2x00/rt2x00dev.c
  89. 2 1
      drivers/net/wireless/rt2x00/rt2x00lib.h
  90. 1 11
      drivers/net/wireless/rt2x00/rt2x00mac.c
  91. 4 4
      drivers/net/wireless/rt2x00/rt2x00pci.h
  92. 119 135
      drivers/net/wireless/rt2x00/rt61pci.c
  93. 2 0
      drivers/net/wireless/rt2x00/rt61pci.h
  94. 112 127
      drivers/net/wireless/rt2x00/rt73usb.c
  95. 2 0
      drivers/net/wireless/rt2x00/rt73usb.h
  96. 1 4
      drivers/net/wireless/rtl8187_dev.c
  97. 188 195
      drivers/net/wireless/rtl8187_rtl8225.c
  98. 2 2
      drivers/net/wireless/wl3501.h
  99. 2 2
      drivers/net/wireless/zd1201.c
  100. 10 0
      include/linux/ieee80211.h

+ 9 - 8
drivers/net/ps3_gelic_wireless.c

@@ -30,10 +30,11 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include <linux/dma-mapping.h>
 #include <net/checksum.h>
@@ -449,9 +450,9 @@ static size_t gelic_wl_synthesize_ie(u8 *buf,
 
 	/* element id */
 	if (rsn)
-		*buf++ = MFIE_TYPE_RSN;
+		*buf++ = WLAN_EID_RSN;
 	else
-		*buf++ = MFIE_TYPE_GENERIC;
+		*buf++ = WLAN_EID_GENERIC;
 
 	/* length filed; set later */
 	buf++;
@@ -539,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
 			break;
 
 		switch (item_id) {
-		case MFIE_TYPE_GENERIC:
+		case WLAN_EID_GENERIC:
 			if ((OUI_LEN + 1 <= item_len) &&
 			    !memcmp(pos, wpa_oui, OUI_LEN) &&
 			    pos[OUI_LEN] == 0x01) {
@@ -547,7 +548,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
 				ie_info->wpa.len = item_len + 2;
 			}
 			break;
-		case MFIE_TYPE_RSN:
+		case WLAN_EID_RSN:
 			ie_info->rsn.data = pos - 2;
 			/* length includes the header */
 			ie_info->rsn.len = item_len + 2;
@@ -581,7 +582,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
 	char *tmp;
 	u8 rate;
 	unsigned int i, j, len;
-	u8 buf[MAX_WPA_IE_LEN];
+	u8 buf[64]; /* arbitrary size large enough */
 
 	pr_debug("%s: <-\n", __func__);
 
@@ -1734,14 +1735,14 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
 		target->essid_len = strnlen(scan_info->essid,
 					    sizeof(scan_info->essid));
 		target->rate_len = 0;
-		for (r = 0; r < MAX_RATES_LENGTH; r++)
+		for (r = 0; r < 12; r++)
 			if (scan_info->rate[r])
 				target->rate_len++;
 		if (8 < target->rate_len)
 			pr_info("%s: AP returns %d rates\n", __func__,
 				target->rate_len);
 		target->rate_ext_len = 0;
-		for (r = 0; r < MAX_RATES_EX_LENGTH; r++)
+		for (r = 0; r < 16; r++)
 			if (scan_info->ext_rate[r])
 				target->rate_ext_len++;
 		list_move_tail(&target->list, &wl->network_list);

+ 2 - 2
drivers/net/ps3_gelic_wireless.h

@@ -164,8 +164,8 @@ struct gelic_eurus_scan_info {
 	__be16 security;
 	u8  bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */
 	u8  essid[32]; /* IW_ESSID_MAX_SIZE */
-	u8  rate[16]; /* first MAX_RATES_LENGTH(12) are valid */
-	u8  ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */
+	u8  rate[16]; /* first 12 are valid */
+	u8  ext_rate[16]; /* first 16 are valid */
 	__be32 reserved1;
 	__be32 reserved2;
 	__be32 reserved3;

+ 1 - 8
drivers/net/wireless/Makefile

@@ -16,14 +16,7 @@ obj-$(CONFIG_WAVELAN)		+= wavelan.o
 obj-$(CONFIG_PCMCIA_NETWAVE)	+= netwave_cs.o
 obj-$(CONFIG_PCMCIA_WAVELAN)	+= wavelan_cs.o
 
-obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o hermes_dld.o
-obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
-obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
-obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
-obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
-obj-$(CONFIG_TMD_HERMES)	+= orinoco_tmd.o
-obj-$(CONFIG_NORTEL_HERMES)	+= orinoco_nortel.o
-obj-$(CONFIG_PCMCIA_SPECTRUM)	+= spectrum_cs.o
+obj-$(CONFIG_HERMES)		+= orinoco/
 
 obj-$(CONFIG_AIRO)		+= airo.o
 obj-$(CONFIG_AIRO_CS)		+= airo_cs.o airo.o

+ 0 - 23
drivers/net/wireless/adm8211.c

@@ -1297,22 +1297,6 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
 	ADM8211_CSR_WRITE(ABDA1, reg);
 }
 
-static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
-{
-	struct adm8211_priv *priv = dev->priv;
-	u8 buf[36];
-
-	if (ssid_len > 32)
-		return -EINVAL;
-
-	memset(buf, 0, sizeof(buf));
-	buf[0] = ssid_len;
-	memcpy(buf + 1, ssid, ssid_len);
-	adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
-	/* TODO: configure beacon for adhoc? */
-	return 0;
-}
-
 static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
 {
 	struct adm8211_priv *priv = dev->priv;
@@ -1338,13 +1322,6 @@ static int adm8211_config_interface(struct ieee80211_hw *dev,
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 	}
 
-	if (conf->ssid_len != priv->ssid_len ||
-	    memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
-		adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
-		priv->ssid_len = conf->ssid_len;
-		memcpy(priv->ssid, conf->ssid, conf->ssid_len);
-	}
-
 	return 0;
 }
 

+ 0 - 2
drivers/net/wireless/adm8211.h

@@ -553,8 +553,6 @@ struct adm8211_priv {
 
 	int channel;
 	u8 bssid[ETH_ALEN];
-	u8 ssid[32];
-	size_t ssid_len;
 
 	u8 soft_rx_crc;
 	u8 retry_limit;

+ 24 - 26
drivers/net/wireless/airo.c

@@ -47,10 +47,11 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <asm/uaccess.h>
-#include <net/ieee80211.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
+#include <linux/ieee80211.h>
+
 #include "airo.h"
 
 #define DRV_NAME "airo"
@@ -7265,56 +7266,53 @@ static inline char *airo_translate_scan(struct net_device *dev,
 	if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
 		unsigned int num_null_ies = 0;
 		u16 length = sizeof (bss->extra.iep);
-		struct ieee80211_info_element *info_element =
-			(struct ieee80211_info_element *) &bss->extra.iep;
+		u8 *ie = (void *)&bss->extra.iep;
 
-		while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
-			if (sizeof(*info_element) + info_element->len > length) {
+		while ((length >= 2) && (num_null_ies < 2)) {
+			if (2 + ie[1] > length) {
 				/* Invalid element, don't continue parsing IE */
 				break;
 			}
 
-			switch (info_element->id) {
-			case MFIE_TYPE_SSID:
+			switch (ie[0]) {
+			case WLAN_EID_SSID:
 				/* Two zero-length SSID elements
 				 * mean we're done parsing elements */
-				if (!info_element->len)
+				if (!ie[1])
 					num_null_ies++;
 				break;
 
-			case MFIE_TYPE_GENERIC:
-				if (info_element->len >= 4 &&
-				    info_element->data[0] == 0x00 &&
-				    info_element->data[1] == 0x50 &&
-				    info_element->data[2] == 0xf2 &&
-				    info_element->data[3] == 0x01) {
+			case WLAN_EID_GENERIC:
+				if (ie[1] >= 4 &&
+				    ie[2] == 0x00 &&
+				    ie[3] == 0x50 &&
+				    ie[4] == 0xf2 &&
+				    ie[5] == 0x01) {
 					iwe.cmd = IWEVGENIE;
-					iwe.u.data.length = min(info_element->len + 2,
-								  MAX_WPA_IE_LEN);
+					/* 64 is an arbitrary cut-off */
+					iwe.u.data.length = min(ie[1] + 2,
+								64);
 					current_ev = iwe_stream_add_point(
 							info, current_ev,
-							end_buf, &iwe,
-							(char *) info_element);
+							end_buf, &iwe, ie);
 				}
 				break;
 
-			case MFIE_TYPE_RSN:
+			case WLAN_EID_RSN:
 				iwe.cmd = IWEVGENIE;
-				iwe.u.data.length = min(info_element->len + 2,
-							  MAX_WPA_IE_LEN);
+				/* 64 is an arbitrary cut-off */
+				iwe.u.data.length = min(ie[1] + 2, 64);
 				current_ev = iwe_stream_add_point(
 					info, current_ev, end_buf,
-					&iwe, (char *) info_element);
+					&iwe, ie);
 				break;
 
 			default:
 				break;
 			}
 
-			length -= sizeof(*info_element) + info_element->len;
-			info_element =
-			    (struct ieee80211_info_element *)&info_element->
-			    data[info_element->len];
+			length -= 2 + ie[1];
+			ie += 2 + ie[1];
 		}
 	}
 	return current_ev;

+ 2 - 1
drivers/net/wireless/ath5k/ath5k.h

@@ -1093,10 +1093,11 @@ struct ath5k_hw {
 
 	u8			ah_sta_id[ETH_ALEN];
 
-	/* Current BSSID we are trying to assoc to / creating.
+	/* Current BSSID we are trying to assoc to / create.
 	 * This is passed by mac80211 on config_interface() and cached here for
 	 * use in resets */
 	u8			ah_bssid[ETH_ALEN];
+	u8			ah_bssid_mask[ETH_ALEN];
 
 	u32			ah_gpio[AR5K_MAX_GPIO];
 	int			ah_gpio_npins;

+ 9 - 3
drivers/net/wireless/ath5k/base.c

@@ -60,6 +60,9 @@
 #include "debug.h"
 
 static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
 
 /******************\
@@ -2975,12 +2978,13 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	struct ath5k_softc *sc = hw->priv;
 	int ret = 0;
 
+	if (modparam_nohwcrypt)
+		return -EOPNOTSUPP;
+
 	switch (key->alg) {
 	case ALG_WEP:
-	/* XXX: fix hardware encryption, its not working. For now
-	 * allow software encryption */
-		/* break; */
 	case ALG_TKIP:
+		break;
 	case ALG_CCMP:
 		return -EOPNOTSUPP;
 	default:
@@ -2999,6 +3003,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		}
 		__set_bit(key->keyidx, sc->keymap);
 		key->hw_key_idx = key->keyidx;
+		key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV |
+			       IEEE80211_KEY_FLAG_GENERATE_MMIC);
 		break;
 	case DISABLE_KEY:
 		ath5k_hw_reset_key(sc->ah, key->keyidx);

+ 158 - 26
drivers/net/wireless/ath5k/pcu.c

@@ -46,34 +46,45 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
 {
 	u32 pcu_reg, beacon_reg, low_id, high_id;
 
-	pcu_reg = 0;
+
+	/* Preserve rest settings */
+	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
+			| AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
+			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+
 	beacon_reg = 0;
 
 	ATH5K_TRACE(ah->ah_sc);
 
 	switch (ah->ah_op_mode) {
 	case NL80211_IFTYPE_ADHOC:
-		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_NO_PSPOLL : 0);
+		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
 		beacon_reg |= AR5K_BCR_ADHOC;
+		if (ah->ah_version == AR5K_AR5210)
+			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+		else
+			AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
 		break;
 
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_MESH_POINT:
-		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_NO_PSPOLL : 0);
+		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
 		beacon_reg |= AR5K_BCR_AP;
+		if (ah->ah_version == AR5K_AR5210)
+			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+		else
+			AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
 		break;
 
 	case NL80211_IFTYPE_STATION:
-		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
+		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
 				AR5K_STA_ID1_PWR_SV : 0);
 	case NL80211_IFTYPE_MONITOR:
-		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
+		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
 				AR5K_STA_ID1_NO_PSPOLL : 0);
 		break;
 
@@ -130,6 +141,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
 		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
 		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
 	}
+
+	/* TODO: Handle ANI stats */
 }
 
 /**
@@ -254,6 +267,10 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
  * @mac: The card's mac address
  *
  * Set station id on hw using the provided mac address
+ *
+ * NOTE: This is only called during attach, don't call it
+ * on reset because it overwrites all AR5K_STA_ID1 settings.
+ * We have set_opmode (above) for reset.
  */
 int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
 {
@@ -290,8 +307,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
 	 * Set simple BSSID mask on 5212
 	 */
 	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
+		ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM1);
 	}
 
 	/*
@@ -415,6 +434,9 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
 	u32 low_id, high_id;
 	ATH5K_TRACE(ah->ah_sc);
 
+	/* Cache bssid mask so that we can restore it
+	 * on reset */
+	memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
 	if (ah->ah_version == AR5K_AR5212) {
 		low_id = AR5K_LOW_ID(mask);
 		high_id = AR5K_HIGH_ID(mask);
@@ -576,7 +598,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
 		filter |= AR5K_RX_FILTER_PROM;
 	}
 
-	/*Zero length DMA*/
+	/*Zero length DMA (phy error reporting) */
 	if (data)
 		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
 	else
@@ -661,7 +683,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
 	 * Set the additional timers by mode
 	 */
 	switch (ah->ah_op_mode) {
+	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_STATION:
+		/* In STA mode timer1 is used as next wakeup
+		 * timer and timer2 as next CFP duration start
+		 * timer. Both in 1/8TUs. */
+		/* TODO: PCF handling */
 		if (ah->ah_version == AR5K_AR5210) {
 			timer1 = 0xffffffff;
 			timer2 = 0xffffffff;
@@ -669,27 +696,60 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
 			timer1 = 0x0000ffff;
 			timer2 = 0x0007ffff;
 		}
+		/* Mark associated AP as PCF incapable for now */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
 		break;
-
+	case NL80211_IFTYPE_ADHOC:
+		AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
 	default:
+		/* On non-STA modes timer1 is used as next DMA
+		 * beacon alert (DBA) timer and timer2 as next
+		 * software beacon alert. Both in 1/8TUs. */
 		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
 		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
+		break;
 	}
 
+	/* Timer3 marks the end of our ATIM window
+	 * a zero length window is not allowed because
+	 * we 'll get no beacons */
 	timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
 
 	/*
 	 * Set the beacon register and enable all timers.
-	 * (next beacon, DMA beacon, software beacon, ATIM window time)
 	 */
-	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
+	/* When in AP mode zero timer0 to start TSF */
+	if (ah->ah_op_mode == NL80211_IFTYPE_AP)
+		ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
+	else
+		ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
 	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
 	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
 	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
 
+	/* Force a TSF reset if requested and enable beacons */
+	if (interval & AR5K_BEACON_RESET_TSF)
+		ath5k_hw_reset_tsf(ah);
+
 	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
-			AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
-		AR5K_BEACON);
+					AR5K_BEACON_ENABLE),
+						AR5K_BEACON);
+
+	/* Flush any pending BMISS interrupts on ISR by
+	 * performing a clear-on-write operation on PISR
+	 * register for the BMISS bit (writing a bit on
+	 * ISR togles a reset for that bit and leaves
+	 * the rest bits intact) */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
+	else
+		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
+
+	/* TODO: Set enchanced sleep registers on AR5212
+	 * based on vif->bss_conf params, until then
+	 * disable power save reporting.*/
+	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
+
 }
 
 #if 0
@@ -899,14 +959,26 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
  */
 int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
 {
-	unsigned int i;
+	unsigned int i, type;
+	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
 
 	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
 
+	type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
+
 	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
 		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
 
+	/* Reset associated MIC entry if TKIP
+	 * is enabled located at offset (entry + 64) */
+	if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+		AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
+		for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
+			ath5k_hw_reg_write(ah, 0,
+				AR5K_KEYTABLE_OFF(micentry, i));
+	}
+
 	/*
 	 * Set NULL encryption on AR5212+
 	 *
@@ -916,10 +988,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
 	 * Note2: Windows driver (ndiswrapper) sets this to
 	 *        0x00000714 instead of 0x00000007
 	 */
-	if (ah->ah_version > AR5K_AR5211)
+	if (ah->ah_version > AR5K_AR5211) {
 		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
 				AR5K_KEYTABLE_TYPE(entry));
 
+		if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+			ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(micentry));
+		}
+	}
+
 	return 0;
 }
 
@@ -943,17 +1021,29 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
 		const struct ieee80211_key_conf *key, const u8 *mac)
 {
 	unsigned int i;
+	int keylen;
 	__le32 key_v[5] = {};
+	__le32 key0 = 0, key1 = 0;
+	__le32 *rxmic, *txmic;
 	u32 keytype;
+	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
+	bool is_tkip;
 
 	ATH5K_TRACE(ah->ah_sc);
 
-	/* key->keylen comes in from mac80211 in bytes */
+	is_tkip = (key->alg == ALG_TKIP);
+
+	/*
+	 * key->keylen comes in from mac80211 in bytes.
+	 * TKIP is 128 bit + 128 bit mic
+	 */
+	keylen = (is_tkip) ? (128 / 8) : key->keylen;
 
-	if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
+	if (entry > AR5K_KEYTABLE_SIZE ||
+		(is_tkip && micentry > AR5K_KEYTABLE_SIZE))
 		return -EOPNOTSUPP;
 
-	switch (key->keylen) {
+	switch (keylen) {
 	/* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
 	case 40 / 8:
 		memcpy(&key_v[0], key->key, 5);
@@ -967,24 +1057,66 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
 		memcpy(&key_v[4], &key->key[12], 1);
 		keytype = AR5K_KEYTABLE_TYPE_104;
 		break;
-	/* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
+	/* WEP/TKIP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
 	case 128 / 8:
 		memcpy(&key_v[0], &key->key[0], 6);
 		memcpy(&key_v[2], &key->key[6], 6);
 		memcpy(&key_v[4], &key->key[12], 4);
-		keytype = AR5K_KEYTABLE_TYPE_128;
+		keytype = is_tkip ?
+			AR5K_KEYTABLE_TYPE_TKIP :
+			AR5K_KEYTABLE_TYPE_128;
 		break;
 
 	default:
 		return -EINVAL; /* shouldn't happen */
 	}
 
+	/* intentionally corrupt key until mic is installed */
+	if (is_tkip) {
+		key0 = key_v[0] = ~key_v[0];
+		key1 = key_v[1] = ~key_v[1];
+	}
+
 	for (i = 0; i < ARRAY_SIZE(key_v); i++)
 		ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
 				AR5K_KEYTABLE_OFF(entry, i));
 
 	ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
 
+	if (is_tkip) {
+		/* Install rx/tx MIC */
+		rxmic = (__le32 *) &key->key[16];
+		txmic = (__le32 *) &key->key[24];
+#if 0
+		/* MISC_MODE register & 0x04 - for mac srev >= griffin */
+		key_v[0] = rxmic[0];
+		key_v[1] = (txmic[0] >> 16) & 0xffff;
+		key_v[2] = rxmic[1];
+		key_v[3] = txmic[0] & 0xffff;
+		key_v[4] = txmic[1];
+#else
+		key_v[0] = rxmic[0];
+		key_v[1] = 0;
+		key_v[2] = rxmic[1];
+		key_v[3] = 0;
+		key_v[4] = 0;
+#endif
+		for (i = 0; i < ARRAY_SIZE(key_v); i++)
+			ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
+				AR5K_KEYTABLE_OFF(micentry, i));
+
+		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+			AR5K_KEYTABLE_TYPE(micentry));
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
+
+		/* restore first 2 words of key */
+		ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
+			AR5K_KEYTABLE_OFF(entry, 0));
+		ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
+			AR5K_KEYTABLE_OFF(entry, 1));
+	}
+
 	return ath5k_hw_set_key_lladdr(ah, entry, mac);
 }
 

+ 9 - 3
drivers/net/wireless/ath5k/reg.h

@@ -1114,14 +1114,16 @@
 #define AR5K_PCU_MAX	0x8fff
 
 /*
- * First station id register (MAC address in lower 32 bits)
+ * First station id register (Lower 32 bits of MAC address)
  */
-#define AR5K_STA_ID0	0x8000
+#define AR5K_STA_ID0		0x8000
+#define	AR5K_STA_ID0_ARRD_L32	0xffffffff
 
 /*
- * Second station id register (MAC address in upper 16 bits)
+ * Second station id register (Upper 16 bits of MAC address + PCU settings)
  */
 #define AR5K_STA_ID1			0x8004			/* Register Address */
+#define	AR5K_STA_ID1_ADDR_U16		0x0000ffff	/* Upper 16 bits of MAC addres */
 #define AR5K_STA_ID1_AP			0x00010000	/* Set AP mode */
 #define AR5K_STA_ID1_ADHOC		0x00020000	/* Set Ad-Hoc mode */
 #define AR5K_STA_ID1_PWR_SV		0x00040000	/* Power save reporting */
@@ -1811,6 +1813,10 @@
 #define AR5K_KEYTABLE_MAC1(_n)		AR5K_KEYTABLE_OFF(_n, 7)
 #define AR5K_KEYTABLE_VALID		0x00008000
 
+/* If key type is TKIP and MIC is enabled
+ * MIC key goes in offset entry + 64 */
+#define	AR5K_KEYTABLE_MIC_OFFSET	64
+
 /* WEP 40-bit	= 40-bit  entered key + 24 bit IV = 64-bit
  * WEP 104-bit	= 104-bit entered key + 24-bit IV = 128-bit
  * WEP 128-bit	= 128-bit entered key + 24 bit IV = 152-bit

+ 4 - 0
drivers/net/wireless/ath9k/Makefile

@@ -1,4 +1,8 @@
 ath9k-y +=	hw.o \
+		eeprom.o \
+		mac.o \
+		calib.o \
+		ani.o \
 		phy.o \
 		regd.o \
 		beacon.o \

+ 854 - 0
drivers/net/wireless/ath9k/ani.c

@@ -0,0 +1,854 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
+					struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+		if (ahp->ah_ani[i].c.channel == chan->channel)
+			return i;
+		if (ahp->ah_ani[i].c.channel == 0) {
+			ahp->ah_ani[i].c.channel = chan->channel;
+			ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
+			return i;
+		}
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"No more channel states left. Using channel 0\n");
+
+	return 0;
+}
+
+static bool ath9k_hw_ani_control(struct ath_hal *ah,
+				 enum ath9k_ani_cmd cmd, int param)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState = ahp->ah_curani;
+
+	switch (cmd & ahp->ah_ani_function) {
+	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"%s: level out of range (%u > %u)\n",
+				__func__, level,
+				(unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired));
+			return false;
+		}
+
+		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+			      AR_PHY_DESIRED_SZ_TOT_DES,
+			      ahp->ah_totalSizeDesired[level]);
+		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+			      AR_PHY_AGC_CTL1_COARSE_LOW,
+			      ahp->ah_coarseLow[level]);
+		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+			      AR_PHY_AGC_CTL1_COARSE_HIGH,
+			      ahp->ah_coarseHigh[level]);
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRPWR,
+			      ahp->ah_firpwr[level]);
+
+		if (level > aniState->noiseImmunityLevel)
+			ahp->ah_stats.ast_ani_niup++;
+		else if (level < aniState->noiseImmunityLevel)
+			ahp->ah_stats.ast_ani_nidown++;
+		aniState->noiseImmunityLevel = level;
+		break;
+	}
+	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+		const int m1ThreshLow[] = { 127, 50 };
+		const int m2ThreshLow[] = { 127, 40 };
+		const int m1Thresh[] = { 127, 0x4d };
+		const int m2Thresh[] = { 127, 0x40 };
+		const int m2CountThr[] = { 31, 16 };
+		const int m2CountThrLow[] = { 63, 48 };
+		u32 on = param ? 1 : 0;
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+			      m1ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+			      m2ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M1_THRESH,
+			      m1Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2_THRESH,
+			      m2Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2COUNT_THR,
+			      m2CountThr[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+			      m2CountThrLow[on]);
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+			      m1ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+			      m2ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH,
+			      m1Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH,
+			      m2Thresh[on]);
+
+		if (on)
+			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+		else
+			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+		if (!on != aniState->ofdmWeakSigDetectOff) {
+			if (on)
+				ahp->ah_stats.ast_ani_ofdmon++;
+			else
+				ahp->ah_stats.ast_ani_ofdmoff++;
+			aniState->ofdmWeakSigDetectOff = !on;
+		}
+		break;
+	}
+	case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+		const int weakSigThrCck[] = { 8, 6 };
+		u32 high = param ? 1 : 0;
+
+		REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
+			      AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
+			      weakSigThrCck[high]);
+		if (high != aniState->cckWeakSigThreshold) {
+			if (high)
+				ahp->ah_stats.ast_ani_cckhigh++;
+			else
+				ahp->ah_stats.ast_ani_ccklow++;
+			aniState->cckWeakSigThreshold = high;
+		}
+		break;
+	}
+	case ATH9K_ANI_FIRSTEP_LEVEL:{
+		const int firstep[] = { 0, 4, 8 };
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(firstep)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"%s: level out of range (%u > %u)\n",
+				__func__, level,
+				(unsigned) ARRAY_SIZE(firstep));
+			return false;
+		}
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRSTEP,
+			      firstep[level]);
+		if (level > aniState->firstepLevel)
+			ahp->ah_stats.ast_ani_stepup++;
+		else if (level < aniState->firstepLevel)
+			ahp->ah_stats.ast_ani_stepdown++;
+		aniState->firstepLevel = level;
+		break;
+	}
+	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+		const int cycpwrThr1[] =
+			{ 2, 4, 6, 8, 10, 12, 14, 16 };
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(cycpwrThr1)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"%s: level out of range (%u > %u)\n",
+				__func__, level,
+				(unsigned)
+				ARRAY_SIZE(cycpwrThr1));
+			return false;
+		}
+		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+			      AR_PHY_TIMING5_CYCPWR_THR1,
+			      cycpwrThr1[level]);
+		if (level > aniState->spurImmunityLevel)
+			ahp->ah_stats.ast_ani_spurup++;
+		else if (level < aniState->spurImmunityLevel)
+			ahp->ah_stats.ast_ani_spurdown++;
+		aniState->spurImmunityLevel = level;
+		break;
+	}
+	case ATH9K_ANI_PRESENT:
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"%s: invalid cmd %u\n", __func__, cmd);
+		return false;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__);
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+		"ofdmWeakSigDetectOff=%d\n",
+		aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
+		!aniState->ofdmWeakSigDetectOff);
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"cckWeakSigThreshold=%d, "
+		"firstepLevel=%d, listenTime=%d\n",
+		aniState->cckWeakSigThreshold, aniState->firstepLevel,
+		aniState->listenTime);
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+		aniState->cycleCount, aniState->ofdmPhyErrCount,
+		aniState->cckPhyErrCount);
+
+	return true;
+}
+
+static void ath9k_hw_update_mibstats(struct ath_hal *ah,
+				     struct ath9k_mib_stats *stats)
+{
+	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
+	stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
+	stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
+	stats->rts_good += REG_READ(ah, AR_RTS_OK);
+	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
+}
+
+static void ath9k_ani_restart(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ahp->ah_curani;
+
+	aniState->listenTime = 0;
+	if (ahp->ah_hasHwPhyCounters) {
+		if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
+			aniState->ofdmPhyErrBase = 0;
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"OFDM Trigger is too high for hw counters\n");
+		} else {
+			aniState->ofdmPhyErrBase =
+				AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
+		}
+		if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
+			aniState->cckPhyErrBase = 0;
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"CCK Trigger is too high for hw counters\n");
+		} else {
+			aniState->cckPhyErrBase =
+				AR_PHY_COUNTMAX - aniState->cckTrigHigh;
+		}
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"%s: Writing ofdmbase=%u   cckbase=%u\n",
+			__func__, aniState->ofdmPhyErrBase,
+			aniState->cckPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+	}
+	aniState->ofdmPhyErrCount = 0;
+	aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ar5416AniState *aniState;
+	enum wireless_mode mode;
+	int32_t rssi;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ahp->ah_curani;
+
+	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+					 aniState->noiseImmunityLevel + 1)) {
+			return;
+		}
+	}
+
+	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+					 aniState->spurImmunityLevel + 1)) {
+			return;
+		}
+	}
+
+	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+		}
+		return;
+	}
+	rssi = BEACON_RSSI(ahp);
+	if (rssi > aniState->rssiThrHigh) {
+		if (!aniState->ofdmWeakSigDetectOff) {
+			if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+					 false)) {
+				ath9k_hw_ani_control(ah,
+					ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+				return;
+			}
+		}
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+			return;
+		}
+	} else if (rssi > aniState->rssiThrLow) {
+		if (aniState->ofdmWeakSigDetectOff)
+			ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     true);
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+		return;
+	} else {
+		mode = ath9k_hw_chan2wmode(ah, chan);
+		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+			if (!aniState->ofdmWeakSigDetectOff)
+				ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     false);
+			if (aniState->firstepLevel > 0)
+				ath9k_hw_ani_control(ah,
+					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
+			return;
+		}
+	}
+}
+
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ar5416AniState *aniState;
+	enum wireless_mode mode;
+	int32_t rssi;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ahp->ah_curani;
+	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+					 aniState->noiseImmunityLevel + 1)) {
+			return;
+		}
+	}
+	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+		}
+		return;
+	}
+	rssi = BEACON_RSSI(ahp);
+	if (rssi > aniState->rssiThrLow) {
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+	} else {
+		mode = ath9k_hw_chan2wmode(ah, chan);
+		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+			if (aniState->firstepLevel > 0)
+				ath9k_hw_ani_control(ah,
+					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
+		}
+	}
+}
+
+static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	int32_t rssi;
+
+	aniState = ahp->ah_curani;
+
+	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+		if (aniState->firstepLevel > 0) {
+			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+						 aniState->firstepLevel - 1))
+				return;
+		}
+	} else {
+		rssi = BEACON_RSSI(ahp);
+		if (rssi > aniState->rssiThrHigh) {
+			/* XXX: Handle me */
+		} else if (rssi > aniState->rssiThrLow) {
+			if (aniState->ofdmWeakSigDetectOff) {
+				if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+					 true) == true)
+					return;
+			}
+			if (aniState->firstepLevel > 0) {
+				if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_FIRSTEP_LEVEL,
+					 aniState->firstepLevel - 1) == true)
+					return;
+			}
+		} else {
+			if (aniState->firstepLevel > 0) {
+				if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_FIRSTEP_LEVEL,
+					 aniState->firstepLevel - 1) == true)
+					return;
+			}
+		}
+	}
+
+	if (aniState->spurImmunityLevel > 0) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+					 aniState->spurImmunityLevel - 1))
+			return;
+	}
+
+	if (aniState->noiseImmunityLevel > 0) {
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+				     aniState->noiseImmunityLevel - 1);
+		return;
+	}
+}
+
+static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	u32 txFrameCount, rxFrameCount, cycleCount;
+	int32_t listenTime;
+
+	txFrameCount = REG_READ(ah, AR_TFCNT);
+	rxFrameCount = REG_READ(ah, AR_RFCNT);
+	cycleCount = REG_READ(ah, AR_CCCNT);
+
+	aniState = ahp->ah_curani;
+	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
+
+		listenTime = 0;
+		ahp->ah_stats.ast_ani_lzero++;
+	} else {
+		int32_t ccdelta = cycleCount - aniState->cycleCount;
+		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
+		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
+		listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+	}
+	aniState->cycleCount = cycleCount;
+	aniState->txFrameCount = txFrameCount;
+	aniState->rxFrameCount = rxFrameCount;
+
+	return listenTime;
+}
+
+void ath9k_ani_reset(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	struct ath9k_channel *chan = ah->ah_curchan;
+	int index;
+
+	if (!DO_ANI(ah))
+		return;
+
+	index = ath9k_hw_get_ani_channel_idx(ah, chan);
+	aniState = &ahp->ah_ani[index];
+	ahp->ah_curani = aniState;
+
+	if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA
+	    && ah->ah_opmode != ATH9K_M_IBSS) {
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"%s: Reset ANI state opmode %u\n", __func__,
+			ah->ah_opmode);
+		ahp->ah_stats.ast_ani_reset++;
+
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     !ATH9K_ANI_USE_OFDM_WEAK_SIG);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+				     ATH9K_ANI_CCK_WEAK_SIG_THR);
+
+		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+				     ATH9K_RX_FILTER_PHYERR);
+
+		if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+			ahp->ah_curani->ofdmTrigHigh =
+				ah->ah_config.ofdm_trig_high;
+			ahp->ah_curani->ofdmTrigLow =
+				ah->ah_config.ofdm_trig_low;
+			ahp->ah_curani->cckTrigHigh =
+				ah->ah_config.cck_trig_high;
+			ahp->ah_curani->cckTrigLow =
+				ah->ah_config.cck_trig_low;
+		}
+		ath9k_ani_restart(ah);
+		return;
+	}
+
+	if (aniState->noiseImmunityLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+				     aniState->noiseImmunityLevel);
+	if (aniState->spurImmunityLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+				     aniState->spurImmunityLevel);
+	if (aniState->ofdmWeakSigDetectOff)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     !aniState->ofdmWeakSigDetectOff);
+	if (aniState->cckWeakSigThreshold)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+				     aniState->cckWeakSigThreshold);
+	if (aniState->firstepLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+				     aniState->firstepLevel);
+	if (ahp->ah_hasHwPhyCounters) {
+		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
+				     ~ATH9K_RX_FILTER_PHYERR);
+		ath9k_ani_restart(ah);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+	} else {
+		ath9k_ani_restart(ah);
+		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+				     ATH9K_RX_FILTER_PHYERR);
+	}
+}
+
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+			  const struct ath9k_node_stats *stats,
+			  struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	int32_t listenTime;
+
+	aniState = ahp->ah_curani;
+	ahp->ah_stats.ast_nodestats = *stats;
+
+	listenTime = ath9k_hw_ani_get_listen_time(ah);
+	if (listenTime < 0) {
+		ahp->ah_stats.ast_ani_lneg++;
+		ath9k_ani_restart(ah);
+		return;
+	}
+
+	aniState->listenTime += listenTime;
+
+	if (ahp->ah_hasHwPhyCounters) {
+		u32 phyCnt1, phyCnt2;
+		u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+		phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+		phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+		if (phyCnt1 < aniState->ofdmPhyErrBase ||
+		    phyCnt2 < aniState->cckPhyErrBase) {
+			if (phyCnt1 < aniState->ofdmPhyErrBase) {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+					"%s: phyCnt1 0x%x, resetting "
+					"counter value to 0x%x\n",
+					__func__, phyCnt1,
+					aniState->ofdmPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_1,
+					  aniState->ofdmPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+					  AR_PHY_ERR_OFDM_TIMING);
+			}
+			if (phyCnt2 < aniState->cckPhyErrBase) {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+					"%s: phyCnt2 0x%x, resetting "
+					"counter value to 0x%x\n",
+					__func__, phyCnt2,
+					aniState->cckPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_2,
+					  aniState->cckPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+					  AR_PHY_ERR_CCK_TIMING);
+			}
+			return;
+		}
+
+		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+		ahp->ah_stats.ast_ani_ofdmerrs +=
+			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+		ahp->ah_stats.ast_ani_cckerrs +=
+			cckPhyErrCnt - aniState->cckPhyErrCount;
+		aniState->cckPhyErrCount = cckPhyErrCnt;
+	}
+
+	if (!DO_ANI(ah))
+		return;
+
+	if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
+		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
+		    aniState->ofdmTrigLow / 1000 &&
+		    aniState->cckPhyErrCount <= aniState->listenTime *
+		    aniState->cckTrigLow / 1000)
+			ath9k_hw_ani_lower_immunity(ah);
+		ath9k_ani_restart(ah);
+	} else if (aniState->listenTime > ahp->ah_aniPeriod) {
+		if (aniState->ofdmPhyErrCount > aniState->listenTime *
+		    aniState->ofdmTrigHigh / 1000) {
+			ath9k_hw_ani_ofdm_err_trigger(ah);
+			ath9k_ani_restart(ah);
+		} else if (aniState->cckPhyErrCount >
+			   aniState->listenTime * aniState->cckTrigHigh /
+			   1000) {
+			ath9k_hw_ani_cck_err_trigger(ah);
+			ath9k_ani_restart(ah);
+		}
+	}
+}
+
+bool ath9k_hw_phycounters(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ahp->ah_hasHwPhyCounters ? true : false;
+}
+
+void ath9k_enable_mib_counters(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
+
+	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+	REG_WRITE(ah, AR_FILT_OFDM, 0);
+	REG_WRITE(ah, AR_FILT_CCK, 0);
+	REG_WRITE(ah, AR_MIBC,
+		  ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
+		  & 0x0f);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+}
+
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
+
+	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
+
+	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+	REG_WRITE(ah, AR_FILT_OFDM, 0);
+	REG_WRITE(ah, AR_FILT_CCK, 0);
+}
+
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+				  u32 *rxc_pcnt,
+				  u32 *rxf_pcnt,
+				  u32 *txf_pcnt)
+{
+	static u32 cycles, rx_clear, rx_frame, tx_frame;
+	u32 good = 1;
+
+	u32 rc = REG_READ(ah, AR_RCCNT);
+	u32 rf = REG_READ(ah, AR_RFCNT);
+	u32 tf = REG_READ(ah, AR_TFCNT);
+	u32 cc = REG_READ(ah, AR_CCCNT);
+
+	if (cycles == 0 || cycles > cc) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"%s: cycle counter wrap. ExtBusy = 0\n",
+			__func__);
+		good = 0;
+	} else {
+		u32 cc_d = cc - cycles;
+		u32 rc_d = rc - rx_clear;
+		u32 rf_d = rf - rx_frame;
+		u32 tf_d = tf - tx_frame;
+
+		if (cc_d != 0) {
+			*rxc_pcnt = rc_d * 100 / cc_d;
+			*rxf_pcnt = rf_d * 100 / cc_d;
+			*txf_pcnt = tf_d * 100 / cc_d;
+		} else {
+			good = 0;
+		}
+	}
+
+	cycles = cc;
+	rx_frame = rf;
+	rx_clear = rc;
+	tx_frame = tf;
+
+	return good;
+}
+
+/*
+ * Process a MIB interrupt.  We may potentially be invoked because
+ * any of the MIB counters overflow/trigger so don't assume we're
+ * here because a PHY error counter triggered.
+ */
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+			   const struct ath9k_node_stats *stats)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 phyCnt1, phyCnt2;
+
+	/* Reset these counters regardless */
+	REG_WRITE(ah, AR_FILT_OFDM, 0);
+	REG_WRITE(ah, AR_FILT_CCK, 0);
+	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
+		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
+
+	/* Clear the mib counters and save them in the stats */
+	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+	ahp->ah_stats.ast_nodestats = *stats;
+
+	if (!DO_ANI(ah))
+		return;
+
+	/* NB: these are not reset-on-read */
+	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
+	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
+		struct ar5416AniState *aniState = ahp->ah_curani;
+		u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
+		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+		ahp->ah_stats.ast_ani_ofdmerrs +=
+			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+		ahp->ah_stats.ast_ani_cckerrs +=
+			cckPhyErrCnt - aniState->cckPhyErrCount;
+		aniState->cckPhyErrCount = cckPhyErrCnt;
+
+		/*
+		 * NB: figure out which counter triggered.  If both
+		 * trigger we'll only deal with one as the processing
+		 * clobbers the error counter so the trigger threshold
+		 * check will never be true.
+		 */
+		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
+			ath9k_hw_ani_ofdm_err_trigger(ah);
+		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
+			ath9k_hw_ani_cck_err_trigger(ah);
+		/* NB: always restart to insure the h/w counters are reset */
+		ath9k_ani_restart(ah);
+	}
+}
+
+void ath9k_hw_ani_setup(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+	const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+	const int coarseLow[] = { -64, -64, -64, -64, -70 };
+	const int firpwr[] = { -78, -78, -78, -78, -80 };
+
+	for (i = 0; i < 5; i++) {
+		ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
+		ahp->ah_coarseHigh[i] = coarseHigh[i];
+		ahp->ah_coarseLow[i] = coarseLow[i];
+		ahp->ah_firpwr[i] = firpwr[i];
+	}
+}
+
+void ath9k_hw_ani_attach(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
+
+	ahp->ah_hasHwPhyCounters = 1;
+
+	memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
+	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+		ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
+		ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
+		ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
+		ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+		ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+		ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+		ahp->ah_ani[i].ofdmWeakSigDetectOff =
+			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
+		ahp->ah_ani[i].cckWeakSigThreshold =
+			ATH9K_ANI_CCK_WEAK_SIG_THR;
+		ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+		ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+		if (ahp->ah_hasHwPhyCounters) {
+			ahp->ah_ani[i].ofdmPhyErrBase =
+				AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
+			ahp->ah_ani[i].cckPhyErrBase =
+				AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
+		}
+	}
+	if (ahp->ah_hasHwPhyCounters) {
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"Setting OfdmErrBase = 0x%08x\n",
+			ahp->ah_ani[0].ofdmPhyErrBase);
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
+			ahp->ah_ani[0].cckPhyErrBase);
+
+		REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
+		ath9k_enable_mib_counters(ah);
+	}
+	ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
+	if (ah->ah_config.enable_ani)
+		ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
+}
+
+void ath9k_hw_ani_detach(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
+
+	if (ahp->ah_hasHwPhyCounters) {
+		ath9k_hw_disable_mib_counters(ah);
+		REG_WRITE(ah, AR_PHY_ERR_1, 0);
+		REG_WRITE(ah, AR_PHY_ERR_2, 0);
+	}
+}

+ 216 - 160
drivers/net/wireless/ath9k/ath9k.h

@@ -828,195 +828,251 @@ struct chan_centers {
 	u16 ext_center;
 };
 
-int ath_hal_getcapability(struct ath_hal *ah,
-			  enum ath9k_capability_type type,
-			  u32 capability,
-			  u32 *result);
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
-						     u32 mode);
-void ath9k_hw_detach(struct ath_hal *ah);
-struct ath_hal *ath9k_hw_attach(u16 devid,
-				struct ath_softc *sc,
-				void __iomem *mem,
-				int *error);
-bool ath9k_regd_init_channels(struct ath_hal *ah,
-			      u32 maxchans, u32 *nchans,
-			      u8 *regclassids,
-			      u32 maxregids, u32 *nregids,
-			      u16 cc,
-			      bool enableOutdoor,
-			      bool enableExtendedChannels);
+/* Helpers */
+
+enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+			       const struct ath9k_channel *chan);
+bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val);
+u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+			     u16 flags, u16 *low,
+			     u16 *high);
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+			   const struct ath9k_rate_table *rates,
+			   u32 frameLen, u16 rateix,
+			   bool shortPreamble);
 u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah,
-				     enum ath9k_int ints);
-bool ath9k_hw_reset(struct ath_hal *ah,
-		    struct ath9k_channel *chan,
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  struct chan_centers *centers);
+
+/* Attach, Detach */
+
+const char *ath9k_hw_probe(u16 vendorid, u16 devid);
+void ath9k_hw_detach(struct ath_hal *ah);
+struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
+				void __iomem *mem, int *error);
+void ath9k_hw_rfdetach(struct ath_hal *ah);
+
+
+/* HW Reset */
+
+bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 		    enum ath9k_ht_macmode macmode,
 		    u8 txchainmask, u8 rxchainmask,
 		    enum ath9k_ht_extprotspacing extprotspacing,
-		    bool bChannelChange,
-		    int *status);
-bool ath9k_hw_phy_disable(struct ath_hal *ah);
-void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
-			     bool *isCalDone);
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
-			  const struct ath9k_node_stats *stats,
-			  struct ath9k_channel *chan);
-bool ath9k_hw_calibrate(struct ath_hal *ah,
-			struct ath9k_channel *chan,
-			u8 rxchainmask,
-			bool longcal,
-			bool *isCalDone);
-s16 ath9k_hw_getchan_noise(struct ath_hal *ah,
-			       struct ath9k_channel *chan);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-			    u16 assocId);
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-			    u16 assocId);
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
-void ath9k_hw_reset_tsf(struct ath_hal *ah);
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
-			const u8 *mac);
-bool ath9k_hw_set_keycache_entry(struct ath_hal *ah,
-				 u16 entry,
-				 const struct ath9k_keyval *k,
-				 const u8 *mac,
-				 int xorKey);
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah,
-			    u32 setting);
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
-bool ath9k_hw_intrpend(struct ath_hal *ah);
-bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
-bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah,
-				bool bIncTrigLevel);
-void ath9k_hw_procmibevent(struct ath_hal *ah,
-			   const struct ath9k_node_stats *stats);
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
-bool ath9k_hw_phycounters(struct ath_hal *ah);
+		    bool bChannelChange, int *status);
+
+/* Key Cache Management */
+
 bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_getcapability(struct ath_hal *ah,
-			    enum ath9k_capability_type type,
-			    u32 capability,
-			    u32 *result);
-bool ath9k_hw_setcapability(struct ath_hal *ah,
-			    enum ath9k_capability_type type,
-			    u32 capability,
-			    u32 setting,
-			    int *status);
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
-bool ath9k_hw_setbssidmask(struct ath_hal *ah,
-			   const u8 *mask);
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac);
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+				 const struct ath9k_keyval *k,
+				 const u8 *mac, int xorKey);
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
+
+/* Power Management */
+
 bool ath9k_hw_setpower(struct ath_hal *ah,
 		       enum ath9k_power_mode mode);
-enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
-u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
+
+/* Beacon timers */
+
+void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period);
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+				    const struct ath9k_beacon_state *bs);
+
+/* Rate table */
+
+const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
+						     u32 mode);
+
+/* HW Capabilities */
+
+bool ath9k_hw_fill_cap_info(struct ath_hal *ah);
+bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 *result);
+bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 setting, int *status);
+
+/* GPIO / RFKILL / Antennae */
+
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+			 u32 ah_signal_type);
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val);
+#ifdef CONFIG_RFKILL
+void ath9k_enable_rfkill(struct ath_hal *ah);
+#endif
+int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);
 u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
 bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
 			       enum ath9k_ant_setting settings,
 			       struct ath9k_channel *chan,
 			       u8 *tx_chainmask,
 			       u8 *rx_chainmask,
 			       u8 *antenna_cfgd);
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
-int ath9k_hw_select_antconfig(struct ath_hal *ah,
-			      u32 cfg);
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
-		       u32 txdp);
+
+/* General Operation */
+
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
+bool ath9k_hw_phy_disable(struct ath_hal *ah);
+bool ath9k_hw_disable(struct ath_hal *ah);
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
+void ath9k_hw_setopmode(struct ath_hal *ah);
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1);
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
+bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask);
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId);
+u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_reset_tsf(struct ath_hal *ah);
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting);
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
+
+/* Regulatory */
+
+bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
+struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah,
+			 const struct ath9k_channel *c);
+u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
+u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
+				   struct ath9k_channel *chan);
+bool ath9k_regd_init_channels(struct ath_hal *ah,
+			      u32 maxchans, u32 *nchans, u8 *regclassids,
+			      u32 maxregids, u32 *nregids, u16 cc,
+			      bool enableOutdoor, bool enableExtendedChannels);
+
+/* ANI */
+
+void ath9k_ani_reset(struct ath_hal *ah);
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+			  const struct ath9k_node_stats *stats,
+			  struct ath9k_channel *chan);
+bool ath9k_hw_phycounters(struct ath_hal *ah);
+void ath9k_enable_mib_counters(struct ath_hal *ah);
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah);
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+				  u32 *rxc_pcnt,
+				  u32 *rxf_pcnt,
+				  u32 *txf_pcnt);
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+			   const struct ath9k_node_stats *stats);
+void ath9k_hw_ani_setup(struct ath_hal *ah);
+void ath9k_hw_ani_attach(struct ath_hal *ah);
+void ath9k_hw_ani_detach(struct ath_hal *ah);
+
+/* Calibration */
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+			     bool *isCalDone);
+void ath9k_hw_start_nfcal(struct ath_hal *ah);
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan);
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+		       struct ath9k_channel *chan);
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah);
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+			u8 rxchainmask, bool longcal,
+			bool *isCalDone);
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+		       struct ath9k_channel *chan);
+
+
+/* EEPROM */
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+			 struct ath9k_channel *chan,
+			 u16 cfgCtl,
+			 u8 twiceAntennaReduction,
+			 u8 twiceMaxRegulatoryPower,
+			 u8 powerLimit);
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
+				       struct ath9k_channel *chan,
+				       int16_t *ratesArray,
+				       u16 cfgCtl,
+				       u8 AntennaReduction,
+				       u8 twiceMaxRegulatoryPower,
+				       u8 powerLimit);
+bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset);
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+				      struct ath9k_channel *chan);
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+				    struct ath9k_channel *chan,
+				    u8 index, u16 *config);
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+			       enum ieee80211_band freq_band);
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz);
+int ath9k_hw_eeprom_attach(struct ath_hal *ah);
+
+/* Interrupt Handling */
+
+bool ath9k_hw_intrpend(struct ath_hal *ah);
+bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
+enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints);
+
+/* MAC (PCU/QCU) */
+
+void ath9k_hw_dmaRegDump(struct ath_hal *ah);
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp);
 bool ath9k_hw_txstart(struct ath_hal *ah, u32 q);
-u16 ath9k_hw_computetxtime(struct ath_hal *ah,
-				 const struct ath9k_rate_table *rates,
-				 u32 frameLen, u16 rateix,
-				 bool shortPreamble);
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel);
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+			 u32 segLen, bool firstSeg,
+			 bool lastSeg, const struct ath_desc *ds0);
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+			    u32 keyIx, enum ath9k_key_type keyType, u32 flags);
 void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
 				  struct ath_desc *lastds,
 				  u32 durUpdateEn, u32 rtsctsRate,
 				  u32 rtsctsDuration,
 				  struct ath9k_11n_rate_series series[],
 				  u32 nseries, u32 flags);
-void ath9k_hw_set11n_burstduration(struct ath_hal *ah,
-				   struct ath_desc *ds,
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+				u32 aggrLen);
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+				 u32 numDelims);
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
 				   u32 burstDuration);
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
-u32 ath9k_hw_reverse_bits(u32 val, u32 n);
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
-u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
-u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
-				     struct ath9k_channel *chan);
-u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
-			    struct ath9k_tx_queue_info *qinfo);
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+				     u32 vmf);
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
 bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
 			    const struct ath9k_tx_queue_info *qinfo);
-struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah,
-					      const struct ath9k_channel *c);
-void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
-			    u32 pktLen, enum ath9k_pkt_type type,
-			    u32 txPower, u32 keyIx,
-			    enum ath9k_key_type keyType, u32 flags);
-bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
-			 u32 segLen, bool firstSeg,
-			 bool lastSeg,
-			 const struct ath_desc *ds0);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
-					u32 *rxc_pcnt,
-					u32 *rxf_pcnt,
-					u32 *txf_pcnt);
-void ath9k_hw_dmaRegDump(struct ath_hal *ah);
-void ath9k_hw_beaconinit(struct ath_hal *ah,
-			 u32 next_beacon, u32 beacon_period);
-void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
-				    const struct ath9k_beacon_state *bs);
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+			    struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+			  const struct ath9k_tx_queue_info *qinfo);
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+			u32 pa, struct ath_desc *nds, u64 tsf);
 bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
 			  u32 size, u32 flags);
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
 void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp);
 void ath9k_hw_rxena(struct ath_hal *ah);
-void ath9k_hw_setopmode(struct ath_hal *ah);
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
-void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
-			     u32 filter1);
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
 void ath9k_hw_startpcureceive(struct ath_hal *ah);
 void ath9k_hw_stoppcurecv(struct ath_hal *ah);
 bool ath9k_hw_stopdmarecv(struct ath_hal *ah);
-int ath9k_hw_rxprocdesc(struct ath_hal *ah,
-			struct ath_desc *ds, u32 pa,
-			struct ath_desc *nds, u64 tsf);
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
-int ath9k_hw_txprocdesc(struct ath_hal *ah,
-			struct ath_desc *ds);
-void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
-				 u32 numDelims);
-void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
-				u32 aggrLen);
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah,
-				     struct ath_desc *ds, u32 vmf);
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
-bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
-int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
-			  const struct ath9k_tx_queue_info *qinfo);
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
-const char *ath9k_hw_probe(u16 vendorid, u16 devid);
-bool ath9k_hw_disable(struct ath_hal *ah);
-void ath9k_hw_rfdetach(struct ath_hal *ah);
-void ath9k_hw_get_channel_centers(struct ath_hal *ah,
-				  struct ath9k_channel *chan,
-				  struct chan_centers *centers);
-bool ath9k_get_channel_edges(struct ath_hal *ah,
-			     u16 flags, u16 *low,
-			     u16 *high);
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
-			u32 ah_signal_type);
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+
 #endif

+ 28 - 14
drivers/net/wireless/ath9k/beacon.c

@@ -114,7 +114,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
 	ath9k_hw_set11n_txdesc(ah, ds,
 			       skb->len + FCS_LEN,     /* frame length */
 			       ATH9K_PKT_TYPE_BEACON,  /* Atheros packet type */
-			       avp->av_btxctl.txpower, /* txpower XXX */
+			       MAX_RATE_POWER,         /* FIXME */
 			       ATH9K_TXKEYIX_INVALID,  /* no encryption */
 			       ATH9K_KEY_TYPE_CLEAR,   /* no encryption */
 			       flags                   /* no ack,
@@ -152,12 +152,14 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 	struct ath_vap *avp;
 	struct sk_buff *skb;
 	struct ath_txq *cabq;
+	struct ieee80211_vif *vif;
 	struct ieee80211_tx_info *info;
 	int cabq_depth;
 
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp);
+	vif = sc->sc_vaps[if_id];
+	ASSERT(vif);
 
+	avp = (void *)vif->drv_priv;
 	cabq = sc->sc_cabq;
 
 	if (avp->av_bcbuf == NULL) {
@@ -174,7 +176,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 				 PCI_DMA_TODEVICE);
 	}
 
-	skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+	skb = ieee80211_beacon_get(sc->hw, vif);
 	bf->bf_mpdu = skb;
 	if (skb == NULL)
 		return NULL;
@@ -196,7 +198,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 			       skb_end_pointer(skb) - skb->head,
 			       PCI_DMA_TODEVICE);
 
-	skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+	skb = ieee80211_get_buffered_bc(sc->hw, vif);
 
 	/*
 	 * if the CABQ traffic from previous DTIM is pending and the current
@@ -232,7 +234,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 	 */
 	while (skb) {
 		ath_tx_cabq(sc, skb);
-		skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+		skb = ieee80211_get_buffered_bc(sc->hw, vif);
 	}
 
 	return bf;
@@ -244,13 +246,16 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 */
 static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
 {
+	struct ieee80211_vif *vif;
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf;
 	struct ath_vap *avp;
 	struct sk_buff *skb;
 
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp);
+	vif = sc->sc_vaps[if_id];
+	ASSERT(vif);
+
+	avp = (void *)vif->drv_priv;
 
 	if (avp->av_bcbuf == NULL) {
 		DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
@@ -300,14 +305,17 @@ int ath_beaconq_setup(struct ath_hal *ah)
 */
 int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 {
+	struct ieee80211_vif *vif;
 	struct ath_vap *avp;
 	struct ieee80211_hdr *hdr;
 	struct ath_buf *bf;
 	struct sk_buff *skb;
 	__le64 tstamp;
 
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp);
+	vif = sc->sc_vaps[if_id];
+	ASSERT(vif);
+
+	avp = (void *)vif->drv_priv;
 
 	/* Allocate a beacon descriptor if we haven't done so. */
 	if (!avp->av_bcbuf) {
@@ -363,7 +371,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 	 * FIXME: Fill avp->av_btxctl.txpower and
 	 * avp->av_btxctl.shortPreamble
 	 */
-	skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+	skb = ieee80211_beacon_get(sc->hw, vif);
 	if (skb == NULL) {
 		DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n",
 			__func__);
@@ -652,15 +660,21 @@ void ath_bstuck_process(struct ath_softc *sc)
  */
 void ath_beacon_config(struct ath_softc *sc, int if_id)
 {
+	struct ieee80211_vif *vif;
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_beacon_config conf;
+	struct ath_vap *avp;
 	enum ath9k_opmode av_opmode;
 	u32 nexttbtt, intval;
 
-	if (if_id != ATH_IF_ID_ANY)
-		av_opmode = sc->sc_vaps[if_id]->av_opmode;
-	else
+	if (if_id != ATH_IF_ID_ANY) {
+		vif = sc->sc_vaps[if_id];
+		ASSERT(vif);
+		avp = (void *)vif->drv_priv;
+		av_opmode = avp->av_opmode;
+	} else {
 		av_opmode = sc->sc_ah->ah_opmode;
+	}
 
 	memset(&conf, 0, sizeof(struct ath_beacon_config));
 

+ 930 - 0
drivers/net/wireless/ath9k/calib.c

@@ -0,0 +1,930 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
+
+/* We can tune this as we go by monitoring really low values */
+#define ATH9K_NF_TOO_LOW	-60
+
+/* AR5416 may return very high value (like -31 dBm), in those cases the nf
+ * is incorrect and we should use the static NF value. Later we can try to
+ * find out why they are reporting these values */
+
+static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+{
+	if (nf > ATH9K_NF_TOO_LOW) {
+		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+			"%s: noise floor value detected (%d) is "
+			"lower than what we think is a "
+			"reasonable value (%d)\n",
+			__func__, nf, ATH9K_NF_TOO_LOW);
+		return false;
+	}
+	return true;
+}
+
+static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
+{
+	int16_t nfval;
+	int16_t sort[ATH9K_NF_CAL_HIST_MAX];
+	int i, j;
+
+	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
+		sort[i] = nfCalBuffer[i];
+
+	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
+		for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
+			if (sort[j] > sort[j - 1]) {
+				nfval = sort[j];
+				sort[j] = sort[j - 1];
+				sort[j - 1] = nfval;
+			}
+		}
+	}
+	nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
+
+	return nfval;
+}
+
+static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
+					      int16_t *nfarray)
+{
+	int i;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
+
+		if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
+			h[i].currIndex = 0;
+
+		if (h[i].invalidNFcount > 0) {
+			if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
+			    nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
+				h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
+			} else {
+				h[i].invalidNFcount--;
+				h[i].privNF = nfarray[i];
+			}
+		} else {
+			h[i].privNF =
+				ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
+		}
+	}
+	return;
+}
+
+static void ath9k_hw_do_getnf(struct ath_hal *ah,
+			      int16_t nfarray[NUM_NF_READINGS])
+{
+	int16_t nf;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"NF calibrated [ctl] [chain 0] is %d\n", nf);
+	nfarray[0] = nf;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+			AR9280_PHY_CH1_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+			AR_PHY_CH1_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+		"NF calibrated [ctl] [chain 1] is %d\n", nf);
+	nfarray[1] = nf;
+
+	if (!AR_SREV_9280(ah)) {
+		nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
+			AR_PHY_CH2_MINCCA_PWR);
+		if (nf & 0x100)
+			nf = 0 - ((nf ^ 0x1ff) + 1);
+		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+			"NF calibrated [ctl] [chain 2] is %d\n", nf);
+		nfarray[2] = nf;
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+			AR9280_PHY_EXT_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+			AR_PHY_EXT_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+		"NF calibrated [ext] [chain 0] is %d\n", nf);
+	nfarray[3] = nf;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+			AR9280_PHY_CH1_EXT_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+			AR_PHY_CH1_EXT_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"NF calibrated [ext] [chain 1] is %d\n", nf);
+	nfarray[4] = nf;
+
+	if (!AR_SREV_9280(ah)) {
+		nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
+			AR_PHY_CH2_EXT_MINCCA_PWR);
+		if (nf & 0x100)
+			nf = 0 - ((nf ^ 0x1ff) + 1);
+		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+			"NF calibrated [ext] [chain 2] is %d\n", nf);
+		nfarray[5] = nf;
+	}
+}
+
+static bool getNoiseFloorThresh(struct ath_hal *ah,
+				const struct ath9k_channel *chan,
+				int16_t *nft)
+{
+	switch (chan->chanmode) {
+	case CHANNEL_A:
+	case CHANNEL_A_HT20:
+	case CHANNEL_A_HT40PLUS:
+	case CHANNEL_A_HT40MINUS:
+		*nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
+		break;
+	case CHANNEL_B:
+	case CHANNEL_G:
+	case CHANNEL_G_HT20:
+	case CHANNEL_G_HT40PLUS:
+	case CHANNEL_G_HT40MINUS:
+		*nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"%s: invalid channel flags 0x%x\n", __func__,
+			chan->channelFlags);
+		return false;
+	}
+
+	return true;
+}
+
+static void ath9k_hw_setup_calibration(struct ath_hal *ah,
+				       struct hal_cal_list *currCal)
+{
+	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
+		      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+		      currCal->calData->calCountMax);
+
+	switch (currCal->calData->calType) {
+	case IQ_MISMATCH_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: starting IQ Mismatch Calibration\n",
+			__func__);
+		break;
+	case ADC_GAIN_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: starting ADC Gain Calibration\n", __func__);
+		break;
+	case ADC_DC_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: starting ADC DC Calibration\n", __func__);
+		break;
+	case ADC_DC_INIT_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: starting Init ADC DC Calibration\n",
+			__func__);
+		break;
+	}
+
+	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+		    AR_PHY_TIMING_CTRL4_DO_CAL);
+}
+
+static void ath9k_hw_reset_calibration(struct ath_hal *ah,
+				       struct hal_cal_list *currCal)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	ath9k_hw_setup_calibration(ah, currCal);
+
+	currCal->calState = CAL_RUNNING;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_Meas0.sign[i] = 0;
+		ahp->ah_Meas1.sign[i] = 0;
+		ahp->ah_Meas2.sign[i] = 0;
+		ahp->ah_Meas3.sign[i] = 0;
+	}
+
+	ahp->ah_CalSamples = 0;
+}
+
+static void ath9k_hw_per_calibration(struct ath_hal *ah,
+				     struct ath9k_channel *ichan,
+				     u8 rxchainmask,
+				     struct hal_cal_list *currCal,
+				     bool *isCalDone)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	*isCalDone = false;
+
+	if (currCal->calState == CAL_RUNNING) {
+		if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+		      AR_PHY_TIMING_CTRL4_DO_CAL)) {
+
+			currCal->calData->calCollect(ah);
+			ahp->ah_CalSamples++;
+
+			if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
+				int i, numChains = 0;
+				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+					if (rxchainmask & (1 << i))
+						numChains++;
+				}
+
+				currCal->calData->calPostProc(ah, numChains);
+				ichan->CalValid |= currCal->calData->calType;
+				currCal->calState = CAL_DONE;
+				*isCalDone = true;
+			} else {
+				ath9k_hw_setup_calibration(ah, currCal);
+			}
+		}
+	} else if (!(ichan->CalValid & currCal->calData->calType)) {
+		ath9k_hw_reset_calibration(ah, currCal);
+	}
+}
+
+static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
+				     struct ath9k_channel *chan,
+				     enum hal_cal_types calType)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	bool retval = false;
+
+	switch (calType & ahp->ah_suppCals) {
+	case IQ_MISMATCH_CAL:
+		if (!IS_CHAN_B(chan))
+			retval = true;
+		break;
+	case ADC_GAIN_CAL:
+	case ADC_DC_CAL:
+		if (!IS_CHAN_B(chan)
+		    && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+			retval = true;
+		break;
+	}
+
+	return retval;
+}
+
+static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_totalPowerMeasI[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ahp->ah_totalPowerMeasQ[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ahp->ah_totalIqCorrMeas[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+			ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
+			ahp->ah_totalPowerMeasQ[i],
+			ahp->ah_totalIqCorrMeas[i]);
+	}
+}
+
+static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_totalAdcIOddPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ahp->ah_totalAdcIEvenPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ahp->ah_totalAdcQOddPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		ahp->ah_totalAdcQEvenPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+			"oddq=0x%08x; evenq=0x%08x;\n",
+			ahp->ah_CalSamples, i,
+			ahp->ah_totalAdcIOddPhase[i],
+			ahp->ah_totalAdcIEvenPhase[i],
+			ahp->ah_totalAdcQOddPhase[i],
+			ahp->ah_totalAdcQEvenPhase[i]);
+	}
+}
+
+static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+			"oddq=0x%08x; evenq=0x%08x;\n",
+			ahp->ah_CalSamples, i,
+			ahp->ah_totalAdcDcOffsetIOddPhase[i],
+			ahp->ah_totalAdcDcOffsetIEvenPhase[i],
+			ahp->ah_totalAdcDcOffsetQOddPhase[i],
+			ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
+	}
+}
+
+static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 powerMeasQ, powerMeasI, iqCorrMeas;
+	u32 qCoffDenom, iCoffDenom;
+	int32_t qCoff, iCoff;
+	int iqCorrNeg, i;
+
+	for (i = 0; i < numChains; i++) {
+		powerMeasI = ahp->ah_totalPowerMeasI[i];
+		powerMeasQ = ahp->ah_totalPowerMeasQ[i];
+		iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Starting IQ Cal and Correction for Chain %d\n",
+			i);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Orignal: Chn %diq_corr_meas = 0x%08x\n",
+			i, ahp->ah_totalIqCorrMeas[i]);
+
+		iqCorrNeg = 0;
+
+		if (iqCorrMeas > 0x80000000) {
+			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+			iqCorrNeg = 1;
+		}
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+			iqCorrNeg);
+
+		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+		qCoffDenom = powerMeasQ / 64;
+
+		if (powerMeasQ != 0) {
+			iCoff = iqCorrMeas / iCoffDenom;
+			qCoff = powerMeasI / qCoffDenom - 64;
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d iCoff = 0x%08x\n", i, iCoff);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+			iCoff = iCoff & 0x3f;
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+			if (iqCorrNeg == 0x0)
+				iCoff = 0x40 - iCoff;
+
+			if (qCoff > 15)
+				qCoff = 15;
+			else if (qCoff <= -16)
+				qCoff = 16;
+
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
+				i, iCoff, qCoff);
+
+			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+				      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
+				      iCoff);
+			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+				      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
+				      qCoff);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"IQ Cal and Correction done for Chain %d\n",
+				i);
+		}
+	}
+
+	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
+}
+
+static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
+	u32 qGainMismatch, iGainMismatch, val, i;
+
+	for (i = 0; i < numChains; i++) {
+		iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
+		iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
+		qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
+		qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Starting ADC Gain Cal for Chain %d\n", i);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+			iOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_i = 0x%08x\n", i,
+			iEvenMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+			qOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_q = 0x%08x\n", i,
+			qEvenMeasOffset);
+
+		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
+			iGainMismatch =
+				((iEvenMeasOffset * 32) /
+				 iOddMeasOffset) & 0x3f;
+			qGainMismatch =
+				((qOddMeasOffset * 32) /
+				 qEvenMeasOffset) & 0x3f;
+
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d gain_mismatch_i = 0x%08x\n", i,
+				iGainMismatch);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d gain_mismatch_q = 0x%08x\n", i,
+				qGainMismatch);
+
+			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+			val &= 0xfffff000;
+			val |= (qGainMismatch) | (iGainMismatch << 6);
+			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"ADC Gain Cal done for Chain %d\n", i);
+		}
+	}
+
+	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
+}
+
+static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
+	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
+	const struct hal_percal_data *calData =
+		ahp->ah_cal_list_curr->calData;
+	u32 numSamples =
+		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+
+	for (i = 0; i < numChains; i++) {
+		iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
+		iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
+		qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
+		qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Starting ADC DC Offset Cal for Chain %d\n", i);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_i = %d\n", i,
+			iOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_i = %d\n", i,
+			iEvenMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_q = %d\n", i,
+			qOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_q = %d\n", i,
+			qEvenMeasOffset);
+
+		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
+			       numSamples) & 0x1ff;
+		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
+			       numSamples) & 0x1ff;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+			iDcMismatch);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+			qDcMismatch);
+
+		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+		val &= 0xc0000fff;
+		val |= (qDcMismatch << 12) | (iDcMismatch << 21);
+		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"ADC DC Offset Cal done for Chain %d\n", i);
+	}
+
+	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+		  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
+}
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+			     bool *isCalDone)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *ichan =
+		ath9k_regd_check_channel(ah, chan);
+	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+
+	*isCalDone = true;
+
+	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
+		return;
+
+	if (currCal == NULL)
+		return;
+
+	if (ichan == NULL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: invalid channel %u/0x%x; no mapping\n",
+			__func__, chan->channel, chan->channelFlags);
+		return;
+	}
+
+
+	if (currCal->calState != CAL_DONE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: Calibration state incorrect, %d\n",
+			__func__, currCal->calState);
+		return;
+	}
+
+
+	if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
+		return;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"%s: Resetting Cal %d state for channel %u/0x%x\n",
+		__func__, currCal->calData->calType, chan->channel,
+		chan->channelFlags);
+
+	ichan->CalValid &= ~currCal->calData->calType;
+	currCal->calState = CAL_WAITING;
+
+	*isCalDone = false;
+}
+
+void ath9k_hw_start_nfcal(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_ENABLE_NF);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+}
+
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+	struct ath9k_nfcal_hist *h;
+	int i, j;
+	int32_t val;
+	const u32 ar5416_cca_regs[6] = {
+		AR_PHY_CCA,
+		AR_PHY_CH1_CCA,
+		AR_PHY_CH2_CCA,
+		AR_PHY_EXT_CCA,
+		AR_PHY_CH1_EXT_CCA,
+		AR_PHY_CH2_EXT_CCA
+	};
+	u8 chainmask;
+
+	if (AR_SREV_9280(ah))
+		chainmask = 0x1B;
+	else
+		chainmask = 0x3F;
+
+#ifdef ATH_NF_PER_CHAN
+	h = chan->nfCalHist;
+#else
+	h = ah->nfCalHist;
+#endif
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			val = REG_READ(ah, ar5416_cca_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+			REG_WRITE(ah, ar5416_cca_regs[i], val);
+		}
+	}
+
+	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_ENABLE_NF);
+	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+	for (j = 0; j < 1000; j++) {
+		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+		     AR_PHY_AGC_CONTROL_NF) == 0)
+			break;
+		udelay(10);
+	}
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			val = REG_READ(ah, ar5416_cca_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) (-50) << 1) & 0x1ff);
+			REG_WRITE(ah, ar5416_cca_regs[i], val);
+		}
+	}
+}
+
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+		       struct ath9k_channel *chan)
+{
+	int16_t nf, nfThresh;
+	int16_t nfarray[NUM_NF_READINGS] = { 0 };
+	struct ath9k_nfcal_hist *h;
+	u8 chainmask;
+
+	if (AR_SREV_9280(ah))
+		chainmask = 0x1B;
+	else
+		chainmask = 0x3F;
+
+	chan->channelFlags &= (~CHANNEL_CW_INT);
+	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: NF did not complete in calibration window\n",
+			__func__);
+		nf = 0;
+		chan->rawNoiseFloor = nf;
+		return chan->rawNoiseFloor;
+	} else {
+		ath9k_hw_do_getnf(ah, nfarray);
+		nf = nfarray[0];
+		if (getNoiseFloorThresh(ah, chan, &nfThresh)
+		    && nf > nfThresh) {
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"%s: noise floor failed detected; "
+				"detected %d, threshold %d\n", __func__,
+				nf, nfThresh);
+			chan->channelFlags |= CHANNEL_CW_INT;
+		}
+	}
+
+#ifdef ATH_NF_PER_CHAN
+	h = chan->nfCalHist;
+#else
+	h = ah->nfCalHist;
+#endif
+
+	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
+	chan->rawNoiseFloor = h[0].privNF;
+
+	return chan->rawNoiseFloor;
+}
+
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
+{
+	int i, j;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		ah->nfCalHist[i].currIndex = 0;
+		ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+		ah->nfCalHist[i].invalidNFcount =
+			AR_PHY_CCA_FILTERWINDOW_LENGTH;
+		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+			ah->nfCalHist[i].nfCalBuffer[j] =
+				AR_PHY_CCA_MAX_GOOD_VALUE;
+		}
+	}
+	return;
+}
+
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+	struct ath9k_channel *ichan;
+	s16 nf;
+
+	ichan = ath9k_regd_check_channel(ah, chan);
+	if (ichan == NULL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+			"%s: invalid channel %u/0x%x; no mapping\n",
+			__func__, chan->channel, chan->channelFlags);
+		return ATH_DEFAULT_NOISE_FLOOR;
+	}
+	if (ichan->rawNoiseFloor == 0) {
+		enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
+		nf = NOISE_FLOOR[mode];
+	} else
+		nf = ichan->rawNoiseFloor;
+
+	if (!ath9k_hw_nf_in_range(ah, nf))
+		nf = ATH_DEFAULT_NOISE_FLOOR;
+
+	return nf;
+}
+
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+			u8 rxchainmask, bool longcal,
+			bool *isCalDone)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+	struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+	*isCalDone = true;
+
+	if (ichan == NULL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"%s: invalid channel %u/0x%x; no mapping\n",
+			__func__, chan->channel, chan->channelFlags);
+		return false;
+	}
+
+	if (currCal &&
+	    (currCal->calState == CAL_RUNNING ||
+	     currCal->calState == CAL_WAITING)) {
+		ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
+					 isCalDone);
+		if (*isCalDone) {
+			ahp->ah_cal_list_curr = currCal = currCal->calNext;
+
+			if (currCal->calState == CAL_WAITING) {
+				*isCalDone = false;
+				ath9k_hw_reset_calibration(ah, currCal);
+			}
+		}
+	}
+
+	if (longcal) {
+		ath9k_hw_getnf(ah, ichan);
+		ath9k_hw_loadnf(ah, ah->ah_curchan);
+		ath9k_hw_start_nfcal(ah);
+
+		if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
+			chan->channelFlags |= CHANNEL_CW_INT;
+			ichan->channelFlags &= ~CHANNEL_CW_INT;
+		}
+	}
+
+	return true;
+}
+
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+		       struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
+		  AR_PHY_AGC_CONTROL_CAL);
+
+	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%s: offset calibration failed to complete in 1ms; "
+			"noisy environment?\n", __func__);
+		return false;
+	}
+
+	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
+		  AR_PHY_AGC_CONTROL_NF);
+
+	ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
+
+	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
+		if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
+			INIT_CAL(&ahp->ah_adcGainCalData);
+			INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"%s: enabling ADC Gain Calibration.\n",
+				__func__);
+		}
+		if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
+			INIT_CAL(&ahp->ah_adcDcCalData);
+			INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"%s: enabling ADC DC Calibration.\n",
+				__func__);
+		}
+		if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+			INIT_CAL(&ahp->ah_iqCalData);
+			INSERT_CAL(ahp, &ahp->ah_iqCalData);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"%s: enabling IQ Calibration.\n",
+				__func__);
+		}
+
+		ahp->ah_cal_list_curr = ahp->ah_cal_list;
+
+		if (ahp->ah_cal_list_curr)
+			ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
+	}
+
+	ichan->CalValid = 0;
+
+	return true;
+}
+
+const struct hal_percal_data iq_cal_multi_sample = {
+	IQ_MISMATCH_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ath9k_hw_iqcal_collect,
+	ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data iq_cal_single_sample = {
+	IQ_MISMATCH_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ath9k_hw_iqcal_collect,
+	ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data adc_gain_cal_multi_sample = {
+	ADC_GAIN_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ath9k_hw_adc_gaincal_collect,
+	ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_gain_cal_single_sample = {
+	ADC_GAIN_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ath9k_hw_adc_gaincal_collect,
+	ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_multi_sample = {
+	ADC_DC_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ath9k_hw_adc_dccal_collect,
+	ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_single_sample = {
+	ADC_DC_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ath9k_hw_adc_dccal_collect,
+	ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_init_dc_cal = {
+	ADC_DC_INIT_CAL,
+	MIN_CAL_SAMPLES,
+	INIT_LOG_COUNT,
+	ath9k_hw_adc_dccal_collect,
+	ath9k_hw_adc_dccal_calibrate
+};

+ 126 - 357
drivers/net/wireless/ath9k/core.c

@@ -14,13 +14,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
- /* Implementation of the main "ATH" layer. */
-
 #include "core.h"
 #include "regd.h"
 
-static int ath_outdoor;		/* enable outdoor use */
-
 static u32 ath_chainmask_sel_up_rssi_thres =
 	ATH_CHAINMASK_SEL_UP_RSSI_THRES;
 static u32 ath_chainmask_sel_down_rssi_thres =
@@ -47,6 +43,41 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz)
 		*csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
 }
 
+static u8 parse_mpdudensity(u8 mpdudensity)
+{
+	/*
+	 * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
+	 *   0 for no restriction
+	 *   1 for 1/4 us
+	 *   2 for 1/2 us
+	 *   3 for 1 us
+	 *   4 for 2 us
+	 *   5 for 4 us
+	 *   6 for 8 us
+	 *   7 for 16 us
+	 */
+	switch (mpdudensity) {
+	case 0:
+		return 0;
+	case 1:
+	case 2:
+	case 3:
+		/* Our lower layer calculations limit our precision to
+		   1 microsecond */
+		return 1;
+	case 4:
+		return 2;
+	case 5:
+		return 4;
+	case 6:
+		return 8;
+	case 7:
+		return 16;
+	default:
+		return 0;
+	}
+}
+
 /*
  *  Set current operating mode
  *
@@ -155,17 +186,10 @@ static int ath_setup_channels(struct ath_softc *sc)
 	struct ath9k_channel *c;
 
 	/* Fill in ah->ah_channels */
-	if (!ath9k_regd_init_channels(ah,
-				      ATH_CHAN_MAX,
-				      (u32 *)&nchan,
-				      regclassids,
-				      ATH_REGCLASSIDS_MAX,
-				      &nregclass,
-				      CTRY_DEFAULT,
-				      false,
-				      1)) {
+	if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
+				      regclassids, ATH_REGCLASSIDS_MAX,
+				      &nregclass, CTRY_DEFAULT, false, 1)) {
 		u32 rd = ah->ah_currentRD;
-
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"%s: unable to collect channel list; "
 			"regdomain likely %u country code %u\n",
@@ -186,40 +210,32 @@ static int ath_setup_channels(struct ath_softc *sc)
 			chan_2ghz[a].max_power = c->maxTxPower;
 
 			if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
-				chan_2ghz[a].flags |=
-					IEEE80211_CHAN_NO_IBSS;
+				chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
 			if (c->channelFlags & CHANNEL_PASSIVE)
-				chan_2ghz[a].flags |=
-					IEEE80211_CHAN_PASSIVE_SCAN;
+				chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 
 			band_2ghz->n_channels = ++a;
 
 			DPRINTF(sc, ATH_DBG_CONFIG,
 				"%s: 2MHz channel: %d, "
 				"channelFlags: 0x%x\n",
-				__func__,
-				c->channel,
-				c->channelFlags);
+				__func__, c->channel, c->channelFlags);
 		} else if (IS_CHAN_5GHZ(c)) {
 			chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
 			chan_5ghz[b].center_freq = c->channel;
 			chan_5ghz[b].max_power = c->maxTxPower;
 
 			if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
-				chan_5ghz[b].flags |=
-					IEEE80211_CHAN_NO_IBSS;
+				chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
 			if (c->channelFlags & CHANNEL_PASSIVE)
-				chan_5ghz[b].flags |=
-					IEEE80211_CHAN_PASSIVE_SCAN;
+				chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 
 			band_5ghz->n_channels = ++b;
 
 			DPRINTF(sc, ATH_DBG_CONFIG,
 				"%s: 5MHz channel: %d, "
 				"channelFlags: 0x%x\n",
-				__func__,
-				c->channel,
-				c->channelFlags);
+				__func__, c->channel, c->channelFlags);
 		}
 	}
 
@@ -260,44 +276,6 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
 	return ATH9K_MODE_11B;
 }
 
-/*
- * Stop the device, grabbing the top-level lock to protect
- * against concurrent entry through ath_init (which can happen
- * if another thread does a system call and the thread doing the
- * stop is preempted).
- */
-
-static int ath_stop(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n",
-		__func__, sc->sc_flags & SC_OP_INVALID);
-
-	/*
-	 * Shutdown the hardware and driver:
-	 *    stop output from above
-	 *    turn off timers
-	 *    disable interrupts
-	 *    clear transmit machinery
-	 *    clear receive machinery
-	 *    turn off the radio
-	 *    reclaim beacon resources
-	 *
-	 * Note that some of this work is not possible if the
-	 * hardware is gone (invalid).
-	 */
-
-	ath_draintxq(sc, false);
-	if (!(sc->sc_flags & SC_OP_INVALID)) {
-		ath_stoprecv(sc);
-		ath9k_hw_phy_disable(ah);
-	} else
-		sc->sc_rxlink = NULL;
-
-	return 0;
-}
-
 /*
  * Set the current channel
  *
@@ -606,114 +584,6 @@ static void ath_ani_calibrate(unsigned long data)
 	mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
 }
 
-/******************/
-/* VAP management */
-/******************/
-
-int ath_vap_attach(struct ath_softc *sc,
-		   int if_id,
-		   struct ieee80211_vif *if_data,
-		   enum ath9k_opmode opmode)
-{
-	struct ath_vap *avp;
-
-	if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Invalid interface id = %u\n", __func__, if_id);
-		return -EINVAL;
-	}
-
-	switch (opmode) {
-	case ATH9K_M_STA:
-	case ATH9K_M_IBSS:
-	case ATH9K_M_MONITOR:
-		break;
-	case ATH9K_M_HOSTAP:
-		/* XXX not right, beacon buffer is allocated on RUN trans */
-		if (list_empty(&sc->sc_bbuf))
-			return -ENOMEM;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* create ath_vap */
-	avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL);
-	if (avp == NULL)
-		return -ENOMEM;
-
-	memset(avp, 0, sizeof(struct ath_vap));
-	avp->av_if_data = if_data;
-	/* Set the VAP opmode */
-	avp->av_opmode = opmode;
-	avp->av_bslot = -1;
-
-	if (opmode == ATH9K_M_HOSTAP)
-		ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
-
-	sc->sc_vaps[if_id] = avp;
-	sc->sc_nvaps++;
-	/* Set the device opmode */
-	sc->sc_ah->ah_opmode = opmode;
-
-	/* default VAP configuration */
-	avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
-	avp->av_config.av_fixed_retryset = 0x03030303;
-
-	return 0;
-}
-
-int ath_vap_detach(struct ath_softc *sc, int if_id)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	struct ath_vap *avp;
-
-	avp = sc->sc_vaps[if_id];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
-			__func__, if_id);
-		return -EINVAL;
-	}
-
-	/*
-	 * Quiesce the hardware while we remove the vap.  In
-	 * particular we need to reclaim all references to the
-	 * vap state by any frames pending on the tx queues.
-	 *
-	 * XXX can we do this w/o affecting other vap's?
-	 */
-	ath9k_hw_set_interrupts(ah, 0);	/* disable interrupts */
-	ath_draintxq(sc, false);	/* stop xmit side */
-	ath_stoprecv(sc);	/* stop recv side */
-	ath_flushrecv(sc);	/* flush recv queue */
-
-	kfree(avp);
-	sc->sc_vaps[if_id] = NULL;
-	sc->sc_nvaps--;
-
-	return 0;
-}
-
-int ath_vap_config(struct ath_softc *sc,
-	int if_id, struct ath_vap_config *if_config)
-{
-	struct ath_vap *avp;
-
-	if (if_id >= ATH_BCBUF) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Invalid interface id = %u\n", __func__, if_id);
-		return -EINVAL;
-	}
-
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp != NULL);
-
-	if (avp)
-		memcpy(&avp->av_config, if_config, sizeof(avp->av_config));
-
-	return 0;
-}
-
 /********/
 /* Core */
 /********/
@@ -727,16 +597,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
 	DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
 		__func__, sc->sc_ah->ah_opmode);
 
-	/*
-	 * Stop anything previously setup.  This is safe
-	 * whether this is the first time through or not.
-	 */
-	ath_stop(sc);
-
-	/* Initialize chanmask selection */
-	sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
-	sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
-
 	/* Reset SERDES registers */
 	ath9k_hw_configpcipowersave(ah, 0);
 
@@ -762,6 +622,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
 		goto done;
 	}
 	spin_unlock_bh(&sc->sc_resetlock);
+
 	/*
 	 * This is needed only to setup initial state
 	 * but it's best done after a reset.
@@ -781,6 +642,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
 		error = -EIO;
 		goto done;
 	}
+
 	/* Setup our intr mask. */
 	sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
 		| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
@@ -810,30 +672,60 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
 	    (sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
 	    !sc->sc_config.swBeaconProcess)
 		sc->sc_imask |= ATH9K_INT_TIM;
-	/*
-	 *  Don't enable interrupts here as we've not yet built our
-	 *  vap and node data structures, which will be needed as soon
-	 *  as we start receiving.
-	 */
+
 	ath_setcurmode(sc, ath_chan2mode(initial_chan));
 
-	/* XXX: we must make sure h/w is ready and clear invalid flag
-	 * before turning on interrupt. */
 	sc->sc_flags &= ~SC_OP_INVALID;
+
+	/* Disable BMISS interrupt when we're not associated */
+	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+	ath9k_hw_set_interrupts(sc->sc_ah,sc->sc_imask);
+
+	ieee80211_wake_queues(sc->hw);
 done:
 	return error;
 }
 
+void ath_stop(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__);
+
+	ieee80211_stop_queues(sc->hw);
+
+	/* make sure h/w will not generate any interrupt
+	 * before setting the invalid flag. */
+	ath9k_hw_set_interrupts(ah, 0);
+
+	if (!(sc->sc_flags & SC_OP_INVALID)) {
+		ath_draintxq(sc, false);
+		ath_stoprecv(sc);
+		ath9k_hw_phy_disable(ah);
+	} else
+		sc->sc_rxlink = NULL;
+
+#ifdef CONFIG_RFKILL
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+	/* disable HAL and put h/w to sleep */
+	ath9k_hw_disable(sc->sc_ah);
+	ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+
+	sc->sc_flags |= SC_OP_INVALID;
+}
+
 int ath_reset(struct ath_softc *sc, bool retry_tx)
 {
 	struct ath_hal *ah = sc->sc_ah;
 	int status;
 	int error = 0;
 
-	ath9k_hw_set_interrupts(ah, 0);	/* disable interrupts */
-	ath_draintxq(sc, retry_tx);	/* stop xmit */
-	ath_stoprecv(sc);		/* stop recv */
-	ath_flushrecv(sc);		/* flush recv queue */
+	ath9k_hw_set_interrupts(ah, 0);
+	ath_draintxq(sc, retry_tx);
+	ath_stoprecv(sc);
+	ath_flushrecv(sc);
 
 	/* Reset chip */
 	spin_lock_bh(&sc->sc_resetlock);
@@ -848,7 +740,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	}
 	spin_unlock_bh(&sc->sc_resetlock);
 
-	if (ath_startrecv(sc) != 0)	/* restart recv */
+	if (ath_startrecv(sc) != 0)
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"%s: unable to start recv logic\n", __func__);
 
@@ -881,29 +773,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	return error;
 }
 
-int ath_suspend(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-
-	/* No I/O if device has been surprise removed */
-	if (sc->sc_flags & SC_OP_INVALID)
-		return -EIO;
-
-	/* Shut off the interrupt before setting sc->sc_invalid to '1' */
-	ath9k_hw_set_interrupts(ah, 0);
-
-	/* XXX: we must make sure h/w will not generate any interrupt
-	 * before setting the invalid flag. */
-	sc->sc_flags |= SC_OP_INVALID;
-
-	/* disable HAL and put h/w to sleep */
-	ath9k_hw_disable(sc->sc_ah);
-
-	ath9k_hw_configpcipowersave(sc->sc_ah, 1);
-
-	return 0;
-}
-
 /* Interrupt handler.  Most of the actual processing is deferred.
  * It's the caller's responsibility to ensure the chip is awake. */
 
@@ -1071,11 +940,9 @@ int ath_init(u16 devid, struct ath_softc *sc)
 
 	/* XXX: hardware will not be ready until ath_open() being called */
 	sc->sc_flags |= SC_OP_INVALID;
-
 	sc->sc_debug = DBG_DEFAULT;
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);
 
-	/* Initialize tasklet */
+	spin_lock_init(&sc->sc_resetlock);
 	tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
 	tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
 		     (unsigned long)sc);
@@ -1088,8 +955,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
 	/* XXX assert csz is non-zero */
 	sc->sc_cachelsz = csz << 2;	/* convert to bytes */
 
-	spin_lock_init(&sc->sc_resetlock);
-
 	ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
 	if (ah == NULL) {
 		DPRINTF(sc, ATH_DBG_FATAL,
@@ -1100,10 +965,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
 	}
 	sc->sc_ah = ah;
 
-	/* Initializes the noise floor to a reasonable default value.
-	 * Later on this will be updated during ANI processing. */
-	sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
-
 	/* Get the hardware key cache size. */
 	sc->sc_keymax = ah->ah_caps.keycache_size;
 	if (sc->sc_keymax > ATH_KEYMAX) {
@@ -1131,17 +992,14 @@ int ath_init(u16 devid, struct ath_softc *sc)
 		set_bit(i + 64, sc->sc_keymap);
 		set_bit(i + 32 + 64, sc->sc_keymap);
 	}
-	/*
-	 * Collect the channel list using the default country
-	 * code and including outdoor channels.  The 802.11 layer
-	 * is resposible for filtering this list based on settings
-	 * like the phy mode.
-	 */
+
+	/* Collect the channel list using the default country code */
+
 	error = ath_setup_channels(sc);
 	if (error)
 		goto bad;
 
-	/* default to STA mode */
+	/* default to MONITOR mode */
 	sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
 
 	/* Setup rate tables */
@@ -1211,6 +1069,10 @@ int ath_init(u16 devid, struct ath_softc *sc)
 		goto bad2;
 	}
 
+	/* Initializes the noise floor to a reasonable default value.
+	 * Later on this will be updated during ANI processing. */
+
+	sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
 	setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
 
 	sc->sc_rc = ath_rate_attach(ah);
@@ -1271,6 +1133,7 @@ int ath_init(u16 devid, struct ath_softc *sc)
 		ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
 		ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
 	}
+
 	sc->sc_slottime = ATH9K_SLOT_TIME_9;	/* default to short slot time */
 
 	/* initialize beacon slots */
@@ -1285,6 +1148,22 @@ int ath_init(u16 devid, struct ath_softc *sc)
 	ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
 #endif
 
+	/* setup channels and rates */
+
+	sc->sbands[IEEE80211_BAND_2GHZ].channels =
+		sc->channels[IEEE80211_BAND_2GHZ];
+	sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
+		sc->rates[IEEE80211_BAND_2GHZ];
+	sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+
+	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
+		sc->sbands[IEEE80211_BAND_5GHZ].channels =
+			sc->channels[IEEE80211_BAND_5GHZ];
+		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+			sc->rates[IEEE80211_BAND_5GHZ];
+		sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+	}
+
 	return 0;
 bad2:
 	/* cleanup tx queues */
@@ -1294,125 +1173,39 @@ bad2:
 bad:
 	if (ah)
 		ath9k_hw_detach(ah);
-	return error;
-}
-
-void ath_deinit(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int i;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
-
-	tasklet_kill(&sc->intr_tq);
-	tasklet_kill(&sc->bcon_tasklet);
-	ath_stop(sc);
-	if (!(sc->sc_flags & SC_OP_INVALID))
-		ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
-	ath_rate_detach(sc->sc_rc);
-	/* cleanup tx queues */
-	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-		if (ATH_TXQ_SETUP(sc, i))
-			ath_tx_cleanupq(sc, &sc->sc_txq[i]);
-	ath9k_hw_detach(ah);
+	return error;
 }
 
 /*******************/
 /* Node Management */
 /*******************/
 
-struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id)
+void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
-	struct ath_vap *avp;
 	struct ath_node *an;
 
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp != NULL);
+	an = (struct ath_node *)sta->drv_priv;
 
-	/* mac80211 sta_notify callback is from an IRQ context, so no sleep */
-	an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC);
-	if (an == NULL)
-		return NULL;
-	memset(an, 0, sizeof(*an));
+	if (sc->sc_flags & SC_OP_TXAGGR)
+		ath_tx_node_init(sc, an);
 
-	an->an_sc = sc;
-	memcpy(an->an_addr, addr, ETH_ALEN);
-	atomic_set(&an->an_refcnt, 1);
-
-	/* set up per-node tx/rx state */
-	ath_tx_node_init(sc, an);
-	ath_rx_node_init(sc, an);
+	an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+			     sta->ht_cap.ampdu_factor);
+	an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
 
 	ath_chainmask_sel_init(sc, an);
 	ath_chainmask_sel_timerstart(&an->an_chainmask_sel);
-	list_add(&an->list, &sc->node_list);
-
-	return an;
 }
 
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
+void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
-	unsigned long flags;
+	struct ath_node *an = (struct ath_node *)sta->drv_priv;
 
 	ath_chainmask_sel_timerstop(&an->an_chainmask_sel);
-	an->an_flags |= ATH_NODE_CLEAN;
-	ath_tx_node_cleanup(sc, an, bh_flag);
-	ath_rx_node_cleanup(sc, an);
-
-	ath_tx_node_free(sc, an);
-	ath_rx_node_free(sc, an);
-
-	spin_lock_irqsave(&sc->node_lock, flags);
-
-	list_del(&an->list);
-
-	spin_unlock_irqrestore(&sc->node_lock, flags);
 
-	kfree(an);
-}
-
-/* Finds a node and increases the refcnt if found */
-
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr)
-{
-	struct ath_node *an = NULL, *an_found = NULL;
-
-	if (list_empty(&sc->node_list)) /* FIXME */
-		goto out;
-	list_for_each_entry(an, &sc->node_list, list) {
-		if (!compare_ether_addr(an->an_addr, addr)) {
-			atomic_inc(&an->an_refcnt);
-			an_found = an;
-			break;
-		}
-	}
-out:
-	return an_found;
-}
-
-/* Decrements the refcnt and if it drops to zero, detach the node */
-
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
-{
-	if (atomic_dec_and_test(&an->an_refcnt))
-		ath_node_detach(sc, an, bh_flag);
-}
-
-/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr)
-{
-	struct ath_node *an = NULL, *an_found = NULL;
-
-	if (list_empty(&sc->node_list))
-		return NULL;
-
-	list_for_each_entry(an, &sc->node_list, list)
-		if (!compare_ether_addr(an->an_addr, addr)) {
-			an_found = an;
-			break;
-		}
-
-	return an_found;
+	if (sc->sc_flags & SC_OP_TXAGGR)
+		ath_tx_node_cleanup(sc, an);
 }
 
 /*
@@ -1433,11 +1226,8 @@ void ath_newassoc(struct ath_softc *sc,
 		for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
 			if (sc->sc_flags & SC_OP_TXAGGR)
 				ath_tx_aggr_teardown(sc, an, tidno);
-			if (sc->sc_flags & SC_OP_RXAGGR)
-				ath_rx_aggr_teardown(sc, an, tidno);
 		}
 	}
-	an->an_flags = 0;
 }
 
 /**************/
@@ -1488,27 +1278,6 @@ void ath_update_txpow(struct ath_softc *sc)
 	}
 }
 
-/* Return the current country and domain information */
-void ath_get_currentCountry(struct ath_softc *sc,
-	struct ath9k_country_entry *ctry)
-{
-	ath9k_regd_get_current_country(sc->sc_ah, ctry);
-
-	/* If HAL not specific yet, since it is band dependent,
-	 * use the one we passed in. */
-	if (ctry->countryCode == CTRY_DEFAULT) {
-		ctry->iso[0] = 0;
-		ctry->iso[1] = 0;
-	} else if (ctry->iso[0] && ctry->iso[1]) {
-		if (!ctry->iso[2]) {
-			if (ath_outdoor)
-				ctry->iso[2] = 'O';
-			else
-				ctry->iso[2] = 'I';
-		}
-	}
-}
-
 /**************************/
 /* Slow Antenna Diversity */
 /**************************/

+ 24 - 133
drivers/net/wireless/ath9k/core.h

@@ -84,9 +84,6 @@ struct ath_node;
 #define TSF_TO_TU(_h,_l) \
 	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 
-#define ATH9K_BH_STATUS_INTACT		0
-#define ATH9K_BH_STATUS_CHANGE		1
-
 #define	ATH_TXQ_SETUP(sc, i)        ((sc)->sc_txqsetup & (1<<i))
 
 static inline unsigned long get_timestamp(void)
@@ -209,6 +206,7 @@ struct ath_buf_state {
 	struct ath_rc_series bfs_rcs[4];	/* rate series */
 	u32 bf_type;				/* BUF_* (enum buffer_type) */
 	/* key type use to encrypt this frame */
+	u32 bfs_keyix;
 	enum ath9k_key_type bfs_keytype;
 };
 
@@ -219,6 +217,7 @@ struct ath_buf_state {
 #define bf_seqno        	bf_state.bfs_seqno
 #define bf_tidno        	bf_state.bfs_tidno
 #define bf_rcs          	bf_state.bfs_rcs
+#define bf_keyix                bf_state.bfs_keyix
 #define bf_keytype      	bf_state.bfs_keytype
 #define bf_isdata(bf)		(bf->bf_state.bf_type & BUF_DATA)
 #define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
@@ -244,7 +243,6 @@ struct ath_buf {
 	struct ath_buf *bf_next;	/* next subframe in the aggregate */
 	struct ath_buf *bf_rifslast;	/* last buf for RIFS burst */
 	void *bf_mpdu;			/* enclosing frame structure */
-	void *bf_node;			/* pointer to the node */
 	struct ath_desc *bf_desc;	/* virtual addr of desc */
 	dma_addr_t bf_daddr;		/* physical addr of desc */
 	dma_addr_t bf_buf_addr;		/* physical addr of data buffer */
@@ -306,15 +304,7 @@ void ath_descdma_cleanup(struct ath_softc *sc,
 
 #define ATH_MAX_ANTENNA          3
 #define ATH_RXBUF                512
-#define ATH_RX_TIMEOUT           40      /* 40 milliseconds */
 #define WME_NUM_TID              16
-#define IEEE80211_BAR_CTL_TID_M  0xF000  /* tid mask */
-#define IEEE80211_BAR_CTL_TID_S  12      /* tid shift */
-
-enum ATH_RX_TYPE {
-	ATH_RX_NON_CONSUMED = 0,
-	ATH_RX_CONSUMED
-};
 
 /* per frame rx status block */
 struct ath_recv_status {
@@ -348,48 +338,18 @@ struct ath_rxbuf {
 	struct ath_recv_status rx_status;	/* cached rx status */
 };
 
-/* Per-TID aggregate receiver state for a node */
-struct ath_arx_tid {
-	struct ath_node *an;
-	struct ath_rxbuf *rxbuf;	/* re-ordering buffer */
-	struct timer_list timer;
-	spinlock_t tidlock;
-	int baw_head;			/* seq_next at head */
-	int baw_tail;			/* tail of block-ack window */
-	int seq_reset;			/* need to reset start sequence */
-	int addba_exchangecomplete;
-	u16 seq_next;			/* next expected sequence */
-	u16 baw_size;			/* block-ack window size */
-};
-
-/* Per-node receiver aggregate state */
-struct ath_arx {
-	struct ath_arx_tid tid[WME_NUM_TID];
-};
-
 int ath_startrecv(struct ath_softc *sc);
 bool ath_stoprecv(struct ath_softc *sc);
 void ath_flushrecv(struct ath_softc *sc);
 u32 ath_calcrxfilter(struct ath_softc *sc);
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
 void ath_handle_rx_intr(struct ath_softc *sc);
 int ath_rx_init(struct ath_softc *sc, int nbufs);
 void ath_rx_cleanup(struct ath_softc *sc);
 int ath_rx_tasklet(struct ath_softc *sc, int flush);
-int ath_rx_input(struct ath_softc *sc,
-		 struct ath_node *node,
-		 struct sk_buff *skb,
-		 struct ath_recv_status *rx_status,
-		 enum ATH_RX_TYPE *status);
 int _ath_rx_indicate(struct ath_softc *sc,
 		     struct sk_buff *skb,
 		     struct ath_recv_status *status,
 		     u16 keyix);
-int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
-		    struct ath_recv_status *status);
-
 /******/
 /* TX */
 /******/
@@ -418,12 +378,6 @@ int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
 #define WME_AC_VO               3 /* voice */
 #define WME_NUM_AC              4
 
-enum ATH_SM_PWRSAV{
-	ATH_SM_ENABLE,
-	ATH_SM_PWRSAV_STATIC,
-	ATH_SM_PWRSAV_DYNAMIC,
-};
-
 /*
  * Data transmit queue state.  One of these exists for each
  * hardware transmit queue.  Packets sent to us from above
@@ -456,6 +410,10 @@ struct ath_txq {
 	struct list_head axq_acq;
 };
 
+#define AGGR_CLEANUP         BIT(1)
+#define AGGR_ADDBA_COMPLETE  BIT(2)
+#define AGGR_ADDBA_PROGRESS  BIT(3)
+
 /* per TID aggregate tx state for a destination */
 struct ath_atx_tid {
 	struct list_head list;		/* round-robin tid entry */
@@ -471,9 +429,7 @@ struct ath_atx_tid {
 	int baw_tail;			/* next unused tx buffer slot */
 	int sched;
 	int paused;
-	int cleanup_inprogress;
-	u32 addba_exchangecomplete:1;
-	int32_t addba_exchangeinprogress;
+	u8 state;
 	int addba_exchangeattempts;
 };
 
@@ -494,24 +450,8 @@ struct ath_atx {
 
 /* per-frame tx control block */
 struct ath_tx_control {
-	struct ath_node *an;
+	struct ath_txq *txq;
 	int if_id;
-	int qnum;
-	u32 ht:1;
-	u32 ps:1;
-	u32 use_minrate:1;
-	enum ath9k_pkt_type atype;
-	enum ath9k_key_type keytype;
-	u32 flags;
-	u16 seqno;
-	u16 tidno;
-	u16 txpower;
-	u16 frmlen;
-	u32 keyix;
-	int min_rate;
-	int mcast_rate;
-	struct ath_softc *dev;
-	dma_addr_t dmacontext;
 };
 
 /* per frame tx status block */
@@ -546,33 +486,29 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx);
 void ath_tx_draintxq(struct ath_softc *sc,
 		     struct ath_txq *txq, bool retry_tx);
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_tx_node_cleanup(struct ath_softc *sc,
-			 struct ath_node *an, bool bh_flag);
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
 void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
 int ath_tx_init(struct ath_softc *sc, int nbufs);
 int ath_tx_cleanup(struct ath_softc *sc);
 int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
 int ath_txq_update(struct ath_softc *sc, int qnum,
 		   struct ath9k_tx_queue_info *q);
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb);
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+		 struct ath_tx_control *txctl);
 void ath_tx_tasklet(struct ath_softc *sc);
 u32 ath_txq_depth(struct ath_softc *sc, int qnum);
 u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum);
 void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
 void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-		     struct ath_xmit_status *tx_status, struct ath_node *an);
+		     struct ath_xmit_status *tx_status);
 void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
 
 /**********************/
 /* Node / Aggregation */
 /**********************/
 
-/* indicates the node is clened up */
-#define ATH_NODE_CLEAN          0x1
-/* indicates the node is 80211 power save */
-#define ATH_NODE_PWRSAVE        0x2
-
 #define ADDBA_EXCHANGE_ATTEMPTS    10
 #define ATH_AGGR_DELIM_SZ          4   /* delimiter size   */
 #define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
@@ -584,6 +520,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
 #define IEEE80211_SEQ_SEQ_SHIFT    4
 #define IEEE80211_SEQ_MAX          4096
 #define IEEE80211_MIN_AMPDU_BUF    0x8
+#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
 
 /* return whether a bit at index _n in bitmap _bm is set
  * _sz is the size of the bitmap  */
@@ -614,14 +551,6 @@ enum ATH_AGGR_STATUS {
 	ATH_AGGR_8K_LIMITED,
 };
 
-enum ATH_AGGR_CHECK {
-	AGGR_NOT_REQUIRED,
-	AGGR_REQUIRED,
-	AGGR_CLEANUP_PROGRESS,
-	AGGR_EXCHANGE_PROGRESS,
-	AGGR_EXCHANGE_DONE
-};
-
 struct aggr_rifs_param {
 	int param_max_frames;
 	int param_max_len;
@@ -633,54 +562,30 @@ struct aggr_rifs_param {
 /* Per-node aggregation state */
 struct ath_node_aggr {
 	struct ath_atx tx;	/* node transmit state */
-	struct ath_arx rx;	/* node receive state */
 };
 
 /* driver-specific node state */
 struct ath_node {
-	struct list_head list;
 	struct ath_softc *an_sc;
-	atomic_t an_refcnt;
 	struct ath_chainmask_sel an_chainmask_sel;
 	struct ath_node_aggr an_aggr;
-	u8 an_smmode; /* SM Power save mode */
-	u8 an_flags;
-	u8 an_addr[ETH_ALEN];
-
 	u16 maxampdu;
 	u8 mpdudensity;
 };
 
 void ath_tx_resume_tid(struct ath_softc *sc,
 	struct ath_atx_tid *tid);
-enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
-	struct ath_node *an, u8 tidno);
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
 void ath_tx_aggr_teardown(struct ath_softc *sc,
 	struct ath_node *an, u8 tidno);
-void ath_rx_aggr_teardown(struct ath_softc *sc,
-	struct ath_node *an, u8 tidno);
-int ath_rx_aggr_start(struct ath_softc *sc,
-		      const u8 *addr,
-		      u16 tid,
-		      u16 *ssn);
-int ath_rx_aggr_stop(struct ath_softc *sc,
-		     const u8 *addr,
-		     u16 tid);
-int ath_tx_aggr_start(struct ath_softc *sc,
-		      const u8 *addr,
-		      u16 tid,
-		      u16 *ssn);
-int ath_tx_aggr_stop(struct ath_softc *sc,
-		     const u8 *addr,
-		     u16 tid);
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+		      u16 tid, u16 *ssn);
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 void ath_newassoc(struct ath_softc *sc,
 	struct ath_node *node, int isnew, int isuapsd);
-struct ath_node *ath_node_attach(struct ath_softc *sc,
-	u8 addr[ETH_ALEN], int if_id);
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]);
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr);
+void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta);
+void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta);
 
 /*******************/
 /* Beacon Handling */
@@ -744,23 +649,14 @@ struct ath_vap_config {
 
 /* driver-specific vap state */
 struct ath_vap {
-	struct ieee80211_vif *av_if_data;
+	int av_bslot;			/* beacon slot index */
 	enum ath9k_opmode av_opmode;	/* VAP operational mode */
 	struct ath_buf *av_bcbuf;	/* beacon buffer */
 	struct ath_tx_control av_btxctl;  /* txctl information for beacon */
-	int av_bslot;			/* beacon slot index */
 	struct ath_vap_config av_config;/* vap configuration parameters*/
 	struct ath_rate_node *rc_node;
 };
 
-int ath_vap_attach(struct ath_softc *sc,
-		   int if_id,
-		   struct ieee80211_vif *if_data,
-		   enum ath9k_opmode opmode);
-int ath_vap_detach(struct ath_softc *sc, int if_id);
-int ath_vap_config(struct ath_softc *sc,
-		   int if_id, struct ath_vap_config *if_config);
-
 /*********************/
 /* Antenna diversity */
 /*********************/
@@ -968,14 +864,13 @@ struct ath_softc {
 
 	u8 sc_nbcnvaps;			/* # of vaps sending beacons */
 	u16 sc_nvaps;			/* # of active virtual ap's */
-	struct ath_vap *sc_vaps[ATH_BCBUF];
+	struct ieee80211_vif *sc_vaps[ATH_BCBUF];
 
 	u8 sc_mcastantenna;
 	u8 sc_defant;			/* current default antenna */
 	u8 sc_rxotherant;		/* rx's on non-default antenna */
 
 	struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
-	struct list_head node_list;
 	struct ath_ht_info sc_ht_info;
 	enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
 
@@ -1036,7 +931,6 @@ struct ath_softc {
 	spinlock_t sc_rxbuflock;
 	spinlock_t sc_txbuflock;
 	spinlock_t sc_resetlock;
-	spinlock_t node_lock;
 
 	/* LEDs */
 	struct ath_led radio_led;
@@ -1052,9 +946,8 @@ struct ath_softc {
 };
 
 int ath_init(u16 devid, struct ath_softc *sc);
-void ath_deinit(struct ath_softc *sc);
 int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
-int ath_suspend(struct ath_softc *sc);
+void ath_stop(struct ath_softc *sc);
 irqreturn_t ath_isr(int irq, void *dev);
 int ath_reset(struct ath_softc *sc, bool retry_tx);
 int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
@@ -1073,8 +966,6 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
 void ath_setslottime(struct ath_softc *sc);
 void ath_update_txpow(struct ath_softc *sc);
 int ath_cabq_update(struct ath_softc *);
-void ath_get_currentCountry(struct ath_softc *sc,
-	struct ath9k_country_entry *ctry);
 u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
 
 #endif /* CORE_H */

+ 1605 - 0
drivers/net/wireless/ath9k/eeprom.c

@@ -0,0 +1,1605 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
+				      u32 reg, u32 mask,
+				      u32 shift, u32 val)
+{
+	u32 regVal;
+
+	regVal = REG_READ(ah, reg) & ~mask;
+	regVal |= (val << shift) & mask;
+
+	REG_WRITE(ah, reg, regVal);
+
+	if (ah->ah_config.analog_shiftreg)
+		udelay(100);
+
+	return;
+}
+
+static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
+{
+
+	if (fbin == AR5416_BCHAN_UNUSED)
+		return fbin;
+
+	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+static inline int16_t ath9k_hw_interpolate(u16 target,
+					   u16 srcLeft, u16 srcRight,
+					   int16_t targetLeft,
+					   int16_t targetRight)
+{
+	int16_t rv;
+
+	if (srcRight == srcLeft) {
+		rv = targetLeft;
+	} else {
+		rv = (int16_t) (((target - srcLeft) * targetRight +
+				 (srcRight - target) * targetLeft) /
+				(srcRight - srcLeft));
+	}
+	return rv;
+}
+
+static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList,
+						  u16 listSize, u16 *indexL,
+						  u16 *indexR)
+{
+	u16 i;
+
+	if (target <= pList[0]) {
+		*indexL = *indexR = 0;
+		return true;
+	}
+	if (target >= pList[listSize - 1]) {
+		*indexL = *indexR = (u16) (listSize - 1);
+		return true;
+	}
+
+	for (i = 0; i < listSize - 1; i++) {
+		if (pList[i] == target) {
+			*indexL = *indexR = i;
+			return true;
+		}
+		if (target < pList[i + 1]) {
+			*indexL = i;
+			*indexR = (u16) (i + 1);
+			return false;
+		}
+	}
+	return false;
+}
+
+static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+	(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+
+	if (!ath9k_hw_wait(ah,
+			   AR_EEPROM_STATUS_DATA,
+			   AR_EEPROM_STATUS_DATA_BUSY |
+			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+		return false;
+	}
+
+	*data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+		   AR_EEPROM_STATUS_DATA_VAL);
+
+	return true;
+}
+
+static int ath9k_hw_flash_map(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
+
+	if (!ahp->ah_cal_mem) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"%s: cannot remap eeprom region \n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	*data = ioread16(ahp->ah_cal_mem + off);
+
+	return true;
+}
+
+static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+	if (ath9k_hw_use_flash(ah))
+		return ath9k_hw_flash_read(ah, off, data);
+	else
+		return ath9k_hw_eeprom_read(ah, off, data);
+}
+
+static bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+	u16 *eep_data;
+	int addr, ar5416_eep_start_loc = 0;
+
+	if (!ath9k_hw_use_flash(ah)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"%s: Reading from EEPROM, not flash\n", __func__);
+		ar5416_eep_start_loc = 256;
+	}
+
+	if (AR_SREV_9100(ah))
+		ar5416_eep_start_loc = 256;
+
+	eep_data = (u16 *)eep;
+
+	for (addr = 0; addr < sizeof(struct ar5416_eeprom) / sizeof(u16); addr++) {
+		if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+					 eep_data)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"%s: Unable to read eeprom region \n",
+				__func__);
+			return false;
+		}
+		eep_data++;
+	}
+	return true;
+}
+
+static int ath9k_hw_check_eeprom(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep =
+		(struct ar5416_eeprom *) &ahp->ah_eeprom;
+	u16 *eepdata, temp, magic, magic2;
+	u32 sum = 0, el;
+	bool need_swap = false;
+	int i, addr, size;
+
+	if (!ath9k_hw_use_flash(ah)) {
+		if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+					 &magic)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"%s: Reading Magic # failed\n", __func__);
+			return false;
+		}
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n",
+			 __func__, magic);
+
+		if (magic != AR5416_EEPROM_MAGIC) {
+			magic2 = swab16(magic);
+
+			if (magic2 == AR5416_EEPROM_MAGIC) {
+				size = sizeof(struct ar5416_eeprom);
+				need_swap = true;
+				eepdata = (u16 *) (&ahp->ah_eeprom);
+
+				for (addr = 0; addr < size / sizeof(u16); addr++) {
+					temp = swab16(*eepdata);
+					*eepdata = temp;
+					eepdata++;
+
+					DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+						"0x%04X  ", *eepdata);
+
+					if (((addr + 1) % 6) == 0)
+						DPRINTF(ah->ah_sc,
+							ATH_DBG_EEPROM, "\n");
+				}
+			} else {
+				DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+					"Invalid EEPROM Magic. "
+					"endianness mismatch.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+		need_swap ? "True" : "False");
+
+	if (need_swap)
+		el = swab16(ahp->ah_eeprom.baseEepHeader.length);
+	else
+		el = ahp->ah_eeprom.baseEepHeader.length;
+
+	if (el > sizeof(struct ar5416_eeprom))
+		el = sizeof(struct ar5416_eeprom) / sizeof(u16);
+	else
+		el = el / sizeof(u16);
+
+	eepdata = (u16 *)(&ahp->ah_eeprom);
+
+	for (i = 0; i < el; i++)
+		sum ^= *eepdata++;
+
+	if (need_swap) {
+		u32 integer, j;
+		u16 word;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"EEPROM Endianness is not native.. Changing \n");
+
+		word = swab16(eep->baseEepHeader.length);
+		eep->baseEepHeader.length = word;
+
+		word = swab16(eep->baseEepHeader.checksum);
+		eep->baseEepHeader.checksum = word;
+
+		word = swab16(eep->baseEepHeader.version);
+		eep->baseEepHeader.version = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[0]);
+		eep->baseEepHeader.regDmn[0] = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[1]);
+		eep->baseEepHeader.regDmn[1] = word;
+
+		word = swab16(eep->baseEepHeader.rfSilent);
+		eep->baseEepHeader.rfSilent = word;
+
+		word = swab16(eep->baseEepHeader.blueToothOptions);
+		eep->baseEepHeader.blueToothOptions = word;
+
+		word = swab16(eep->baseEepHeader.deviceCap);
+		eep->baseEepHeader.deviceCap = word;
+
+		for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+			struct modal_eep_header *pModal =
+				&eep->modalHeader[j];
+			integer = swab32(pModal->antCtrlCommon);
+			pModal->antCtrlCommon = integer;
+
+			for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+				integer = swab32(pModal->antCtrlChain[i]);
+				pModal->antCtrlChain[i] = integer;
+			}
+
+			for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+				word = swab16(pModal->spurChans[i].spurChan);
+				pModal->spurChans[i].spurChan = word;
+			}
+		}
+	}
+
+	if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
+	    ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+			sum, ar5416_get_eep_ver(ahp));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+					   u8 *pVpdList, u16 numIntercepts,
+					   u8 *pRetVpdList)
+{
+	u16 i, k;
+	u8 currPwr = pwrMin;
+	u16 idxL = 0, idxR = 0;
+
+	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
+		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
+					       numIntercepts, &(idxL),
+					       &(idxR));
+		if (idxR < 1)
+			idxR = 1;
+		if (idxL == numIntercepts - 1)
+			idxL = (u16) (numIntercepts - 2);
+		if (pPwrList[idxL] == pPwrList[idxR])
+			k = pVpdList[idxL];
+		else
+			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
+				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
+				  (pPwrList[idxR] - pPwrList[idxL]));
+		pRetVpdList[i] = (u8) k;
+		currPwr += 2;
+	}
+
+	return true;
+}
+
+static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
+				struct ath9k_channel *chan,
+				struct cal_data_per_freq *pRawDataSet,
+				u8 *bChans, u16 availPiers,
+				u16 tPdGainOverlap, int16_t *pMinCalPower,
+				u16 *pPdGainBoundaries, u8 *pPDADCValues,
+				u16 numXpdGains)
+{
+	int i, j, k;
+	int16_t ss;
+	u16 idxL = 0, idxR = 0, numPiers;
+	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+	u8 minPwrT4[AR5416_NUM_PD_GAINS];
+	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+	int16_t vpdStep;
+	int16_t tmpVal;
+	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+	bool match;
+	int16_t minDelta = 0;
+	struct chan_centers centers;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	for (numPiers = 0; numPiers < availPiers; numPiers++) {
+		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+			break;
+	}
+
+	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+							     IS_CHAN_2GHZ(chan)),
+					       bChans, numPiers, &idxL, &idxR);
+
+	if (match) {
+		for (i = 0; i < numXpdGains; i++) {
+			minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+			maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+					pRawDataSet[idxL].pwrPdg[i],
+					pRawDataSet[idxL].vpdPdg[i],
+					AR5416_PD_GAIN_ICEPTS,
+					vpdTableI[i]);
+		}
+	} else {
+		for (i = 0; i < numXpdGains; i++) {
+			pVpdL = pRawDataSet[idxL].vpdPdg[i];
+			pPwrL = pRawDataSet[idxL].pwrPdg[i];
+			pVpdR = pRawDataSet[idxR].vpdPdg[i];
+			pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+			maxPwrT4[i] =
+				min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
+				    pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
+
+
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrL, pVpdL,
+						AR5416_PD_GAIN_ICEPTS,
+						vpdTableL[i]);
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrR, pVpdR,
+						AR5416_PD_GAIN_ICEPTS,
+						vpdTableR[i]);
+
+			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+				vpdTableI[i][j] =
+					(u8)(ath9k_hw_interpolate((u16)
+					     FREQ2FBIN(centers.
+						       synth_center,
+						       IS_CHAN_2GHZ
+						       (chan)),
+					     bChans[idxL], bChans[idxR],
+					     vpdTableL[i][j], vpdTableR[i][j]));
+			}
+		}
+	}
+
+	*pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+	k = 0;
+
+	for (i = 0; i < numXpdGains; i++) {
+		if (i == (numXpdGains - 1))
+			pPdGainBoundaries[i] =
+				(u16)(maxPwrT4[i] / 2);
+		else
+			pPdGainBoundaries[i] =
+				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+		pPdGainBoundaries[i] =
+			min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+		if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+			minDelta = pPdGainBoundaries[0] - 23;
+			pPdGainBoundaries[0] = 23;
+		} else {
+			minDelta = 0;
+		}
+
+		if (i == 0) {
+			if (AR_SREV_9280_10_OR_LATER(ah))
+				ss = (int16_t)(0 - (minPwrT4[i] / 2));
+			else
+				ss = 0;
+		} else {
+			ss = (int16_t)((pPdGainBoundaries[i - 1] -
+					(minPwrT4[i] / 2)) -
+				       tPdGainOverlap + 1 + minDelta);
+		}
+		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+			ss++;
+		}
+
+		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+				(minPwrT4[i] / 2));
+		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+			tgtIndex : sizeCurrVpdTable;
+
+		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			pPDADCValues[k++] = vpdTableI[i][ss++];
+		}
+
+		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+				    vpdTableI[i][sizeCurrVpdTable - 2]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		if (tgtIndex > maxIndex) {
+			while ((ss <= tgtIndex) &&
+			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+						    (ss - maxIndex + 1) * vpdStep));
+				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+							 255 : tmpVal);
+				ss++;
+			}
+		}
+	}
+
+	while (i < AR5416_PD_GAINS_IN_MASK) {
+		pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
+		i++;
+	}
+
+	while (k < AR5416_NUM_PDADC_VALUES) {
+		pPDADCValues[k] = pPDADCValues[k - 1];
+		k++;
+	}
+
+	return;
+}
+
+static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
+				      struct ath9k_channel *chan,
+				      struct cal_target_power_leg *powInfo,
+				      u16 numChannels,
+				      struct cal_target_power_leg *pNewPower,
+				      u16 numRates, bool isExtTarget)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
+				       IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						      IS_CHAN_2GHZ(chan))) &&
+				   (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						      IS_CHAN_2GHZ(chan)))) {
+				lowIndex = i - 1;
+				break;
+			}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] =
+				(u8)ath9k_hw_interpolate(freq, clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+static void ath9k_hw_get_target_powers(struct ath_hal *ah,
+				       struct ath9k_channel *chan,
+				       struct cal_target_power_ht *powInfo,
+				       u16 numChannels,
+				       struct cal_target_power_ht *pNewPower,
+				       u16 numRates, bool isHt40Target)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else
+				if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) &&
+				    (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						       IS_CHAN_2GHZ(chan)))) {
+					lowIndex = i - 1;
+					break;
+				}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
+						clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+static u16 ath9k_hw_get_max_edge_power(u16 freq,
+				       struct cal_ctl_edges *pRdEdgesPower,
+				       bool is2GHz)
+{
+	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+	int i;
+
+	for (i = 0; (i < AR5416_NUM_BAND_EDGES) &&
+		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
+			twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+			break;
+		} else if ((i > 0) &&
+			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
+						      is2GHz))) {
+			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
+					       is2GHz) < freq &&
+			    pRdEdgesPower[i - 1].flag) {
+				twiceMaxEdgePower =
+					pRdEdgesPower[i - 1].tPower;
+			}
+			break;
+		}
+	}
+
+	return twiceMaxEdgePower;
+}
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+			 struct ath9k_channel *chan,
+			 u16 cfgCtl,
+			 u8 twiceAntennaReduction,
+			 u8 twiceMaxRegulatoryPower,
+			 u8 powerLimit)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *pEepData = &ahp->ah_eeprom;
+	struct modal_eep_header *pModal =
+		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+	int16_t ratesArray[Ar5416RateSize];
+	int16_t txPowerIndexOffset = 0;
+	u8 ht40PowerIncForPdadc = 2;
+	int i;
+
+	memset(ratesArray, 0, sizeof(ratesArray));
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+	}
+
+	if (!ath9k_hw_set_power_per_rate_table(ah, chan,
+					       &ratesArray[0], cfgCtl,
+					       twiceAntennaReduction,
+					       twiceMaxRegulatoryPower,
+					       powerLimit)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"ath9k_hw_set_txpower: unable to set "
+			"tx power per rate table\n");
+		return -EIO;
+	}
+
+	if (!ath9k_hw_set_power_cal_table(ah, chan, &txPowerIndexOffset)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			 "ath9k_hw_set_txpower: unable to set power table\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
+		if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+			ratesArray[i] = AR5416_MAX_RATE_POWER;
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		for (i = 0; i < Ar5416RateSize; i++)
+			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+	if (IS_CHAN_2GHZ(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+			  ATH9K_POW_SM(ratesArray[rate2s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate2l], 16)
+			  | ATH9K_POW_SM(ratesArray[rateXr], 8)
+			  | ATH9K_POW_SM(ratesArray[rate1l], 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+			  ATH9K_POW_SM(ratesArray[rate11s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate11l], 16)
+			  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+	if (IS_CHAN_HT40(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+					 ht40PowerIncForPdadc, 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+					 ht40PowerIncForPdadc, 0));
+
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+	i = rate6mb;
+
+	if (IS_CHAN_HT40(chan))
+		i = rateHt40_0;
+	else if (IS_CHAN_HT20(chan))
+		i = rateHt20_0;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		ah->ah_maxPowerLevel =
+			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+	else
+		ah->ah_maxPowerLevel = ratesArray[i];
+
+	return 0;
+}
+
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+	struct modal_eep_header *pModal;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+	u8 biaslevel;
+
+	if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+		return;
+
+	if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+		return;
+
+	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+	if (pModal->xpaBiasLvl != 0xff) {
+		biaslevel = pModal->xpaBiasLvl;
+	} else {
+		u16 resetFreqBin, freqBin, freqCount = 0;
+		struct chan_centers centers;
+
+		ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+		resetFreqBin = FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan));
+		freqBin = pModal->xpaBiasLvlFreq[0] & 0xff;
+		biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14);
+
+		freqCount++;
+
+		while (freqCount < 3) {
+			if (pModal->xpaBiasLvlFreq[freqCount] == 0x0)
+				break;
+
+			freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff;
+			if (resetFreqBin >= freqBin) {
+				biaslevel = (u8)(pModal->xpaBiasLvlFreq[freqCount] >> 14);
+			} else {
+				break;
+			}
+			freqCount++;
+		}
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		INI_RA(&ahp->ah_iniAddac, 7, 1) =
+			(INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel	<< 3;
+	} else {
+		INI_RA(&ahp->ah_iniAddac, 6, 1) =
+			(INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel	<< 6;
+	}
+}
+
+bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
+				       struct ath9k_channel *chan,
+				       int16_t *ratesArray,
+				       u16 cfgCtl,
+				       u8 AntennaReduction,
+				       u8 twiceMaxRegulatoryPower,
+				       u8 powerLimit)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *pEepData = &ahp->ah_eeprom;
+	u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] =
+		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+	int i;
+	int8_t twiceLargestAntenna;
+	struct cal_ctl_data *rep;
+	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+		0, { 0, 0, 0, 0}
+	};
+	struct cal_target_power_leg targetPowerOfdmExt = {
+		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+		0, { 0, 0, 0, 0 }
+	};
+	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+		0, {0, 0, 0, 0}
+	};
+	u8 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	u16 ctlModesFor11a[] =
+		{ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
+	u16 ctlModesFor11g[] =
+		{ CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+		  CTL_2GHT40
+		};
+	u16 numCtlModes, *pCtlMode, ctlMode, freq;
+	struct chan_centers centers;
+	int tx_chainmask;
+	u8 twiceMinEdgePower;
+
+	tx_chainmask = ahp->ah_txchainmask;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	twiceLargestAntenna = max(
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+	twiceLargestAntenna = max((u8)twiceLargestAntenna,
+				  pEepData->modalHeader
+				  [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+	twiceLargestAntenna = (int8_t)min(AntennaReduction - twiceLargestAntenna, 0);
+
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+
+	switch (ar5416_get_ntxchains(tx_chainmask)) {
+	case 1:
+		break;
+	case 2:
+		scaledPower -=
+			pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain;
+		break;
+	case 3:
+		scaledPower -=
+			pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain;
+		break;
+	}
+
+	scaledPower = max(0, (int32_t) scaledPower);
+
+	if (IS_CHAN_2GHZ(chan)) {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+			SUB_NUM_CTL_MODES_AT_2G_40;
+		pCtlMode = ctlModesFor11g;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPowerCck,
+			AR5416_NUM_2G_CCK_TARGET_POWERS,
+			&targetPowerCck, 4, false);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower2G,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, false);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower2GHT20,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, false);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower2GHT40,
+				AR5416_NUM_2G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPowerCck,
+				AR5416_NUM_2G_CCK_TARGET_POWERS,
+				&targetPowerCckExt, 4, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower2G,
+				AR5416_NUM_2G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, true);
+		}
+	} else {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+			SUB_NUM_CTL_MODES_AT_5G_40;
+		pCtlMode = ctlModesFor11a;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower5G,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, false);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower5GHT20,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, false);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower5GHT40,
+				AR5416_NUM_5G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower5G,
+				AR5416_NUM_5G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, true);
+		}
+	}
+
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2)
+			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+			"EXT_ADDITIVE %d\n",
+			ctlMode, numCtlModes, isHt40CtlMode,
+			(pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+		for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+				"  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+				"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+				"chan %d\n",
+				i, cfgCtl, pCtlMode[ctlMode],
+				pEepData->ctlIndex[i], chan->channel);
+
+			if ((((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     pEepData->ctlIndex[i]) ||
+			    (((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+				rep = &(pEepData->ctlData[i]);
+
+				twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+				rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
+				IS_CHAN_2GHZ(chan));
+
+				DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+					"    MATCH-EE_IDX %d: ch %d is2 %d "
+					"2xMinEdge %d chainmask %d chains %d\n",
+					i, freq, IS_CHAN_2GHZ(chan),
+					twiceMinEdgePower, tx_chainmask,
+					ar5416_get_ntxchains
+					(tx_chainmask));
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower = min(twiceMaxEdgePower,
+								twiceMinEdgePower);
+				} else {
+					twiceMaxEdgePower = twiceMinEdgePower;
+					break;
+				}
+			}
+		}
+
+		minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"    SEL-Min ctlMode %d pCtlMode %d "
+			"2xMaxEdge %d sP %d minCtlPwr %d\n",
+			ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+			scaledPower, minCtlPower);
+
+		switch (pCtlMode[ctlMode]) {
+		case CTL_11B:
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+				targetPowerCck.tPow2x[i] =
+					min(targetPowerCck.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11A:
+		case CTL_11G:
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+				targetPowerOfdm.tPow2x[i] =
+					min(targetPowerOfdm.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_5GHT20:
+		case CTL_2GHT20:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+				targetPowerHt20.tPow2x[i] =
+					min(targetPowerHt20.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11B_EXT:
+			targetPowerCckExt.tPow2x[0] =
+				min(targetPowerCckExt.tPow2x[0], minCtlPower);
+			break;
+		case CTL_11A_EXT:
+		case CTL_11G_EXT:
+			targetPowerOfdmExt.tPow2x[0] =
+				min(targetPowerOfdmExt.tPow2x[0], minCtlPower);
+			break;
+		case CTL_5GHT40:
+		case CTL_2GHT40:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+				targetPowerHt40.tPow2x[i] =
+					min(targetPowerHt40.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+		ratesArray[rate18mb] = ratesArray[rate24mb] =
+		targetPowerOfdm.tPow2x[0];
+	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+	if (IS_CHAN_2GHZ(chan)) {
+		ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+		ratesArray[rate2s] = ratesArray[rate2l] =
+			targetPowerCck.tPow2x[1];
+		ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+			targetPowerCck.tPow2x[2];
+		;
+		ratesArray[rate11s] = ratesArray[rate11l] =
+			targetPowerCck.tPow2x[3];
+		;
+	}
+	if (IS_CHAN_HT40(chan)) {
+		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+			ratesArray[rateHt40_0 + i] =
+				targetPowerHt40.tPow2x[i];
+		}
+		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+		if (IS_CHAN_2GHZ(chan)) {
+			ratesArray[rateExtCck] =
+				targetPowerCckExt.tPow2x[0];
+		}
+	}
+	return true;
+}
+
+bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *pEepData = &ahp->ah_eeprom;
+	struct cal_data_per_freq *pRawDataset;
+	u8 *pCalBChans = NULL;
+	u16 pdGainOverlap_t2;
+	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+	u16 numPiers, i, j;
+	int16_t tMinCalPower;
+	u16 numXpdGain, xpdMask;
+	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+	u32 reg32, regOffset, regChainOffset;
+	int16_t modalIdx;
+
+	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+	xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		pdGainOverlap_t2 =
+			pEepData->modalHeader[modalIdx].pdGainOverlap;
+	} else {
+		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		pCalBChans = pEepData->calFreqPier2G;
+		numPiers = AR5416_NUM_2G_CAL_PIERS;
+	} else {
+		pCalBChans = pEepData->calFreqPier5G;
+		numPiers = AR5416_NUM_5G_CAL_PIERS;
+	}
+
+	numXpdGain = 0;
+
+	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+			if (numXpdGain >= AR5416_NUM_PD_GAINS)
+				break;
+			xpdGainValues[numXpdGain] =
+				(u16)(AR5416_PD_GAINS_IN_MASK - i);
+			numXpdGain++;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+		      (numXpdGain - 1) & 0x3);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+		      xpdGainValues[0]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+		      xpdGainValues[1]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+		      xpdGainValues[2]);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_5416_V20_OR_LATER(ah) &&
+		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
+		    (i != 0)) {
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		} else
+			regChainOffset = i * 0x1000;
+
+		if (pEepData->baseEepHeader.txMask & (1 << i)) {
+			if (IS_CHAN_2GHZ(chan))
+				pRawDataset = pEepData->calPierData2G[i];
+			else
+				pRawDataset = pEepData->calPierData5G[i];
+
+			ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
+					    pRawDataset, pCalBChans,
+					    numPiers, pdGainOverlap_t2,
+					    &tMinCalPower, gainBoundaries,
+					    pdadcValues, numXpdGain);
+
+			if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+				REG_WRITE(ah,
+					  AR_PHY_TPCRG5 + regChainOffset,
+					  SM(pdGainOverlap_t2,
+					     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+					  | SM(gainBoundaries[0],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+					  | SM(gainBoundaries[1],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+					  | SM(gainBoundaries[2],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+					  | SM(gainBoundaries[3],
+				       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+			}
+
+			regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+			for (j = 0; j < 32; j++) {
+				reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+					((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+					((pdadcValues[4 * j + 2] & 0xFF) << 16) |
+					((pdadcValues[4 * j + 3] & 0xFF) << 24);
+				REG_WRITE(ah, regOffset, reg32);
+
+				DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+					"PDADC (%d,%4x): %4.4x %8.8x\n",
+					i, regChainOffset, regOffset,
+					reg32);
+				DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+					"PDADC: Chain %d | PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d |\n",
+					i, 4 * j, pdadcValues[4 * j],
+					4 * j + 1, pdadcValues[4 * j + 1],
+					4 * j + 2, pdadcValues[4 * j + 2],
+					4 * j + 3,
+					pdadcValues[4 * j + 3]);
+
+				regOffset += 4;
+			}
+		}
+	}
+
+	*pTxPowerIndexOffset = 0;
+
+	return true;
+}
+
+/* XXX: Clean me up, make me more legible */
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+				      struct ath9k_channel *chan)
+{
+	struct modal_eep_header *pModal;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+	int i, regChainOffset;
+	u8 txRxAttenLocal;
+	u16 ant_config;
+
+	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+	txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+
+	ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 1, &ant_config);
+	REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_9280(ah)) {
+			if (i >= 2)
+				break;
+		}
+
+		if (AR_SREV_5416_V20_OR_LATER(ah) &&
+		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
+		    && (i != 0))
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		else
+			regChainOffset = i * 0x1000;
+
+		REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+			  pModal->antCtrlChain[i]);
+
+		REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+			  (REG_READ(ah,
+				    AR_PHY_TIMING_CTRL4(0) +
+				    regChainOffset) &
+			   ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+			  SM(pModal->iqCalICh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+			  SM(pModal->iqCalQCh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+		if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+			if ((eep->baseEepHeader.version &
+			     AR5416_EEP_VER_MINOR_MASK) >=
+			    AR5416_EEP_MINOR_VER_3) {
+				txRxAttenLocal = pModal->txRxAttenCh[i];
+				if (AR_SREV_9280_10_OR_LATER(ah)) {
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+						pModal->
+						bswMargin[i]);
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+						pModal->
+						bswAtten[i]);
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+						pModal->
+						xatten2Margin[i]);
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+						pModal->
+						xatten2Db[i]);
+				} else {
+					REG_WRITE(ah,
+						  AR_PHY_GAIN_2GHZ +
+						  regChainOffset,
+						  (REG_READ(ah,
+							    AR_PHY_GAIN_2GHZ +
+							    regChainOffset) &
+						   ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+						  | SM(pModal->
+						  bswMargin[i],
+						  AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+					REG_WRITE(ah,
+						  AR_PHY_GAIN_2GHZ +
+						  regChainOffset,
+						  (REG_READ(ah,
+							    AR_PHY_GAIN_2GHZ +
+							    regChainOffset) &
+						   ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+						  | SM(pModal->bswAtten[i],
+						  AR_PHY_GAIN_2GHZ_BSW_ATTEN));
+				}
+			}
+			if (AR_SREV_9280_10_OR_LATER(ah)) {
+				REG_RMW_FIELD(ah,
+					      AR_PHY_RXGAIN +
+					      regChainOffset,
+					      AR9280_PHY_RXGAIN_TXRX_ATTEN,
+					      txRxAttenLocal);
+				REG_RMW_FIELD(ah,
+					      AR_PHY_RXGAIN +
+					      regChainOffset,
+					      AR9280_PHY_RXGAIN_TXRX_MARGIN,
+					      pModal->rxTxMarginCh[i]);
+			} else {
+				REG_WRITE(ah,
+					  AR_PHY_RXGAIN + regChainOffset,
+					  (REG_READ(ah,
+						    AR_PHY_RXGAIN +
+						    regChainOffset) &
+					   ~AR_PHY_RXGAIN_TXRX_ATTEN) |
+					  SM(txRxAttenLocal,
+					     AR_PHY_RXGAIN_TXRX_ATTEN));
+				REG_WRITE(ah,
+					  AR_PHY_GAIN_2GHZ +
+					  regChainOffset,
+					  (REG_READ(ah,
+						    AR_PHY_GAIN_2GHZ +
+						    regChainOffset) &
+					   ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+					  SM(pModal->rxTxMarginCh[i],
+					     AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
+			}
+		}
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		if (IS_CHAN_2GHZ(chan)) {
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+						  AR_AN_RF2G1_CH0_OB,
+						  AR_AN_RF2G1_CH0_OB_S,
+						  pModal->ob);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+						  AR_AN_RF2G1_CH0_DB,
+						  AR_AN_RF2G1_CH0_DB_S,
+						  pModal->db);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+						  AR_AN_RF2G1_CH1_OB,
+						  AR_AN_RF2G1_CH1_OB_S,
+						  pModal->ob_ch1);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+						  AR_AN_RF2G1_CH1_DB,
+						  AR_AN_RF2G1_CH1_DB_S,
+						  pModal->db_ch1);
+		} else {
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+						  AR_AN_RF5G1_CH0_OB5,
+						  AR_AN_RF5G1_CH0_OB5_S,
+						  pModal->ob);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+						  AR_AN_RF5G1_CH0_DB5,
+						  AR_AN_RF5G1_CH0_DB5_S,
+						  pModal->db);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+						  AR_AN_RF5G1_CH1_OB5,
+						  AR_AN_RF5G1_CH1_OB5_S,
+						  pModal->ob_ch1);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+						  AR_AN_RF5G1_CH1_DB5,
+						  AR_AN_RF5G1_CH1_DB5_S,
+						  pModal->db_ch1);
+		}
+		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+					  AR_AN_TOP2_XPABIAS_LVL,
+					  AR_AN_TOP2_XPABIAS_LVL_S,
+					  pModal->xpaBiasLvl);
+		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+					  AR_AN_TOP2_LOCALBIAS,
+					  AR_AN_TOP2_LOCALBIAS_S,
+					  pModal->local_bias);
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n",
+			pModal->force_xpaon);
+		REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
+			      pModal->force_xpaon);
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+		      pModal->switchSettling);
+	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+		      pModal->adcDesiredSize);
+
+	if (!AR_SREV_9280_10_OR_LATER(ah))
+		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+			      AR_PHY_DESIRED_SZ_PGA,
+			      pModal->pgaDesiredSize);
+
+	REG_WRITE(ah, AR_PHY_RF_CTL4,
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+		  | SM(pModal->txEndToXpaOff,
+		       AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+		  | SM(pModal->txFrameToXpaOn,
+		       AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+		  | SM(pModal->txFrameToXpaOn,
+		       AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+		      pModal->txEndToRxOn);
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+			      pModal->thresh62);
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+			      AR_PHY_EXT_CCA0_THRESH62,
+			      pModal->thresh62);
+	} else {
+		REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
+			      pModal->thresh62);
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+			      AR_PHY_EXT_CCA_THRESH62,
+			      pModal->thresh62);
+	}
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+			      AR_PHY_TX_END_DATA_START,
+			      pModal->txFrameToDataStart);
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+			      pModal->txFrameToPaOn);
+	}
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_3) {
+		if (IS_CHAN_HT40(chan))
+			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+				      AR_PHY_SETTLING_SWITCH,
+				      pModal->swSettleHt40);
+	}
+
+	return true;
+}
+
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+				    struct ath9k_channel *chan,
+				    u8 index, u16 *config)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+	struct modal_eep_header *pModal =
+		&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+
+	switch (index) {
+	case 0:
+		*config = pModal->antCtrlCommon & 0xFFFF;
+		return 0;
+	case 1:
+		if (pBase->version >= 0x0E0D) {
+			if (pModal->useAnt1) {
+				*config =
+				((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
+				return 0;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+			       enum ieee80211_band freq_band)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+	struct modal_eep_header *pModal =
+		&(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]);
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+	u8 num_ant_config;
+
+	num_ant_config = 1;
+
+	if (pBase->version >= 0x0E0D)
+		if (pModal->useAnt1)
+			num_ant_config += 1;
+
+	return num_ant_config;
+}
+
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep =
+		(struct ar5416_eeprom *) &ahp->ah_eeprom;
+	u16 spur_val = AR_NO_SPUR;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"Getting spur idx %d is2Ghz. %d val %x\n",
+		i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
+
+	switch (ah->ah_config.spurmode) {
+	case SPUR_DISABLE:
+		break;
+	case SPUR_ENABLE_IOCTL:
+		spur_val = ah->ah_config.spurchans[i][is2GHz];
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"Getting spur val from new loc. %d\n", spur_val);
+		break;
+	case SPUR_ENABLE_EEPROM:
+		spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan;
+		break;
+
+	}
+
+	return spur_val;
+}
+
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
+			enum eeprom_param param)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+	struct modal_eep_header *pModal = eep->modalHeader;
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+
+	switch (param) {
+	case EEP_NFTHRESH_5:
+		return -pModal[0].noiseFloorThreshCh[0];
+	case EEP_NFTHRESH_2:
+		return -pModal[1].noiseFloorThreshCh[0];
+	case AR_EEPROM_MAC(0):
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case AR_EEPROM_MAC(1):
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case AR_EEPROM_MAC(2):
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_OB_5:
+		return pModal[0].ob;
+	case EEP_DB_5:
+		return pModal[0].db;
+	case EEP_OB_2:
+		return pModal[1].ob;
+	case EEP_DB_2:
+		return pModal[1].db;
+	case EEP_MINOR_REV:
+		return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	default:
+		return 0;
+	}
+}
+
+int ath9k_hw_eeprom_attach(struct ath_hal *ah)
+{
+	int status;
+
+	if (ath9k_hw_use_flash(ah))
+		ath9k_hw_flash_map(ah);
+
+	if (!ath9k_hw_fill_eeprom(ah))
+		return -EIO;
+
+	status = ath9k_hw_check_eeprom(ah);
+
+	return status;
+}

File diff suppressed because it is too large
+ 311 - 1029
drivers/net/wireless/ath9k/hw.c


+ 1 - 1
drivers/net/wireless/ath9k/hw.h

@@ -923,7 +923,7 @@ struct ath_hal_5416 {
 #define OFDM_PLCP_BITS_QUARTER      22
 #define OFDM_SYMBOL_TIME_QUARTER    16
 
-u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
 			enum eeprom_param param);
 
 #endif

+ 1031 - 0
drivers/net/wireless/ath9k/mac.c

@@ -0,0 +1,1031 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
+					struct ath9k_tx_queue_info *qi)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+		"%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+		__func__, ahp->ah_txOkInterruptMask,
+		ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask,
+		ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask);
+
+	REG_WRITE(ah, AR_IMR_S0,
+		  SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
+		  | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
+	REG_WRITE(ah, AR_IMR_S1,
+		  SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
+		  | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
+	REG_RMW_FIELD(ah, AR_IMR_S2,
+		      AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+}
+
+void ath9k_hw_dmaRegDump(struct ath_hal *ah)
+{
+	u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
+	int qcuOffset = 0, dcuOffset = 0;
+	u32 *qcuBase = &val[0], *dcuBase = &val[4];
+	int i;
+
+	REG_WRITE(ah, AR_MACMISC,
+		  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+		   (AR_MACMISC_MISC_OBS_BUS_1 <<
+		    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n");
+
+	for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
+		if (i % 4 == 0)
+			DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
+
+		val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
+		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]);
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n");
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
+
+	for (i = 0; i < ATH9K_NUM_QUEUES;
+	     i++, qcuOffset += 4, dcuOffset += 5) {
+		if (i == 8) {
+			qcuOffset = 0;
+			qcuBase++;
+		}
+
+		if (i == 6) {
+			dcuOffset = 0;
+			dcuBase++;
+		}
+
+		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+			"%2d          %2x      %1x     %2x           %2x\n",
+			i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
+			(*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
+			val[2] & (0x7 << (i * 3)) >> (i * 3),
+			(*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
+		(val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"qcu_complete state: %2x    dcu_complete state:     %2x\n",
+		(val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"dcu_arb state:      %2x    dcu_fp state:           %2x\n",
+		(val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
+		(val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
+		(val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
+		(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n",
+		REG_READ(ah, AR_OBS_BUS_1));
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"AR_CR 0x%x \n", REG_READ(ah, AR_CR));
+}
+
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+{
+	return REG_READ(ah, AR_QTXDP(q));
+}
+
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp)
+{
+	REG_WRITE(ah, AR_QTXDP(q), txdp);
+
+	return true;
+}
+
+bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+{
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+
+	REG_WRITE(ah, AR_Q_TXE, 1 << q);
+
+	return true;
+}
+
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+{
+	u32 npend;
+
+	npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
+	if (npend == 0) {
+
+		if (REG_READ(ah, AR_Q_TXE) & (1 << q))
+			npend = 1;
+	}
+
+	return npend;
+}
+
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 txcfg, curLevel, newLevel;
+	enum ath9k_int omask;
+
+	if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
+		return false;
+
+	omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
+
+	txcfg = REG_READ(ah, AR_TXCFG);
+	curLevel = MS(txcfg, AR_FTRIG);
+	newLevel = curLevel;
+	if (bIncTrigLevel) {
+		if (curLevel < MAX_TX_FIFO_THRESHOLD)
+			newLevel++;
+	} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
+		newLevel--;
+	if (newLevel != curLevel)
+		REG_WRITE(ah, AR_TXCFG,
+			  (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+
+	ath9k_hw_set_interrupts(ah, omask);
+
+	ah->ah_txTrigLevel = newLevel;
+
+	return newLevel != curLevel;
+}
+
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+{
+	u32 tsfLow, j, wait;
+
+	REG_WRITE(ah, AR_Q_TXD, 1 << q);
+
+	for (wait = 1000; wait != 0; wait--) {
+		if (ath9k_hw_numtxpending(ah, q) == 0)
+			break;
+		udelay(100);
+	}
+
+	if (ath9k_hw_numtxpending(ah, q)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+			"%s: Num of pending TX Frames %d on Q %d\n",
+			__func__, ath9k_hw_numtxpending(ah, q), q);
+
+		for (j = 0; j < 2; j++) {
+			tsfLow = REG_READ(ah, AR_TSF_L32);
+			REG_WRITE(ah, AR_QUIET2,
+				  SM(10, AR_QUIET2_QUIET_DUR));
+			REG_WRITE(ah, AR_QUIET_PERIOD, 100);
+			REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
+			REG_SET_BIT(ah, AR_TIMER_MODE,
+				       AR_QUIET_TIMER_EN);
+
+			if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
+				break;
+
+			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+				"%s: TSF have moved while trying to set "
+				"quiet time TSF: 0x%08x\n",
+				__func__, tsfLow);
+		}
+
+		REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+
+		udelay(200);
+		REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+
+		wait = 1000;
+
+		while (ath9k_hw_numtxpending(ah, q)) {
+			if ((--wait) == 0) {
+				DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+					"%s: Failed to stop Tx DMA in 100 "
+					"msec after killing last frame\n",
+					__func__);
+				break;
+			}
+			udelay(100);
+		}
+
+		REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+	}
+
+	REG_WRITE(ah, AR_Q_TXD, 0);
+
+	return wait != 0;
+}
+
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+			 u32 segLen, bool firstSeg,
+			 bool lastSeg, const struct ath_desc *ds0)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if (firstSeg) {
+		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
+	} else if (lastSeg) {
+		ads->ds_ctl0 = 0;
+		ads->ds_ctl1 = segLen;
+		ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
+		ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+	} else {
+		ads->ds_ctl0 = 0;
+		ads->ds_ctl1 = segLen | AR_TxMore;
+		ads->ds_ctl2 = 0;
+		ads->ds_ctl3 = 0;
+	}
+	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+
+	return true;
+}
+
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if ((ads->ds_txstatus9 & AR_TxDone) == 0)
+		return -EINPROGRESS;
+
+	ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
+	ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
+	ds->ds_txstat.ts_status = 0;
+	ds->ds_txstat.ts_flags = 0;
+
+	if (ads->ds_txstatus1 & AR_ExcessiveRetries)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
+	if (ads->ds_txstatus1 & AR_Filtered)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
+	if (ads->ds_txstatus1 & AR_FIFOUnderrun)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+	if (ads->ds_txstatus9 & AR_TxOpExceeded)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
+	if (ads->ds_txstatus1 & AR_TxTimerExpired)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+
+	if (ads->ds_txstatus1 & AR_DescCfgErr)
+		ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+	if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
+		ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, true);
+	}
+	if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
+		ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, true);
+	}
+	if (ads->ds_txstatus0 & AR_TxBaStatus) {
+		ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
+		ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
+		ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
+	}
+
+	ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
+	switch (ds->ds_txstat.ts_rateindex) {
+	case 0:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
+		break;
+	case 1:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
+		break;
+	case 2:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
+		break;
+	case 3:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
+		break;
+	}
+
+	ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
+	ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
+	ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
+	ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
+	ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
+	ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
+	ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
+	ds->ds_txstat.evm0 = ads->AR_TxEVM0;
+	ds->ds_txstat.evm1 = ads->AR_TxEVM1;
+	ds->ds_txstat.evm2 = ads->AR_TxEVM2;
+	ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
+	ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
+	ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+	ds->ds_txstat.ts_antenna = 1;
+
+	return 0;
+}
+
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+			    u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	txPower += ahp->ah_txPowerIndexOffset;
+	if (txPower > 63)
+		txPower = 63;
+
+	ads->ds_ctl0 = (pktLen & AR_FrameLen)
+		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+		| SM(txPower, AR_XmitPower)
+		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+		| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+	ads->ds_ctl1 =
+		(keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+		| SM(type, AR_FrameType)
+		| (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+		| (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+		| (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+	ads->ds_ctl6 = SM(keyType, AR_EncrType);
+
+	if (AR_SREV_9285(ah)) {
+		ads->ds_ctl8 = 0;
+		ads->ds_ctl9 = 0;
+		ads->ds_ctl10 = 0;
+		ads->ds_ctl11 = 0;
+	}
+}
+
+void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
+				  struct ath_desc *lastds,
+				  u32 durUpdateEn, u32 rtsctsRate,
+				  u32 rtsctsDuration,
+				  struct ath9k_11n_rate_series series[],
+				  u32 nseries, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ar5416_desc *last_ads = AR5416DESC(lastds);
+	u32 ds_ctl0;
+
+	(void) nseries;
+	(void) rtsctsDuration;
+
+	if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+		ds_ctl0 = ads->ds_ctl0;
+
+		if (flags & ATH9K_TXDESC_RTSENA) {
+			ds_ctl0 &= ~AR_CTSEnable;
+			ds_ctl0 |= AR_RTSEnable;
+		} else {
+			ds_ctl0 &= ~AR_RTSEnable;
+			ds_ctl0 |= AR_CTSEnable;
+		}
+
+		ads->ds_ctl0 = ds_ctl0;
+	} else {
+		ads->ds_ctl0 =
+			(ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+	}
+
+	ads->ds_ctl2 = set11nTries(series, 0)
+		| set11nTries(series, 1)
+		| set11nTries(series, 2)
+		| set11nTries(series, 3)
+		| (durUpdateEn ? AR_DurUpdateEna : 0)
+		| SM(0, AR_BurstDur);
+
+	ads->ds_ctl3 = set11nRate(series, 0)
+		| set11nRate(series, 1)
+		| set11nRate(series, 2)
+		| set11nRate(series, 3);
+
+	ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
+		| set11nPktDurRTSCTS(series, 1);
+
+	ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
+		| set11nPktDurRTSCTS(series, 3);
+
+	ads->ds_ctl7 = set11nRateFlags(series, 0)
+		| set11nRateFlags(series, 1)
+		| set11nRateFlags(series, 2)
+		| set11nRateFlags(series, 3)
+		| SM(rtsctsRate, AR_RTSCTSRate);
+	last_ads->ds_ctl2 = ads->ds_ctl2;
+	last_ads->ds_ctl3 = ads->ds_ctl3;
+}
+
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+				u32 aggrLen)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+	ads->ds_ctl6 &= ~AR_AggrLen;
+	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+}
+
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+				 u32 numDelims)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	unsigned int ctl6;
+
+	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+	ctl6 = ads->ds_ctl6;
+	ctl6 &= ~AR_PadDelim;
+	ctl6 |= SM(numDelims, AR_PadDelim);
+	ads->ds_ctl6 = ctl6;
+}
+
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 |= AR_IsAggr;
+	ads->ds_ctl1 &= ~AR_MoreAggr;
+	ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
+				   u32 burstDuration)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl2 &= ~AR_BurstDur;
+	ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+}
+
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+				     u32 vmf)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if (vmf)
+		ads->ds_ctl0 |= AR_VirtMoreFrag;
+	else
+		ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+}
+
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	*txqs &= ahp->ah_intrTxqs;
+	ahp->ah_intrTxqs &= ~(*txqs);
+}
+
+bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
+			    const struct ath9k_tx_queue_info *qinfo)
+{
+	u32 cw;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_tx_queue_info *qi;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+			 __func__, q);
+		return false;
+	}
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
+			 __func__);
+		return false;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi);
+
+	qi->tqi_ver = qinfo->tqi_ver;
+	qi->tqi_subtype = qinfo->tqi_subtype;
+	qi->tqi_qflags = qinfo->tqi_qflags;
+	qi->tqi_priority = qinfo->tqi_priority;
+	if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
+		qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
+	else
+		qi->tqi_aifs = INIT_AIFS;
+	if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
+		cw = min(qinfo->tqi_cwmin, 1024U);
+		qi->tqi_cwmin = 1;
+		while (qi->tqi_cwmin < cw)
+			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
+	} else
+		qi->tqi_cwmin = qinfo->tqi_cwmin;
+	if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
+		cw = min(qinfo->tqi_cwmax, 1024U);
+		qi->tqi_cwmax = 1;
+		while (qi->tqi_cwmax < cw)
+			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
+	} else
+		qi->tqi_cwmax = INIT_CWMAX;
+
+	if (qinfo->tqi_shretry != 0)
+		qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
+	else
+		qi->tqi_shretry = INIT_SH_RETRY;
+	if (qinfo->tqi_lgretry != 0)
+		qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
+	else
+		qi->tqi_lgretry = INIT_LG_RETRY;
+	qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
+	qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
+	qi->tqi_burstTime = qinfo->tqi_burstTime;
+	qi->tqi_readyTime = qinfo->tqi_readyTime;
+
+	switch (qinfo->tqi_subtype) {
+	case ATH9K_WME_UPSD:
+		if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
+			qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
+		break;
+	default:
+		break;
+	}
+
+	return true;
+}
+
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+			    struct ath9k_tx_queue_info *qinfo)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_tx_queue_info *qi;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+			 __func__, q);
+		return false;
+	}
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
+			 __func__);
+		return false;
+	}
+
+	qinfo->tqi_qflags = qi->tqi_qflags;
+	qinfo->tqi_ver = qi->tqi_ver;
+	qinfo->tqi_subtype = qi->tqi_subtype;
+	qinfo->tqi_qflags = qi->tqi_qflags;
+	qinfo->tqi_priority = qi->tqi_priority;
+	qinfo->tqi_aifs = qi->tqi_aifs;
+	qinfo->tqi_cwmin = qi->tqi_cwmin;
+	qinfo->tqi_cwmax = qi->tqi_cwmax;
+	qinfo->tqi_shretry = qi->tqi_shretry;
+	qinfo->tqi_lgretry = qi->tqi_lgretry;
+	qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
+	qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
+	qinfo->tqi_burstTime = qi->tqi_burstTime;
+	qinfo->tqi_readyTime = qi->tqi_readyTime;
+
+	return true;
+}
+
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+			  const struct ath9k_tx_queue_info *qinfo)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_tx_queue_info *qi;
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	int q;
+
+	switch (type) {
+	case ATH9K_TX_QUEUE_BEACON:
+		q = pCap->total_queues - 1;
+		break;
+	case ATH9K_TX_QUEUE_CAB:
+		q = pCap->total_queues - 2;
+		break;
+	case ATH9K_TX_QUEUE_PSPOLL:
+		q = 1;
+		break;
+	case ATH9K_TX_QUEUE_UAPSD:
+		q = pCap->total_queues - 3;
+		break;
+	case ATH9K_TX_QUEUE_DATA:
+		for (q = 0; q < pCap->total_queues; q++)
+			if (ahp->ah_txq[q].tqi_type ==
+			    ATH9K_TX_QUEUE_INACTIVE)
+				break;
+		if (q == pCap->total_queues) {
+			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+				"%s: no available tx queue\n", __func__);
+			return -1;
+		}
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n",
+			__func__, type);
+		return -1;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+			"%s: tx queue %u already active\n", __func__, q);
+		return -1;
+	}
+	memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
+	qi->tqi_type = type;
+	if (qinfo == NULL) {
+		qi->tqi_qflags =
+			TXQ_FLAG_TXOKINT_ENABLE
+			| TXQ_FLAG_TXERRINT_ENABLE
+			| TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
+		qi->tqi_aifs = INIT_AIFS;
+		qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+		qi->tqi_cwmax = INIT_CWMAX;
+		qi->tqi_shretry = INIT_SH_RETRY;
+		qi->tqi_lgretry = INIT_LG_RETRY;
+		qi->tqi_physCompBuf = 0;
+	} else {
+		qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+		(void) ath9k_hw_set_txq_props(ah, q, qinfo);
+	}
+
+	return q;
+}
+
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_tx_queue_info *qi;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+			 __func__, q);
+		return false;
+	}
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
+			 __func__, q);
+		return false;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n",
+		__func__, q);
+
+	qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
+	ahp->ah_txOkInterruptMask &= ~(1 << q);
+	ahp->ah_txErrInterruptMask &= ~(1 << q);
+	ahp->ah_txDescInterruptMask &= ~(1 << q);
+	ahp->ah_txEolInterruptMask &= ~(1 << q);
+	ahp->ah_txUrnInterruptMask &= ~(1 << q);
+	ath9k_hw_set_txq_interrupts(ah, qi);
+
+	return true;
+}
+
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ath9k_tx_queue_info *qi;
+	u32 cwMin, chanCwMin, value;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+			 __func__, q);
+		return false;
+	}
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
+			 __func__, q);
+		return true;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q);
+
+	if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
+		if (chan && IS_CHAN_B(chan))
+			chanCwMin = INIT_CWMIN_11B;
+		else
+			chanCwMin = INIT_CWMIN;
+
+		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
+	} else
+		cwMin = qi->tqi_cwmin;
+
+	REG_WRITE(ah, AR_DLCL_IFS(q),
+		  SM(cwMin, AR_D_LCL_IFS_CWMIN) |
+		  SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
+		  SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
+
+	REG_WRITE(ah, AR_DRETRY_LIMIT(q),
+		  SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
+		  SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
+		  SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
+
+	REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+	REG_WRITE(ah, AR_DMISC(q),
+		  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+	if (qi->tqi_cbrPeriod) {
+		REG_WRITE(ah, AR_QCBRCFG(q),
+			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
+			  SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
+		REG_WRITE(ah, AR_QMISC(q),
+			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
+			  (qi->tqi_cbrOverflowLimit ?
+			   AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
+	}
+	if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
+		REG_WRITE(ah, AR_QRDYTIMECFG(q),
+			  SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
+			  AR_Q_RDYTIMECFG_EN);
+	}
+
+	REG_WRITE(ah, AR_DCHNTIME(q),
+		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
+		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
+
+	if (qi->tqi_burstTime
+	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
+		REG_WRITE(ah, AR_QMISC(q),
+			  REG_READ(ah, AR_QMISC(q)) |
+			  AR_Q_MISC_RDYTIME_EXP_POLICY);
+
+	}
+
+	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
+		REG_WRITE(ah, AR_DMISC(q),
+			  REG_READ(ah, AR_DMISC(q)) |
+			  AR_D_MISC_POST_FR_BKOFF_DIS);
+	}
+	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
+		REG_WRITE(ah, AR_DMISC(q),
+			  REG_READ(ah, AR_DMISC(q)) |
+			  AR_D_MISC_FRAG_BKOFF_EN);
+	}
+	switch (qi->tqi_type) {
+	case ATH9K_TX_QUEUE_BEACON:
+		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+			  | AR_Q_MISC_FSP_DBA_GATED
+			  | AR_Q_MISC_BEACON_USE
+			  | AR_Q_MISC_CBR_INCR_DIS1);
+
+		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
+			  | AR_D_MISC_BEACON_USE
+			  | AR_D_MISC_POST_FR_BKOFF_DIS);
+		break;
+	case ATH9K_TX_QUEUE_CAB:
+		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+			  | AR_Q_MISC_FSP_DBA_GATED
+			  | AR_Q_MISC_CBR_INCR_DIS1
+			  | AR_Q_MISC_CBR_INCR_DIS0);
+		value = (qi->tqi_readyTime -
+			 (ah->ah_config.sw_beacon_response_time -
+			  ah->ah_config.dma_beacon_response_time) -
+			 ah->ah_config.additional_swba_backoff) * 1024;
+		REG_WRITE(ah, AR_QRDYTIMECFG(q),
+			  value | AR_Q_RDYTIMECFG_EN);
+		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+		break;
+	case ATH9K_TX_QUEUE_PSPOLL:
+		REG_WRITE(ah, AR_QMISC(q),
+			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
+		break;
+	case ATH9K_TX_QUEUE_UAPSD:
+		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
+			  AR_D_MISC_POST_FR_BKOFF_DIS);
+		break;
+	default:
+		break;
+	}
+
+	if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+		REG_WRITE(ah, AR_DMISC(q),
+			  REG_READ(ah, AR_DMISC(q)) |
+			  SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+			     AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+			  AR_D_MISC_POST_FR_BKOFF_DIS);
+	}
+
+	if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
+		ahp->ah_txOkInterruptMask |= 1 << q;
+	else
+		ahp->ah_txOkInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
+		ahp->ah_txErrInterruptMask |= 1 << q;
+	else
+		ahp->ah_txErrInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
+		ahp->ah_txDescInterruptMask |= 1 << q;
+	else
+		ahp->ah_txDescInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
+		ahp->ah_txEolInterruptMask |= 1 << q;
+	else
+		ahp->ah_txEolInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
+		ahp->ah_txUrnInterruptMask |= 1 << q;
+	else
+		ahp->ah_txUrnInterruptMask &= ~(1 << q);
+	ath9k_hw_set_txq_interrupts(ah, qi);
+
+	return true;
+}
+
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+			u32 pa, struct ath_desc *nds, u64 tsf)
+{
+	struct ar5416_desc ads;
+	struct ar5416_desc *adsp = AR5416DESC(ds);
+	u32 phyerr;
+
+	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
+		return -EINPROGRESS;
+
+	ads.u.rx = adsp->u.rx;
+
+	ds->ds_rxstat.rs_status = 0;
+	ds->ds_rxstat.rs_flags = 0;
+
+	ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+	ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+
+	ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+	ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
+	ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
+	ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
+	ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
+	ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
+	ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
+		ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+	else
+		ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+	ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
+	ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+
+	ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+	ds->ds_rxstat.rs_moreaggr =
+		(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
+	ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+	ds->ds_rxstat.rs_flags =
+		(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
+	ds->ds_rxstat.rs_flags |=
+		(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
+		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
+		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
+		ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
+		if (ads.ds_rxstatus8 & AR_CRCErr)
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
+		else if (ads.ds_rxstatus8 & AR_PHYErr) {
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
+			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
+			ds->ds_rxstat.rs_phyerr = phyerr;
+		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
+		else if (ads.ds_rxstatus8 & AR_MichaelErr)
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
+	}
+
+	return 0;
+}
+
+bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
+			  u32 size, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+	ads->ds_ctl1 = size & AR_BufLen;
+	if (flags & ATH9K_RXDESC_INTREQ)
+		ads->ds_ctl1 |= AR_RxIntrReq;
+
+	ads->ds_rxstatus8 &= ~AR_RxDone;
+	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+		memset(&(ads->u), 0, sizeof(ads->u));
+
+	return true;
+}
+
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+{
+	u32 reg;
+
+	if (set) {
+		REG_SET_BIT(ah, AR_DIAG_SW,
+			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+		if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
+			REG_CLR_BIT(ah, AR_DIAG_SW,
+				    (AR_DIAG_RX_DIS |
+				     AR_DIAG_RX_ABORT));
+
+			reg = REG_READ(ah, AR_OBS_BUS_1);
+			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+				"%s: rx failed to go idle in 10 ms RXSM=0x%x\n",
+				__func__, reg);
+
+			return false;
+		}
+	} else {
+		REG_CLR_BIT(ah, AR_DIAG_SW,
+			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+	}
+
+	return true;
+}
+
+void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+{
+	REG_WRITE(ah, AR_RXDP, rxdp);
+}
+
+void ath9k_hw_rxena(struct ath_hal *ah)
+{
+	REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+void ath9k_hw_startpcureceive(struct ath_hal *ah)
+{
+	REG_CLR_BIT(ah, AR_DIAG_SW,
+		    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+	ath9k_enable_mib_counters(ah);
+
+	ath9k_ani_reset(ah);
+}
+
+void ath9k_hw_stoppcurecv(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+
+	ath9k_hw_disable_mib_counters(ah);
+}
+
+bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
+{
+	REG_WRITE(ah, AR_CR, AR_CR_RXD);
+
+	if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+			"%s: dma failed to stop in 10ms\n"
+			"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
+			__func__,
+			REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+		return false;
+	} else {
+		return true;
+	}
+}

+ 135 - 302
drivers/net/wireless/ath9k/main.c

@@ -21,8 +21,6 @@
 
 #define ATH_PCI_VERSION "0.1"
 
-#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR	13
-
 static char *dev_info = "ath9k";
 
 MODULE_AUTHOR("Atheros Communications");
@@ -164,7 +162,7 @@ static int ath_key_config(struct ath_softc *sc,
 	if (!sc->sc_vaps[0])
 		return -EIO;
 
-	vif = sc->sc_vaps[0]->av_if_data;
+	vif = sc->sc_vaps[0];
 	opmode = vif->type;
 
 	/*
@@ -297,41 +295,6 @@ static void ath9k_rx_prepare(struct ath_softc *sc,
 	rx_status->flag |= RX_FLAG_TSFT;
 }
 
-static u8 parse_mpdudensity(u8 mpdudensity)
-{
-	/*
-	 * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
-	 *   0 for no restriction
-	 *   1 for 1/4 us
-	 *   2 for 1/2 us
-	 *   3 for 1 us
-	 *   4 for 2 us
-	 *   5 for 4 us
-	 *   6 for 8 us
-	 *   7 for 16 us
-	 */
-	switch (mpdudensity) {
-	case 0:
-		return 0;
-	case 1:
-	case 2:
-	case 3:
-		/* Our lower layer calculations limit our precision to
-		   1 microsecond */
-		return 1;
-	case 4:
-		return 2;
-	case 5:
-		return 4;
-	case 6:
-		return 8;
-	case 7:
-		return 16;
-	default:
-		return 0;
-	}
-}
-
 static void ath9k_ht_conf(struct ath_softc *sc,
 			  struct ieee80211_bss_conf *bss_conf)
 {
@@ -350,11 +313,12 @@ static void ath9k_ht_conf(struct ath_softc *sc,
 }
 
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
+				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *bss_conf)
 {
 	struct ieee80211_hw *hw = sc->hw;
 	struct ieee80211_channel *curchan = hw->conf.channel;
-	struct ath_vap *avp;
+	struct ath_vap *avp = (void *)vif->drv_priv;
 	int pos;
 
 	if (bss_conf->assoc) {
@@ -362,13 +326,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
 			__func__,
 			bss_conf->aid);
 
-		avp = sc->sc_vaps[0];
-		if (avp == NULL) {
-			DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-				__func__);
-			return;
-		}
-
 		/* New association, store aid */
 		if (avp->av_opmode == ATH9K_M_STA) {
 			sc->sc_curaid = bss_conf->aid;
@@ -449,7 +406,7 @@ void ath_get_beaconconfig(struct ath_softc *sc,
 }
 
 void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-		     struct ath_xmit_status *tx_status, struct ath_node *an)
+		     struct ath_xmit_status *tx_status)
 {
 	struct ieee80211_hw *hw = sc->hw;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -479,8 +436,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 	tx_info->status.rates[0].count = tx_status->retries + 1;
 
 	ieee80211_tx_status(hw, skb);
-	if (an)
-		ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
 }
 
 int _ath_rx_indicate(struct ath_softc *sc,
@@ -489,12 +444,10 @@ int _ath_rx_indicate(struct ath_softc *sc,
 		     u16 keyix)
 {
 	struct ieee80211_hw *hw = sc->hw;
-	struct ath_node *an = NULL;
 	struct ieee80211_rx_status rx_status;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 	int padsize;
-	enum ATH_RX_TYPE st;
 
 	/* see if any padding is done by the hw and remove it */
 	if (hdrlen & 3) {
@@ -518,33 +471,6 @@ int _ath_rx_indicate(struct ath_softc *sc,
 			rx_status.flag |= RX_FLAG_DECRYPTED;
 	}
 
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, hdr->addr2);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (an) {
-		ath_rx_input(sc, an,
-			     skb, status, &st);
-	}
-	if (!an || (st != ATH_RX_CONSUMED))
-		__ieee80211_rx(hw, skb, &rx_status);
-
-	return 0;
-}
-
-int ath_rx_subframe(struct ath_node *an,
-		    struct sk_buff *skb,
-		    struct ath_recv_status *status)
-{
-	struct ath_softc *sc = an->an_sc;
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_rx_status rx_status;
-
-	/* Prepare rx status */
-	ath9k_rx_prepare(sc, skb, status, &rx_status);
-	if (!(status->flags & ATH_RX_DECRYPT_ERROR))
-		rx_status.flag |= RX_FLAG_DECRYPTED;
-
 	__ieee80211_rx(hw, skb, &rx_status);
 
 	return 0;
@@ -666,6 +592,7 @@ fail:
 }
 
 #ifdef CONFIG_RFKILL
+
 /*******************/
 /*	Rfkill	   */
 /*******************/
@@ -866,43 +793,72 @@ static void ath_deinit_rfkill(struct ath_softc *sc)
 		sc->rf_kill.rfkill = NULL;
 	}
 }
+
+static int ath_start_rfkill_poll(struct ath_softc *sc)
+{
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
+
+	if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+		if (rfkill_register(sc->rf_kill.rfkill)) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"Unable to register rfkill\n");
+			rfkill_free(sc->rf_kill.rfkill);
+
+			/* Deinitialize the device */
+			if (sc->pdev->irq)
+				free_irq(sc->pdev->irq, sc);
+			ath_detach(sc);
+			pci_iounmap(sc->pdev, sc->mem);
+			pci_release_region(sc->pdev, 0);
+			pci_disable_device(sc->pdev);
+			ieee80211_free_hw(hw);
+			return -EIO;
+		} else {
+			sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+		}
+	}
+
+	return 0;
+}
 #endif /* CONFIG_RFKILL */
 
-static int ath_detach(struct ath_softc *sc)
+static void ath_detach(struct ath_softc *sc)
 {
 	struct ieee80211_hw *hw = sc->hw;
+	int i = 0;
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
 
-	/* Deinit LED control */
+	ieee80211_unregister_hw(hw);
+
 	ath_deinit_leds(sc);
 
 #ifdef CONFIG_RFKILL
-	/* deinit rfkill */
 	ath_deinit_rfkill(sc);
 #endif
-
-	/* Unregister hw */
-
-	ieee80211_unregister_hw(hw);
-
-	/* unregister Rate control */
 	ath_rate_control_unregister();
-
-	/* tx/rx cleanup */
+	ath_rate_detach(sc->sc_rc);
 
 	ath_rx_cleanup(sc);
 	ath_tx_cleanup(sc);
 
-	/* Deinit */
+	tasklet_kill(&sc->intr_tq);
+	tasklet_kill(&sc->bcon_tasklet);
 
-	ath_deinit(sc);
+	if (!(sc->sc_flags & SC_OP_INVALID))
+		ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 
-	return 0;
+	/* cleanup tx queues */
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		if (ATH_TXQ_SETUP(sc, i))
+			ath_tx_cleanupq(sc, &sc->sc_txq[i]);
+
+	ath9k_hw_detach(sc->sc_ah);
 }
 
-static int ath_attach(u16 devid,
-		      struct ath_softc *sc)
+static int ath_attach(u16 devid, struct ath_softc *sc)
 {
 	struct ieee80211_hw *hw = sc->hw;
 	int error = 0;
@@ -913,47 +869,23 @@ static int ath_attach(u16 devid,
 	if (error != 0)
 		return error;
 
-	/* Init nodes */
-
-	INIT_LIST_HEAD(&sc->node_list);
-	spin_lock_init(&sc->node_lock);
-
 	/* get mac address from hardware and set in mac80211 */
 
 	SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
 
-	/* setup channels and rates */
-
-	sc->sbands[IEEE80211_BAND_2GHZ].channels =
-		sc->channels[IEEE80211_BAND_2GHZ];
-	sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
-		sc->rates[IEEE80211_BAND_2GHZ];
-	sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
-
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-		/* Setup HT capabilities for 2.4Ghz*/
-		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
-
-	hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-		&sc->sbands[IEEE80211_BAND_2GHZ];
-
-	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
-		sc->sbands[IEEE80211_BAND_5GHZ].channels =
-			sc->channels[IEEE80211_BAND_5GHZ];
-		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
-			sc->rates[IEEE80211_BAND_5GHZ];
-		sc->sbands[IEEE80211_BAND_5GHZ].band =
-			IEEE80211_BAND_5GHZ;
-
-		if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-			/* Setup HT capabilities for 5Ghz*/
-			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		IEEE80211_HW_SIGNAL_DBM |
+		IEEE80211_HW_AMPDU_AGGREGATION;
 
-		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-			&sc->sbands[IEEE80211_BAND_5GHZ];
-	}
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC);
 
 	hw->queues = 4;
+	hw->sta_data_size = sizeof(struct ath_node);
+	hw->vif_data_size = sizeof(struct ath_vap);
 
 	/* Register rate control */
 	hw->rate_control_algorithm = "ath9k_rate_control";
@@ -966,6 +898,17 @@ static int ath_attach(u16 devid,
 		goto bad;
 	}
 
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+		if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+	}
+
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] =	&sc->sbands[IEEE80211_BAND_2GHZ];
+	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+			&sc->sbands[IEEE80211_BAND_5GHZ];
+
 	error = ieee80211_register_hw(hw);
 	if (error != 0) {
 		ath_rate_control_unregister();
@@ -1011,62 +954,44 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
 		"initial channel: %d MHz\n", __func__, curchan->center_freq);
 
+	memset(&sc->sc_ht_info, 0, sizeof(struct ath_ht_info));
+
 	/* setup initial channel */
 
 	pos = ath_get_channel(sc, curchan);
 	if (pos == -1) {
 		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
-		return -EINVAL;
+		error = -EINVAL;
+		goto exit;
 	}
 
 	sc->sc_ah->ah_channels[pos].chanmode =
 		(curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
 
-	/* open ath_dev */
 	error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
 	if (error) {
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"%s: Unable to complete ath_open\n", __func__);
-		return error;
+		goto exit;
 	}
 
 #ifdef CONFIG_RFKILL
-	/* Start rfkill polling */
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-		queue_delayed_work(sc->hw->workqueue,
-				   &sc->rf_kill.rfkill_poll, 0);
-
-	if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
-		if (rfkill_register(sc->rf_kill.rfkill)) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-					"Unable to register rfkill\n");
-			rfkill_free(sc->rf_kill.rfkill);
-
-			/* Deinitialize the device */
-			if (sc->pdev->irq)
-				free_irq(sc->pdev->irq, sc);
-			ath_detach(sc);
-			pci_iounmap(sc->pdev, sc->mem);
-			pci_release_region(sc->pdev, 0);
-			pci_disable_device(sc->pdev);
-			ieee80211_free_hw(hw);
-			return -EIO;
-		} else {
-			sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
-		}
-	}
+	error = ath_start_rfkill_poll(sc);
 #endif
 
-	ieee80211_wake_queues(hw);
-	return 0;
+exit:
+	return error;
 }
 
 static int ath9k_tx(struct ieee80211_hw *hw,
 		    struct sk_buff *skb)
 {
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ath_softc *sc = hw->priv;
+	struct ath_tx_control txctl;
 	int hdrlen, padsize;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	memset(&txctl, 0, sizeof(struct ath_tx_control));
 
 	/*
 	 * As a temporary workaround, assign seq# here; this will likely need
@@ -1091,45 +1016,47 @@ static int ath9k_tx(struct ieee80211_hw *hw,
 		memmove(skb->data, skb->data + padsize, hdrlen);
 	}
 
+	/* Check if a tx queue is available */
+
+	txctl.txq = ath_test_get_txq(sc, skb);
+	if (!txctl.txq)
+		goto exit;
+
 	DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
 		__func__,
 		skb);
 
-	if (ath_tx_start(sc, skb) != 0) {
+	if (ath_tx_start(sc, skb, &txctl) != 0) {
 		DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
-		dev_kfree_skb_any(skb);
-		/* FIXME: Check for proper return value from ATH_DEV */
-		return 0;
+		goto exit;
 	}
 
+	return 0;
+exit:
+	dev_kfree_skb_any(skb);
 	return 0;
 }
 
 static void ath9k_stop(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
-	int error;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
-
-	error = ath_suspend(sc);
-	if (error)
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: Device is no longer present\n", __func__);
+	if (sc->sc_flags & SC_OP_INVALID) {
+		DPRINTF(sc, ATH_DBG_ANY, "%s: Device not present\n", __func__);
+		return;
+	}
 
-	ieee80211_stop_queues(hw);
+	ath_stop(sc);
 
-#ifdef CONFIG_RFKILL
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
-#endif
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
 }
 
 static int ath9k_add_interface(struct ieee80211_hw *hw,
 			       struct ieee80211_if_init_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
-	int error, ic_opmode = 0;
+	struct ath_vap *avp = (void *)conf->vif->drv_priv;
+	int ic_opmode = 0;
 
 	/* Support only vap for now */
 
@@ -1157,13 +1084,22 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 		__func__,
 		ic_opmode);
 
-	error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
-	if (error) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to attach vap, error: %d\n",
-			__func__, error);
-		return error;
-	}
+	/* Set the VAP opmode */
+	avp->av_opmode = ic_opmode;
+	avp->av_bslot = -1;
+
+	if (ic_opmode == ATH9K_M_HOSTAP)
+		ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+
+	sc->sc_vaps[0] = conf->vif;
+	sc->sc_nvaps++;
+
+	/* Set the device opmode */
+	sc->sc_ah->ah_opmode = ic_opmode;
+
+	/* default VAP configuration */
+	avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
+	avp->av_config.av_fixed_retryset = 0x03030303;
 
 	if (conf->type == NL80211_IFTYPE_AP) {
 		/* TODO: is this a suitable place to start ANI for AP mode? */
@@ -1179,27 +1115,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 				   struct ieee80211_if_init_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_vap *avp;
-	int error;
+	struct ath_vap *avp = (void *)conf->vif->drv_priv;
 
 	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
 
-	avp = sc->sc_vaps[0];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-			__func__);
-		return;
-	}
-
 #ifdef CONFIG_SLOW_ANT_DIV
 	ath_slow_ant_div_stop(&sc->sc_antdiv);
 #endif
 	/* Stop ANI */
 	del_timer_sync(&sc->sc_ani.timer);
 
-	/* Update ratectrl */
-	ath_rate_newstate(sc, avp);
-
 	/* Reclaim beacon resources */
 	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
 	    sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
@@ -1207,16 +1132,10 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 		ath_beacon_return(sc, avp);
 	}
 
-	/* Set interrupt mask */
-	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
 	sc->sc_flags &= ~SC_OP_BEACONS;
 
-	error = ath_vap_detach(sc, 0);
-	if (error)
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to detach vap, error: %d\n",
-			__func__, error);
+	sc->sc_vaps[0] = NULL;
+	sc->sc_nvaps--;
 }
 
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1264,17 +1183,10 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
 {
 	struct ath_softc *sc = hw->priv;
 	struct ath_hal *ah = sc->sc_ah;
-	struct ath_vap *avp;
+	struct ath_vap *avp = (void *)vif->drv_priv;
 	u32 rfilt = 0;
 	int error, i;
 
-	avp = sc->sc_vaps[0];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-			__func__);
-		return -EINVAL;
-	}
-
 	/* TODO: Need to decide which hw opmode to use for multi-interface
 	 * cases */
 	if (vif->type == NL80211_IFTYPE_AP &&
@@ -1303,23 +1215,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
 			/* Set aggregation protection mode parameters */
 			sc->sc_config.ath_aggr_prot = 0;
 
-			/*
-			 * Reset our TSF so that its value is lower than the
-			 * beacon that we are trying to catch.
-			 * Only then hw will update its TSF register with the
-			 * new beacon. Reset the TSF before setting the BSSID
-			 * to avoid allowing in any frames that would update
-			 * our TSF only to have us clear it
-			 * immediately thereafter.
-			 */
-			ath9k_hw_reset_tsf(sc->sc_ah);
-
-			/* Disable BMISS interrupt when we're not associated */
-			ath9k_hw_set_interrupts(sc->sc_ah,
-					sc->sc_imask &
-					~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
-			sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-
 			DPRINTF(sc, ATH_DBG_CONFIG,
 				"%s: RX filter 0x%x bssid %pM aid 0x%x\n",
 				__func__, rfilt,
@@ -1355,7 +1250,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
 	}
 
 	/* Check for WLAN_CAPABILITY_PRIVACY ? */
-	if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
+	if ((avp->av_opmode != ATH9K_M_STA)) {
 		for (i = 0; i < IEEE80211_WEP_NKID; i++)
 			if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
 				ath9k_hw_keysetmac(sc->sc_ah,
@@ -1410,44 +1305,13 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
 			     struct ieee80211_sta *sta)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_node *an;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sc->node_lock, flags);
-	an = ath_node_find(sc, sta->addr);
-	spin_unlock_irqrestore(&sc->node_lock, flags);
 
 	switch (cmd) {
 	case STA_NOTIFY_ADD:
-		spin_lock_irqsave(&sc->node_lock, flags);
-		if (!an) {
-			ath_node_attach(sc, sta->addr, 0);
-			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %pM\n",
-				__func__, sta->addr);
-		} else {
-			ath_node_get(sc, sta->addr);
-		}
-
-		/* XXX: Is this right? Can the capabilities change? */
-		an = ath_node_find(sc, sta->addr);
-		an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
-					sta->ht_cap.ampdu_factor);
-		an->mpdudensity =
-			parse_mpdudensity(sta->ht_cap.ampdu_density);
-
-		spin_unlock_irqrestore(&sc->node_lock, flags);
+		ath_node_attach(sc, sta);
 		break;
 	case STA_NOTIFY_REMOVE:
-		if (!an)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Removal of a non-existent node\n",
-				__func__);
-		else {
-			ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
-			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %pM\n",
-				__func__,
-				sta->addr);
-		}
+		ath_node_detach(sc, sta);
 		break;
 	default:
 		break;
@@ -1562,7 +1426,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
 			__func__,
 			bss_conf->assoc);
-		ath9k_bss_assoc_info(sc, bss_conf);
+		ath9k_bss_assoc_info(sc, vif, bss_conf);
 	}
 }
 
@@ -1595,21 +1459,13 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
-		ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to start RX aggregation\n",
-				__func__);
+		if (!(sc->sc_flags & SC_OP_RXAGGR))
+			ret = -ENOTSUPP;
 		break;
 	case IEEE80211_AMPDU_RX_STOP:
-		ret = ath_rx_aggr_stop(sc, sta->addr, tid);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to stop RX aggregation\n",
-				__func__);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn);
+		ret = ath_tx_aggr_start(sc, sta, tid, ssn);
 		if (ret < 0)
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"%s: Unable to start TX aggregation\n",
@@ -1618,7 +1474,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 			ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_STOP:
-		ret = ath_tx_aggr_stop(sc, sta->addr, tid);
+		ret = ath_tx_aggr_stop(sc, sta, tid);
 		if (ret < 0)
 			DPRINTF(sc, ATH_DBG_FATAL,
 				"%s: Unable to stop TX aggregation\n",
@@ -1626,6 +1482,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 
 		ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
 		break;
+	case IEEE80211_AMPDU_TX_RESUME:
+		ath_tx_aggr_resume(sc, sta, tid);
+		break;
 	default:
 		DPRINTF(sc, ATH_DBG_FATAL,
 			"%s: Unknown AMPDU action\n", __func__);
@@ -1648,20 +1507,12 @@ static struct ieee80211_ops ath9k_ops = {
 	.config 	    = ath9k_config,
 	.config_interface   = ath9k_config_interface,
 	.configure_filter   = ath9k_configure_filter,
-	.get_stats          = NULL,
 	.sta_notify         = ath9k_sta_notify,
 	.conf_tx 	    = ath9k_conf_tx,
-	.get_tx_stats 	    = NULL,
 	.bss_info_changed   = ath9k_bss_info_changed,
-	.set_tim            = NULL,
 	.set_key            = ath9k_set_key,
-	.hw_scan            = NULL,
-	.get_tkip_seq       = NULL,
-	.set_rts_threshold  = NULL,
-	.set_frag_threshold = NULL,
 	.get_tsf 	    = ath9k_get_tsf,
 	.reset_tsf 	    = ath9k_reset_tsf,
-	.tx_last_beacon     = NULL,
 	.ampdu_action       = ath9k_ampdu_action,
 	.set_frag_threshold = ath9k_no_fragmentation,
 };
@@ -1739,17 +1590,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto bad2;
 	}
 
-	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-		IEEE80211_HW_SIGNAL_DBM |
-		IEEE80211_HW_NOISE_DBM |
-		IEEE80211_HW_AMPDU_AGGREGATION;
-
-	hw->wiphy->interface_modes =
-		BIT(NL80211_IFTYPE_AP) |
-		BIT(NL80211_IFTYPE_STATION) |
-		BIT(NL80211_IFTYPE_ADHOC);
-
 	SET_IEEE80211_DEV(hw, &pdev->dev);
 	pci_set_drvdata(pdev, hw);
 
@@ -1797,17 +1637,10 @@ static void ath_pci_remove(struct pci_dev *pdev)
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath_softc *sc = hw->priv;
-	enum ath9k_int status;
 
-	if (pdev->irq) {
-		ath9k_hw_set_interrupts(sc->sc_ah, 0);
-		/* clear the ISR */
-		ath9k_hw_getisr(sc->sc_ah, &status);
-		sc->sc_flags |= SC_OP_INVALID;
-		free_irq(pdev->irq, sc);
-	}
 	ath_detach(sc);
-
+	if (pdev->irq)
+		free_irq(pdev->irq, sc);
 	pci_iounmap(pdev, sc->mem);
 	pci_release_region(pdev, 0);
 	pci_disable_device(pdev);

+ 5 - 5
drivers/net/wireless/ath9k/phy.c

@@ -215,7 +215,7 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
 	if (AR_SREV_9280_10_OR_LATER(ah))
 		return true;
 
-	eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV);
+	eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV);
 
 	RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
 
@@ -235,15 +235,15 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
 
 	if (eepMinorRev >= 2) {
 		if (IS_CHAN_2GHZ(chan)) {
-			ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2);
-			db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2);
+			ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2);
+			db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
 						   ob2GHz, 3, 197, 0);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
 						   db2GHz, 3, 194, 0);
 		} else {
-			ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5);
-			db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5);
+			ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5);
+			db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
 						   ob5GHz, 3, 203, 0);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,

+ 13 - 77
drivers/net/wireless/ath9k/rc.c

@@ -816,7 +816,7 @@ void ath_rate_detach(struct ath_rate_softc *asc)
 }
 
 u8 ath_rate_findrateix(struct ath_softc *sc,
-			     u8 dot11rate)
+		       u8 dot11rate)
 {
 	const struct ath_rate_table *ratetable;
 	struct ath_rate_softc *rsc = sc->sc_rc;
@@ -1867,9 +1867,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
 	/* XXX: UGLY HACK!! */
 	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
 
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, hdr->addr1);
-	spin_unlock_bh(&sc->node_lock);
+	an = (struct ath_node *)sta->drv_priv;
 
 	if (tx_info_priv == NULL)
 		return;
@@ -1881,49 +1879,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
 	tx_info->control.vif = NULL;
 }
 
-static void ath_tx_aggr_resp(struct ath_softc *sc,
-			     struct ieee80211_supported_band *sband,
-			     struct ieee80211_sta *sta,
-			     struct ath_node *an,
-			     u8 tidno)
-{
-	struct ath_atx_tid *txtid;
-	u16 buffersize = 0;
-	int state;
-	struct sta_info *si;
-
-	if (!(sc->sc_flags & SC_OP_TXAGGR))
-		return;
-
-	txtid = ATH_AN_2_TID(an, tidno);
-	if (!txtid->paused)
-		return;
-
-	/*
-	 * XXX: This is entirely busted, we aren't supposed to
-	 *	access the sta from here because it's internal
-	 *	to mac80211, and looking at the state without
-	 *	locking is wrong too.
-	 */
-	si = container_of(sta, struct sta_info, sta);
-	buffersize = IEEE80211_MIN_AMPDU_BUF <<
-		sband->ht_cap.ampdu_factor; /* FIXME */
-	state = si->ampdu_mlme.tid_state_tx[tidno];
-
-	if (state & HT_ADDBA_RECEIVED_MSK) {
-		txtid->addba_exchangecomplete = 1;
-		txtid->addba_exchangeinprogress = 0;
-		txtid->baw_size = buffersize;
-
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Resuming tid, buffersize: %d\n",
-			__func__,
-			buffersize);
-
-		ath_tx_resume_tid(sc, txtid);
-	}
-}
-
 static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 			 struct ieee80211_tx_rate_control *txrc)
 {
@@ -1936,7 +1891,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	struct ath_rate_node *ath_rc_priv = priv_sta;
 	struct ath_node *an;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	int is_probe = FALSE, chk, ret;
+	int is_probe = FALSE;
 	s8 lowest_idx;
 	__le16 fc = hdr->frame_control;
 	u8 *qc, tid;
@@ -1983,35 +1938,10 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 		if (ieee80211_is_data_qos(fc)) {
 			qc = ieee80211_get_qos_ctl(hdr);
 			tid = qc[0] & 0xf;
+			an = (struct ath_node *)sta->drv_priv;
 
-			spin_lock_bh(&sc->node_lock);
-			an = ath_node_find(sc, hdr->addr1);
-			spin_unlock_bh(&sc->node_lock);
-
-			if (!an) {
-				DPRINTF(sc, ATH_DBG_AGGR,
-					"%s: Node not found to "
-					"init/chk TX aggr\n", __func__);
-				return;
-			}
-
-			chk = ath_tx_aggr_check(sc, an, tid);
-			if (chk == AGGR_REQUIRED) {
-				ret = ieee80211_start_tx_ba_session(hw,
-					hdr->addr1, tid);
-				if (ret)
-					DPRINTF(sc, ATH_DBG_AGGR,
-						"%s: Unable to start tx "
-						"aggr for: %pM\n",
-						__func__,
-						hdr->addr1);
-				else
-					DPRINTF(sc, ATH_DBG_AGGR,
-						"%s: Started tx aggr for: %pM\n",
-						__func__,
-						hdr->addr1);
-			} else if (chk == AGGR_EXCHANGE_PROGRESS)
-				ath_tx_aggr_resp(sc, sband, sta, an, tid);
+			if(ath_tx_aggr_check(sc, an, tid))
+				ieee80211_start_tx_ba_session(hw, hdr->addr1, tid);
 		}
 	}
 }
@@ -2053,12 +1983,18 @@ static void ath_rate_free(void *priv)
 
 static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 {
+	struct ieee80211_vif *vif;
 	struct ath_softc *sc = priv;
-	struct ath_vap *avp = sc->sc_vaps[0];
+	struct ath_vap *avp;
 	struct ath_rate_node *rate_priv;
 
 	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
 
+	vif = sc->sc_vaps[0];
+	ASSERT(vif);
+
+	avp = (void *)vif->drv_priv;
+
 	rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
 	if (!rate_priv) {
 		DPRINTF(sc, ATH_DBG_FATAL,

+ 0 - 536
drivers/net/wireless/ath9k/recv.c

@@ -64,328 +64,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
 	ath9k_hw_rxena(ah);
 }
 
-/* Process received BAR frame */
-
-static int ath_bar_rx(struct ath_softc *sc,
-		      struct ath_node *an,
-		      struct sk_buff *skb)
-{
-	struct ieee80211_bar *bar;
-	struct ath_arx_tid *rxtid;
-	struct sk_buff *tskb;
-	struct ath_recv_status *rx_status;
-	int tidno, index, cindex;
-	u16 seqno;
-
-	/* look at BAR contents	 */
-
-	bar = (struct ieee80211_bar *)skb->data;
-	tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M)
-		>> IEEE80211_BAR_CTL_TID_S;
-	seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT;
-
-	/* process BAR - indicate all pending RX frames till the BAR seqno */
-
-	rxtid = &an->an_aggr.rx.tid[tidno];
-
-	spin_lock_bh(&rxtid->tidlock);
-
-	/* get relative index */
-
-	index = ATH_BA_INDEX(rxtid->seq_next, seqno);
-
-	/* drop BAR if old sequence (index is too large) */
-
-	if ((index > rxtid->baw_size) &&
-	    (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))))
-		/* discard frame, ieee layer may not treat frame as a dup */
-		goto unlock_and_free;
-
-	/* complete receive processing for all pending frames upto BAR seqno */
-
-	cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
-	while ((rxtid->baw_head != rxtid->baw_tail) &&
-	       (rxtid->baw_head != cindex)) {
-		tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
-		rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
-		rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
-		if (tskb != NULL)
-			ath_rx_subframe(an, tskb, rx_status);
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-	/* ... and indicate rest of the frames in-order */
-
-	while (rxtid->baw_head != rxtid->baw_tail &&
-	       rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) {
-		tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
-		rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
-		rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
-		ath_rx_subframe(an, tskb, rx_status);
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-unlock_and_free:
-	spin_unlock_bh(&rxtid->tidlock);
-	/* free bar itself */
-	dev_kfree_skb(skb);
-	return IEEE80211_FTYPE_CTL;
-}
-
-/* Function to handle a subframe of aggregation when HT is enabled */
-
-static int ath_ampdu_input(struct ath_softc *sc,
-			   struct ath_node *an,
-			   struct sk_buff *skb,
-			   struct ath_recv_status *rx_status)
-{
-	struct ieee80211_hdr *hdr;
-	struct ath_arx_tid *rxtid;
-	struct ath_rxbuf *rxbuf;
-	u8 type, subtype;
-	u16 rxseq;
-	int tid = 0, index, cindex, rxdiff;
-	__le16 fc;
-	u8 *qc;
-
-	hdr = (struct ieee80211_hdr *)skb->data;
-	fc = hdr->frame_control;
-
-	/* collect stats of frames with non-zero version */
-
-	if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) {
-		dev_kfree_skb(skb);
-		return -1;
-	}
-
-	type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
-	subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
-
-	if (ieee80211_is_back_req(fc))
-		return ath_bar_rx(sc, an, skb);
-
-	/* special aggregate processing only for qos unicast data frames */
-
-	if (!ieee80211_is_data(fc) ||
-	    !ieee80211_is_data_qos(fc) ||
-	    is_multicast_ether_addr(hdr->addr1))
-		return ath_rx_subframe(an, skb, rx_status);
-
-	/* lookup rx tid state */
-
-	if (ieee80211_is_data_qos(fc)) {
-		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
-	}
-
-	if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
-		/* Drop the frame not belonging to me. */
-		if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) {
-			dev_kfree_skb(skb);
-			return -1;
-		}
-	}
-
-	rxtid = &an->an_aggr.rx.tid[tid];
-
-	spin_lock(&rxtid->tidlock);
-
-	rxdiff = (rxtid->baw_tail - rxtid->baw_head) &
-		(ATH_TID_MAX_BUFS - 1);
-
-	/*
-	 * If the ADDBA exchange has not been completed by the source,
-	 * process via legacy path (i.e. no reordering buffer is needed)
-	 */
-	if (!rxtid->addba_exchangecomplete) {
-		spin_unlock(&rxtid->tidlock);
-		return ath_rx_subframe(an, skb, rx_status);
-	}
-
-	/* extract sequence number from recvd frame */
-
-	rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
-
-	if (rxtid->seq_reset) {
-		rxtid->seq_reset = 0;
-		rxtid->seq_next = rxseq;
-	}
-
-	index = ATH_BA_INDEX(rxtid->seq_next, rxseq);
-
-	/* drop frame if old sequence (index is too large) */
-
-	if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) {
-		/* discard frame, ieee layer may not treat frame as a dup */
-		spin_unlock(&rxtid->tidlock);
-		dev_kfree_skb(skb);
-		return IEEE80211_FTYPE_DATA;
-	}
-
-	/* sequence number is beyond block-ack window */
-
-	if (index >= rxtid->baw_size) {
-
-		/* complete receive processing for all pending frames */
-
-		while (index >= rxtid->baw_size) {
-
-			rxbuf = rxtid->rxbuf + rxtid->baw_head;
-
-			if (rxbuf->rx_wbuf != NULL) {
-				ath_rx_subframe(an, rxbuf->rx_wbuf,
-						&rxbuf->rx_status);
-				rxbuf->rx_wbuf = NULL;
-			}
-
-			INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-			INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-
-			index--;
-		}
-	}
-
-	/* add buffer to the recv ba window */
-
-	cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
-	rxbuf = rxtid->rxbuf + cindex;
-
-	if (rxbuf->rx_wbuf != NULL) {
-		spin_unlock(&rxtid->tidlock);
-		/* duplicate frame */
-		dev_kfree_skb(skb);
-		return IEEE80211_FTYPE_DATA;
-	}
-
-	rxbuf->rx_wbuf = skb;
-	rxbuf->rx_time = get_timestamp();
-	rxbuf->rx_status = *rx_status;
-
-	/* advance tail if sequence received is newer
-	 * than any received so far */
-
-	if (index >= rxdiff) {
-		rxtid->baw_tail = cindex;
-		INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS);
-	}
-
-	/* indicate all in-order received frames */
-
-	while (rxtid->baw_head != rxtid->baw_tail) {
-		rxbuf = rxtid->rxbuf + rxtid->baw_head;
-		if (!rxbuf->rx_wbuf)
-			break;
-
-		ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status);
-		rxbuf->rx_wbuf = NULL;
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-	/*
-	 * start a timer to flush all received frames if there are pending
-	 * receive frames
-	 */
-	if (rxtid->baw_head != rxtid->baw_tail)
-		mod_timer(&rxtid->timer, ATH_RX_TIMEOUT);
-	else
-		del_timer_sync(&rxtid->timer);
-
-	spin_unlock(&rxtid->tidlock);
-	return IEEE80211_FTYPE_DATA;
-}
-
-/* Timer to flush all received sub-frames */
-
-static void ath_rx_timer(unsigned long data)
-{
-	struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data;
-	struct ath_node *an = rxtid->an;
-	struct ath_rxbuf *rxbuf;
-	int nosched;
-
-	spin_lock_bh(&rxtid->tidlock);
-	while (rxtid->baw_head != rxtid->baw_tail) {
-		rxbuf = rxtid->rxbuf + rxtid->baw_head;
-		if (!rxbuf->rx_wbuf) {
-			INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-			INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-			continue;
-		}
-
-		/*
-		 * Stop if the next one is a very recent frame.
-		 *
-		 * Call get_timestamp in every iteration to protect against the
-		 * case in which a new frame is received while we are executing
-		 * this function. Using a timestamp obtained before entering
-		 * the loop could lead to a very large time interval
-		 * (a negative value typecast to unsigned), breaking the
-		 * function's logic.
-		 */
-		if ((get_timestamp() - rxbuf->rx_time) <
-			(ATH_RX_TIMEOUT * HZ / 1000))
-			break;
-
-		ath_rx_subframe(an, rxbuf->rx_wbuf,
-				&rxbuf->rx_status);
-		rxbuf->rx_wbuf = NULL;
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-	/*
-	 * start a timer to flush all received frames if there are pending
-	 * receive frames
-	 */
-	if (rxtid->baw_head != rxtid->baw_tail)
-		nosched = 0;
-	else
-		nosched = 1; /* no need to re-arm the timer again */
-
-	spin_unlock_bh(&rxtid->tidlock);
-}
-
-/* Free all pending sub-frames in the re-ordering buffer */
-
-static void ath_rx_flush_tid(struct ath_softc *sc,
-	struct ath_arx_tid *rxtid, int drop)
-{
-	struct ath_rxbuf *rxbuf;
-	unsigned long flag;
-
-	spin_lock_irqsave(&rxtid->tidlock, flag);
-	while (rxtid->baw_head != rxtid->baw_tail) {
-		rxbuf = rxtid->rxbuf + rxtid->baw_head;
-		if (!rxbuf->rx_wbuf) {
-			INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-			INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-			continue;
-		}
-
-		if (drop)
-			dev_kfree_skb(rxbuf->rx_wbuf);
-		else
-			ath_rx_subframe(rxtid->an,
-					rxbuf->rx_wbuf,
-					&rxbuf->rx_status);
-
-		rxbuf->rx_wbuf = NULL;
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-	spin_unlock_irqrestore(&rxtid->tidlock, flag);
-}
-
 static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
 	u32 len)
 {
@@ -716,23 +394,6 @@ void ath_flushrecv(struct ath_softc *sc)
 	spin_unlock_bh(&sc->sc_rxflushlock);
 }
 
-/* Process an individual frame */
-
-int ath_rx_input(struct ath_softc *sc,
-		 struct ath_node *an,
-		 struct sk_buff *skb,
-		 struct ath_recv_status *rx_status,
-		 enum ATH_RX_TYPE *status)
-{
-	if (sc->sc_flags & SC_OP_RXAGGR) {
-		*status = ATH_RX_CONSUMED;
-		return ath_ampdu_input(sc, an, skb, rx_status);
-	} else {
-		*status = ATH_RX_NON_CONSUMED;
-		return -1;
-	}
-}
-
 /* Process receive queue, as well as LED, etc. */
 
 int ath_rx_tasklet(struct ath_softc *sc, int flush)
@@ -1091,200 +752,3 @@ rx_next:
 	return 0;
 #undef PA2DESC
 }
-
-/* Process ADDBA request in per-TID data structure */
-
-int ath_rx_aggr_start(struct ath_softc *sc,
-		      const u8 *addr,
-		      u16 tid,
-		      u16 *ssn)
-{
-	struct ath_arx_tid *rxtid;
-	struct ath_node *an;
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_supported_band *sband;
-	u16 buffersize = 0;
-
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, (u8 *) addr);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (!an) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Node not found to initialize RX aggregation\n",
-			__func__);
-		return -1;
-	}
-
-	sband = hw->wiphy->bands[hw->conf.channel->band];
-	buffersize = IEEE80211_MIN_AMPDU_BUF <<
-		sband->ht_cap.ampdu_factor; /* FIXME */
-
-	rxtid = &an->an_aggr.rx.tid[tid];
-
-	spin_lock_bh(&rxtid->tidlock);
-	if (sc->sc_flags & SC_OP_RXAGGR) {
-		/* Allow aggregation reception
-		 * Adjust rx BA window size. Peer might indicate a
-		 * zero buffer size for a _dont_care_ condition.
-		 */
-		if (buffersize)
-			rxtid->baw_size = min(buffersize, rxtid->baw_size);
-
-		/* set rx sequence number */
-		rxtid->seq_next = *ssn;
-
-		/* Allocate the receive buffers for this TID */
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Allcating rxbuffer for TID %d\n", __func__, tid);
-
-		if (rxtid->rxbuf == NULL) {
-			/*
-			* If the rxbuff is not NULL at this point, we *probably*
-			* already allocated the buffer on a previous ADDBA,
-			* and this is a subsequent ADDBA that got through.
-			* Don't allocate, but use the value in the pointer,
-			* we zero it out when we de-allocate.
-			*/
-			rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS *
-				sizeof(struct ath_rxbuf), GFP_ATOMIC);
-		}
-		if (rxtid->rxbuf == NULL) {
-			DPRINTF(sc, ATH_DBG_AGGR,
-				"%s: Unable to allocate RX buffer, "
-				"refusing ADDBA\n", __func__);
-		} else {
-			/* Ensure the memory is zeroed out (all internal
-			 * pointers are null) */
-			memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS *
-				sizeof(struct ath_rxbuf));
-			DPRINTF(sc, ATH_DBG_AGGR,
-				"%s: Allocated @%p\n", __func__, rxtid->rxbuf);
-
-			/* Allow aggregation reception */
-			rxtid->addba_exchangecomplete = 1;
-		}
-	}
-	spin_unlock_bh(&rxtid->tidlock);
-
-	return 0;
-}
-
-/* Process DELBA */
-
-int ath_rx_aggr_stop(struct ath_softc *sc,
-		     const u8 *addr,
-		     u16 tid)
-{
-	struct ath_node *an;
-
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, (u8 *) addr);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (!an) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: RX aggr stop for non-existent node\n", __func__);
-		return -1;
-	}
-
-	ath_rx_aggr_teardown(sc, an, tid);
-	return 0;
-}
-
-/* Rx aggregation tear down */
-
-void ath_rx_aggr_teardown(struct ath_softc *sc,
-	struct ath_node *an, u8 tid)
-{
-	struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid];
-
-	if (!rxtid->addba_exchangecomplete)
-		return;
-
-	del_timer_sync(&rxtid->timer);
-	ath_rx_flush_tid(sc, rxtid, 0);
-	rxtid->addba_exchangecomplete = 0;
-
-	/* De-allocate the receive buffer array allocated when addba started */
-
-	if (rxtid->rxbuf) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Deallocating TID %d rxbuff @%p\n",
-			__func__, tid, rxtid->rxbuf);
-		kfree(rxtid->rxbuf);
-
-		/* Set pointer to null to avoid reuse*/
-		rxtid->rxbuf = NULL;
-	}
-}
-
-/* Initialize per-node receive state */
-
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
-{
-	if (sc->sc_flags & SC_OP_RXAGGR) {
-		struct ath_arx_tid *rxtid;
-		int tidno;
-
-		/* Init per tid rx state */
-		for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
-				tidno < WME_NUM_TID;
-				tidno++, rxtid++) {
-			rxtid->an        = an;
-			rxtid->seq_reset = 1;
-			rxtid->seq_next  = 0;
-			rxtid->baw_size  = WME_MAX_BA;
-			rxtid->baw_head  = rxtid->baw_tail = 0;
-
-			/*
-			 * Ensure the buffer pointer is null at this point
-			 * (needs to be allocated when addba is received)
-			*/
-
-			rxtid->rxbuf     = NULL;
-			setup_timer(&rxtid->timer, ath_rx_timer,
-				(unsigned long)rxtid);
-			spin_lock_init(&rxtid->tidlock);
-
-			/* ADDBA state */
-			rxtid->addba_exchangecomplete = 0;
-		}
-	}
-}
-
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
-{
-	if (sc->sc_flags & SC_OP_RXAGGR) {
-		struct ath_arx_tid *rxtid;
-		int tidno, i;
-
-		/* Init per tid rx state */
-		for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
-				tidno < WME_NUM_TID;
-				tidno++, rxtid++) {
-
-			if (!rxtid->addba_exchangecomplete)
-				continue;
-
-			/* must cancel timer first */
-			del_timer_sync(&rxtid->timer);
-
-			/* drop any pending sub-frames */
-			ath_rx_flush_tid(sc, rxtid, 1);
-
-			for (i = 0; i < ATH_TID_MAX_BUFS; i++)
-				ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL);
-
-			rxtid->addba_exchangecomplete = 0;
-		}
-	}
-
-}
-
-/* Cleanup per-node receive state */
-
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an)
-{
-	ath_rx_node_cleanup(sc, an);
-}

File diff suppressed because it is too large
+ 298 - 389
drivers/net/wireless/ath9k/xmit.c


+ 35 - 35
drivers/net/wireless/atmel.c

@@ -67,7 +67,7 @@
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/jiffies.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 #include "atmel.h"
 
 #define DRIVER_MAJOR 0
@@ -569,7 +569,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
 static void atmel_command_irq(struct atmel_private *priv);
 static int atmel_validate_channel(struct atmel_private *priv, int channel);
 static void atmel_management_frame(struct atmel_private *priv,
-				   struct ieee80211_hdr_4addr *header,
+				   struct ieee80211_hdr *header,
 				   u16 frame_len, u8 rssi);
 static void atmel_management_timer(u_long a);
 static void atmel_send_command(struct atmel_private *priv, int command,
@@ -577,7 +577,7 @@ static void atmel_send_command(struct atmel_private *priv, int command,
 static int atmel_send_command_wait(struct atmel_private *priv, int command,
 				   void *cmd, int cmd_size);
 static void atmel_transmit_management_frame(struct atmel_private *priv,
-					    struct ieee80211_hdr_4addr *header,
+					    struct ieee80211_hdr *header,
 					    u8 *body, int body_len);
 
 static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@ -785,7 +785,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 	struct atmel_private *priv = netdev_priv(dev);
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 	unsigned long flags;
 	u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
@@ -823,7 +823,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
 	frame_ctl = IEEE80211_FTYPE_DATA;
 	header.duration_id = 0;
-	header.seq_ctl = 0;
+	header.seq_ctrl = 0;
 	if (priv->wep_is_on)
 		frame_ctl |= IEEE80211_FCTL_PROTECTED;
 	if (priv->operating_mode == IW_MODE_ADHOC) {
@@ -840,7 +840,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 	if (priv->use_wpa)
 		memcpy(&header.addr4, SNAP_RFC1024, 6);
 
-	header.frame_ctl = cpu_to_le16(frame_ctl);
+	header.frame_control = cpu_to_le16(frame_ctl);
 	/* Copy the wireless header into the card */
 	atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
 	/* Copy the packet sans its 802.3 header addresses which have been replaced */
@@ -860,7 +860,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 }
 
 static void atmel_transmit_management_frame(struct atmel_private *priv,
-					    struct ieee80211_hdr_4addr *header,
+					    struct ieee80211_hdr *header,
 					    u8 *body, int body_len)
 {
 	u16 buff;
@@ -876,7 +876,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
 }
 
 static void fast_rx_path(struct atmel_private *priv,
-			 struct ieee80211_hdr_4addr *header,
+			 struct ieee80211_hdr *header,
 			 u16 msdu_size, u16 rx_packet_loc, u32 crc)
 {
 	/* fast path: unfragmented packet copy directly into skbuf */
@@ -914,7 +914,7 @@ static void fast_rx_path(struct atmel_private *priv,
 	}
 
 	memcpy(skbp, header->addr1, 6); /* destination address */
-	if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+	if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
 		memcpy(&skbp[6], header->addr3, 6);
 	else
 		memcpy(&skbp[6], header->addr2, 6); /* source address */
@@ -949,7 +949,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
 }
 
 static void frag_rx_path(struct atmel_private *priv,
-			 struct ieee80211_hdr_4addr *header,
+			 struct ieee80211_hdr *header,
 			 u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
 			 u8 frag_no, int more_frags)
 {
@@ -957,7 +957,7 @@ static void frag_rx_path(struct atmel_private *priv,
 	u8 source[6];
 	struct sk_buff *skb;
 
-	if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+	if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
 		memcpy(source, header->addr3, 6);
 	else
 		memcpy(source, header->addr2, 6);
@@ -1039,7 +1039,7 @@ static void frag_rx_path(struct atmel_private *priv,
 static void rx_done_irq(struct atmel_private *priv)
 {
 	int i;
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 
 	for (i = 0;
 	     atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@ -1066,10 +1066,10 @@ static void rx_done_irq(struct atmel_private *priv)
 			goto next;
 		}
 
-		/* Get header as far as end of seq_ctl */
+		/* Get header as far as end of seq_ctrl */
 		atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24);
-		frame_ctl = le16_to_cpu(header.frame_ctl);
-		seq_control = le16_to_cpu(header.seq_ctl);
+		frame_ctl = le16_to_cpu(header.frame_control);
+		seq_control = le16_to_cpu(header.seq_ctrl);
 
 		/* probe for CRC use here if needed  once five packets have
 		   arrived with the same crc status, we assume we know what's
@@ -1819,7 +1819,7 @@ static int atmel_set_encodeext(struct net_device *dev,
 	/* Determine and validate the key index */
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if (idx < 1 || idx > WEP_KEYS)
+		if (idx < 1 || idx > 4)
 			return -EINVAL;
 		idx--;
 	} else
@@ -1882,7 +1882,7 @@ static int atmel_get_encodeext(struct net_device *dev,
 
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if (idx < 1 || idx > WEP_KEYS)
+		if (idx < 1 || idx > 4)
 			return -EINVAL;
 		idx--;
 	} else
@@ -2797,7 +2797,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
 				u8 channel)
 {
 	int rejoin = 0;
-	int new = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+	int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
 		SHORT_PREAMBLE : LONG_PREAMBLE;
 
 	if (priv->preamble != new) {
@@ -2826,19 +2826,19 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
 static void send_authentication_request(struct atmel_private *priv, u16 system,
 					u8 *challenge, int challenge_len)
 {
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 	struct auth_body auth;
 
-	header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
+	header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
 	header.duration_id = cpu_to_le16(0x8000);
-	header.seq_ctl = 0;
+	header.seq_ctrl = 0;
 	memcpy(header.addr1, priv->CurrentBSSID, 6);
 	memcpy(header.addr2, priv->dev->dev_addr, 6);
 	memcpy(header.addr3, priv->CurrentBSSID, 6);
 
 	if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
 		/* no WEP for authentication frames with TrSeqNo 1 */
-                header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+                header.frame_control |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 
 	auth.alg = cpu_to_le16(system);
 
@@ -2861,7 +2861,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 {
 	u8 *ssid_el_p;
 	int bodysize;
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 	struct ass_req_format {
 		__le16 capability;
 		__le16 listen_interval;
@@ -2874,10 +2874,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 		u8 rates[4];
 	} body;
 
-	header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+	header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 		(is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
 	header.duration_id = cpu_to_le16(0x8000);
-	header.seq_ctl = 0;
+	header.seq_ctrl = 0;
 
 	memcpy(header.addr1, priv->CurrentBSSID, 6);
 	memcpy(header.addr2, priv->dev->dev_addr, 6);
@@ -2887,7 +2887,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 	if (priv->wep_is_on)
 		body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
 	if (priv->preamble == SHORT_PREAMBLE)
-		body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT);
+		body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
 
 	body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period);
 
@@ -2901,10 +2901,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 		bodysize = 12 + priv->SSID_size;
 	}
 
-	ssid_el_p[0] = MFIE_TYPE_SSID;
+	ssid_el_p[0] = WLAN_EID_SSID;
 	ssid_el_p[1] = priv->SSID_size;
 	memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size);
-	ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES;
+	ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES;
 	ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */
 	memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4);
 
@@ -2912,9 +2912,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 }
 
 static int is_frame_from_current_bss(struct atmel_private *priv,
-				     struct ieee80211_hdr_4addr *header)
+				     struct ieee80211_hdr *header)
 {
-	if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+	if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
 		return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
 	else
 		return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
@@ -2962,7 +2962,7 @@ static int retrieve_bss(struct atmel_private *priv)
 }
 
 static void store_bss_info(struct atmel_private *priv,
-			   struct ieee80211_hdr_4addr *header, u16 capability,
+			   struct ieee80211_hdr *header, u16 capability,
 			   u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len,
 			   u8 *ssid, int is_beacon)
 {
@@ -3001,7 +3001,7 @@ static void store_bss_info(struct atmel_private *priv,
 	else if (capability & WLAN_CAPABILITY_ESS)
 		priv->BSSinfo[index].BSStype =IW_MODE_INFRA;
 
-	priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+	priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
 		SHORT_PREAMBLE : LONG_PREAMBLE;
 }
 
@@ -3037,7 +3037,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
 			}
 		} else if (system == WLAN_AUTH_SHARED_KEY) {
 			if (trans_seq_no == 0x0002 &&
-			    auth->el_id == MFIE_TYPE_CHALLENGE) {
+			    auth->el_id == WLAN_EID_CHALLENGE) {
 				send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
 				return;
 			} else if (trans_seq_no == 0x0004) {
@@ -3288,12 +3288,12 @@ static void atmel_smooth_qual(struct atmel_private *priv)
 
 /* deals with incoming managment frames. */
 static void atmel_management_frame(struct atmel_private *priv,
-				   struct ieee80211_hdr_4addr *header,
+				   struct ieee80211_hdr *header,
 				   u16 frame_len, u8 rssi)
 {
 	u16 subtype;
 
-	subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE;
+	subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE;
 	switch (subtype) {
 	case IEEE80211_STYPE_BEACON:
 	case IEEE80211_STYPE_PROBE_RESP:

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

@@ -718,7 +718,6 @@ struct b43_wldev {
 
 	bool bad_frames_preempt;	/* Use "Bad Frames Preemption" (default off) */
 	bool dfq_valid;		/* Directed frame queue valid (IBSS PS mode, ATIM) */
-	bool short_slot;	/* TRUE, if short slot timing is enabled. */
 	bool radio_hw_enable;	/* saved state of radio hardware enabled state */
 	bool suspend_in_progress;	/* TRUE, if we are in a suspend/resume cycle */
 

+ 99 - 33
drivers/net/wireless/b43/main.c

@@ -703,13 +703,11 @@ static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
 static void b43_short_slot_timing_enable(struct b43_wldev *dev)
 {
 	b43_set_slot_time(dev, 9);
-	dev->short_slot = 1;
 }
 
 static void b43_short_slot_timing_disable(struct b43_wldev *dev)
 {
 	b43_set_slot_time(dev, 20);
-	dev->short_slot = 0;
 }
 
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -1674,25 +1672,6 @@ static void b43_update_templates(struct b43_wl *wl)
 	queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
 }
 
-static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
-{
-	u32 tmp;
-	u16 i, len;
-
-	len = min((u16) ssid_len, (u16) 0x100);
-	for (i = 0; i < len; i += sizeof(u32)) {
-		tmp = (u32) (ssid[i + 0]);
-		if (i + 1 < len)
-			tmp |= (u32) (ssid[i + 1]) << 8;
-		if (i + 2 < len)
-			tmp |= (u32) (ssid[i + 2]) << 16;
-		if (i + 3 < len)
-			tmp |= (u32) (ssid[i + 3]) << 24;
-		b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
-	}
-	b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
-}
-
 static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 {
 	b43_time_lock(dev);
@@ -3380,16 +3359,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 	if (conf->channel->hw_value != phy->channel)
 		b43_switch_channel(dev, conf->channel->hw_value);
 
-	/* Enable/Disable ShortSlot timing. */
-	if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
-	    dev->short_slot) {
-		B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-		if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-			b43_short_slot_timing_enable(dev);
-		else
-			b43_short_slot_timing_disable(dev);
-	}
-
 	dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
 
 	/* Adjust the desired TX power level. */
@@ -3440,6 +3409,104 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 	return err;
 }
 
+static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates)
+{
+	struct ieee80211_supported_band *sband =
+		dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
+	struct ieee80211_rate *rate;
+	int i;
+	u16 basic, direct, offset, basic_offset, rateptr;
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		rate = &sband->bitrates[i];
+
+		if (b43_is_cck_rate(rate->hw_value)) {
+			direct = B43_SHM_SH_CCKDIRECT;
+			basic = B43_SHM_SH_CCKBASIC;
+			offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+			offset &= 0xF;
+		} else {
+			direct = B43_SHM_SH_OFDMDIRECT;
+			basic = B43_SHM_SH_OFDMBASIC;
+			offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+			offset &= 0xF;
+		}
+
+		rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+		if (b43_is_cck_rate(rate->hw_value)) {
+			basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+			basic_offset &= 0xF;
+		} else {
+			basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+			basic_offset &= 0xF;
+		}
+
+		/*
+		 * Get the pointer that we need to point to
+		 * from the direct map
+		 */
+		rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
+					 direct + 2 * basic_offset);
+		/* and write it to the basic map */
+		b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
+				rateptr);
+	}
+}
+
+static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_bss_conf *conf,
+				    u32 changed)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev;
+	struct b43_phy *phy;
+	unsigned long flags;
+	u32 savedirqs;
+
+	mutex_lock(&wl->mutex);
+
+	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);
+		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);
+
+	if (changed & BSS_CHANGED_BASIC_RATES)
+		b43_update_basic_rates(dev, conf->basic_rates);
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		if (conf->use_short_slot)
+			b43_short_slot_timing_enable(dev);
+		else
+			b43_short_slot_timing_disable(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:
+	mutex_unlock(&wl->mutex);
+
+	return;
+}
+
 static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			   const u8 *local_addr, const u8 *addr,
 			   struct ieee80211_key_conf *key)
@@ -3602,8 +3669,6 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
 		if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
 		    b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
 			B43_WARN_ON(vif->type != wl->if_type);
-			if (conf->changed & IEEE80211_IFCC_SSID)
-				b43_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43_update_templates(wl);
 		} else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
@@ -4231,6 +4296,7 @@ static const struct ieee80211_ops b43_hw_ops = {
 	.add_interface		= b43_op_add_interface,
 	.remove_interface	= b43_op_remove_interface,
 	.config			= b43_op_config,
+	.bss_info_changed	= b43_op_bss_info_changed,
 	.config_interface	= b43_op_config_interface,
 	.configure_filter	= b43_op_configure_filter,
 	.set_key		= b43_op_set_key,

+ 1 - 1
drivers/net/wireless/b43legacy/dma.c

@@ -919,7 +919,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 
-				dma_test = ssb_dma_map_single(dev->dev,
+			dma_test = ssb_dma_map_single(dev->dev,
 					ring->txhdr_cache,
 					sizeof(struct b43legacy_txhdr_fw3),
 					DMA_TO_DEVICE);

+ 0 - 24
drivers/net/wireless/b43legacy/main.c

@@ -1160,29 +1160,6 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
 	wl->beacon1_uploaded = 0;
 }
 
-static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
-			       const u8 *ssid, u8 ssid_len)
-{
-	u32 tmp;
-	u16 i;
-	u16 len;
-
-	len = min((u16)ssid_len, (u16)0x100);
-	for (i = 0; i < len; i += sizeof(u32)) {
-		tmp = (u32)(ssid[i + 0]);
-		if (i + 1 < len)
-			tmp |= (u32)(ssid[i + 1]) << 8;
-		if (i + 2 < len)
-			tmp |= (u32)(ssid[i + 2]) << 16;
-		if (i + 3 < len)
-			tmp |= (u32)(ssid[i + 3]) << 24;
-		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
-				      0x380 + i, tmp);
-	}
-	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
-			      0x48, len);
-}
-
 static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
 				     u16 beacon_int)
 {
@@ -2744,7 +2721,6 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
 	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
 		if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
 			B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
-			b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43legacy_update_templates(wl);
 		} else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {

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

@@ -828,8 +828,6 @@ struct iwl3945_priv {
 	unsigned long last_statistics_time;
 
 	/* context information */
-	u8 essid[IW_ESSID_MAX_SIZE];
-	u8 essid_len;
 	u16 rates_mask;
 
 	u32 power_mode;

+ 2 - 2
drivers/net/wireless/iwlwifi/iwl-4965.c

@@ -2323,7 +2323,7 @@ static struct iwl_lib_ops iwl4965_lib = {
 		.reset = iwl4965_apm_reset,
 		.stop = iwl4965_apm_stop,
 		.config = iwl4965_nic_config,
-		.set_pwr_src = iwl4965_set_pwr_src,
+		.set_pwr_src = iwl_set_pwr_src,
 	},
 	.eeprom_ops = {
 		.regulatory_bands = {
@@ -2342,7 +2342,7 @@ static struct iwl_lib_ops iwl4965_lib = {
 		.query_addr = iwlcore_eeprom_query_addr,
 	},
 	.send_tx_power	= iwl4965_send_tx_power,
-	.update_chain_flags = iwl4965_update_chain_flags,
+	.update_chain_flags = iwl_update_chain_flags,
 	.temperature = iwl4965_temperature_calib,
 };
 

+ 6 - 6
drivers/net/wireless/iwlwifi/iwl-5000.c

@@ -535,7 +535,7 @@ static int iwl5000_load_section(struct iwl_priv *priv,
 	iwl_write_direct32(priv,
 		FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
 		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE	|
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
+		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE	|
 		FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
 	iwl_release_nic_access(priv);
@@ -549,14 +549,13 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
 {
 	int ret = 0;
 
-	ret = iwl5000_load_section(
-		priv, inst_image, RTC_INST_LOWER_BOUND);
+	ret = iwl5000_load_section(priv, inst_image, RTC_INST_LOWER_BOUND);
 	if (ret)
 		return ret;
 
 	IWL_DEBUG_INFO("INST uCode section being loaded...\n");
 	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-				priv->ucode_write_complete, 5 * HZ);
+					priv->ucode_write_complete, 5 * HZ);
 	if (ret == -ERESTARTSYS) {
 		IWL_ERROR("Could not load the INST uCode section due "
 			"to interrupt\n");
@@ -753,6 +752,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
 	priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
 
 	iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+
 	/* map qos queues to fifos one-to-one */
 	for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
 		int ac = iwl5000_default_queue_to_tx_fifo[i];
@@ -1474,13 +1474,13 @@ static struct iwl_lib_ops iwl5000_lib = {
 	.alive_notify = iwl5000_alive_notify,
 	.send_tx_power = iwl5000_send_tx_power,
 	.temperature = iwl5000_temperature,
-	.update_chain_flags = iwl4965_update_chain_flags,
+	.update_chain_flags = iwl_update_chain_flags,
 	.apm_ops = {
 		.init =	iwl5000_apm_init,
 		.reset = iwl5000_apm_reset,
 		.stop = iwl5000_apm_stop,
 		.config = iwl5000_nic_config,
-		.set_pwr_src = iwl4965_set_pwr_src,
+		.set_pwr_src = iwl_set_pwr_src,
 	},
 	.eeprom_ops = {
 		.regulatory_bands = {

+ 2 - 4
drivers/net/wireless/iwlwifi/iwl-agn-rs.c

@@ -2071,15 +2071,13 @@ static void rs_initialize_lq(struct iwl_priv *priv,
 	if ((i < 0) || (i >= IWL_RATE_COUNT))
 		i = 0;
 
-	/* FIXME:RS: This is also wrong in 4965 */
 	rate = iwl_rates[i].plcp;
-	rate |= RATE_MCS_ANT_B_MSK;
-	rate &= ~RATE_MCS_ANT_A_MSK;
+	tbl->ant_type = first_antenna(valid_tx_ant);
+	rate |= tbl->ant_type << RATE_MCS_ANT_POS;
 
 	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
 		rate |= RATE_MCS_CCK_MSK;
 
-	tbl->ant_type = ANT_B;
 	rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
 	if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
 	    rs_toggle_antenna(valid_tx_ant, &rate, tbl);

+ 4 - 4
drivers/net/wireless/iwlwifi/iwl-agn-rs.h

@@ -294,7 +294,7 @@ static inline u8 first_antenna(u8 mask)
 }
 
 
-static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
 {
 	u8 rate = iwl_rates[rate_index].prev_ieee;
 
@@ -304,11 +304,11 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
 }
 
 /**
- * iwl4965_rate_control_register - Register the rate control algorithm callbacks
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
  *
  * Since the rate control algorithm is hardware specific, there is no need
  * or reason to place it as a stand alone module.  The driver can call
- * iwl4965_rate_control_register in order to register the rate control callbacks
+ * iwl_rate_control_register in order to register the rate control callbacks
  * with the mac80211 subsystem.  This should be performed prior to calling
  * ieee80211_register_hw
  *
@@ -316,7 +316,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
 extern int iwlagn_rate_control_register(void);
 
 /**
- * iwl4965_rate_control_unregister - Unregister the rate control callbacks
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
  *
  * This should be called after calling ieee80211_unregister_hw, but before
  * the driver is unloaded.

File diff suppressed because it is too large
+ 129 - 126
drivers/net/wireless/iwlwifi/iwl-agn.c


+ 3 - 3
drivers/net/wireless/iwlwifi/iwl-commands.h

@@ -66,8 +66,8 @@
  * Please use iwl-dev.h for driver implementation definitions.
  */
 
-#ifndef __iwl4965_commands_h__
-#define __iwl4965_commands_h__
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
 
 enum {
 	REPLY_ALIVE = 0x1,
@@ -3064,4 +3064,4 @@ struct iwl_rx_packet {
 
 #define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl4965_rx_frame))
 
-#endif				/* __iwl4965_commands_h__ */
+#endif				/* __iwl_commands_h__ */

+ 2 - 4
drivers/net/wireless/iwlwifi/iwl-dev.h

@@ -576,8 +576,8 @@ extern int iwl_send_add_sta(struct iwl_priv *priv,
 			    struct iwl_addsta_cmd *sta, u8 flags);
 extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
 			int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
-extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
-extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+extern void iwl_update_chain_flags(struct iwl_priv *priv);
+extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
 extern const u8 iwl_bcast_addr[ETH_ALEN];
 extern int iwl_rxq_stop(struct iwl_priv *priv);
 extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
@@ -926,8 +926,6 @@ struct iwl_priv {
 	unsigned long last_statistics_time;
 
 	/* context information */
-	u8 essid[IW_ESSID_MAX_SIZE];
-	u8 essid_len;
 	u16 rates_mask;
 
 	u32 power_mode;

+ 29 - 23
drivers/net/wireless/iwlwifi/iwl-fh.h

@@ -318,34 +318,40 @@
 #define FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
 
 /* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
-	(FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+#define FH49_TCSR_CHNL_NUM                            (7)
+#define FH50_TCSR_CHNL_NUM                            (8)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl)	\
+		(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
+#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl)	\
+		(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl)	\
+		(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF		(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV		(0x00000001)
 
-#define FH_TCSR_CHNL_NUM                            (7)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE	(0x00000008)
 
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY          (0x00000000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT           (0x00002000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00000003)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD	(0x00100000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD	(0x00200000)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT           (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD          (0x00100000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD	(0x00400000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD	(0x00800000)
 
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM      (20)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX      (12)
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
-	(FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
-#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
-	  (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
-	 (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF	(0x40000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE	(0x80000000)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY	(0x00000000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT	(0x00002000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID	(0x00000003)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM		(20)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX		(12)
 
 /**
  * Tx Shared Status Registers (TSSR)
@@ -362,7 +368,7 @@
 #define FH_TSSR_LOWER_BOUND		(FH_MEM_LOWER_BOUND + 0xEA0)
 #define FH_TSSR_UPPER_BOUND		(FH_MEM_LOWER_BOUND + 0xEC0)
 
-#define FH_TSSR_TX_STATUS_REG	(FH_TSSR_LOWER_BOUND + 0x010)
+#define FH_TSSR_TX_STATUS_REG		(FH_TSSR_LOWER_BOUND + 0x010)
 
 #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
 #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)

+ 0 - 7
drivers/net/wireless/iwlwifi/iwl-scan.c

@@ -743,13 +743,6 @@ static void iwl_bg_request_scan(struct work_struct *data)
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		n_probes++;
-	} else if (!iwl_is_associated(priv) && priv->essid_len) {
-		IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
-				print_ssid(ssid, priv->essid, priv->essid_len));
-		scan->direct_scan[0].id = WLAN_EID_SSID;
-		scan->direct_scan[0].len = priv->essid_len;
-		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-		n_probes++;
 	} else {
 		IWL_DEBUG_SCAN("Start indirect scan.\n");
 	}

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

@@ -870,7 +870,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
 
 		link_cmd.rs_table[i].rate_n_flags =
 			iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-		r = iwl4965_get_prev_ieee_rate(r);
+		r = iwl_get_prev_ieee_rate(r);
 	}
 
 	link_cmd.general_params.single_stream_ant_msk =

+ 2 - 2
drivers/net/wireless/iwlwifi/iwl-tx.c

@@ -431,8 +431,8 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 
 	/* Enable DMA channel, using same id as for TFD queue */
 	iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
+			FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+			FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
 
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);

+ 11 - 54
drivers/net/wireless/iwlwifi/iwl3945-base.c

@@ -1593,7 +1593,7 @@ static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate,
  */
 static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
 			      struct ieee80211_mgmt *frame,
-			      int left, int is_direct)
+			      int left)
 {
 	int len = 0;
 	u8 *pos = NULL;
@@ -1623,20 +1623,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
 	*pos++ = WLAN_EID_SSID;
 	*pos++ = 0;
 
-	/* fill in our direct SSID IE... */
-	if (is_direct) {
-		/* ...next IE... */
-		left -= 2 + priv->essid_len;
-		if (left < 0)
-			return 0;
-		/* ... fill it in... */
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = priv->essid_len;
-		memcpy(pos, priv->essid, priv->essid_len);
-		pos += priv->essid_len;
-		len += 2 + priv->essid_len;
-	}
-
 	/* fill in supported rate */
 	/* ...next IE... */
 	left -= 2;
@@ -2189,13 +2175,14 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv,
 /*
  * initialize rxon structure with default values from eeprom
  */
-static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
+static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv,
+					      int mode)
 {
 	const struct iwl3945_channel_info *ch_info;
 
 	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
-	switch (priv->iw_mode) {
+	switch (mode) {
 	case NL80211_IFTYPE_AP:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
 		break;
@@ -2218,7 +2205,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
 		break;
 	default:
-		IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+		IWL_ERROR("Unsupported interface type %d\n", mode);
 		break;
 	}
 
@@ -2241,8 +2228,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
 	 * in some case A channels are all non IBSS
 	 * in this case force B/G channel
 	 */
-	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
-	    !(is_channel_ibss(ch_info)))
+	if ((mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info)))
 		ch_info = &priv->channel_info[0];
 
 	priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
@@ -2275,9 +2261,7 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
 		}
 	}
 
-	priv->iw_mode = mode;
-
-	iwl3945_connection_init_rx_config(priv);
+	iwl3945_connection_init_rx_config(priv, mode);
 	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
 	iwl3945_clear_stations_table(priv);
@@ -5699,7 +5683,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	} else {
 		/* Initialize our rx_config data */
-		iwl3945_connection_init_rx_config(priv);
+		iwl3945_connection_init_rx_config(priv, priv->iw_mode);
 		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 	}
 
@@ -6015,6 +5999,7 @@ static void iwl3945_bg_set_monitor(struct work_struct *work)
 			IWL_ERROR("iwl3945_set_mode() failed\n");
 
 	mutex_unlock(&priv->mutex);
+	ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC);
 }
 
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
@@ -6162,14 +6147,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		n_probes++;
-	} else if (!iwl3945_is_associated(priv) && priv->essid_len) {
-		IWL_DEBUG_SCAN
-		  ("Kicking off one direct scan for '%s' when not associated\n",
-		   print_ssid(ssid, priv->essid, priv->essid_len));
-		scan->direct_scan[0].id = WLAN_EID_SSID;
-		scan->direct_scan[0].len = priv->essid_len;
-		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-		n_probes++;
 	} else
 		IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
 
@@ -6177,7 +6154,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 	 * that based on the direct_mask added to each channel entry */
 	scan->tx_cmd.len = cpu_to_le16(
 		iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
-			IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
+			IWL_MAX_SCAN_SIZE - sizeof(*scan)));
 	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
 	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
 	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -6566,6 +6543,7 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
 
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->vif = conf->vif;
+	priv->iw_mode = conf->type;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -6742,7 +6720,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 				    struct ieee80211_if_conf *conf)
 {
 	struct iwl3945_priv *priv = hw->priv;
-	unsigned long flags;
 	int rc;
 
 	if (conf == NULL)
@@ -6764,15 +6741,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 			return rc;
 	}
 
-	/* XXX: this MUST use conf->mac_addr */
-
-	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
-	    (!conf->ssid_len)) {
-		IWL_DEBUG_MAC80211
-		    ("Leaving in AP mode because HostAPD is not ready.\n");
-		return 0;
-	}
-
 	if (!iwl3945_is_alive(priv))
 		return -EAGAIN;
 
@@ -6839,15 +6807,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 	}
 
  done:
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!conf->ssid_len)
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-	else
-		memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
-	priv->essid_len = conf->ssid_len;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	IWL_DEBUG_MAC80211("leave\n");
 	mutex_unlock(&priv->mutex);
 
@@ -6890,8 +6849,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
 	if (priv->vif == conf->vif) {
 		priv->vif = NULL;
 		memset(priv->bssid, 0, ETH_ALEN);
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-		priv->essid_len = 0;
 	}
 	mutex_unlock(&priv->mutex);
 

+ 10 - 8
drivers/net/wireless/libertas/assoc.c

@@ -2,6 +2,8 @@
 
 #include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
 #include <net/lib80211.h>
 
 #include "assoc.h"
@@ -341,12 +343,12 @@ static int lbs_adhoc_start(struct lbs_private *priv,
 	WARN_ON(!assoc_req->channel);
 
 	/* set Physical parameter set */
-	cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET;
+	cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS;
 	cmd.phyparamset.dsparamset.len = 1;
 	cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
 
 	/* set IBSS parameter set */
-	cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET;
+	cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS;
 	cmd.ssparamset.ibssparamset.len = 2;
 	cmd.ssparamset.ibssparamset.atimwindow = 0;
 
@@ -430,8 +432,8 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
 {
 	if (!secinfo->wep_enabled  && !secinfo->WPAenabled
 	    && !secinfo->WPA2enabled
-	    && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
-	    && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+	    && match_bss->wpa_ie[0] != WLAN_EID_GENERIC
+	    && match_bss->rsn_ie[0] != WLAN_EID_RSN
 	    && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
 		return 1;
 	else
@@ -453,7 +455,7 @@ static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
 				struct bss_descriptor *match_bss)
 {
 	if (!secinfo->wep_enabled && secinfo->WPAenabled
-	    && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+	    && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
 	    /* privacy bit may NOT be set in some APs like LinkSys WRT54G
 	    && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
 	   )
@@ -466,7 +468,7 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
 				 struct bss_descriptor *match_bss)
 {
 	if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
-	    (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+	    (match_bss->rsn_ie[0] == WLAN_EID_RSN)
 	    /* privacy bit may NOT be set in some APs like LinkSys WRT54G
 	    (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
 	   )
@@ -480,8 +482,8 @@ static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
 {
 	if (!secinfo->wep_enabled && !secinfo->WPAenabled
 	    && !secinfo->WPA2enabled
-	    && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
-	    && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+	    && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC)
+	    && (match_bss->rsn_ie[0] != WLAN_EID_RSN)
 	    && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
 		return 1;
 	else

+ 2 - 3
drivers/net/wireless/libertas/cmd.c

@@ -5,7 +5,6 @@
 
 #include <net/iw_handler.h>
 #include <net/lib80211.h>
-#include <net/ieee80211.h>
 #include <linux/kfifo.h>
 #include "host.h"
 #include "hostcmd.h"
@@ -1071,7 +1070,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
 
 	switch (action) {
 	case CMD_ACT_MESH_CONFIG_START:
-		ie->hdr.id = MFIE_TYPE_GENERIC;
+		ie->id = WLAN_EID_GENERIC;
 		ie->val.oui[0] = 0x00;
 		ie->val.oui[1] = 0x50;
 		ie->val.oui[2] = 0x43;
@@ -1083,7 +1082,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
 		ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
 		ie->val.mesh_id_len = priv->mesh_ssid_len;
 		memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
-		ie->hdr.len = sizeof(struct mrvl_meshie_val) -
+		ie->len = sizeof(struct mrvl_meshie_val) -
 			IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
 		cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
 		break;

+ 6 - 1
drivers/net/wireless/libertas/dev.h

@@ -10,7 +10,6 @@
 #include <linux/wireless.h>
 #include <linux/ethtool.h>
 #include <linux/debugfs.h>
-#include <net/ieee80211.h>
 
 #include "defs.h"
 #include "hostcmd.h"
@@ -278,6 +277,12 @@ struct lbs_private {
 	struct enc_key wpa_mcast_key;
 	struct enc_key wpa_unicast_key;
 
+/*
+ * In theory, the IE is limited to the IE length, 255,
+ * but in practice 64 bytes are enough.
+ */
+#define MAX_WPA_IE_LEN 64
+
 	/** WPA Information Elements*/
 	u8 wpa_ie[MAX_WPA_IE_LEN];
 	u8 wpa_ie_len;

+ 19 - 20
drivers/net/wireless/libertas/main.c

@@ -12,9 +12,8 @@
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
 #include <linux/stddef.h>
-
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include "host.h"
 #include "decl.h"
@@ -223,7 +222,7 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
 static ssize_t lbs_anycast_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_access mesh_access;
 	int ret;
 
@@ -242,7 +241,7 @@ static ssize_t lbs_anycast_get(struct device *dev,
 static ssize_t lbs_anycast_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_access mesh_access;
 	uint32_t datum;
 	int ret;
@@ -270,7 +269,7 @@ static void lbs_remove_mesh(struct lbs_private *priv);
 static ssize_t lbs_rtap_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	return snprintf(buf, 5, "0x%X\n", priv->monitormode);
 }
 
@@ -281,7 +280,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
 	int monitor_mode;
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 
 	sscanf(buf, "%x", &monitor_mode);
 	if (monitor_mode) {
@@ -332,7 +331,7 @@ static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
 static ssize_t lbs_mesh_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
 }
 
@@ -342,7 +341,7 @@ static ssize_t lbs_mesh_get(struct device *dev,
 static ssize_t lbs_mesh_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	int enable;
 	int ret, action = CMD_ACT_MESH_CONFIG_STOP;
 
@@ -393,7 +392,7 @@ static struct attribute_group lbs_mesh_attr_group = {
  */
 static int lbs_dev_open(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv ;
+	struct lbs_private *priv = netdev_priv(dev) ;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_NET);
@@ -435,7 +434,7 @@ static int lbs_dev_open(struct net_device *dev)
  */
 static int lbs_mesh_stop(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) (dev->priv);
+	struct lbs_private *priv = dev->ml_priv;
 
 	lbs_deb_enter(LBS_DEB_MESH);
 	spin_lock_irq(&priv->driver_lock);
@@ -462,7 +461,7 @@ static int lbs_mesh_stop(struct net_device *dev)
  */
 static int lbs_eth_stop(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_NET);
 
@@ -479,7 +478,7 @@ static int lbs_eth_stop(struct net_device *dev)
 
 static void lbs_tx_timeout(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_TX);
 
@@ -531,7 +530,7 @@ EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
  */
 static struct net_device_stats *lbs_get_stats(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_NET);
 	return &priv->stats;
@@ -540,7 +539,7 @@ static struct net_device_stats *lbs_get_stats(struct net_device *dev)
 static int lbs_set_mac_address(struct net_device *dev, void *addr)
 {
 	int ret = 0;
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct sockaddr *phwaddr = addr;
 	struct cmd_ds_802_11_mac_address cmd;
 
@@ -673,7 +672,7 @@ static void lbs_set_mcast_worker(struct work_struct *work)
 
 static void lbs_set_multicast_list(struct net_device *dev)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	schedule_work(&priv->mcast_work);
 }
@@ -689,7 +688,7 @@ static void lbs_set_multicast_list(struct net_device *dev)
 static int lbs_thread(void *data)
 {
 	struct net_device *dev = data;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	wait_queue_t wait;
 
 	lbs_deb_enter(LBS_DEB_THREAD);
@@ -1124,7 +1123,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
 		lbs_pr_err("init ethX device failed\n");
 		goto done;
 	}
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 
 	if (lbs_init_adapter(priv)) {
 		lbs_pr_err("failed to initialize adapter structure.\n");
@@ -1377,7 +1376,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
 		ret = -ENOMEM;
 		goto done;
 	}
-	mesh_dev->priv = priv;
+	mesh_dev->ml_priv = priv;
 	priv->mesh_dev = mesh_dev;
 
 	mesh_dev->open = lbs_dev_open;
@@ -1590,7 +1589,7 @@ static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = dev->ml_priv;
 	lbs_deb_enter(LBS_DEB_NET);
 	return &priv->stats;
 }
@@ -1631,7 +1630,7 @@ static int lbs_add_rtap(struct lbs_private *priv)
 	rtap_dev->stop = lbs_rtap_stop;
 	rtap_dev->get_stats = lbs_rtap_get_stats;
 	rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
-	rtap_dev->priv = priv;
+	rtap_dev->ml_priv = priv;
 	SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
 
 	ret = register_netdev(rtap_dev);

+ 1 - 1
drivers/net/wireless/libertas/persistcfg.c

@@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
 	/* SSID len */
 	ie->val.mesh_id_len = len;
 	/* IE len */
-	ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+	ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
 
 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 				   CMD_TYPE_MESH_SET_MESH_IE);

+ 39 - 38
drivers/net/wireless/libertas/scan.c

@@ -6,8 +6,8 @@
   */
 #include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 #include <asm/unaligned.h>
-
 #include <net/lib80211.h>
 
 #include "host.h"
@@ -55,6 +55,8 @@
 //! Scan time specified in the channel TLV for each channel for active scans
 #define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
 
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+
 static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
 			      struct cmd_header *resp);
 
@@ -591,38 +593,36 @@ static int lbs_process_bss(struct bss_descriptor *bss,
 
 	/* process variable IE */
 	while (pos <= end - 2) {
-		struct ieee80211_info_element * elem = (void *)pos;
-
-		if (pos + elem->len > end) {
+		if (pos + pos[1] > end) {
 			lbs_deb_scan("process_bss: error in processing IE, "
 				     "bytes left < IE length\n");
 			break;
 		}
 
-		switch (elem->id) {
-		case MFIE_TYPE_SSID:
-			bss->ssid_len = min_t(int, 32, elem->len);
-			memcpy(bss->ssid, elem->data, bss->ssid_len);
+		switch (pos[0]) {
+		case WLAN_EID_SSID:
+			bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
+			memcpy(bss->ssid, pos + 2, bss->ssid_len);
 			lbs_deb_scan("got SSID IE: '%s', len %u\n",
 			             print_ssid(ssid, bss->ssid, bss->ssid_len),
 			             bss->ssid_len);
 			break;
 
-		case MFIE_TYPE_RATES:
-			n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len);
-			memcpy(bss->rates, elem->data, n_basic_rates);
+		case WLAN_EID_SUPP_RATES:
+			n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
+			memcpy(bss->rates, pos + 2, n_basic_rates);
 			got_basic_rates = 1;
 			lbs_deb_scan("got RATES IE\n");
 			break;
 
-		case MFIE_TYPE_FH_SET:
+		case WLAN_EID_FH_PARAMS:
 			pFH = (struct ieeetypes_fhparamset *) pos;
 			memmove(&bss->phyparamset.fhparamset, pFH,
 				sizeof(struct ieeetypes_fhparamset));
 			lbs_deb_scan("got FH IE\n");
 			break;
 
-		case MFIE_TYPE_DS_SET:
+		case WLAN_EID_DS_PARAMS:
 			pDS = (struct ieeetypes_dsparamset *) pos;
 			bss->channel = pDS->currentchan;
 			memcpy(&bss->phyparamset.dsparamset, pDS,
@@ -630,14 +630,14 @@ static int lbs_process_bss(struct bss_descriptor *bss,
 			lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
 			break;
 
-		case MFIE_TYPE_CF_SET:
+		case WLAN_EID_CF_PARAMS:
 			pCF = (struct ieeetypes_cfparamset *) pos;
 			memcpy(&bss->ssparamset.cfparamset, pCF,
 			       sizeof(struct ieeetypes_cfparamset));
 			lbs_deb_scan("got CF IE\n");
 			break;
 
-		case MFIE_TYPE_IBSS_SET:
+		case WLAN_EID_IBSS_PARAMS:
 			pibss = (struct ieeetypes_ibssparamset *) pos;
 			bss->atimwindow = le16_to_cpu(pibss->atimwindow);
 			memmove(&bss->ssparamset.ibssparamset, pibss,
@@ -645,7 +645,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
 			lbs_deb_scan("got IBSS IE\n");
 			break;
 
-		case MFIE_TYPE_COUNTRY:
+		case WLAN_EID_COUNTRY:
 			pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
 			lbs_deb_scan("got COUNTRY IE\n");
 			if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
@@ -662,7 +662,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
 				    (int) (pcountryinfo->len + 2));
 			break;
 
-		case MFIE_TYPE_RATES_EX:
+		case WLAN_EID_EXT_SUPP_RATES:
 			/* only process extended supported rate if data rate is
 			 * already found. Data rate IE should come before
 			 * extended supported rate IE
@@ -673,50 +673,51 @@ static int lbs_process_bss(struct bss_descriptor *bss,
 				break;
 			}
 
-			n_ex_rates = elem->len;
+			n_ex_rates = pos[1];
 			if (n_basic_rates + n_ex_rates > MAX_RATES)
 				n_ex_rates = MAX_RATES - n_basic_rates;
 
 			p = bss->rates + n_basic_rates;
-			memcpy(p, elem->data, n_ex_rates);
+			memcpy(p, pos + 2, n_ex_rates);
 			break;
 
-		case MFIE_TYPE_GENERIC:
-			if (elem->len >= 4 &&
-			    elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
-			    elem->data[2] == 0xf2 && elem->data[3] == 0x01) {
-				bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
-				memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
+		case WLAN_EID_GENERIC:
+			if (pos[1] >= 4 &&
+			    pos[2] == 0x00 && pos[3] == 0x50 &&
+			    pos[4] == 0xf2 && pos[5] == 0x01) {
+				bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+				memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
 				lbs_deb_scan("got WPA IE\n");
-				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len);
-			} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
-				   elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
-				   elem->data[2] == 0x43 && elem->data[3] == 0x04) {
+				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
+					    bss->wpa_ie_len);
+			} else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
+				   pos[2] == 0x00 && pos[3] == 0x50 &&
+				   pos[4] == 0x43 && pos[4] == 0x04) {
 				lbs_deb_scan("got mesh IE\n");
 				bss->mesh = 1;
 			} else {
 				lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
-					elem->data[0], elem->data[1],
-					elem->data[2], elem->data[3],
-					elem->len);
+					pos[2], pos[3],
+					pos[4], pos[5],
+					pos[1]);
 			}
 			break;
 
-		case MFIE_TYPE_RSN:
+		case WLAN_EID_RSN:
 			lbs_deb_scan("got RSN IE\n");
-			bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
-			memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
+			bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+			memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
 			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
-				    bss->rsn_ie, elem->len);
+				    bss->rsn_ie, bss->rsn_ie_len);
 			break;
 
 		default:
 			lbs_deb_scan("got IE 0x%04x, len %d\n",
-				     elem->id, elem->len);
+				     pos[0], pos[1]);
 			break;
 		}
 
-		pos += elem->len + 2;
+		pos += pos[1] + 2;
 	}
 
 	/* Timestamp */

+ 4 - 0
drivers/net/wireless/libertas/scan.h

@@ -7,6 +7,10 @@
 #ifndef _LBS_SCAN_H
 #define _LBS_SCAN_H
 
+#include <net/iw_handler.h>
+
+#define MAX_NETWORK_COUNT 128
+
 /**
  *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
  */

+ 2 - 3
drivers/net/wireless/libertas/types.h

@@ -7,7 +7,6 @@
 #include <linux/if_ether.h>
 #include <asm/byteorder.h>
 #include <linux/wireless.h>
-#include <net/ieee80211.h>
 
 struct ieeetypes_cfparamset {
 	u8 elementid;
@@ -258,7 +257,7 @@ struct mrvlietypes_ledbhv {
  * Note that the len member of the ieee80211_info_element varies depending on
  * the mesh_id_len */
 struct mrvl_meshie_val {
-	uint8_t oui[P80211_OUI_LEN];
+	uint8_t oui[3];
 	uint8_t type;
 	uint8_t subtype;
 	uint8_t version;
@@ -270,7 +269,7 @@ struct mrvl_meshie_val {
 } __attribute__ ((packed));
 
 struct mrvl_meshie {
-	struct ieee80211_info_element hdr;
+	u8 id, len;
 	struct mrvl_meshie_val val;
 } __attribute__ ((packed));
 

+ 0 - 1
drivers/net/wireless/libertas/wext.c

@@ -9,7 +9,6 @@
 #include <linux/bitops.h>
 
 #include <net/lib80211.h>
-#include <net/ieee80211.h>
 #include <net/iw_handler.h>
 
 #include "host.h"

+ 1 - 1
drivers/net/wireless/libertas_tf/if_usb.c

@@ -331,7 +331,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
 	/* Fill the receive configuration URB and initialise the Rx call back */
 	usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
 			  usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
-			  (void *) (skb->tail),
+			  skb_tail_pointer(skb),
 			  MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp);
 
 	cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;

+ 234 - 0
drivers/net/wireless/mac80211_hwsim.c

@@ -21,6 +21,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/etherdevice.h>
+#include <linux/debugfs.h>
 
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
@@ -32,6 +33,9 @@ MODULE_PARM_DESC(radios, "Number of simulated radios");
 
 struct hwsim_vif_priv {
 	u32 magic;
+	u8 bssid[ETH_ALEN];
+	bool assoc;
+	u16 aid;
 };
 
 #define HWSIM_VIF_MAGIC	0x69537748
@@ -132,6 +136,12 @@ struct mac80211_hwsim_data {
 	unsigned int rx_filter;
 	int started;
 	struct timer_list beacon_timer;
+	enum ps_mode {
+		PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
+	} ps;
+	bool ps_poll_pending;
+	struct dentry *debugfs;
+	struct dentry *debugfs_ps;
 };
 
 
@@ -196,6 +206,34 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
 }
 
 
+static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
+			   struct sk_buff *skb)
+{
+	switch (data->ps) {
+	case PS_DISABLED:
+		return true;
+	case PS_ENABLED:
+		return false;
+	case PS_AUTO_POLL:
+		/* TODO: accept (some) Beacons by default and other frames only
+		 * if pending PS-Poll has been sent */
+		return true;
+	case PS_MANUAL_POLL:
+		/* Allow unicast frames to own address if there is a pending
+		 * PS-Poll */
+		if (data->ps_poll_pending &&
+		    memcmp(data->hw->wiphy->perm_addr, skb->data + 4,
+			   ETH_ALEN) == 0) {
+			data->ps_poll_pending = false;
+			return true;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+
 static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
 				    struct sk_buff *skb)
 {
@@ -212,6 +250,9 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
 	rx_status.rate_idx = info->control.rates[0].idx;
 	/* TODO: simulate signal strength (and optional packet drop) */
 
+	if (data->ps != PS_DISABLED)
+		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+
 	/* Copy skb to all enabled radios that are on the current frequency */
 	spin_lock(&hwsim_radio_lock);
 	list_for_each_entry(data2, &hwsim_radios, list) {
@@ -221,6 +262,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
 			continue;
 
 		if (!data2->started || !data2->radio_enabled ||
+		    !hwsim_ps_rx_ok(data2, skb) ||
 		    data->channel->center_freq != data2->channel->center_freq)
 			continue;
 
@@ -290,6 +332,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 	data->started = 0;
+	del_timer(&data->beacon_timer);
 	printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
 }
 
@@ -403,7 +446,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif,
 					   struct ieee80211_if_conf *conf)
 {
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
 	hwsim_check_magic(vif);
+	if (conf->changed & IEEE80211_IFCC_BSSID) {
+		DECLARE_MAC_BUF(mac);
+		printk(KERN_DEBUG "%s:%s: BSSID changed: %s\n",
+		       wiphy_name(hw->wiphy), __func__,
+		       print_mac(mac, conf->bssid));
+		memcpy(vp->bssid, conf->bssid, ETH_ALEN);
+	}
 	return 0;
 }
 
@@ -412,7 +464,48 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
 					    struct ieee80211_bss_conf *info,
 					    u32 changed)
 {
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
 	hwsim_check_magic(vif);
+
+	printk(KERN_DEBUG "%s:%s(changed=0x%x)\n",
+	       wiphy_name(hw->wiphy), __func__, changed);
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		printk(KERN_DEBUG "  %s: ASSOC: assoc=%d aid=%d\n",
+		       wiphy_name(hw->wiphy), info->assoc, info->aid);
+		vp->assoc = info->assoc;
+		vp->aid = info->aid;
+	}
+
+	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+		printk(KERN_DEBUG "  %s: ERP_CTS_PROT: %d\n",
+		       wiphy_name(hw->wiphy), info->use_cts_prot);
+	}
+
+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+		printk(KERN_DEBUG "  %s: ERP_PREAMBLE: %d\n",
+		       wiphy_name(hw->wiphy), info->use_short_preamble);
+	}
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		printk(KERN_DEBUG "  %s: ERP_SLOT: %d\n",
+		       wiphy_name(hw->wiphy), info->use_short_slot);
+	}
+
+	if (changed & BSS_CHANGED_HT) {
+		printk(KERN_DEBUG "  %s: HT: sec_ch_offs=%d width_40_ok=%d "
+		       "op_mode=%d\n",
+		       wiphy_name(hw->wiphy),
+		       info->ht.secondary_channel_offset,
+		       info->ht.width_40_ok, info->ht.operation_mode);
+	}
+
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		printk(KERN_DEBUG "  %s: BASIC_RATES: 0x%llx\n",
+		       wiphy_name(hw->wiphy),
+		       (unsigned long long) info->basic_rates);
+	}
 }
 
 static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
@@ -439,6 +532,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
 	return 0;
 }
 
+static int mac80211_hwsim_conf_tx(
+	struct ieee80211_hw *hw, u16 queue,
+	const struct ieee80211_tx_queue_params *params)
+{
+	printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d "
+	       "aifs=%d)\n",
+	       wiphy_name(hw->wiphy), __func__, queue,
+	       params->txop, params->cw_min, params->cw_max, params->aifs);
+	return 0;
+}
+
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
 	.tx = mac80211_hwsim_tx,
@@ -452,6 +556,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
 	.bss_info_changed = mac80211_hwsim_bss_info_changed,
 	.sta_notify = mac80211_hwsim_sta_notify,
 	.set_tim = mac80211_hwsim_set_tim,
+	.conf_tx = mac80211_hwsim_conf_tx,
 };
 
 
@@ -468,6 +573,8 @@ static void mac80211_hwsim_free(void)
 	spin_unlock_bh(&hwsim_radio_lock);
 
 	list_for_each_entry(data, &tmplist, list) {
+		debugfs_remove(data->debugfs_ps);
+		debugfs_remove(data->debugfs);
 		ieee80211_unregister_hw(data->hw);
 		device_unregister(data->dev);
 		ieee80211_free_hw(data->hw);
@@ -493,6 +600,127 @@ static void hwsim_mon_setup(struct net_device *dev)
 }
 
 
+static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
+{
+	struct mac80211_hwsim_data *data = dat;
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+	DECLARE_MAC_BUF(buf);
+	struct sk_buff *skb;
+	struct ieee80211_pspoll *pspoll;
+
+	if (!vp->assoc)
+		return;
+
+	printk(KERN_DEBUG "%s:%s: send PS-Poll to %s for aid %d\n",
+	       wiphy_name(data->hw->wiphy), __func__,
+	       print_mac(buf, vp->bssid), vp->aid);
+
+	skb = dev_alloc_skb(sizeof(*pspoll));
+	if (!skb)
+		return;
+	pspoll = (void *) skb_put(skb, sizeof(*pspoll));
+	pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+					    IEEE80211_STYPE_PSPOLL |
+					    IEEE80211_FCTL_PM);
+	pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
+	memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
+	memcpy(pspoll->ta, mac, ETH_ALEN);
+	if (data->radio_enabled &&
+	    !mac80211_hwsim_tx_frame(data->hw, skb))
+		printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
+	dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
+				struct ieee80211_vif *vif, int ps)
+{
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+	DECLARE_MAC_BUF(buf);
+	struct sk_buff *skb;
+	struct ieee80211_hdr *hdr;
+
+	if (!vp->assoc)
+		return;
+
+	printk(KERN_DEBUG "%s:%s: send data::nullfunc to %s ps=%d\n",
+	       wiphy_name(data->hw->wiphy), __func__,
+	       print_mac(buf, vp->bssid), ps);
+
+	skb = dev_alloc_skb(sizeof(*hdr));
+	if (!skb)
+		return;
+	hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN);
+	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+					 IEEE80211_STYPE_NULLFUNC |
+					 (ps ? IEEE80211_FCTL_PM : 0));
+	hdr->duration_id = cpu_to_le16(0);
+	memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
+	memcpy(hdr->addr2, mac, ETH_ALEN);
+	memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
+	if (data->radio_enabled &&
+	    !mac80211_hwsim_tx_frame(data->hw, skb))
+		printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
+	dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc_ps(void *dat, u8 *mac,
+				   struct ieee80211_vif *vif)
+{
+	struct mac80211_hwsim_data *data = dat;
+	hwsim_send_nullfunc(data, mac, vif, 1);
+}
+
+
+static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac,
+				      struct ieee80211_vif *vif)
+{
+	struct mac80211_hwsim_data *data = dat;
+	hwsim_send_nullfunc(data, mac, vif, 0);
+}
+
+
+static int hwsim_fops_ps_read(void *dat, u64 *val)
+{
+	struct mac80211_hwsim_data *data = dat;
+	*val = data->ps;
+	return 0;
+}
+
+static int hwsim_fops_ps_write(void *dat, u64 val)
+{
+	struct mac80211_hwsim_data *data = dat;
+	enum ps_mode old_ps;
+
+	if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL &&
+	    val != PS_MANUAL_POLL)
+		return -EINVAL;
+
+	old_ps = data->ps;
+	data->ps = val;
+
+	if (val == PS_MANUAL_POLL) {
+		ieee80211_iterate_active_interfaces(data->hw,
+						    hwsim_send_ps_poll, data);
+		data->ps_poll_pending = true;
+	} else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
+		ieee80211_iterate_active_interfaces(data->hw,
+						    hwsim_send_nullfunc_ps,
+						    data);
+	} else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
+		ieee80211_iterate_active_interfaces(data->hw,
+						    hwsim_send_nullfunc_no_ps,
+						    data);
+	}
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
+			"%llu\n");
+
+
 static int __init init_mac80211_hwsim(void)
 {
 	int i, err = 0;
@@ -584,6 +812,12 @@ static int __init init_mac80211_hwsim(void)
 		       wiphy_name(hw->wiphy),
 		       hw->wiphy->perm_addr);
 
+		data->debugfs = debugfs_create_dir("hwsim",
+						   hw->wiphy->debugfsdir);
+		data->debugfs_ps = debugfs_create_file("ps", 0666,
+						       data->debugfs, data,
+						       &hwsim_fops_ps);
+
 		setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
 			    (unsigned long) hw);
 

+ 12 - 0
drivers/net/wireless/orinoco/Makefile

@@ -0,0 +1,12 @@
+#
+# Makefile for the orinoco wireless device drivers.
+#
+
+obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o hermes_dld.o
+obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
+obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
+obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
+obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
+obj-$(CONFIG_TMD_HERMES)	+= orinoco_tmd.o
+obj-$(CONFIG_NORTEL_HERMES)	+= orinoco_nortel.o
+obj-$(CONFIG_PCMCIA_SPECTRUM)	+= spectrum_cs.o

+ 0 - 0
drivers/net/wireless/airport.c → drivers/net/wireless/orinoco/airport.c


+ 0 - 0
drivers/net/wireless/hermes.c → drivers/net/wireless/orinoco/hermes.c


+ 0 - 0
drivers/net/wireless/hermes.h → drivers/net/wireless/orinoco/hermes.h


+ 0 - 0
drivers/net/wireless/hermes_dld.c → drivers/net/wireless/orinoco/hermes_dld.c


+ 0 - 0
drivers/net/wireless/hermes_dld.h → drivers/net/wireless/orinoco/hermes_dld.h


+ 0 - 0
drivers/net/wireless/hermes_rid.h → drivers/net/wireless/orinoco/hermes_rid.h


+ 16 - 14
drivers/net/wireless/orinoco.c → drivers/net/wireless/orinoco/orinoco.c

@@ -86,8 +86,8 @@
 #include <linux/firmware.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include <linux/scatterlist.h>
 #include <linux/crypto.h>
@@ -143,7 +143,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 #define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
 
 #define ORINOCO_MIN_MTU		256
-#define ORINOCO_MAX_MTU		(IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
+#define ORINOCO_MAX_MTU		(IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
 
 #define SYMBOL_MAX_VER_LEN	(14)
 #define USER_BAP		0
@@ -392,7 +392,7 @@ static void orinoco_bss_data_init(struct orinoco_private *priv)
 }
 
 static inline u8 *orinoco_get_ie(u8 *data, size_t len,
-				 enum ieee80211_mfie eid)
+				 enum ieee80211_eid eid)
 {
 	u8 *p = data;
 	while ((p + 2) < (data + len)) {
@@ -409,7 +409,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
 {
 	u8 *p = data;
 	while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
-		if ((p[0] == MFIE_TYPE_GENERIC) &&
+		if ((p[0] == WLAN_EID_GENERIC) &&
 		    (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
 			return p;
 		p += p[1] + 2;
@@ -839,7 +839,8 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 	if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
 		return -EINVAL;
 
-	if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
+	/* MTU + encapsulation + header length */
+	if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
 	     (priv->nicbuf_size - ETH_HLEN) )
 		return -EINVAL;
 
@@ -1254,7 +1255,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
 	}
 
 	/* sanity check the length */
-	if (datalen > IEEE80211_DATA_LEN + 12) {
+	if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
 		printk(KERN_DEBUG "%s: oversized monitor frame, "
 		       "data length = %d\n", dev->name, datalen);
 		stats->rx_length_errors++;
@@ -1382,7 +1383,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
                    data. */
 		goto out;
 	}
-	if (length > IEEE80211_DATA_LEN) {
+	if (length > IEEE80211_MAX_DATA_LEN) {
 		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
 		       dev->name, length);
 		stats->rx_length_errors++;
@@ -3285,7 +3286,7 @@ static int orinoco_init(struct net_device *dev)
 
 	/* No need to lock, the hw_unavailable flag is already set in
 	 * alloc_orinocodev() */
-	priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
+	priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
 
 	/* Initialize the firmware */
 	err = hermes_init(hw);
@@ -4681,7 +4682,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
 	/* Determine and validate the key index */
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if ((idx < 1) || (idx > WEP_KEYS))
+		if ((idx < 1) || (idx > 4))
 			goto out;
 		idx--;
 	} else
@@ -4786,7 +4787,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
 
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if ((idx < 1) || (idx > WEP_KEYS))
+		if ((idx < 1) || (idx > 4))
 			goto out;
 		idx--;
 	} else
@@ -4949,7 +4950,8 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
 	unsigned long flags;
 	int err = 0;
 
-	if ((wrqu->data.length > MAX_WPA_IE_LEN) ||
+	/* cut off at IEEE80211_MAX_DATA_LEN */
+	if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
 	    (wrqu->data.length && (extra == NULL)))
 		return -EINVAL;
 
@@ -5632,7 +5634,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
 						  &iwe, IW_EV_UINT_LEN);
 	}
 
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET);
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
 	channel = ie ? ie[2] : 0;
 	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
 		/* Add channel and frequency */
@@ -5682,7 +5684,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
 	}
 
 	/* RSN IE */
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN);
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
 	if (ie) {
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = ie[1] + 2;
@@ -5690,7 +5692,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
 						  &iwe, ie);
 	}
 
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES);
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
 	if (ie) {
 		char *p = current_ev + iwe_stream_lcp_len(info);
 		int i;

+ 0 - 0
drivers/net/wireless/orinoco.h → drivers/net/wireless/orinoco/orinoco.h


+ 0 - 0
drivers/net/wireless/orinoco_cs.c → drivers/net/wireless/orinoco/orinoco_cs.c


+ 0 - 0
drivers/net/wireless/orinoco_nortel.c → drivers/net/wireless/orinoco/orinoco_nortel.c


+ 0 - 0
drivers/net/wireless/orinoco_pci.c → drivers/net/wireless/orinoco/orinoco_pci.c


+ 0 - 0
drivers/net/wireless/orinoco_pci.h → drivers/net/wireless/orinoco/orinoco_pci.h


+ 0 - 0
drivers/net/wireless/orinoco_plx.c → drivers/net/wireless/orinoco/orinoco_plx.c


+ 0 - 0
drivers/net/wireless/orinoco_tmd.c → drivers/net/wireless/orinoco/orinoco_tmd.c


+ 0 - 0
drivers/net/wireless/spectrum_cs.c → drivers/net/wireless/orinoco/spectrum_cs.c


+ 1 - 0
drivers/net/wireless/p54/p54.h

@@ -108,6 +108,7 @@ struct p54_common {
 	struct timer_list stats_timer;
 	struct completion stats_comp;
 	struct sk_buff *cached_stats;
+	struct sk_buff *cached_beacon;
 	int noise;
 	void *eeprom;
 	struct completion eeprom_comp;

+ 396 - 56
drivers/net/wireless/p54/p54common.c

@@ -9,7 +9,7 @@
  * - the islsm (softmac prism54) driver, which is:
  *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
  * - stlc45xx driver
- * C  Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -214,12 +214,17 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
 		printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
 			fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
 
+	if (priv->fw_var < 0x500)
+		printk(KERN_INFO "p54: you are using an obsolete firmware. "
+		       "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+		       "and grab one for \"kernel >= 2.6.28\"!\n");
+
 	if (priv->fw_var >= 0x300) {
 		/* Firmware supports QoS, use it! */
-		priv->tx_stats[4].limit = 3;
-		priv->tx_stats[5].limit = 4;
-		priv->tx_stats[6].limit = 3;
-		priv->tx_stats[7].limit = 1;
+		priv->tx_stats[4].limit = 3;		/* AC_VO */
+		priv->tx_stats[5].limit = 4;		/* AC_VI */
+		priv->tx_stats[6].limit = 3;		/* AC_BE */
+		priv->tx_stats[7].limit = 2;		/* AC_BK */
 		dev->queues = 4;
 	}
 
@@ -415,6 +420,30 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 			/* make it overrun */
 			entry_len = len;
 			break;
+		case PDR_MANUFACTURING_PART_NUMBER:
+		case PDR_PDA_VERSION:
+		case PDR_NIC_SERIAL_NUMBER:
+		case PDR_REGULATORY_DOMAIN_LIST:
+		case PDR_TEMPERATURE_TYPE:
+		case PDR_PRISM_PCI_IDENTIFIER:
+		case PDR_COUNTRY_INFORMATION:
+		case PDR_OEM_NAME:
+		case PDR_PRODUCT_NAME:
+		case PDR_UTF8_OEM_NAME:
+		case PDR_UTF8_PRODUCT_NAME:
+		case PDR_COUNTRY_LIST:
+		case PDR_DEFAULT_COUNTRY:
+		case PDR_ANTENNA_GAIN:
+		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_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+		case PDR_RADIATED_TRANSMISSION_CORRECTION:
+		case PDR_PRISM_TX_IQ_CALIBRATION:
+		case PDR_BASEBAND_REGISTERS:
+		case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
+			break;
 		default:
 			printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n",
 				le16_to_cpu(entry->code));
@@ -431,12 +460,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 		goto err;
 	}
 
-	priv->rxhw = synth & 0x07;
+	priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
 	if (priv->rxhw == 4)
 		p54_init_xbow_synth(dev);
-	if (!(synth & 0x40))
+	if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
 		dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
-	if (!(synth & 0x80))
+	if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
 		dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
 
 	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
@@ -621,6 +650,12 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 		__skb_unlink(entry, &priv->tx_queue);
 		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
+		if (unlikely(entry == priv->cached_beacon)) {
+			kfree_skb(entry);
+			priv->cached_beacon = NULL;
+			goto out;
+		}
+
 		/*
 		 * Clear manually, ieee80211_tx_info_clear_status would
 		 * clear the counts too and we need them.
@@ -654,7 +689,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
 		     (!payload->status))
 			info->flags |= IEEE80211_TX_STAT_ACK;
-		if (payload->status & 0x02)
+		if (payload->status & P54_TX_PSM_CANCELLED)
 			info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
 		info->status.ack_signal = p54_rssi_to_dbm(dev,
 				(int)payload->ack_rssi);
@@ -706,6 +741,35 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
 	mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
 }
 
+static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+	struct p54_trap *trap = (struct p54_trap *) hdr->data;
+	u16 event = le16_to_cpu(trap->event);
+	u16 freq = le16_to_cpu(trap->frequency);
+
+	switch (event) {
+	case P54_TRAP_BEACON_TX:
+		break;
+	case P54_TRAP_RADAR:
+		printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+			wiphy_name(dev->wiphy), freq);
+		break;
+	case P54_TRAP_NO_BEACON:
+		break;
+	case P54_TRAP_SCAN:
+		break;
+	case P54_TRAP_TBTT:
+		break;
+	case P54_TRAP_TIMER:
+		break;
+	default:
+		printk(KERN_INFO "%s: received event:%x freq:%d\n",
+		       wiphy_name(dev->wiphy), event, freq);
+		break;
+	}
+}
+
 static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
@@ -714,6 +778,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 	case P54_CONTROL_TYPE_TXDONE:
 		p54_rx_frame_sent(dev, skb);
 		break;
+	case P54_CONTROL_TYPE_TRAP:
+		p54_rx_trap(dev, skb);
+		break;
 	case P54_CONTROL_TYPE_BBP:
 		break;
 	case P54_CONTROL_TYPE_STAT_READBACK:
@@ -734,9 +801,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 /* returns zero if skb can be reused */
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
-	u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
+	u16 type = le16_to_cpu(*((__le16 *)skb->data));
 
-	if (type == 0x80)
+	if (type & P54_HDR_FLAG_CONTROL)
 		return p54_rx_control(dev, skb);
 	else
 		return p54_rx_data(dev, skb);
@@ -897,41 +964,162 @@ free:
 }
 EXPORT_SYMBOL_GPL(p54_read_eeprom);
 
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+		bool set)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_tim *tim;
+
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+		      sizeof(struct p54_hdr) + sizeof(*tim),
+		      P54_CONTROL_TYPE_TIM, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+	tim->count = 1;
+	tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
+	priv->tx(dev, skb, 1);
+	return 0;
+}
+
+static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_sta_unlock *sta;
+
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+		sizeof(struct p54_hdr) + sizeof(*sta),
+		P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+	memcpy(sta->addr, addr, ETH_ALEN);
+	priv->tx(dev, skb, 1);
+	return 0;
+}
+
+static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_hdr *hdr;
+	struct p54_txcancel *cancel;
+
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+		sizeof(struct p54_hdr) + sizeof(*cancel),
+		P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	hdr = (void *)entry->data;
+	cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+	cancel->req_id = hdr->req_id;
+	priv->tx(dev, skb, 1);
+	return 0;
+}
+
+static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
+		struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
+		u16 *flags, u16 *aid)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct p54_common *priv = dev->priv;
+	int ret = 0;
+
+	if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+		if (ieee80211_is_beacon(hdr->frame_control)) {
+			*aid = 0;
+			*queue = 0;
+			*extra_len = IEEE80211_MAX_TIM_LEN;
+			*flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+			return 0;
+		} else if (ieee80211_is_probe_resp(hdr->frame_control)) {
+			*aid = 0;
+			*queue = 2;
+			*flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+				 P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+			return 0;
+		} else {
+			*queue = 2;
+			ret = 0;
+		}
+	} else {
+		*queue += 4;
+		ret = 1;
+	}
+
+	switch (priv->mode) {
+	case NL80211_IFTYPE_STATION:
+		*aid = 1;
+		break;
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+		if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+			*aid = 0;
+			*queue = 3;
+			return 0;
+		}
+		if (info->control.sta)
+			*aid = info->control.sta->aid;
+		else
+			*flags = P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+	}
+	return ret;
+}
+
 static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_tx_queue_stats *current_queue;
+	struct ieee80211_tx_queue_stats *current_queue = NULL;
 	struct p54_common *priv = dev->priv;
 	struct p54_hdr *hdr;
 	struct p54_tx_data *txhdr;
-	size_t padding, len;
+	size_t padding, len, tim_len = 0;
 	int i, j, ridx;
-	u8 rate;
+	u16 hdr_flags = 0, aid = 0;
+	u8 rate, queue;
 	u8 cts_rate = 0x20;
 	u8 rc_flags;
 	u8 calculated_tries[4];
 	u8 nrates = 0, nremaining = 8;
 
-	current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
-	if (unlikely(current_queue->len > current_queue->limit))
-		return NETDEV_TX_BUSY;
-	current_queue->len++;
-	current_queue->count++;
-	if (current_queue->len == current_queue->limit)
-		ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+	queue = skb_get_queue_mapping(skb);
+
+	if (p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid)) {
+		current_queue = &priv->tx_stats[queue];
+		if (unlikely(current_queue->len > current_queue->limit))
+			return NETDEV_TX_BUSY;
+		current_queue->len++;
+		current_queue->count++;
+		if (current_queue->len == current_queue->limit)
+			ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+	}
 
 	padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
 	len = skb->len;
 
+	if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) {
+		if (info->control.sta)
+			if (p54_sta_unlock(dev, info->control.sta->addr)) {
+				if (current_queue) {
+					current_queue->len--;
+					current_queue->count--;
+				}
+				return NETDEV_TX_BUSY;
+			}
+	}
+
 	txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
 	hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
 
 	if (padding)
-		hdr->flags = cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN);
-	else
-		hdr->flags = cpu_to_le16(0);
+		hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
 	hdr->len = cpu_to_le16(len);
-	hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
+	hdr->type = cpu_to_le16(aid);
 	hdr->rts_tries = info->control.rates[0].count;
 
 	/*
@@ -998,12 +1186,18 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 			ridx++;
 		}
 	}
+
+	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+		hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+	/* TODO: enable bursting */
+	hdr->flags = cpu_to_le16(hdr_flags);
 	hdr->tries = ridx;
 	txhdr->crypt_offset = 0;
 	txhdr->rts_rate_idx = 0;
 	txhdr->key_type = 0;
 	txhdr->key_len = 0;
-	txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
+	txhdr->hw_queue = queue;
 	txhdr->backlog = 32;
 	memset(txhdr->durations, 0, sizeof(txhdr->durations));
 	txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
@@ -1014,8 +1208,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 		txhdr->align[0] = padding;
 
 	/* modifies skb->cb and with it info, so must be last! */
-	if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) {
+	if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) {
 		skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
+		if (current_queue) {
+			current_queue->len--;
+			current_queue->count--;
+		}
 		return NETDEV_TX_BUSY;
 	}
 	priv->tx(dev, skb, 0);
@@ -1043,8 +1241,10 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid)
 	else
 		memcpy(setup->bssid, bssid, ETH_ALEN);
 	setup->rx_antenna = priv->rx_antenna;
+	setup->rx_align = 0;
 	if (priv->fw_var < 0x500) {
 		setup->v1.basic_rate_mask = cpu_to_le32(0x15f);
+		memset(setup->v1.rts_rates, 0, 8);
 		setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
 		setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
 		setup->v1.rxhw = cpu_to_le16(priv->rxhw);
@@ -1069,13 +1269,14 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid)
 	return 0;
 }
 
-static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
+static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency)
 {
 	struct p54_common *priv = dev->priv;
 	struct sk_buff *skb;
 	struct p54_scan *chan;
 	unsigned int i;
 	void *entry;
+	__le16 freq = cpu_to_le16(frequency);
 
 	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
 			    sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
@@ -1127,11 +1328,11 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
 		}
 
 		entry += sizeof(__le16);
-		chan->pa_points_per_curve =
-			min(priv->curve_data->points_per_channel, (u8) 8);
-
-		memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
-		       chan->pa_points_per_curve);
+		chan->pa_points_per_curve = 8;
+		memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+		memcpy(chan->curve_data, entry,
+		       sizeof(struct p54_pa_curve_data_sample) *
+		       min((u8)8, priv->curve_data->points_per_channel));
 		break;
 	}
 
@@ -1207,6 +1408,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev)
 	/* (see prism54/isl_oid.h for further details) */
 	edcf->frameburst = cpu_to_le16(0);
 	edcf->round_trip_delay = cpu_to_le16(0);
+	edcf->flags = 0;
 	memset(edcf->mapping, 0, sizeof(edcf->mapping));
 	memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
 	priv->tx(dev, skb, 1);
@@ -1227,11 +1429,94 @@ static int p54_init_stats(struct ieee80211_hw *dev)
 	return 0;
 }
 
+static int p54_beacon_tim(struct sk_buff *skb)
+{
+	/*
+	 * the good excuse for this mess is ... the firmware.
+	 * The dummy TIM MUST be at the end of the beacon frame,
+	 * because it'll be overwritten!
+	 */
+
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
+	u8 *pos, *end;
+
+	if (skb->len <= sizeof(mgmt)) {
+		printk(KERN_ERR "p54: beacon is too short!\n");
+		return -EINVAL;
+	}
+
+	pos = (u8 *)mgmt->u.beacon.variable;
+	end = skb->data + skb->len;
+	while (pos < end) {
+		if (pos + 2 + pos[1] > end) {
+			printk(KERN_ERR "p54: parsing beacon failed\n");
+			return -EINVAL;
+		}
+
+		if (pos[0] == WLAN_EID_TIM) {
+			u8 dtim_len = pos[1];
+			u8 dtim_period = pos[3];
+			u8 *next = pos + 2 + dtim_len;
+
+			if (dtim_len < 3) {
+				printk(KERN_ERR "p54: invalid dtim len!\n");
+				return -EINVAL;
+			}
+			memmove(pos, next, end - next);
+
+			if (dtim_len > 3)
+				skb_trim(skb, skb->len - (dtim_len - 3));
+
+			pos = end - (dtim_len + 2);
+
+			/* add the dummy at the end */
+			pos[0] = WLAN_EID_TIM;
+			pos[1] = 3;
+			pos[2] = 0;
+			pos[3] = dtim_period;
+			pos[4] = 0;
+			return 0;
+		}
+		pos += 2 + pos[1];
+	}
+	return 0;
+}
+
+static int p54_beacon_update(struct ieee80211_hw *dev,
+			struct ieee80211_vif *vif)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *beacon;
+	int ret;
+
+	if (priv->cached_beacon) {
+		p54_tx_cancel(dev, priv->cached_beacon);
+		/* wait for the last beacon the be freed */
+		msleep(10);
+	}
+
+	beacon = ieee80211_beacon_get(dev, vif);
+	if (!beacon)
+		return -ENOMEM;
+	ret = p54_beacon_tim(beacon);
+	if (ret)
+		return ret;
+	ret = p54_tx(dev, beacon);
+	if (ret)
+		return ret;
+	priv->cached_beacon = beacon;
+	priv->tsf_high32 = 0;
+	priv->tsf_low32 = 0;
+
+	return 0;
+}
+
 static int p54_start(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
 	int err;
 
+	mutex_lock(&priv->conf_mutex);
 	err = priv->open(dev);
 	if (!err)
 		priv->mode = NL80211_IFTYPE_MONITOR;
@@ -1243,6 +1528,7 @@ static int p54_start(struct ieee80211_hw *dev)
 	if (!err)
 		err = p54_init_stats(dev);
 
+	mutex_unlock(&priv->conf_mutex);
 	return err;
 }
 
@@ -1251,15 +1537,22 @@ static void p54_stop(struct ieee80211_hw *dev)
 	struct p54_common *priv = dev->priv;
 	struct sk_buff *skb;
 
+	mutex_lock(&priv->conf_mutex);
 	del_timer(&priv->stats_timer);
 	p54_free_skb(dev, priv->cached_stats);
 	priv->cached_stats = NULL;
+	if (priv->cached_beacon)
+		p54_tx_cancel(dev, priv->cached_beacon);
+
 	while ((skb = skb_dequeue(&priv->tx_queue)))
 		kfree_skb(skb);
 
+	kfree(priv->cached_beacon);
+	priv->cached_beacon = NULL;
 	priv->stop(dev);
 	priv->tsf_high32 = priv->tsf_low32 = 0;
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+	mutex_unlock(&priv->conf_mutex);
 }
 
 static int p54_add_interface(struct ieee80211_hw *dev,
@@ -1267,14 +1560,20 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 {
 	struct p54_common *priv = dev->priv;
 
-	if (priv->mode != NL80211_IFTYPE_MONITOR)
+	mutex_lock(&priv->conf_mutex);
+	if (priv->mode != NL80211_IFTYPE_MONITOR) {
+		mutex_unlock(&priv->conf_mutex);
 		return -EOPNOTSUPP;
+	}
 
 	switch (conf->type) {
 	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_AP:
 		priv->mode = conf->type;
 		break;
 	default:
+		mutex_unlock(&priv->conf_mutex);
 		return -EOPNOTSUPP;
 	}
 
@@ -1286,6 +1585,12 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 	case NL80211_IFTYPE_STATION:
 		p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL);
 		break;
+	case NL80211_IFTYPE_AP:
+		p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr);
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL);
+		break;
 	default:
 		BUG();	/* impossible */
 		break;
@@ -1293,6 +1598,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 
 	p54_set_leds(dev, 1, 0, 0);
 
+	mutex_unlock(&priv->conf_mutex);
 	return 0;
 }
 
@@ -1300,9 +1606,14 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
+
+	mutex_lock(&priv->conf_mutex);
+	if (priv->cached_beacon)
+		p54_tx_cancel(dev, priv->cached_beacon);
+	p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL);
 	priv->mode = NL80211_IFTYPE_MONITOR;
 	memset(priv->mac_addr, 0, ETH_ALEN);
-	p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL);
+	mutex_unlock(&priv->conf_mutex);
 }
 
 static int p54_config(struct ieee80211_hw *dev, u32 changed)
@@ -1314,7 +1625,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
 	mutex_lock(&priv->conf_mutex);
 	priv->rx_antenna = 2; /* automatic */
 	priv->output_power = conf->power_level << 2;
-	ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
+	ret = p54_set_freq(dev, conf->channel->center_freq);
 	if (!ret)
 		ret = p54_set_edcf(dev);
 	mutex_unlock(&priv->conf_mutex);
@@ -1326,13 +1637,41 @@ static int p54_config_interface(struct ieee80211_hw *dev,
 				struct ieee80211_if_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
+	int ret = 0;
 
 	mutex_lock(&priv->conf_mutex);
-	p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid);
-	p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
-	memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+	switch (priv->mode) {
+	case NL80211_IFTYPE_STATION:
+		ret = p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid);
+		if (ret)
+			goto out;
+		ret = p54_set_leds(dev, 1,
+				   !is_multicast_ether_addr(conf->bssid), 0);
+		if (ret)
+			goto out;
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+		break;
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+		ret = p54_set_freq(dev, dev->conf.channel->center_freq);
+		if (ret)
+			goto out;
+		ret = p54_setup_mac(dev, priv->mac_mode, priv->bssid);
+		if (ret)
+			goto out;
+		if (conf->changed & IEEE80211_IFCC_BEACON) {
+			ret = p54_beacon_update(dev, vif);
+			if (ret)
+				goto out;
+			ret = p54_set_edcf(dev);
+			if (ret)
+				goto out;
+		}
+	}
+out:
 	mutex_unlock(&priv->conf_mutex);
-	return 0;
+	return ret;
 }
 
 static void p54_configure_filter(struct ieee80211_hw *dev,
@@ -1367,14 +1706,18 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
 		       const struct ieee80211_tx_queue_params *params)
 {
 	struct p54_common *priv = dev->priv;
+	int ret;
 
+	mutex_lock(&priv->conf_mutex);
 	if ((params) && !(queue > 4)) {
 		P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
 			params->cw_min, params->cw_max, params->txop);
 	} else
-		return -EINVAL;
-
-	return p54_set_edcf(dev);
+		ret = -EINVAL;
+	if (!ret)
+		ret = p54_set_edcf(dev);
+	mutex_unlock(&priv->conf_mutex);
+	return ret;
 }
 
 static int p54_init_xbow_synth(struct ieee80211_hw *dev)
@@ -1457,6 +1800,7 @@ static const struct ieee80211_ops p54_ops = {
 	.stop			= p54_stop,
 	.add_interface		= p54_add_interface,
 	.remove_interface	= p54_remove_interface,
+	.set_tim		= p54_set_tim,
 	.config			= p54_config,
 	.config_interface	= p54_config_interface,
 	.bss_info_changed	= p54_bss_info_changed,
@@ -1478,24 +1822,20 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 	priv = dev->priv;
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	skb_queue_head_init(&priv->tx_queue);
-	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
-		     IEEE80211_HW_RX_INCLUDES_FCS |
+	dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		     IEEE80211_HW_SIGNAL_DBM |
 		     IEEE80211_HW_NOISE_DBM;
 
-	/*
-	 * XXX: when this driver gets support for any mode that
-	 *	requires beacons (AP, MESH, IBSS) then it must
-	 *	implement IEEE80211_TX_CTL_ASSIGN_SEQ.
-	 */
-	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION |
+					  NL80211_IFTYPE_ADHOC |
+					  NL80211_IFTYPE_AP);
 
 	dev->channel_change_time = 1000;	/* TODO: find actual value */
-	priv->tx_stats[0].limit = 1;
-	priv->tx_stats[1].limit = 1;
-	priv->tx_stats[2].limit = 1;
-	priv->tx_stats[3].limit = 1;
-	priv->tx_stats[4].limit = 5;
+	priv->tx_stats[0].limit = 1;		/* Beacon queue */
+	priv->tx_stats[1].limit = 1;		/* Probe queue for HW scan */
+	priv->tx_stats[2].limit = 3;		/* queue for MLMEs */
+	priv->tx_stats[3].limit = 3;		/* Broadcast / MC queue */
+	priv->tx_stats[4].limit = 5;		/* Data */
 	dev->queues = 1;
 	priv->noise = -94;
 	/*

+ 30 - 1
drivers/net/wireless/p54/p54common.h

@@ -25,6 +25,22 @@ struct bootrec {
 	u32 data[10];
 } __attribute__((packed));
 
+#define PDR_SYNTH_FRONTEND_MASK		0x0007
+#define PDR_SYNTH_IQ_CAL_MASK		0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR	0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED	0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF		0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK	0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED	0x0001
+#define PDR_SYNTH_24_GHZ_MASK		0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED	0x0040
+#define PDR_SYNTH_5_GHZ_MASK		0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED	0x0080
+#define PDR_SYNTH_RX_DIV_MASK		0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED	0x0100
+#define PDR_SYNTH_TX_DIV_MASK		0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED	0x0200
+
 struct bootrec_exp_if {
 	__le16 role;
 	__le16 if_id;
@@ -210,6 +226,19 @@ struct pda_pa_curve_data {
 #define PDR_BASEBAND_REGISTERS			0x8000
 #define PDR_PER_CHANNEL_BASEBAND_REGISTERS	0x8001
 
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE		0x80
+#define PDR_COUNTRY_CERT_CODE_REAL	0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO	0x80
+#define PDR_COUNTRY_CERT_BAND		0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ	0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ	0x40
+#define PDR_COUNTRY_CERT_IODOOR		0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH	0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR	0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR	0x30
+#define PDR_COUNTRY_CERT_INDEX		0x0F
+
 /* stored in skb->cb */
 struct memrecord {
 	u32 start_addr;
@@ -507,7 +536,7 @@ struct p54_sta_unlock {
 } __attribute__ ((packed));
 
 #define P54_TIM_CLEAR BIT(15)
-struct p54_tx_control_tim {
+struct p54_tim {
 	u8 count;
 	u8 padding[3];
 	__le16 entry[8];

+ 6 - 3
drivers/net/wireless/p54/p54pci.c

@@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_DESCRIPTION("Prism54 PCI wireless driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54pci");
+MODULE_FIRMWARE("isl3886pci");
 
 static struct pci_device_id p54p_table[] __devinitdata = {
 	/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
@@ -72,11 +73,13 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
 	P54P_WRITE(ctrl_stat, reg);
 	wmb();
 
-	err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
+	err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev);
 	if (err) {
 		printk(KERN_ERR "%s (p54pci): cannot find firmware "
-		       "(isl3886)\n", pci_name(priv->pdev));
-		return err;
+		       "(isl3886pci)\n", pci_name(priv->pdev));
+		err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
+		if (err)
+			return err;
 	}
 
 	err = p54_parse_firmware(dev, fw_entry);

+ 16 - 7
drivers/net/wireless/p54/p54usb.c

@@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_DESCRIPTION("Prism54 USB wireless driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54usb");
+MODULE_FIRMWARE("isl3886usb");
+MODULE_FIRMWARE("isl3887usb");
 
 static struct usb_device_id p54u_table[] __devinitdata = {
 	/* Version 1 devices (pci chip + net2280) */
@@ -415,10 +417,13 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
 		goto err_reset;
 	}
 
-	err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
+	err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
 	if (err) {
-		printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
-		goto err_req_fw_failed;
+		printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb)\n");
+		err = request_firmware(&fw_entry, "isl3887usb_bare",
+			&priv->udev->dev);
+		if (err)
+			goto err_req_fw_failed;
 	}
 
 	err = p54_parse_firmware(dev, fw_entry);
@@ -553,11 +558,15 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
 		return -ENOMEM;
 	}
 
-	err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
+	err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
 	if (err) {
-		printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
-		kfree(buf);
-		return err;
+		printk(KERN_ERR "p54usb: cannot find firmware (isl3886usb)\n");
+		err = request_firmware(&fw_entry, "isl3890usb",
+			&priv->udev->dev);
+		if (err) {
+			kfree(buf);
+			return err;
+			}
 	}
 
 	err = p54_parse_firmware(dev, fw_entry);

+ 12 - 12
drivers/net/wireless/rndis_wlan.c

@@ -37,11 +37,11 @@
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 #include <linux/usb/usbnet.h>
 #include <linux/usb/rndis_host.h>
 
@@ -1652,7 +1652,7 @@ static char *rndis_translate_scan(struct net_device *dev,
 #ifdef DEBUG
 	struct usbnet *usbdev = dev->priv;
 #endif
-	struct ieee80211_info_element *ie;
+	u8 *ie;
 	char *current_val;
 	int bssid_len, ie_len, i;
 	u32 beacon, atim;
@@ -1750,20 +1750,20 @@ static char *rndis_translate_scan(struct net_device *dev,
 	ie_len = min(bssid_len - (int)sizeof(*bssid),
 					(int)le32_to_cpu(bssid->ie_length));
 	ie_len -= sizeof(struct ndis_80211_fixed_ies);
-	while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) {
-		if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 &&
-				memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) ||
-				ie->id == MFIE_TYPE_RSN) {
+	while (ie_len >= 2 && 2 + ie[1] <= ie_len) {
+		if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 &&
+		     memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) ||
+		    ie[0] == WLAN_EID_RSN) {
 			devdbg(usbdev, "IE: WPA%d",
-					(ie->id == MFIE_TYPE_RSN) ? 2 : 1);
+					(ie[0] == WLAN_EID_RSN) ? 2 : 1);
 			iwe.cmd = IWEVGENIE;
-			iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
-			cev = iwe_stream_add_point(info, cev, end_buf, &iwe,
-								(u8 *)ie);
+			/* arbitrary cut-off at 64 */
+			iwe.u.data.length = min(ie[1] + 2, 64);
+			cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie);
 		}
 
-		ie_len -= sizeof(*ie) + ie->len;
-		ie = (struct ieee80211_info_element *)&ie->data[ie->len];
+		ie_len -= 2 + ie[1];
+		ie += 2 + ie[1];
 	}
 
 	return cev;

+ 87 - 103
drivers/net/wireless/rt2x00/rt2400pci.c

@@ -188,43 +188,34 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev,
-			       const unsigned int word, u32 *data)
-{
-	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev,
-				const unsigned int word, u32 data)
-{
-	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt2400pci_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt2400pci_read_csr,
-		.write		= rt2400pci_write_csr,
+		.read		= rt2x00pci_register_read,
+		.write		= rt2x00pci_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt2400pci_bbp_read,
 		.write		= rt2400pci_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt2400pci_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -396,12 +387,74 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
 	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
 	rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+	rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+	rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+	rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+	rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
 }
 
-static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-				     const int basic_rate_mask)
+static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev,
+				 struct antenna_setup *ant)
 {
-	rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+	u8 r1;
+	u8 r4;
+
+	/*
+	 * We should never come here because rt2x00lib is supposed
+	 * to catch this and send us the correct antenna explicitely.
+	 */
+	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+	       ant->tx == ANTENNA_SW_DIVERSITY);
+
+	rt2400pci_bbp_read(rt2x00dev, 4, &r4);
+	rt2400pci_bbp_read(rt2x00dev, 1, &r1);
+
+	/*
+	 * Configure the TX antenna.
+	 */
+	switch (ant->tx) {
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+		break;
+	}
+
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		break;
+	}
+
+	rt2400pci_bbp_write(rt2x00dev, 4, r4);
+	rt2400pci_bbp_write(rt2x00dev, 1, r1);
 }
 
 static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -460,56 +513,17 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
 	rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower));
 }
 
-static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     struct antenna_setup *ant)
+static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+					 struct rt2x00lib_conf *libconf)
 {
-	u8 r1;
-	u8 r4;
-
-	/*
-	 * We should never come here because rt2x00lib is supposed
-	 * to catch this and send us the correct antenna explicitely.
-	 */
-	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
-	       ant->tx == ANTENNA_SW_DIVERSITY);
-
-	rt2400pci_bbp_read(rt2x00dev, 4, &r4);
-	rt2400pci_bbp_read(rt2x00dev, 1, &r1);
-
-	/*
-	 * Configure the TX antenna.
-	 */
-	switch (ant->tx) {
-	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
-		break;
-	case ANTENNA_A:
-		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
-		break;
-	}
-
-	/*
-	 * Configure the RX antenna.
-	 */
-	switch (ant->rx) {
-	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		break;
-	case ANTENNA_A:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
-		break;
-	}
+	u32 reg;
 
-	rt2400pci_bbp_write(rt2x00dev, 4, r4);
-	rt2400pci_bbp_write(rt2x00dev, 1, r1);
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+			   libconf->conf->short_frame_max_tx_count);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
 static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -517,20 +531,6 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
 {
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
-	rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
-	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
-	rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
-	rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
-	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
 	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
 	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
 	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -548,16 +548,14 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
 			     struct rt2x00lib_conf *libconf,
 			     const unsigned int flags)
 {
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2400pci_config_channel(rt2x00dev, &libconf->rf);
-	if (flags & CONFIG_UPDATE_TXPOWER)
+	if (flags & IEEE80211_CONF_CHANGE_POWER)
 		rt2400pci_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2400pci_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt2400pci_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt2400pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -1502,20 +1500,6 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
-				     u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
-	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	return 0;
-}
-
 static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
 			     const struct ieee80211_tx_queue_params *params)
 {
@@ -1601,8 +1585,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 	.config_filter		= rt2400pci_config_filter,
 	.config_intf		= rt2400pci_config_intf,
 	.config_erp		= rt2400pci_config_erp,
+	.config_ant		= rt2400pci_config_ant,
 	.config			= rt2400pci_config,
-	.set_retry_limit	= rt2400pci_set_retry_limit,
 };
 
 static const struct data_queue_desc rt2400pci_queue_rx = {

+ 2 - 0
drivers/net/wireless/rt2x00/rt2400pci.h

@@ -46,7 +46,9 @@
 #define CSR_REG_SIZE			0x014c
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0100
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0020
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0010
 
 /*

+ 107 - 122
drivers/net/wireless/rt2x00/rt2500pci.c

@@ -188,43 +188,34 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev,
-			       const unsigned int word, u32 *data)
-{
-	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev,
-				const unsigned int word, u32 data)
-{
-	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt2500pci_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt2500pci_read_csr,
-		.write		= rt2500pci_write_csr,
+		.read		= rt2x00pci_register_read,
+		.write		= rt2x00pci_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt2500pci_bbp_read,
 		.write		= rt2500pci_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt2500pci_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -402,12 +393,94 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
 	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
 	rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+	rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+	rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+	rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+	rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
 }
 
-static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-				     const int basic_rate_mask)
+static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
+				 struct antenna_setup *ant)
 {
-	rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+	u32 reg;
+	u8 r14;
+	u8 r2;
+
+	/*
+	 * We should never come here because rt2x00lib is supposed
+	 * to catch this and send us the correct antenna explicitely.
+	 */
+	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+	       ant->tx == ANTENNA_SW_DIVERSITY);
+
+	rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+	rt2500pci_bbp_read(rt2x00dev, 14, &r14);
+	rt2500pci_bbp_read(rt2x00dev, 2, &r2);
+
+	/*
+	 * Configure the TX antenna.
+	 */
+	switch (ant->tx) {
+	case ANTENNA_A:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+		break;
+	}
+
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
+	case ANTENNA_A:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+		break;
+	}
+
+	/*
+	 * RT2525E and RT5222 need to flip TX I/Q
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
+
+		/*
+		 * RT2525E does not need RX I/Q Flip.
+		 */
+		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+	} else {
+		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
+	}
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+	rt2500pci_bbp_write(rt2x00dev, 14, r14);
+	rt2500pci_bbp_write(rt2x00dev, 2, r2);
 }
 
 static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -489,76 +562,17 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
 	rt2500pci_rf_write(rt2x00dev, 3, rf3);
 }
 
-static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     struct antenna_setup *ant)
+static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+					 struct rt2x00lib_conf *libconf)
 {
 	u32 reg;
-	u8 r14;
-	u8 r2;
-
-	/*
-	 * We should never come here because rt2x00lib is supposed
-	 * to catch this and send us the correct antenna explicitely.
-	 */
-	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
-	       ant->tx == ANTENNA_SW_DIVERSITY);
-
-	rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
-	rt2500pci_bbp_read(rt2x00dev, 14, &r14);
-	rt2500pci_bbp_read(rt2x00dev, 2, &r2);
 
-	/*
-	 * Configure the TX antenna.
-	 */
-	switch (ant->tx) {
-	case ANTENNA_A:
-		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
-		rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
-		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
-		break;
-	}
-
-	/*
-	 * Configure the RX antenna.
-	 */
-	switch (ant->rx) {
-	case ANTENNA_A:
-		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
-		break;
-	}
-
-	/*
-	 * RT2525E and RT5222 need to flip TX I/Q
-	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
-		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
-		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
-
-		/*
-		 * RT2525E does not need RX I/Q Flip.
-		 */
-		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
-			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
-	} else {
-		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
-	}
-
-	rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
-	rt2500pci_bbp_write(rt2x00dev, 14, r14);
-	rt2500pci_bbp_write(rt2x00dev, 2, r2);
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+			   libconf->conf->short_frame_max_tx_count);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
 static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -566,20 +580,6 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
 {
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
-	rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
-	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
-	rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
-	rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
-	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
 	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
 	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
 	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -597,17 +597,16 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
 			     struct rt2x00lib_conf *libconf,
 			     const unsigned int flags)
 {
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2500pci_config_channel(rt2x00dev, &libconf->rf,
 					 libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt2500pci_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2500pci_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt2500pci_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt2500pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -1827,20 +1826,6 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
-				     u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
-	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	return 0;
-}
-
 static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1901,8 +1886,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 	.config_filter		= rt2500pci_config_filter,
 	.config_intf		= rt2500pci_config_intf,
 	.config_erp		= rt2500pci_config_erp,
+	.config_ant		= rt2500pci_config_ant,
 	.config			= rt2500pci_config,
-	.set_retry_limit	= rt2500pci_set_retry_limit,
 };
 
 static const struct data_queue_desc rt2500pci_queue_rx = {

+ 2 - 0
drivers/net/wireless/rt2x00/rt2500pci.h

@@ -57,7 +57,9 @@
 #define CSR_REG_SIZE			0x0174
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0200
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0040
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*

+ 67 - 68
drivers/net/wireless/rt2x00/rt2500usb.c

@@ -245,43 +245,48 @@ rf_write:
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u16)) )
-
-static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev,
-			       const unsigned int word, u32 *data)
+static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
+				     const unsigned int offset,
+				     u32 *value)
 {
-	rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
+	rt2500usb_register_read(rt2x00dev, offset, (u16 *)value);
 }
 
-static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev,
-				const unsigned int word, u32 data)
+static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
+				      const unsigned int offset,
+				      u32 value)
 {
-	rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+	rt2500usb_register_write(rt2x00dev, offset, value);
 }
 
 static const struct rt2x00debug rt2500usb_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt2500usb_read_csr,
-		.write		= rt2500usb_write_csr,
+		.read		= _rt2500usb_register_read,
+		.write		= _rt2500usb_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= CSR_REG_SIZE / sizeof(u16),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt2500usb_bbp_read,
 		.write		= rt2500usb_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt2500usb_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -423,57 +428,16 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
-}
-
-static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
-				     const int basic_rate_mask)
-{
-	rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
-}
 
-static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
-				     struct rf_channel *rf, const int txpower)
-{
-	/*
-	 * Set TXpower.
-	 */
-	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates);
 
-	/*
-	 * For RT2525E we should first set the channel to half band higher.
-	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
-		static const u32 vals[] = {
-			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
-			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
-			0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
-			0x00000902, 0x00000906
-		};
-
-		rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
-		if (rf->rf4)
-			rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
-	}
-
-	rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
-	if (rf->rf4)
-		rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
-}
-
-static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
-				     const int txpower)
-{
-	u32 rf3;
-
-	rt2x00_rf_read(rt2x00dev, 3, &rf3);
-	rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-	rt2500usb_rf_write(rt2x00dev, 3, rf3);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs);
 }
 
-static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     struct antenna_setup *ant)
+static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
+				 struct antenna_setup *ant)
 {
 	u8 r2;
 	u8 r14;
@@ -555,15 +519,52 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
 	rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6);
 }
 
+static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
+				     struct rf_channel *rf, const int txpower)
+{
+	/*
+	 * Set TXpower.
+	 */
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+	/*
+	 * For RT2525E we should first set the channel to half band higher.
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+		static const u32 vals[] = {
+			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
+			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
+			0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
+			0x00000902, 0x00000906
+		};
+
+		rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+		if (rf->rf4)
+			rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+	}
+
+	rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+	if (rf->rf4)
+		rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+				     const int txpower)
+{
+	u32 rf3;
+
+	rt2x00_rf_read(rt2x00dev, 3, &rf3);
+	rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2500usb_rf_write(rt2x00dev, 3, rf3);
+}
+
 static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
 				      struct rt2x00lib_conf *libconf)
 {
 	u16 reg;
 
-	rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
-	rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs);
-	rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs);
-
 	rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
 	rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
 			   libconf->conf->beacon_int * 4);
@@ -574,17 +575,14 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
 			     struct rt2x00lib_conf *libconf,
 			     const unsigned int flags)
 {
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2500usb_config_channel(rt2x00dev, &libconf->rf,
 					 libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt2500usb_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2500usb_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt2500usb_config_duration(rt2x00dev, libconf);
 }
 
@@ -1794,6 +1792,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
 	.config_filter		= rt2500usb_config_filter,
 	.config_intf		= rt2500usb_config_intf,
 	.config_erp		= rt2500usb_config_erp,
+	.config_ant		= rt2500usb_config_ant,
 	.config			= rt2500usb_config,
 };
 

+ 2 - 0
drivers/net/wireless/rt2x00/rt2500usb.h

@@ -57,7 +57,9 @@
 #define CSR_REG_SIZE			0x0100
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x006a
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0060
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*

+ 13 - 31
drivers/net/wireless/rt2x00/rt2x00.h

@@ -44,7 +44,7 @@
 /*
  * Module information.
  */
-#define DRV_VERSION	"2.2.1"
+#define DRV_VERSION	"2.2.2"
 #define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
 
 /*
@@ -347,13 +347,6 @@ struct rt2x00_intf {
 	 */
 	spinlock_t lock;
 
-	/*
-	 * BSS configuration. Copied from the structure
-	 * passed to us through the bss_info_changed()
-	 * callback funtion.
-	 */
-	struct ieee80211_bss_conf conf;
-
 	/*
 	 * MAC of the device.
 	 */
@@ -433,18 +426,6 @@ struct rt2x00lib_conf {
 
 	struct rf_channel rf;
 	struct channel_info channel;
-
-	struct antenna_setup ant;
-
-	enum ieee80211_band band;
-
-	u32 basic_rates;
-	u32 slot_time;
-
-	short sifs;
-	short pifs;
-	short difs;
-	short eifs;
 };
 
 /*
@@ -456,6 +437,15 @@ struct rt2x00lib_erp {
 
 	int ack_timeout;
 	int ack_consume_time;
+
+	u64 basic_rates;
+
+	int slot_time;
+
+	short sifs;
+	short pifs;
+	short difs;
+	short eifs;
 };
 
 /*
@@ -589,19 +579,11 @@ struct rt2x00lib_ops {
 
 	void (*config_erp) (struct rt2x00_dev *rt2x00dev,
 			    struct rt2x00lib_erp *erp);
+	void (*config_ant) (struct rt2x00_dev *rt2x00dev,
+			    struct antenna_setup *ant);
 	void (*config) (struct rt2x00_dev *rt2x00dev,
 			struct rt2x00lib_conf *libconf,
-			const unsigned int flags);
-#define CONFIG_UPDATE_PHYMODE		( 1 << 1 )
-#define CONFIG_UPDATE_CHANNEL		( 1 << 2 )
-#define CONFIG_UPDATE_TXPOWER		( 1 << 3 )
-#define CONFIG_UPDATE_ANTENNA		( 1 << 4 )
-#define CONFIG_UPDATE_SLOT_TIME 	( 1 << 5 )
-#define CONFIG_UPDATE_BEACON_INT	( 1 << 6 )
-#define CONFIG_UPDATE_ALL		0xffff
-
-	int (*set_retry_limit) (struct ieee80211_hw *hw,
-				u32 short_limit, u32 long_limit);
+			const unsigned int changed_flags);
 };
 
 /*

+ 24 - 140
drivers/net/wireless/rt2x00/rt2x00config.c

@@ -86,13 +86,14 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 	erp.short_preamble = bss_conf->use_short_preamble;
 	erp.cts_protection = bss_conf->use_cts_prot;
 
-	erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
-	erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
+	erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME;
+	erp.sifs = SIFS;
+	erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS;
+	erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
+	erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
 
-	if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-		erp.ack_timeout += SHORT_DIFS;
-	else
-		erp.ack_timeout += DIFS;
+	erp.ack_timeout = PLCP + erp.difs + get_duration(ACK_SIZE, 10);
+	erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
 
 	if (bss_conf->use_short_preamble) {
 		erp.ack_timeout += SHORT_PREAMBLE;
@@ -102,16 +103,18 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 		erp.ack_consume_time += PREAMBLE;
 	}
 
+	erp.basic_rates = bss_conf->basic_rates;
+
 	rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
 }
 
 void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
 			      enum antenna rx, enum antenna tx)
 {
-	struct rt2x00lib_conf libconf;
+	struct antenna_setup ant;
 
-	libconf.ant.rx = rx;
-	libconf.ant.tx = tx;
+	ant.rx = rx;
+	ant.tx = tx;
 
 	if (rx == rt2x00dev->link.ant.active.rx &&
 	    tx == rt2x00dev->link.ant.active.tx)
@@ -129,111 +132,28 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
 	 * The latter is required since we need to recalibrate the
 	 * noise-sensitivity ratio for the new setup.
 	 */
-	rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA);
+	rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant);
+
 	rt2x00lib_reset_link_tuner(rt2x00dev);
 	rt2x00_reset_link_ant_rssi(&rt2x00dev->link);
 
-	rt2x00dev->link.ant.active.rx = libconf.ant.rx;
-	rt2x00dev->link.ant.active.tx = libconf.ant.tx;
+	memcpy(&rt2x00dev->link.ant.active, &ant, sizeof(ant));
 
 	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
 }
 
-static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band)
-{
-	const struct rt2x00_rate *rate;
-	unsigned int i;
-	u32 mask = 0;
-
-	for (i = 0; i < band->n_bitrates; i++) {
-		rate = rt2x00_get_rate(band->bitrates[i].hw_value);
-		if (rate->flags & DEV_RATE_BASIC)
-			mask |= rate->ratemask;
-	}
-
-	return mask;
-}
-
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
-		      struct ieee80211_conf *conf, const int force_config)
+		      struct ieee80211_conf *conf,
+		      unsigned int ieee80211_flags)
 {
 	struct rt2x00lib_conf libconf;
-	struct ieee80211_supported_band *band;
-	struct antenna_setup *default_ant = &rt2x00dev->default_ant;
-	struct antenna_setup *active_ant = &rt2x00dev->link.ant.active;
-	int flags = 0;
-	int short_slot_time;
-
-	/*
-	 * In some situations we want to force all configurations
-	 * to be reloaded (When resuming for instance).
-	 */
-	if (force_config) {
-		flags = CONFIG_UPDATE_ALL;
-		goto config;
-	}
-
-	/*
-	 * Check which configuration options have been
-	 * updated and should be send to the device.
-	 */
-	if (rt2x00dev->rx_status.band != conf->channel->band)
-		flags |= CONFIG_UPDATE_PHYMODE;
-	if (rt2x00dev->rx_status.freq != conf->channel->center_freq)
-		flags |= CONFIG_UPDATE_CHANNEL;
-	if (rt2x00dev->tx_power != conf->power_level)
-		flags |= CONFIG_UPDATE_TXPOWER;
-
-	/*
-	 * Determining changes in the antenna setups request several checks:
-	 * antenna_sel_{r,t}x = 0
-	 *    -> Does active_{r,t}x match default_{r,t}x
-	 *    -> Is default_{r,t}x SW_DIVERSITY
-	 * antenna_sel_{r,t}x = 1/2
-	 *    -> Does active_{r,t}x match antenna_sel_{r,t}x
-	 * The reason for not updating the antenna while SW diversity
-	 * should be used is simple: Software diversity means that
-	 * we should switch between the antenna's based on the
-	 * quality. This means that the current antenna is good enough
-	 * to work with untill the link tuner decides that an antenna
-	 * switch should be performed.
-	 */
-	if (default_ant->rx != ANTENNA_SW_DIVERSITY &&
-	    default_ant->rx != active_ant->rx)
-		flags |= CONFIG_UPDATE_ANTENNA;
-	else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
-		flags |= CONFIG_UPDATE_ANTENNA;
-
-	if (default_ant->tx != ANTENNA_SW_DIVERSITY &&
-	    default_ant->tx != active_ant->tx)
-		flags |= CONFIG_UPDATE_ANTENNA;
-	else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
-		flags |= CONFIG_UPDATE_ANTENNA;
 
-	/*
-	 * The following configuration options are never
-	 * stored anywhere and will always be updated.
-	 */
-	flags |= CONFIG_UPDATE_SLOT_TIME;
-	flags |= CONFIG_UPDATE_BEACON_INT;
-
-	/*
-	 * We have determined what options should be updated,
-	 * now precalculate device configuration values depending
-	 * on what configuration options need to be updated.
-	 */
-config:
 	memset(&libconf, 0, sizeof(libconf));
 
-	if (flags & CONFIG_UPDATE_PHYMODE) {
-		band = &rt2x00dev->bands[conf->channel->band];
-
-		libconf.band = conf->channel->band;
-		libconf.basic_rates = rt2x00lib_get_basic_rates(band);
-	}
+	libconf.conf = conf;
 
-	if (flags & CONFIG_UPDATE_CHANNEL) {
+	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
 		memcpy(&libconf.rf,
 		       &rt2x00dev->spec.channels[conf->channel->hw_value],
 		       sizeof(libconf.rf));
@@ -243,57 +163,21 @@ config:
 		       sizeof(libconf.channel));
 	}
 
-	if (flags & CONFIG_UPDATE_ANTENNA) {
-		if (default_ant->rx != ANTENNA_SW_DIVERSITY)
-			libconf.ant.rx = default_ant->rx;
-		else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
-			libconf.ant.rx = ANTENNA_B;
-		else
-			libconf.ant.rx = active_ant->rx;
-
-		if (default_ant->tx != ANTENNA_SW_DIVERSITY)
-			libconf.ant.tx = default_ant->tx;
-		else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
-			libconf.ant.tx = ANTENNA_B;
-		else
-			libconf.ant.tx = active_ant->tx;
-	}
-
-	if (flags & CONFIG_UPDATE_SLOT_TIME) {
-		short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
-
-		libconf.slot_time =
-		    short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME;
-		libconf.sifs = SIFS;
-		libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
-		libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
-		libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS;
-	}
-
-	libconf.conf = conf;
-
 	/*
 	 * Start configuration.
 	 */
-	rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags);
+	rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags);
 
 	/*
 	 * Some configuration changes affect the link quality
 	 * which means we need to reset the link tuner.
 	 */
-	if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
+	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2x00lib_reset_link_tuner(rt2x00dev);
 
-	if (flags & CONFIG_UPDATE_PHYMODE) {
-		rt2x00dev->curr_band = conf->channel->band;
-		rt2x00dev->rx_status.band = conf->channel->band;
-	}
-
-	rt2x00dev->rx_status.freq = conf->channel->center_freq;
+	rt2x00dev->curr_band = conf->channel->band;
 	rt2x00dev->tx_power = conf->power_level;
 
-	if (flags & CONFIG_UPDATE_ANTENNA) {
-		rt2x00dev->link.ant.active.rx = libconf.ant.rx;
-		rt2x00dev->link.ant.active.tx = libconf.ant.tx;
-	}
+	rt2x00dev->rx_status.band = conf->channel->band;
+	rt2x00dev->rx_status.freq = conf->channel->center_freq;
 }

+ 16 - 6
drivers/net/wireless/rt2x00/rt2x00debug.c

@@ -424,16 +424,21 @@ static ssize_t rt2x00debug_read_##__name(struct file *file,	\
 	const struct rt2x00debug *debug = intf->debug;		\
 	char line[16];						\
 	size_t size;						\
+	unsigned int index = intf->offset_##__name;		\
 	__type value;						\
 								\
 	if (*offset)						\
 		return 0;					\
 								\
-	if (intf->offset_##__name >= debug->__name.word_count)	\
+	if (index >= debug->__name.word_count)			\
 		return -EINVAL;					\
 								\
-	debug->__name.read(intf->rt2x00dev,			\
-			   intf->offset_##__name, &value);	\
+	if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)		\
+		index *= debug->__name.word_size;		\
+								\
+	index += debug->__name.word_base;			\
+								\
+	debug->__name.read(intf->rt2x00dev, index, &value);	\
 								\
 	size = sprintf(line, __format, value);			\
 								\
@@ -454,12 +459,13 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,	\
 	const struct rt2x00debug *debug = intf->debug;		\
 	char line[16];						\
 	size_t size;						\
+	unsigned int index = intf->offset_##__name;		\
 	__type value;						\
 								\
 	if (*offset)						\
 		return 0;					\
 								\
-	if (intf->offset_##__name >= debug->__name.word_count)	\
+	if (index >= debug->__name.word_count)			\
 		return -EINVAL;					\
 								\
 	if (copy_from_user(line, buf, length))			\
@@ -468,8 +474,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,	\
 	size = strlen(line);					\
 	value = simple_strtoul(line, NULL, 0);			\
 								\
-	debug->__name.write(intf->rt2x00dev,			\
-			    intf->offset_##__name, value);	\
+	if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)		\
+		index *= debug->__name.word_size;		\
+								\
+	index += debug->__name.word_base;			\
+								\
+	debug->__name.write(intf->rt2x00dev, index, value);	\
 								\
 	*offset += size;					\
 	return size;						\

+ 13 - 0
drivers/net/wireless/rt2x00/rt2x00debug.h

@@ -28,6 +28,16 @@
 
 struct rt2x00_dev;
 
+/**
+ * enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry
+ *
+ * @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset
+ *	as argument when using the callback function read()/write()
+ */
+enum rt2x00debugfs_entry_flags {
+	RT2X00DEBUGFS_OFFSET	= (1 << 0),
+};
+
 #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type)		\
 struct reg##__name {						\
 	void (*read)(struct rt2x00_dev *rt2x00dev,		\
@@ -35,6 +45,9 @@ struct reg##__name {						\
 	void (*write)(struct rt2x00_dev *rt2x00dev,		\
 		      const unsigned int word, __type data);	\
 								\
+	unsigned int flags;					\
+								\
+	unsigned int word_base;					\
 	unsigned int word_size;					\
 	unsigned int word_count;				\
 } __name

+ 11 - 5
drivers/net/wireless/rt2x00/rt2x00dev.c

@@ -417,7 +417,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 	 */
 	spin_lock(&intf->lock);
 
-	memcpy(&conf, &intf->conf, sizeof(conf));
+	memcpy(&conf, &vif->bss_conf, sizeof(conf));
 	delayed_flags = intf->delayed_flags;
 	intf->delayed_flags = 0;
 
@@ -1056,10 +1056,16 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
 
-	rt2x00dev->hw->wiphy->interface_modes =
-	    BIT(NL80211_IFTYPE_AP) |
-	    BIT(NL80211_IFTYPE_STATION) |
-	    BIT(NL80211_IFTYPE_ADHOC);
+	/*
+	 * Determine which operating modes are supported, all modes
+	 * which require beaconing, depend on the availability of
+	 * beacon entries.
+	 */
+	rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	if (rt2x00dev->ops->bcn->entry_num > 0)
+		rt2x00dev->hw->wiphy->interface_modes |=
+		    BIT(NL80211_IFTYPE_ADHOC) |
+		    BIT(NL80211_IFTYPE_AP);
 
 	/*
 	 * Let the driver probe the device to detect the capabilities.

+ 2 - 1
drivers/net/wireless/rt2x00/rt2x00lib.h

@@ -96,7 +96,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
 			      enum antenna rx, enum antenna tx);
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
-		      struct ieee80211_conf *conf, const int force_config);
+		      struct ieee80211_conf *conf,
+		      const unsigned int changed_flags);
 
 /**
  * DOC: Queue handlers

+ 1 - 11
drivers/net/wireless/rt2x00/rt2x00mac.c

@@ -349,15 +349,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 		return 0;
 
-	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
-		rt2x00dev->ops->lib->set_retry_limit(hw,
-			conf->short_frame_max_tx_count,
-			conf->long_frame_max_tx_count);
-	}
-	changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
-	if (!changed)
-		return 0;
-
 	/*
 	 * Only change device state when the radio is enabled. It does not
 	 * matter what parameters we have configured when the radio is disabled
@@ -379,7 +370,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
 		 * When we've just turned on the radio, we want to reprogram
 		 * everything to ensure a consistent state
 		 */
-		rt2x00lib_config(rt2x00dev, conf, !radio_on);
+		rt2x00lib_config(rt2x00dev, conf, changed);
 
 		/* Turn RX back on */
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
@@ -643,7 +634,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 	}
 
 	spin_lock(&intf->lock);
-	memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
 	if (delayed) {
 		intf->delayed_flags |= delayed;
 		schedule_work(&rt2x00dev->intf_work);

+ 4 - 4
drivers/net/wireless/rt2x00/rt2x00pci.h

@@ -58,7 +58,7 @@
  * Register access.
  */
 static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
-					   const unsigned long offset,
+					   const unsigned int offset,
 					   u32 *value)
 {
 	*value = readl(rt2x00dev->csr.base + offset);
@@ -66,14 +66,14 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
 
 static inline void
 rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
-			     const unsigned long offset,
+			     const unsigned int offset,
 			     void *value, const u16 length)
 {
 	memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
 }
 
 static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
-					    const unsigned long offset,
+					    const unsigned int offset,
 					    u32 value)
 {
 	writel(value, rt2x00dev->csr.base + offset);
@@ -81,7 +81,7 @@ static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
 
 static inline void
 rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
-			      const unsigned long offset,
+			      const unsigned int offset,
 			      const void *value, const u16 length)
 {
 	memcpy_toio(rt2x00dev->csr.base + offset, value, length);

+ 119 - 135
drivers/net/wireless/rt2x00/rt61pci.c

@@ -228,43 +228,34 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev,
-			     const unsigned int word, u32 *data)
-{
-	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev,
-			      const unsigned int word, u32 data)
-{
-	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt61pci_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt61pci_read_csr,
-		.write		= rt61pci_write_csr,
+		.read		= rt2x00pci_register_read,
+		.write		= rt2x00pci_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt61pci_bbp_read,
 		.write		= rt61pci_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt61pci_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -643,95 +634,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
-
-
-static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
-				    struct rt2x00lib_conf *libconf)
-{
-	u16 eeprom;
-	short lna_gain = 0;
-
-	if (libconf->band == IEEE80211_BAND_2GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-			lna_gain += 14;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
-	} else {
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
-			lna_gain += 14;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-	}
 
-	rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-				   const int basic_rate_mask)
-{
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
-
-static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
-				   struct rf_channel *rf, const int txpower)
-{
-	u8 r3;
-	u8 r94;
-	u8 smart;
-
-	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
-	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-		  rt2x00_rf(&rt2x00dev->chip, RF2527));
-
-	rt61pci_bbp_read(rt2x00dev, 3, &r3);
-	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
-	rt61pci_bbp_write(rt2x00dev, 3, r3);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
-	r94 = 6;
-	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
-		r94 += txpower - MAX_TXPOWER;
-	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
-		r94 += txpower;
-	rt61pci_bbp_write(rt2x00dev, 94, r94);
-
-	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-	udelay(200);
-
-	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
-	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-	udelay(200);
-
-	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-	msleep(1);
-}
-
-static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
-				   const int txpower)
-{
-	struct rf_channel rf;
-
-	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
-	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
-	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
-	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
 
-	rt61pci_config_channel(rt2x00dev, &rf, txpower);
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
 }
 
 static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -906,8 +820,8 @@ static const struct antenna_sel antenna_sel_bg[] = {
 	{ 98,  { 0x48, 0x48 } },
 };
 
-static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				   struct antenna_setup *ant)
+static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
+			       struct antenna_setup *ant)
 {
 	const struct antenna_sel *sel;
 	unsigned int lna;
@@ -954,20 +868,105 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
 	}
 }
 
-static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u16 eeprom;
+	short lna_gain = 0;
+
+	if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	} else {
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	}
+
+	rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
+				   struct rf_channel *rf, const int txpower)
+{
+	u8 r3;
+	u8 r94;
+	u8 smart;
+
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+	rt61pci_bbp_read(rt2x00dev, 3, &r3);
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+	rt61pci_bbp_write(rt2x00dev, 3, r3);
+
+	r94 = 6;
+	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+		r94 += txpower - MAX_TXPOWER;
+	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+		r94 += txpower;
+	rt61pci_bbp_write(rt2x00dev, 94, r94);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(200);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(200);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	msleep(1);
+}
+
+static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+				   const int txpower)
+{
+	struct rf_channel rf;
+
+	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+	rt61pci_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
 				    struct rt2x00lib_conf *libconf)
 {
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
-	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+			   libconf->conf->short_frame_max_tx_count);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
 
-	rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
-	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
-	rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
 
 	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
@@ -990,16 +989,15 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
 	/* Always recalculate LNA gain before changing configuration */
 	rt61pci_config_lna_gain(rt2x00dev, libconf);
 
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt61pci_config_channel(rt2x00dev, &libconf->rf,
 				       libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt61pci_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt61pci_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt61pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -2628,20 +2626,6 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
-				   u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
-	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-	return 0;
-}
-
 static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
 			   const struct ieee80211_tx_queue_params *params)
 {
@@ -2755,8 +2739,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 	.config_filter		= rt61pci_config_filter,
 	.config_intf		= rt61pci_config_intf,
 	.config_erp		= rt61pci_config_erp,
+	.config_ant		= rt61pci_config_ant,
 	.config			= rt61pci_config,
-	.set_retry_limit	= rt61pci_set_retry_limit,
 };
 
 static const struct data_queue_desc rt61pci_queue_rx = {

+ 2 - 0
drivers/net/wireless/rt2x00/rt61pci.h

@@ -48,7 +48,9 @@
 #define CSR_REG_SIZE			0x04b0
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0100
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0080
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*

+ 112 - 127
drivers/net/wireless/rt2x00/rt73usb.c

@@ -249,43 +249,34 @@ rf_write:
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev,
-			     const unsigned int word, u32 *data)
-{
-	rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev,
-			      const unsigned int word, u32 data)
-{
-	rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt73usb_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt73usb_read_csr,
-		.write		= rt73usb_write_csr,
+		.read		= rt73usb_register_read,
+		.write		= rt73usb_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt73usb_bbp_read,
 		.write		= rt73usb_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt73usb_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -669,87 +660,18 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
 	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
-
-static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
-				    struct rt2x00lib_conf *libconf)
-{
-	u16 eeprom;
-	short lna_gain = 0;
-
-	if (libconf->band == IEEE80211_BAND_2GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-			lna_gain += 14;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
-	} else {
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-	}
-
-	rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
-				   const int basic_rate_mask)
-{
-	rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
 
-static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
-				   struct rf_channel *rf, const int txpower)
-{
-	u8 r3;
-	u8 r94;
-	u8 smart;
-
-	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
-	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-		  rt2x00_rf(&rt2x00dev->chip, RF2527));
-
-	rt73usb_bbp_read(rt2x00dev, 3, &r3);
-	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
-	rt73usb_bbp_write(rt2x00dev, 3, r3);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
-	r94 = 6;
-	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
-		r94 += txpower - MAX_TXPOWER;
-	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
-		r94 += txpower;
-	rt73usb_bbp_write(rt2x00dev, 94, r94);
-
-	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
-	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-	udelay(10);
-}
-
-static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
-				   const int txpower)
-{
-	struct rf_channel rf;
-
-	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
-	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
-	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
-	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
 
-	rt73usb_config_channel(rt2x00dev, &rf, txpower);
+	rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+	rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
 }
 
 static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -869,8 +791,8 @@ static const struct antenna_sel antenna_sel_bg[] = {
 	{ 98,  { 0x48, 0x48 } },
 };
 
-static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-				   struct antenna_setup *ant)
+static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
+			       struct antenna_setup *ant)
 {
 	const struct antenna_sel *sel;
 	unsigned int lna;
@@ -912,20 +834,98 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
 		rt73usb_config_antenna_2x(rt2x00dev, ant);
 }
 
-static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
 				    struct rt2x00lib_conf *libconf)
+{
+	u16 eeprom;
+	short lna_gain = 0;
+
+	if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	} else {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	}
+
+	rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
+				   struct rf_channel *rf, const int txpower)
+{
+	u8 r3;
+	u8 r94;
+	u8 smart;
+
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+	rt73usb_bbp_read(rt2x00dev, 3, &r3);
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+	rt73usb_bbp_write(rt2x00dev, 3, r3);
+
+	r94 = 6;
+	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+		r94 += txpower - MAX_TXPOWER;
+	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+		r94 += txpower;
+	rt73usb_bbp_write(rt2x00dev, 94, r94);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(10);
+}
+
+static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+				   const int txpower)
+{
+	struct rf_channel rf;
+
+	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+	rt73usb_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+				       struct rt2x00lib_conf *libconf)
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
-	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+			   libconf->conf->short_frame_max_tx_count);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
-	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
-	rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
+static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
 
 	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
@@ -948,16 +948,15 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
 	/* Always recalculate LNA gain before changing configuration */
 	rt73usb_config_lna_gain(rt2x00dev, libconf);
 
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt73usb_config_channel(rt2x00dev, &libconf->rf,
 				       libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt73usb_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt73usb_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt73usb_config_duration(rt2x00dev, libconf);
 }
 
@@ -2209,20 +2208,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
-				   u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
-	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-	return 0;
-}
-
 static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
 			   const struct ieee80211_tx_queue_params *params)
 {
@@ -2345,8 +2330,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 	.config_filter		= rt73usb_config_filter,
 	.config_intf		= rt73usb_config_intf,
 	.config_erp		= rt73usb_config_erp,
+	.config_ant		= rt73usb_config_ant,
 	.config			= rt73usb_config,
-	.set_retry_limit	= rt73usb_set_retry_limit,
 };
 
 static const struct data_queue_desc rt73usb_queue_rx = {

+ 2 - 0
drivers/net/wireless/rt2x00/rt73usb.h

@@ -48,7 +48,9 @@
 #define CSR_REG_SIZE			0x04b0
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0100
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0080
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*

+ 1 - 4
drivers/net/wireless/rtl8187_dev.c

@@ -152,8 +152,6 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 	rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
 	rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
 	rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
-
-	msleep(1);
 }
 
 static void rtl8187_tx_cb(struct urb *urb)
@@ -669,7 +667,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
 	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
 	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
 	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
-	msleep(1100);
+	msleep(100);
 
 	priv->rf->init(dev);
 
@@ -872,7 +870,6 @@ static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
 	 */
 	rtl818x_iowrite32(priv, &priv->map->TX_CONF,
 			  reg | RTL818X_TX_CONF_LOOPBACK_MAC);
-	msleep(10);
 	priv->rf->set_chan(dev, conf);
 	msleep(10);
 	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);

+ 188 - 195
drivers/net/wireless/rtl8187_rtl8225.c

@@ -64,7 +64,6 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
 
 	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
 	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
-	msleep(2);
 }
 
 static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
@@ -98,7 +97,6 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
 
 	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
 	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
-	msleep(2);
 }
 
 static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
@@ -333,21 +331,21 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	rtl8225_write(dev, 0x0, 0x067); msleep(1);
-	rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x3, 0x441); msleep(1);
-	rtl8225_write(dev, 0x4, 0x486); msleep(1);
-	rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
-	rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
-	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-	rtl8225_write(dev, 0x8, 0x01F); msleep(1);
-	rtl8225_write(dev, 0x9, 0x334); msleep(1);
-	rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
-	rtl8225_write(dev, 0xB, 0x391); msleep(1);
-	rtl8225_write(dev, 0xC, 0x050); msleep(1);
-	rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
-	rtl8225_write(dev, 0xE, 0x029); msleep(1);
+	rtl8225_write(dev, 0x0, 0x067);
+	rtl8225_write(dev, 0x1, 0xFE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x486);
+	rtl8225_write(dev, 0x5, 0xBC0);
+	rtl8225_write(dev, 0x6, 0xAE6);
+	rtl8225_write(dev, 0x7, 0x82A);
+	rtl8225_write(dev, 0x8, 0x01F);
+	rtl8225_write(dev, 0x9, 0x334);
+	rtl8225_write(dev, 0xA, 0xFD4);
+	rtl8225_write(dev, 0xB, 0x391);
+	rtl8225_write(dev, 0xC, 0x050);
+	rtl8225_write(dev, 0xD, 0x6DB);
+	rtl8225_write(dev, 0xE, 0x029);
 	rtl8225_write(dev, 0xF, 0x914); msleep(100);
 
 	rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
@@ -375,91 +373,89 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
 
 	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
 		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
-		msleep(1);
 		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
-		msleep(1);
 	}
 
 	msleep(1);
 
-	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x06);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x27);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
 
 	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
 	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
 	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
 	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
 
-	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x00, 0x98);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47);
 	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
 	rtl8225_write_phy_cck(dev, 0x19, 0x00);
 	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
 	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
 	rtl8225_write_phy_cck(dev, 0x40, 0x86);
-	rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18);
+	rtl8225_write_phy_cck(dev, 0x44, 0x1f);
+	rtl8225_write_phy_cck(dev, 0x45, 0x1e);
+	rtl8225_write_phy_cck(dev, 0x46, 0x1a);
+	rtl8225_write_phy_cck(dev, 0x47, 0x15);
+	rtl8225_write_phy_cck(dev, 0x48, 0x10);
+	rtl8225_write_phy_cck(dev, 0x49, 0x0a);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x05);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x02);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05);
 
 	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
 
 	rtl8225_rf_set_tx_power(dev, 1);
 
 	/* RX antenna default to A */
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */
 
 	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
 	msleep(1);
@@ -629,7 +625,7 @@ static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
 		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
-			 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
+			 rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1);
 	msleep(1);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
@@ -687,22 +683,23 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
-	rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x3, 0x441); msleep(1);
-	rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
-	rtl8225_write(dev, 0x5, 0xC72); msleep(1);
-	rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
-	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-	rtl8225_write(dev, 0x8, 0x03F); msleep(1);
-	rtl8225_write(dev, 0x9, 0x335); msleep(1);
-	rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
-	rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
-	rtl8225_write(dev, 0xc, 0x850); msleep(1);
-	rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
-	rtl8225_write(dev, 0xe, 0x02B); msleep(1);
-	rtl8225_write(dev, 0xf, 0x114); msleep(100);
+	rtl8225_write(dev, 0x0, 0x2BF);
+	rtl8225_write(dev, 0x1, 0xEE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x8C3);
+	rtl8225_write(dev, 0x5, 0xC72);
+	rtl8225_write(dev, 0x6, 0x0E6);
+	rtl8225_write(dev, 0x7, 0x82A);
+	rtl8225_write(dev, 0x8, 0x03F);
+	rtl8225_write(dev, 0x9, 0x335);
+	rtl8225_write(dev, 0xa, 0x9D4);
+	rtl8225_write(dev, 0xb, 0x7BB);
+	rtl8225_write(dev, 0xc, 0x850);
+	rtl8225_write(dev, 0xd, 0xCDF);
+	rtl8225_write(dev, 0xe, 0x02B);
+	rtl8225_write(dev, 0xf, 0x114);
+	msleep(100);
 
 	rtl8225_write(dev, 0x0, 0x1B7);
 
@@ -736,94 +733,92 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
 
 	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
 		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
-		msleep(1);
 		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
-		msleep(1);
 	}
 
 	msleep(1);
 
-	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
 	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
-	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
-	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x07);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x17);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+	rtl8225_write_phy_ofdm(dev, 0x23, 0x80);
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
 
 	rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
 	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
 	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
 	rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
 
-	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x00, 0x98);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47);
 	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
 	rtl8225_write_phy_cck(dev, 0x19, 0x00);
 	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
 	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
 	rtl8225_write_phy_cck(dev, 0x40, 0x86);
-	rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18);
+	rtl8225_write_phy_cck(dev, 0x44, 0x36);
+	rtl8225_write_phy_cck(dev, 0x45, 0x35);
+	rtl8225_write_phy_cck(dev, 0x46, 0x2e);
+	rtl8225_write_phy_cck(dev, 0x47, 0x25);
+	rtl8225_write_phy_cck(dev, 0x48, 0x1c);
+	rtl8225_write_phy_cck(dev, 0x49, 0x12);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x09);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x04);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05);
 
 	rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
 
 	rtl8225z2_rf_set_tx_power(dev, 1);
 
 	/* RX antenna default to A */
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */
 
 	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
 	msleep(1);
@@ -835,40 +830,38 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
-	rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x3, 0x441); msleep(1);
-	rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
-	rtl8225_write(dev, 0x5, 0xC72); msleep(1);
-	rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
-	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-	rtl8225_write(dev, 0x8, 0x03F); msleep(1);
-	rtl8225_write(dev, 0x9, 0x335); msleep(1);
-	rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
-	rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
-	rtl8225_write(dev, 0xc, 0x850); msleep(1);
-	rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
-	rtl8225_write(dev, 0xe, 0x02B); msleep(1);
-	rtl8225_write(dev, 0xf, 0x114); msleep(1);
-
-	rtl8225_write(dev, 0x0, 0x1B7); msleep(1);
+	rtl8225_write(dev, 0x0, 0x0B7);
+	rtl8225_write(dev, 0x1, 0xEE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x8C3);
+	rtl8225_write(dev, 0x5, 0xC72);
+	rtl8225_write(dev, 0x6, 0x0E6);
+	rtl8225_write(dev, 0x7, 0x82A);
+	rtl8225_write(dev, 0x8, 0x03F);
+	rtl8225_write(dev, 0x9, 0x335);
+	rtl8225_write(dev, 0xa, 0x9D4);
+	rtl8225_write(dev, 0xb, 0x7BB);
+	rtl8225_write(dev, 0xc, 0x850);
+	rtl8225_write(dev, 0xd, 0xCDF);
+	rtl8225_write(dev, 0xe, 0x02B);
+	rtl8225_write(dev, 0xf, 0x114);
+
+	rtl8225_write(dev, 0x0, 0x1B7);
 
 	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
-		rtl8225_write(dev, 0x1, i + 1); msleep(1);
-		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1);
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
 	}
 
-	rtl8225_write(dev, 0x3, 0x080); msleep(1);
-	rtl8225_write(dev, 0x5, 0x004); msleep(1);
-	rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
-	msleep(3000);
+	rtl8225_write(dev, 0x3, 0x080);
+	rtl8225_write(dev, 0x5, 0x004);
+	rtl8225_write(dev, 0x0, 0x0B7);
 
-	rtl8225_write(dev, 0x2, 0xC4D); msleep(1);
-	msleep(2000);
+	rtl8225_write(dev, 0x2, 0xC4D);
 
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x0, 0x2BF);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
@@ -891,10 +884,10 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
 	rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28);
 	rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
 
-	rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1);
-	rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x97, 0x46);
+	rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
+	rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);
+	rtl8225_write_phy_cck(dev, 0xc1, 0x88);
 }
 
 static void rtl8225_rf_stop(struct ieee80211_hw *dev)
@@ -902,7 +895,7 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev)
 	u8 reg;
 	struct rtl8187_priv *priv = dev->priv;
 
-	rtl8225_write(dev, 0x4, 0x1f); msleep(1);
+	rtl8225_write(dev, 0x4, 0x1f);
 
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);

+ 2 - 2
drivers/net/wireless/wl3501.h

@@ -2,7 +2,7 @@
 #define __WL3501_H__
 
 #include <linux/spinlock.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 
 /* define for WLA 2.0 */
 #define WL3501_BLKSZ 256
@@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr {
 
 struct wl3501_80211_tx_hdr {
 	struct wl3501_80211_tx_plcp_hdr	pclp_hdr;
-	struct ieee80211_hdr_4addr		mac_hdr;
+	struct ieee80211_hdr		mac_hdr;
 } __attribute__ ((packed));
 
 /*

+ 2 - 2
drivers/net/wireless/zd1201.c

@@ -17,11 +17,11 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
 #include <linux/string.h>
 #include <linux/if_arp.h>
 #include <linux/firmware.h>
-#include <net/ieee80211.h>
 #include "zd1201.h"
 
 static struct usb_device_id zd1201_table[] = {
@@ -345,7 +345,7 @@ static void zd1201_usbrx(struct urb *urb)
 				frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
 				if (!frag)
 					goto resubmit;
-				skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2);
+				skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2);
 				if (!skb) {
 					kfree(frag);
 					goto resubmit;

+ 10 - 0
include/linux/ieee80211.h

@@ -97,7 +97,10 @@
 #define IEEE80211_MAX_FRAME_LEN		2352
 
 #define IEEE80211_MAX_SSID_LEN		32
+
 #define IEEE80211_MAX_MESH_ID_LEN	32
+#define IEEE80211_MESH_CONFIG_LEN	19
+
 #define IEEE80211_QOS_CTL_LEN		2
 #define IEEE80211_QOS_CTL_TID_MASK	0x000F
 #define IEEE80211_QOS_CTL_TAG1D_MASK	0x0007
@@ -666,6 +669,13 @@ struct ieee80211_cts {
 	u8 ra[6];
 } __attribute__ ((packed));
 
+struct ieee80211_pspoll {
+	__le16 frame_control;
+	__le16 aid;
+	u8 bssid[6];
+	u8 ta[6];
+} __attribute__ ((packed));
+
 /**
  * struct ieee80211_bar - HT Block Ack Request
  *

Some files were not shown because too many files changed in this diff