瀏覽代碼

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

David S. Miller 16 年之前
父節點
當前提交
b5ddedc9cc
共有 83 個文件被更改,包括 5823 次插入5363 次删除
  1. 16 1
      drivers/net/wireless/Kconfig
  2. 0 7
      drivers/net/wireless/ath5k/ath5k.h
  3. 3 9
      drivers/net/wireless/ath5k/attach.c
  4. 12 3
      drivers/net/wireless/ath5k/base.c
  5. 1047 147
      drivers/net/wireless/ath5k/eeprom.c
  6. 216 37
      drivers/net/wireless/ath5k/eeprom.h
  7. 1 1
      drivers/net/wireless/ath5k/reset.c
  8. 1 2
      drivers/net/wireless/ath9k/Makefile
  9. 17 32
      drivers/net/wireless/ath9k/ath9k.h
  10. 18 70
      drivers/net/wireless/ath9k/beacon.c
  11. 2 2
      drivers/net/wireless/ath9k/calib.c
  12. 0 1652
      drivers/net/wireless/ath9k/core.c
  13. 36 244
      drivers/net/wireless/ath9k/core.h
  14. 8 3
      drivers/net/wireless/ath9k/eeprom.c
  15. 77 199
      drivers/net/wireless/ath9k/hw.c
  16. 22 1
      drivers/net/wireless/ath9k/hw.h
  17. 497 204
      drivers/net/wireless/ath9k/initvals.h
  18. 3 1
      drivers/net/wireless/ath9k/mac.c
  19. 908 231
      drivers/net/wireless/ath9k/main.c
  20. 205 442
      drivers/net/wireless/ath9k/rc.c
  21. 48 171
      drivers/net/wireless/ath9k/rc.h
  22. 228 372
      drivers/net/wireless/ath9k/recv.c
  23. 164 301
      drivers/net/wireless/ath9k/xmit.c
  24. 1 1
      drivers/net/wireless/iwlwifi/iwl-3945-io.h
  25. 0 1
      drivers/net/wireless/iwlwifi/iwl-3945.h
  26. 20 7
      drivers/net/wireless/iwlwifi/iwl-4965.c
  27. 22 5
      drivers/net/wireless/iwlwifi/iwl-5000.c
  28. 20 30
      drivers/net/wireless/iwlwifi/iwl-agn-rs.c
  29. 45 76
      drivers/net/wireless/iwlwifi/iwl-agn.c
  30. 4 22
      drivers/net/wireless/iwlwifi/iwl-core.c
  31. 0 3
      drivers/net/wireless/iwlwifi/iwl-core.h
  32. 1 6
      drivers/net/wireless/iwlwifi/iwl-dev.h
  33. 26 29
      drivers/net/wireless/iwlwifi/iwl-fh.h
  34. 1 1
      drivers/net/wireless/iwlwifi/iwl-hcmd.c
  35. 1 1
      drivers/net/wireless/iwlwifi/iwl-io.h
  36. 0 75
      drivers/net/wireless/iwlwifi/iwl-rx.c
  37. 152 5
      drivers/net/wireless/iwlwifi/iwl-sta.c
  38. 13 1
      drivers/net/wireless/iwlwifi/iwl-sta.h
  39. 1 10
      drivers/net/wireless/iwlwifi/iwl-tx.c
  40. 159 113
      drivers/net/wireless/iwlwifi/iwl3945-base.c
  41. 6 8
      drivers/net/wireless/mac80211_hwsim.c
  42. 129 31
      drivers/net/wireless/orinoco/orinoco.c
  43. 5 1
      drivers/net/wireless/orinoco/orinoco.h
  44. 20 1
      drivers/net/wireless/orinoco/spectrum_cs.c
  45. 3 0
      drivers/net/wireless/p54/p54.h
  46. 52 17
      drivers/net/wireless/p54/p54common.c
  47. 1 1
      drivers/net/wireless/p54/p54common.h
  48. 22 20
      drivers/net/wireless/p54/p54pci.c
  49. 1 1
      drivers/net/wireless/p54/p54pci.h
  50. 42 83
      drivers/net/wireless/rt2x00/rt2400pci.c
  51. 42 83
      drivers/net/wireless/rt2x00/rt2500pci.c
  52. 65 86
      drivers/net/wireless/rt2x00/rt2500usb.c
  53. 1 7
      drivers/net/wireless/rt2x00/rt2x00.h
  54. 0 6
      drivers/net/wireless/rt2x00/rt2x00leds.c
  55. 1 2
      drivers/net/wireless/rt2x00/rt2x00mac.c
  56. 25 0
      drivers/net/wireless/rt2x00/rt2x00pci.c
  57. 18 0
      drivers/net/wireless/rt2x00/rt2x00pci.h
  58. 6 8
      drivers/net/wireless/rt2x00/rt2x00queue.c
  59. 20 2
      drivers/net/wireless/rt2x00/rt2x00queue.h
  60. 104 9
      drivers/net/wireless/rt2x00/rt2x00usb.c
  61. 136 0
      drivers/net/wireless/rt2x00/rt2x00usb.h
  62. 59 102
      drivers/net/wireless/rt2x00/rt61pci.c
  63. 167 266
      drivers/net/wireless/rt2x00/rt73usb.c
  64. 7 0
      drivers/net/wireless/rtl818x/rtl8187.h
  65. 200 14
      drivers/net/wireless/rtl818x/rtl8187_dev.c
  66. 0 6
      drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
  67. 62 0
      include/linux/ieee80211.h
  68. 5 0
      include/linux/nl80211.h
  69. 1 0
      include/linux/rfkill.h
  70. 22 0
      include/net/wireless.h
  71. 4 4
      net/mac80211/Kconfig
  72. 1 1
      net/mac80211/ht.c
  73. 2 3
      net/mac80211/main.c
  74. 13 2
      net/mac80211/mlme.c
  75. 1 1
      net/mac80211/rc80211_pid_algo.c
  76. 4 3
      net/mac80211/wep.c
  77. 16 1
      net/rfkill/rfkill.c
  78. 11 0
      net/wireless/Kconfig
  79. 4 1
      net/wireless/core.c
  80. 13 0
      net/wireless/core.h
  81. 4 1
      net/wireless/nl80211.c
  82. 516 70
      net/wireless/reg.c
  83. 17 4
      net/wireless/reg.h

+ 16 - 1
drivers/net/wireless/Kconfig

@@ -214,6 +214,21 @@ config HERMES
 	  configure your card and that /etc/pcmcia/wireless.opts works :
 	  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
 
+config HERMES_CACHE_FW_ON_INIT
+	bool "Cache Hermes firmware on driver initialisation"
+	depends on HERMES
+	default y
+	---help---
+	  Say Y to cache any firmware required by the Hermes drivers
+	  on startup.  The firmware will remain cached until the
+	  driver is unloaded.  The cache uses 64K of RAM.
+
+	  Otherwise load the firmware from userspace as required.  In
+	  this case the driver should be unloaded and restarted
+	  whenever the firmware is changed.
+
+	  If you are not sure, say Y.
+
 config APPLE_AIRPORT
 	tristate "Apple Airport support (built-in)"
 	depends on PPC_PMAC && HERMES
@@ -508,7 +523,7 @@ config RTL8180
 
 config RTL8187
 	tristate "Realtek 8187 and 8187B USB support"
-	depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
+	depends on MAC80211 && USB && WLAN_80211
 	select EEPROM_93CX6
 	---help---
 	  This is a driver for RTL8187 and RTL8187B based cards.

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

@@ -821,13 +821,6 @@ struct ath5k_athchan_2ghz {
 		return (false);			\
 } while (0)
 
-enum ath5k_ant_setting {
-	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
-	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
-	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
-	AR5K_ANT_MAX		= 3,
-};
-
 /*
  * Hardware interrupt abstraction
  */

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

@@ -106,7 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
 {
 	struct ath5k_hw *ah;
 	struct pci_dev *pdev = sc->pdev;
-	u8 mac[ETH_ALEN];
+	u8 mac[ETH_ALEN] = {};
 	int ret;
 	u32 srev;
 
@@ -317,15 +317,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
 		goto err_free;
 	}
 
-	/* Set MAC address */
-	ret = ath5k_eeprom_read_mac(ah, mac);
-	if (ret) {
-		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
-			sc->pdev->device);
-		goto err_free;
-	}
-
+	/* MAC address is cleared until add_interface */
 	ath5k_hw_set_lladdr(ah, mac);
+
 	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
 	memset(ah->ah_bssid, 0xff, ETH_ALEN);
 	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);

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

@@ -200,7 +200,7 @@ static int		ath5k_pci_resume(struct pci_dev *pdev);
 #endif /* CONFIG_PM */
 
 static struct pci_driver ath5k_pci_driver = {
-	.name		= "ath5k_pci",
+	.name		= KBUILD_MODNAME,
 	.id_table	= ath5k_pci_id_table,
 	.probe		= ath5k_pci_probe,
 	.remove		= __devexit_p(ath5k_pci_remove),
@@ -707,7 +707,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_hw *ah = sc->ah;
-	u8 mac[ETH_ALEN];
+	u8 mac[ETH_ALEN] = {};
 	int ret;
 
 	ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
@@ -777,7 +777,13 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 	tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
 	setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
 
-	ath5k_hw_get_lladdr(ah, mac);
+	ret = ath5k_eeprom_read_mac(ah, mac);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+			sc->pdev->device);
+		goto err_queues;
+	}
+
 	SET_IEEE80211_PERM_ADDR(hw, mac);
 	/* All MAC address bits matter for ACKs */
 	memset(sc->bssidmask, 0xff, ETH_ALEN);
@@ -2765,6 +2771,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
 	/* Set to a reasonable value. Note that this will
 	 * be set to mac80211's value at ath5k_config(). */
 	sc->bintval = 1000;
+	ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
 
 	ret = 0;
 end:
@@ -2777,11 +2784,13 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
 			struct ieee80211_if_init_conf *conf)
 {
 	struct ath5k_softc *sc = hw->priv;
+	u8 mac[ETH_ALEN] = {};
 
 	mutex_lock(&sc->lock);
 	if (sc->vif != conf->vif)
 		goto end;
 
+	ath5k_hw_set_lladdr(sc->ah, mac);
 	sc->vif = NULL;
 end:
 	mutex_unlock(&sc->lock);

+ 1047 - 147
drivers/net/wireless/ath5k/eeprom.c

@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
  * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -63,8 +64,8 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
 /*
  * Translate binary channel representation in EEPROM to frequency
  */
-static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
-				unsigned int mode)
+static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
+                                 unsigned int mode)
 {
 	u16 val;
 
@@ -72,13 +73,13 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
 		return bin;
 
 	if (mode == AR5K_EEPROM_MODE_11A) {
-		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
 			val = (5 * bin) + 4800;
 		else
 			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
 				(bin * 10) + 5100;
 	} else {
-		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
 			val = bin + 2300;
 		else
 			val = bin + 2400;
@@ -87,6 +88,71 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
 	return val;
 }
 
+/*
+ * Initialize eeprom & capabilities structs
+ */
+static int
+ath5k_eeprom_init_header(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int ret;
+	u16 val;
+
+	/* Initial TX thermal adjustment values */
+	ee->ee_tx_clip = 4;
+	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
+	ee->ee_gain_select = 1;
+
+	/*
+	 * Read values from EEPROM and store them in the capability structure
+	 */
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+	/* Return if we have an old EEPROM */
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+		return 0;
+
+#ifdef notyet
+	/*
+	 * Validate the checksum of the EEPROM date. There are some
+	 * devices with invalid EEPROMs.
+	 */
+	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
+		cksum ^= val;
+	}
+	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
+		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+		return -EIO;
+	}
+#endif
+
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+	    ee_ant_gain);
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+	}
+
+	return 0;
+}
+
+
 /*
  * Read antenna infos from eeprom
  */
@@ -100,7 +166,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
 
 	AR5K_EEPROM_READ(o++, val);
 	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
-	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
+	ee->ee_atn_tx_rx[mode]		= (val >> 2) & 0x3f;
 	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
 
 	AR5K_EEPROM_READ(o++, val);
@@ -157,6 +223,30 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
 	u16 val;
 	int ret;
 
+	ee->ee_n_piers[mode] = 0;
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
+		ee->ee_db[mode][3]		= (val >> 2) & 0x7;
+		ee->ee_ob[mode][2]		= (val << 1) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
+		ee->ee_db[mode][2]		= (val >> 12) & 0x7;
+		ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
+		ee->ee_db[mode][1]		= (val >> 6) & 0x7;
+		ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
+		ee->ee_db[mode][0]		= val & 0x7;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+	case AR5K_EEPROM_MODE_11B:
+		ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
+		ee->ee_db[mode][1]		= val & 0x7;
+		break;
+	}
+
 	AR5K_EEPROM_READ(o++, val);
 	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
 	ee->ee_thr_62[mode]		= val & 0xff;
@@ -209,8 +299,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
 		AR5K_EEPROM_READ(o++, val);
 		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
 
-		if (mode == AR5K_EEPROM_MODE_11G)
+		if (mode == AR5K_EEPROM_MODE_11G) {
 			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+			if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
+				ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+		}
 	}
 
 	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
@@ -219,10 +312,77 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
 		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
 	}
 
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
-	    mode == AR5K_EEPROM_MODE_11G)
-		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
+		goto done;
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
+			break;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_margin_tx_rx[mode] = val & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_b[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_b[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_b[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_g[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_g[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_turbo_max_power[mode] = val & 0x7f;
+		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_g[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
 
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+			AR5K_EEPROM_READ(o++, val);
+			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+		}
+		break;
+	}
+
+done:
 	/* return new offset */
 	*offset = o;
 
@@ -230,204 +390,944 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
 }
 
 /*
- * Initialize eeprom & capabilities structs
+ * Read turbo mode information on newer EEPROM versions
  */
-int ath5k_eeprom_init(struct ath5k_hw *ah)
+static int
+ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
+			      u32 *offset, unsigned int mode)
 {
 	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	unsigned int mode, i;
-	int ret;
-	u32 offset;
+	u32 o = *offset;
 	u16 val;
+	int ret;
 
-	/* Initial TX thermal adjustment values */
-	ee->ee_tx_clip = 4;
-	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
-	ee->ee_gain_select = 1;
+	if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
+		return 0;
 
-	/*
-	 * Read values from EEPROM and store them in the capability structure
-	 */
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+	switch (mode){
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
 
-	/* Return if we have an old EEPROM */
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
-		return 0;
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
+
+		if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
+			ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
+
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
+		break;
+	}
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+
+static int
+ath5k_eeprom_init_modes(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 mode_offset[3];
+	unsigned int mode;
+	u32 offset;
+	int ret;
 
-#ifdef notyet
 	/*
-	 * Validate the checksum of the EEPROM date. There are some
-	 * devices with invalid EEPROMs.
+	 * Get values for all modes
 	 */
-	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
-		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
-		cksum ^= val;
+	mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+	ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
+		AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+		offset = mode_offset[mode];
+
+		ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
 	}
-	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
-		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
-		return -EIO;
+
+	/* override for older eeprom versions for better performance */
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
 	}
-#endif
 
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
-	    ee_ant_gain);
+	return 0;
+}
 
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
-	}
+static inline void
+ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
+{
+	const static u16 intercepts3[] =
+		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
+	const static u16 intercepts3_2[] =
+		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+	const u16 *ip;
+	int i;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
+		ip = intercepts3_2;
+	else
+		ip = intercepts3;
 
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+	for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
+		*vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100;
+}
 
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+static inline int
+ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
+                            struct ath5k_chan_pcal_info *pc, u8 *count)
+{
+	int o = *offset;
+	int i = 0;
+	u8 f1, f2;
+	int ret;
+	u16 val;
+
+	while(i < max) {
+		AR5K_EEPROM_READ(o++, val);
+
+		f1 = (val >> 8) & 0xff;
+		f2 = val & 0xff;
+
+		if (f1)
+			pc[i++].freq = f1;
+
+		if (f2)
+			pc[i++].freq = f2;
+
+		if (!f1 || !f2)
+			break;
 	}
+	*offset = o;
+	*count = i;
 
-	/*
-	 * Get conformance test limit values
-	 */
-	offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
-	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
+	return 0;
+}
+
+static int
+ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
+	int i, ret;
+	u16 val;
+	u8 mask;
+
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		ath5k_eeprom_read_freq_list(ah, &offset,
+			AR5K_EEPROM_N_5GHZ_CHAN, pcal,
+			&ee->ee_n_piers[AR5K_EEPROM_MODE_11A]);
+	} else {
+		mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
 
-	for (i = 0; i < ee->ee_ctls; i++) {
 		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_ctl[i] = (val >> 8) & 0xff;
-		ee->ee_ctl[i + 1] = val & 0xff;
+		pcal[0].freq  = (val >> 9) & mask;
+		pcal[1].freq  = (val >> 2) & mask;
+		pcal[2].freq  = (val << 5) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[2].freq |= (val >> 11) & 0x1f;
+		pcal[3].freq  = (val >> 4) & mask;
+		pcal[4].freq  = (val << 3) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[4].freq |= (val >> 13) & 0x7;
+		pcal[5].freq  = (val >> 6) & mask;
+		pcal[6].freq  = (val << 1) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[6].freq |= (val >> 15) & 0x1;
+		pcal[7].freq  = (val >> 8) & mask;
+		pcal[8].freq  = (val >> 1) & mask;
+		pcal[9].freq  = (val << 6) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[9].freq |= (val >> 10) & 0x3f;
+		ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
 	}
 
-	/*
-	 * Get values for 802.11a (5GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11A;
+	for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) {
+		pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+				pcal[i].freq, AR5K_EEPROM_MODE_11A);
+	}
 
-	ee->ee_turbo_max_power[mode] =
-			AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+	return 0;
+}
 
-	offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+static inline int
+ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+	int i;
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11B:
+		pcal = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		pcal = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
 
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
+	ath5k_eeprom_read_freq_list(ah, &offset,
+		AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
+		&ee->ee_n_piers[mode]);
+	for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) {
+		pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+				pcal[i].freq, mode);
+	}
 
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
-	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
-	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
-	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
-	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
-	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
-	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
-	ee->ee_db[mode][0]		= val & 0x7;
-
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
+	return 0;
+}
 
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_margin_tx_rx[mode] = val & 0x3f;
+
+static int
+ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+	int offset, ret;
+	int i, j;
+	u16 val;
+
+	offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ret = ath5k_eeprom_init_11a_pcal_freq(ah,
+			offset + AR5K_EEPROM_GROUP1_OFFSET);
+		if (ret < 0)
+			return ret;
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		pcal = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
+		    !AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_b;
+		offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2412;
+		pcal[1].freq = 2447;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_g;
+		offset += AR5K_EEPROM_GROUP4_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2312;
+		pcal[1].freq = 2412;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	/*
-	 * Get values for 802.11b (2.4GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11B;
-	offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		struct ath5k_chan_pcal_info_rf5111 *cdata =
+			&pcal[i].rf5111_info;
 
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
+		cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
+		cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
 
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
-	ee->ee_db[mode][1]		= val & 0x7;
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[0] |= ((val >> 14) & 0x3);
+		cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
 
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[3] |= ((val >> 12) & 0xf);
+		cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[5] = (val  & AR5K_EEPROM_POWER_M);
 
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
 		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][0] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-		ee->ee_cal_pier[mode][1] =
-			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+		cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
 
 		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][2] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+		cdata->pwr[8] |= ((val >> 14) & 0x3);
+		cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+
+		ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
+			cdata->pcdac_max, cdata->pcdac);
+
+		for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) {
+			cdata->pwr[j] = (u16)
+				(AR5K_EEPROM_POWER_STEP * cdata->pwr[j]);
+		}
 	}
 
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+	return 0;
+}
 
-	/*
-	 * Get values for 802.11g (2.4GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11G;
-	offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+static int
+ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
+	struct ath5k_chan_pcal_info *gen_chan_info;
+	u32 offset;
+	unsigned int i, c;
+	u16 val;
+	int ret;
 
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		/*
+		 * Read 5GHz EEPROM channels
+		 */
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		gen_chan_info = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP4_OFFSET;
+		else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP2_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
 
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
-	ee->ee_db[mode][1]		= val & 0x7;
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		chan_pcal_info = &gen_chan_info[i].rf5112_info;
 
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
+		/* Power values in dBm * 4
+		 * for the lower xpd gain curve
+		 * (0 dBm -> higher output power) */
+		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr_x0[c] = (val & 0xff);
+			chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff);
+		}
 
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements */
 		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][0] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-		ee->ee_cal_pier[mode][1] =
-			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+		chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
+		chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
+		chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
 
+		/* Power values in dBm * 4
+		 * for the higher xpd gain curve
+		 * (18 dBm -> lower output power) */
 		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_turbo_max_power[mode] = val & 0x7f;
-		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+		chan_pcal_info->pwr_x3[0] = (val & 0xff);
+		chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff);
 
 		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][2] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+		chan_pcal_info->pwr_x3[2] = (val & 0xff);
+
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements (static) */
+		chan_pcal_info->pcdac_x3[0] = 20;
+		chan_pcal_info->pcdac_x3[1] = 35;
+		chan_pcal_info->pcdac_x3[2] = 63;
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
+			chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff);
+
+			/* Last xpd0 power level is also channel maximum */
+			gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
+		} else {
+			chan_pcal_info->pcdac_x0[0] = 1;
+			gen_chan_info[i].max_pwr = ((val >> 8) & 0xff);
+		}
 
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+		/* Recreate pcdac_x0 table for this channel using pcdac steps */
+		chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0];
+		chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1];
+		chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2];
+	}
+
+	return 0;
+}
+
+static inline unsigned int
+ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
+{
+	static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
+	unsigned int sz;
+
+	sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
+	sz *= ee->ee_n_piers[mode];
+
+	return sz;
+}
+
+static unsigned int
+ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
+{
+	u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11G:
+		if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11B:
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11A:
+		break;
+	default:
+		break;
+	}
+
+	return offset;
+}
+
+static int
+ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info;
+	struct ath5k_chan_pcal_info *gen_chan_info;
+	unsigned int i, c;
+	u32 offset;
+	int ret;
+	u16 val;
+	u8 pd_gains = 0;
+
+	if (ee->ee_x_gain[mode] & 0x1) pd_gains++;
+	if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++;
+	if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++;
+	if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++;
+	ee->ee_pd_gains[mode] = pd_gains;
+
+	offset = ath5k_cal_data_offset_2413(ee, mode);
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+		offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
+		gen_chan_info = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+			return 0;
 
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		gen_chan_info = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		gen_chan_info = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (pd_gains == 0)
+		return 0;
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		chan_pcal_info = &gen_chan_info[i].rf2413_info;
+
+		/*
+		 * Read pwr_i, pddac_i and the first
+		 * 2 pd points (pwr, pddac)
+		 */
 		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
-		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+		chan_pcal_info->pwr_i[0] = val & 0x1f;
+		chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f;
+		chan_pcal_info->pwr[0][0] =
+					(val >> 12) & 0xf;
 
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pddac[0][0] = val & 0x3f;
+		chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf;
+		chan_pcal_info->pddac[0][1] =
+					(val >> 10) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr[0][2] = val & 0xf;
+		chan_pcal_info->pddac[0][2] =
+					(val >> 4) & 0x3f;
+
+		chan_pcal_info->pwr[0][3] = 0;
+		chan_pcal_info->pddac[0][3] = 0;
+
+		if (pd_gains > 1) {
+			/*
+			 * Pd gain 0 is not the last pd gain
+			 * so it only has 2 pd points.
+			 * Continue wih pd gain 1.
+			 */
+			chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f;
+
+			chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1;
 			AR5K_EEPROM_READ(offset++, val);
-			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+			chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1;
+
+			chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf;
+			chan_pcal_info->pddac[1][0] =
+						(val >> 10) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[1][1] = val & 0xf;
+			chan_pcal_info->pddac[1][1] =
+						(val >> 4) & 0x3f;
+			chan_pcal_info->pwr[1][2] =
+						(val >> 10) & 0xf;
+
+			chan_pcal_info->pddac[1][2] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[1][2] |=
+						(val & 0xF) << 2;
+
+			chan_pcal_info->pwr[1][3] = 0;
+			chan_pcal_info->pddac[1][3] = 0;
+		} else if (pd_gains == 1) {
+			/*
+			 * Pd gain 0 is the last one so
+			 * read the extra point.
+			 */
+			chan_pcal_info->pwr[0][3] =
+						(val >> 10) & 0xf;
+
+			chan_pcal_info->pddac[0][3] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[0][3] |=
+						(val & 0xF) << 2;
+		}
+
+		/*
+		 * Proceed with the other pd_gains
+		 * as above.
+		 */
+		if (pd_gains > 2) {
+			chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f;
+			chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[2][0] =
+						(val >> 0) & 0xf;
+			chan_pcal_info->pddac[2][0] =
+						(val >> 4) & 0x3f;
+			chan_pcal_info->pwr[2][1] =
+						(val >> 10) & 0xf;
+
+			chan_pcal_info->pddac[2][1] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[2][1] |=
+						(val & 0xF) << 2;
+
+			chan_pcal_info->pwr[2][2] =
+						(val >> 4) & 0xf;
+			chan_pcal_info->pddac[2][2] =
+						(val >> 8) & 0x3f;
+
+			chan_pcal_info->pwr[2][3] = 0;
+			chan_pcal_info->pddac[2][3] = 0;
+		} else if (pd_gains == 2) {
+			chan_pcal_info->pwr[1][3] =
+						(val >> 4) & 0xf;
+			chan_pcal_info->pddac[1][3] =
+						(val >> 8) & 0x3f;
+		}
+
+		if (pd_gains > 3) {
+			chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
+
+			chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f;
+			chan_pcal_info->pwr[3][0] =
+						(val >> 10) & 0xf;
+			chan_pcal_info->pddac[3][0] =
+						(val >> 14) & 0x3;
+
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[3][0] |=
+						(val & 0xF) << 2;
+			chan_pcal_info->pwr[3][1] =
+						(val >> 4) & 0xf;
+			chan_pcal_info->pddac[3][1] =
+						(val >> 8) & 0x3f;
+
+			chan_pcal_info->pwr[3][2] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[3][2] |=
+						((val >> 0) & 0x3) << 2;
+
+			chan_pcal_info->pddac[3][2] =
+						(val >> 2) & 0x3f;
+			chan_pcal_info->pwr[3][3] =
+						(val >> 8) & 0xf;
+
+			chan_pcal_info->pddac[3][3] =
+						(val >> 12) & 0xF;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[3][3] |=
+						((val >> 0) & 0x3) << 4;
+		} else if (pd_gains == 3) {
+			chan_pcal_info->pwr[2][3] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[2][3] |=
+						((val >> 0) & 0x3) << 2;
+
+			chan_pcal_info->pddac[2][3] =
+						(val >> 2) & 0x3f;
+		}
+
+		for (c = 0; c < pd_gains; c++) {
+			/* Recreate pwr table for this channel using pwr steps */
+			chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2;
+			chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0];
+			chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1];
+			chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2];
+			if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2])
+				chan_pcal_info->pwr[c][3] = 0;
+
+			/* Recreate pddac table for this channel using pddac steps */
+			chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c];
+			chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0];
+			chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1];
+			chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2];
+			if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2])
+				chan_pcal_info->pddac[c][3] = 0;
 		}
 	}
 
-	/*
-	 * Read 5GHz EEPROM channels
-	 */
+	return 0;
+}
+
+/*
+ * Read per rate target power (this is the maximum tx power
+ * supported by the card). This info is used when setting
+ * tx power, no matter the channel.
+ *
+ * This also works for v5 EEPROMs.
+ */
+static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_rate_pcal_info *rate_pcal_info;
+	u16 *rate_target_pwr_num;
+	u32 offset;
+	u16 val;
+	int ret, i;
+
+	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
+	rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_a;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_b;
+		ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_g;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Different freq mask for older eeproms (<= v3.2) */
+	if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
+			rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
+			rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
+		}
+	} else {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
+			rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
+			rate_pcal_info[i].target_power_54 = (val & 0x3f);
+		}
+	}
+
+	return 0;
+}
+
+static int
+ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int (*read_pcal)(struct ath5k_hw *hw, int mode);
+	int mode;
+	int err;
+
+	if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
+		read_pcal = ath5k_eeprom_read_pcal_info_5112;
+	else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
+		read_pcal = ath5k_eeprom_read_pcal_info_2413;
+	else
+		read_pcal = ath5k_eeprom_read_pcal_info_5111;
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+		err = read_pcal(ah, mode);
+		if (err)
+			return err;
+
+		err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+/* Read conformance test limits */
+static int
+ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_edge_power *rep;
+	unsigned int fmask, pmask;
+	unsigned int ctl_mode;
+	int ret, i, j;
+	u32 offset;
+	u16 val;
+
+	pmask = AR5K_EEPROM_POWER_M;
+	fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
+	offset = AR5K_EEPROM_CTL(ee->ee_version);
+	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
+	for (i = 0; i < ee->ee_ctls; i += 2) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_ctl[i] = (val >> 8) & 0xff;
+		ee->ee_ctl[i + 1] = val & 0xff;
+	}
+
+	offset = AR5K_EEPROM_GROUP8_OFFSET;
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
+		offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
+			AR5K_EEPROM_GROUP5_OFFSET;
+	else
+		offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
+
+	rep = ee->ee_ctl_pwr;
+	for(i = 0; i < ee->ee_ctls; i++) {
+		switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
+		case AR5K_CTL_11A:
+		case AR5K_CTL_TURBO:
+			ctl_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		default:
+			ctl_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		}
+		if (ee->ee_ctl[i] == 0) {
+			if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
+				offset += 8;
+			else
+				offset += 7;
+			rep += AR5K_EEPROM_N_EDGES;
+			continue;
+		}
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].freq = (val >> 8) & fmask;
+				rep[j + 1].freq = val & fmask;
+			}
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].edge = (val >> 8) & pmask;
+				rep[j].flag = (val >> 14) & 1;
+				rep[j + 1].edge = val & pmask;
+				rep[j + 1].flag = (val >> 6) & 1;
+			}
+		} else {
+			AR5K_EEPROM_READ(offset++, val);
+			rep[0].freq = (val >> 9) & fmask;
+			rep[1].freq = (val >> 2) & fmask;
+			rep[2].freq = (val << 5) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[2].freq |= (val >> 11) & 0x1f;
+			rep[3].freq = (val >> 4) & fmask;
+			rep[4].freq = (val << 3) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].freq |= (val >> 13) & 0x7;
+			rep[5].freq = (val >> 6) & fmask;
+			rep[6].freq = (val << 1) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].freq |= (val >> 15) & 0x1;
+			rep[7].freq = (val >> 8) & fmask;
+
+			rep[0].edge = (val >> 2) & pmask;
+			rep[1].edge = (val << 4) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[1].edge |= (val >> 12) & 0xf;
+			rep[2].edge = (val >> 6) & pmask;
+			rep[3].edge = val & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].edge = (val >> 10) & pmask;
+			rep[5].edge = (val >> 4) & pmask;
+			rep[6].edge = (val << 2) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].edge |= (val >> 14) & 0x3;
+			rep[7].edge = (val >> 8) & pmask;
+		}
+		for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
+			rep[j].freq = ath5k_eeprom_bin2freq(ee,
+				rep[j].freq, ctl_mode);
+		}
+		rep += AR5K_EEPROM_N_EDGES;
+	}
 
 	return 0;
 }
 
+
+/*
+ * Initialize eeprom power tables
+ */
+int
+ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+	int err;
+
+	err = ath5k_eeprom_init_header(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_init_modes(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_pcal_info(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_ctl_info(ah);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
 /*
  * Read the MAC address from eeprom
  */

+ 216 - 37
drivers/net/wireless/ath5k/eeprom.h

@@ -25,24 +25,8 @@
 #define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
 #define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
 
-#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
-#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
-#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
-#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
-#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
-#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
-#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
-#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
-#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
-#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
-#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
-#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
-#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
-#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
-#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
 #define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
+#define AR5K_EEPROM_CHECKSUM		0x00c0	/* EEPROM checksum */
 #define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
 #define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
 #define AR5K_EEPROM_INFO_CKSUM		0xffff
@@ -53,15 +37,19 @@
 #define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
 #define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
 #define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
 #define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
 #define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_3		0x4003
+#define AR5K_EEPROM_VERSION_4_3		0x4003	/* power calibration changes */
 #define AR5K_EEPROM_VERSION_4_4		0x4004
 #define AR5K_EEPROM_VERSION_4_5		0x4005
 #define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
-#define AR5K_EEPROM_VERSION_4_7		0x4007
+#define AR5K_EEPROM_VERSION_4_7		0x3007	/* 4007 ? */
+#define AR5K_EEPROM_VERSION_4_9		0x4009	/* EAR futureproofing */
+#define AR5K_EEPROM_VERSION_5_0		0x5000	/* Has 2413 PDADC calibration etc */
+#define AR5K_EEPROM_VERSION_5_1		0x5001	/* Has capability values */
+#define AR5K_EEPROM_VERSION_5_3		0x5003	/* Has spur mitigation tables */
 
 #define AR5K_EEPROM_MODE_11A		0
 #define AR5K_EEPROM_MODE_11B		1
@@ -74,8 +62,8 @@
 #define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
 #define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
 #define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz (?) */
 #define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz */
 
 #define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
 #define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
@@ -87,27 +75,95 @@
 	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
 
 #define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
-#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((int8_t)(((_v) >> 8) & 0xff))
-#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((int8_t)((_v) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((s8)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((s8)((_v) & 0xff))
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0		AR5K_EEPROM_INFO(4)
+#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_HDR_XR2_DIS(_v)	(((_v) >> 12) & 0x1)
+#define AR5K_EEPROM_HDR_XR5_DIS(_v)	(((_v) >> 13) & 0x1)
+#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
+
+#define AR5K_EEPROM_MISC1			AR5K_EEPROM_INFO(5)
+#define AR5K_EEPROM_TARGET_PWRSTART(_v)		((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)		(((_v) >> 14) & 0x1)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v)	(((_v) >> 15) & 0x1)
+
+#define AR5K_EEPROM_MISC2			AR5K_EEPROM_INFO(6)
+#define AR5K_EEPROM_EEP_FILE_VERSION(_v)	(((_v) >> 8) & 0xff)
+#define AR5K_EEPROM_EAR_FILE_VERSION(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC3		AR5K_EEPROM_INFO(7)
+#define AR5K_EEPROM_ART_BUILD_NUM(_v)	(((_v) >> 10) & 0x3f)
+#define AR5K_EEPROM_EAR_FILE_ID(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC4		AR5K_EEPROM_INFO(8)
+#define AR5K_EEPROM_CAL_DATA_START(_v)	(((_v) >> 4) & 0xfff)
+#define AR5K_EEPROM_MASK_R0(_v)		(((_v) >> 2) & 0x3)
+#define AR5K_EEPROM_MASK_R1(_v)		((_v) & 0x3)
+
+#define AR5K_EEPROM_MISC5		AR5K_EEPROM_INFO(9)
+#define AR5K_EEPROM_COMP_DIS(_v)	((_v) & 0x1)
+#define AR5K_EEPROM_AES_DIS(_v)		(((_v) >> 1) & 0x1)
+#define AR5K_EEPROM_FF_DIS(_v)		(((_v) >> 2) & 0x1)
+#define AR5K_EEPROM_BURST_DIS(_v)	(((_v) >> 3) & 0x1)
+#define AR5K_EEPROM_MAX_QCU(_v)		(((_v) >> 4) & 0xf)
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)	(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_KEY_CACHE_SIZE(_v)	(((_v) >> 12) & 0xf)
+
+#define AR5K_EEPROM_MISC6		AR5K_EEPROM_INFO(10)
+#define AR5K_EEPROM_TX_CHAIN_DIS	((_v) & 0x8)
+#define AR5K_EEPROM_RX_CHAIN_DIS	(((_v) >> 3) & 0x8)
+#define AR5K_EEPROM_FCC_MID_EN		(((_v) >> 6) & 0x1)
+#define AR5K_EEPROM_JAP_U1EVEN_EN	(((_v) >> 7) & 0x1)
+#define AR5K_EEPROM_JAP_U2_EN		(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_JAP_U1ODD_EN	(((_v) >> 9) & 0x1)
+#define AR5K_EEPROM_JAP_11A_NEW_EN	(((_v) >> 10) & 0x1)
 
 /* calibration settings */
 #define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
 #define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
 #define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
 #define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
+#define AR5K_EEPROM_GROUPS_START(_v)	AR5K_EEPROM_OFF(_v, 0x0100, 0x0150)	/* Start of Groups */
+#define AR5K_EEPROM_GROUP1_OFFSET	0x0
+#define AR5K_EEPROM_GROUP2_OFFSET	0x5
+#define AR5K_EEPROM_GROUP3_OFFSET	0x37
+#define AR5K_EEPROM_GROUP4_OFFSET	0x46
+#define AR5K_EEPROM_GROUP5_OFFSET	0x55
+#define AR5K_EEPROM_GROUP6_OFFSET	0x65
+#define AR5K_EEPROM_GROUP7_OFFSET	0x69
+#define AR5K_EEPROM_GROUP8_OFFSET	0x6f
+
+#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP5_OFFSET, 0x0000)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP6_OFFSET, 0x0010)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP7_OFFSET, 0x0014)
 
 /* [3.1 - 3.3] */
 #define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
 #define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
 
-/* Misc values available since EEPROM 4.0 */
-#define AR5K_EEPROM_MISC0		0x00c4
-#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
-#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
-#define AR5K_EEPROM_MISC1		0x00c5
-#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
-
+#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
 
 /* Some EEPROM defines */
 #define AR5K_EEPROM_EEP_SCALE		100
@@ -115,8 +171,11 @@
 #define AR5K_EEPROM_N_MODES		3
 #define AR5K_EEPROM_N_5GHZ_CHAN		10
 #define AR5K_EEPROM_N_2GHZ_CHAN		3
+#define AR5K_EEPROM_N_2GHZ_CHAN_2413	4
 #define AR5K_EEPROM_MAX_CHAN		10
+#define AR5K_EEPROM_N_PWR_POINTS_5111	11
 #define AR5K_EEPROM_N_PCDAC		11
+#define AR5K_EEPROM_N_PHASE_CAL		5
 #define AR5K_EEPROM_N_TEST_FREQ		8
 #define AR5K_EEPROM_N_EDGES		8
 #define AR5K_EEPROM_N_INTERCEPTS	11
@@ -136,6 +195,8 @@
 #define AR5K_EEPROM_N_XPD_PER_CHANNEL	4
 #define AR5K_EEPROM_N_XPD0_POINTS	4
 #define AR5K_EEPROM_N_XPD3_POINTS	3
+#define AR5K_EEPROM_N_PD_GAINS		4
+#define AR5K_EEPROM_N_PD_POINTS		5
 #define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
 #define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
 #define AR5K_EEPROM_POWER_M		0x3f
@@ -158,8 +219,99 @@
 #define AR5K_EEPROM_READ_HDR(_o, _v)					\
 	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
 
-/* Struct to hold EEPROM calibration data */
+enum ath5k_ant_setting {
+	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
+	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
+	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
+	AR5K_ANT_MAX		= 3,
+};
+
+enum ath5k_ctl_mode {
+	AR5K_CTL_11A = 0,
+	AR5K_CTL_11B = 1,
+	AR5K_CTL_11G = 2,
+	AR5K_CTL_TURBO = 3,
+	AR5K_CTL_108G = 4,
+	AR5K_CTL_2GHT20 = 5,
+	AR5K_CTL_5GHT20 = 6,
+	AR5K_CTL_2GHT40 = 7,
+	AR5K_CTL_5GHT40 = 8,
+	AR5K_CTL_MODE_M = 15,
+};
+
+/* Per channel calibration data, used for power table setup */
+struct ath5k_chan_pcal_info_rf5111 {
+	/* Power levels in half dbm units
+	 * for one power curve. */
+	u8		pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* PCDAC table steps
+	 * for the above values */
+	u8		pcdac[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* Starting PCDAC step */
+	u8		pcdac_min;
+	/* Final PCDAC step */
+	u8		pcdac_max;
+};
+
+struct ath5k_chan_pcal_info_rf5112 {
+	/* Power levels in quarter dBm units
+	 * for lower (0) and higher (3)
+	 * level curves */
+	s8		pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	s8		pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
+	/* PCDAC table steps
+	 * for the above values */
+	u8	pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	u8	pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
+};
+
+struct ath5k_chan_pcal_info_rf2413 {
+	/* Starting pwr/pddac values */
+	s8		pwr_i[AR5K_EEPROM_N_PD_GAINS];
+	u8	pddac_i[AR5K_EEPROM_N_PD_GAINS];
+	/* (pwr,pddac) points */
+	s8		pwr[AR5K_EEPROM_N_PD_GAINS]
+				[AR5K_EEPROM_N_PD_POINTS];
+	u8	pddac[AR5K_EEPROM_N_PD_GAINS]
+				[AR5K_EEPROM_N_PD_POINTS];
+};
+
+struct ath5k_chan_pcal_info {
+	/* Frequency */
+	u16	freq;
+	/* Max available power */
+	s8		max_pwr;
+	union {
+		struct ath5k_chan_pcal_info_rf5111 rf5111_info;
+		struct ath5k_chan_pcal_info_rf5112 rf5112_info;
+		struct ath5k_chan_pcal_info_rf2413 rf2413_info;
+	};
+};
+
+/* Per rate calibration data for each mode, used for power table setup */
+struct ath5k_rate_pcal_info {
+	u16	freq; /* Frequency */
+	/* Power level for 6-24Mbit/s rates */
+	u16	target_power_6to24;
+	/* Power level for 36Mbit rate */
+	u16	target_power_36;
+	/* Power level for 48Mbit rate */
+	u16	target_power_48;
+	/* Power level for 54Mbit rate */
+	u16	target_power_54;
+};
+
+/* Power edges for conformance test limits */
+struct ath5k_edge_power {
+	u16 freq;
+	u16 edge; /* in half dBm */
+	bool flag;
+};
+
+/* EEPROM calibration data */
 struct ath5k_eeprom_info {
+
+	/* Header information */
 	u16	ee_magic;
 	u16	ee_protect;
 	u16	ee_regdomain;
@@ -168,6 +320,11 @@ struct ath5k_eeprom_info {
 	u16	ee_ant_gain;
 	u16	ee_misc0;
 	u16	ee_misc1;
+	u16	ee_misc2;
+	u16	ee_misc3;
+	u16	ee_misc4;
+	u16	ee_misc5;
+	u16	ee_misc6;
 	u16	ee_cck_ofdm_gain_delta;
 	u16	ee_cck_ofdm_power_delta;
 	u16	ee_scaled_cck_delta;
@@ -185,7 +342,7 @@ struct ath5k_eeprom_info {
 	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
 	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
 	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
-	u16	ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx[AR5K_EEPROM_N_MODES];
 	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
 	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
 	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
@@ -198,18 +355,40 @@ struct ath5k_eeprom_info {
 	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
 	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
 	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES];
 
-	/* Unused */
+	/* Power calibration data */
 	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
-	u16	ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
-	u16	ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
+
+	/* Number of pd gain curves per mode (RF2413) */
+	u8 ee_pd_gains[AR5K_EEPROM_N_MODES];
+
+	u8 ee_n_piers[AR5K_EEPROM_N_MODES];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
+
+	/* Per rate target power levels */
+	u16	ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
 
 	/* Conformance test limits (Unused) */
 	u16	ee_ctls;
 	u16	ee_ctl[AR5K_EEPROM_MAX_CTLS];
+	struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
 
 	/* Noise Floor Calibration settings */
 	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
 	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
 	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pd_gain_overlap;
+
+	u32	ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
 };
+

+ 1 - 1
drivers/net/wireless/ath5k/reset.c

@@ -674,7 +674,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
 			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
 			0xffffc07f);
 		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
-			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
+			(ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000,
 			0xfffc0fff);
 		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
 			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |

+ 1 - 2
drivers/net/wireless/ath9k/Makefile

@@ -9,7 +9,6 @@ ath9k-y +=	hw.o \
 		main.o \
 		recv.o \
 		xmit.o \
-		rc.o \
-		core.o
+		rc.o
 
 obj-$(CONFIG_ATH9K) += ath9k.o

+ 17 - 32
drivers/net/wireless/ath9k/ath9k.h

@@ -401,22 +401,6 @@ enum ath9k_int {
 	ATH9K_INT_NOCARD = 0xffffffff
 };
 
-struct ath9k_rate_table {
-	int rateCount;
-	u8 rateCodeToIndex[256];
-	struct {
-		u8 valid;
-		u8 phy;
-		u32 rateKbps;
-		u8 rateCode;
-		u8 shortPreamble;
-		u8 dot11Rate;
-		u8 controlRate;
-		u16 lpAckDuration;
-		u16 spAckDuration;
-	} info[32];
-};
-
 #define ATH9K_RATESERIES_RTS_CTS  0x0001
 #define ATH9K_RATESERIES_2040     0x0002
 #define ATH9K_RATESERIES_HALFGI   0x0004
@@ -492,12 +476,10 @@ struct ath9k_channel {
        (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
        (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
        (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
-#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B)
 #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
        (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
        (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
        (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
-#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0)
 #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
 #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
 #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
@@ -506,6 +488,7 @@ struct ath9k_channel {
 #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
 
 /* These macros check chanmode and not channelFlags */
+#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
 #define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||	\
 			  ((_c)->chanmode == CHANNEL_G_HT20))
 #define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||	\
@@ -702,13 +685,19 @@ enum ath9k_ani_cmd {
 	ATH9K_ANI_ALL = 0xff
 };
 
-enum phytype {
-	PHY_DS,
-	PHY_FH,
-	PHY_OFDM,
-	PHY_HT,
+enum {
+	WLAN_RC_PHY_OFDM,
+	WLAN_RC_PHY_CCK,
+	WLAN_RC_PHY_HT_20_SS,
+	WLAN_RC_PHY_HT_20_DS,
+	WLAN_RC_PHY_HT_40_SS,
+	WLAN_RC_PHY_HT_40_DS,
+	WLAN_RC_PHY_HT_20_SS_HGI,
+	WLAN_RC_PHY_HT_20_DS_HGI,
+	WLAN_RC_PHY_HT_40_SS_HGI,
+	WLAN_RC_PHY_HT_40_DS_HGI,
+	WLAN_RC_PHY_MAX
 };
-#define PHY_CCK PHY_DS
 
 enum ath9k_tp_scale {
 	ATH9K_TP_SCALE_MAX = 0,
@@ -828,6 +817,8 @@ struct chan_centers {
 	u16 ext_center;
 };
 
+struct ath_rate_table;
+
 /* Helpers */
 
 enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
@@ -838,7 +829,7 @@ 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,
+			   struct ath_rate_table *rates,
 			   u32 frameLen, u16 rateix,
 			   bool shortPreamble);
 u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
@@ -883,12 +874,6 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
 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);
@@ -904,7 +889,7 @@ 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
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 void ath9k_enable_rfkill(struct ath_hal *ah);
 #endif
 int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);

+ 18 - 70
drivers/net/wireless/ath9k/beacon.c

@@ -14,13 +14,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
- /* Implementation of beacon processing. */
-
 #include "core.h"
 
 /*
- *  Configure parameters for the beacon queue
- *
  *  This function will modify certain transmit queue properties depending on
  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
  *  settings and channel width min/max
@@ -54,9 +50,15 @@ static int ath_beaconq_config(struct ath_softc *sc)
 	}
 }
 
+static void ath_bstuck_process(struct ath_softc *sc)
+{
+	DPRINTF(sc, ATH_DBG_BEACON,
+		"%s: stuck beacon; resetting (bmiss count %u)\n",
+		__func__, sc->sc_bmisscount);
+	ath_reset(sc, false);
+}
+
 /*
- *  Setup the beacon frame for transmit.
- *
  *  Associates the beacon frame buffer with a transmit descriptor.  Will set
  *  up all required antenna switch parameters, rate codes, and channel flags.
  *  Beacons are always sent out at the lowest rate, and are not retried.
@@ -68,7 +70,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_desc *ds;
 	struct ath9k_11n_rate_series series[4];
-	const struct ath9k_rate_table *rt;
+	struct ath_rate_table *rt;
 	int flags, antenna;
 	u8 rix, rate;
 	int ctsrate = 0;
@@ -106,10 +108,10 @@ static void ath_beacon_setup(struct ath_softc *sc,
 	 * XXX everything at min xmit rate
 	 */
 	rix = 0;
-	rt = sc->sc_currates;
-	rate = rt->info[rix].rateCode;
+	rt = sc->hw_rate_table[sc->sc_curmode];
+	rate = rt->info[rix].ratecode;
 	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-		rate |= rt->info[rix].shortPreamble;
+		rate |= rt->info[rix].short_preamble;
 
 	ath9k_hw_set11n_txdesc(ah, ds,
 			       skb->len + FCS_LEN,     /* frame length */
@@ -138,14 +140,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
 		ctsrate, ctsduration, series, 4, 0);
 }
 
-/*
- *  Generate beacon frame and queue cab data for a vap.
- *
- *  Updates the contents of the beacon frame.  It is assumed that the buffer for
- *  the beacon frame has been allocated in the ATH object, and simply needs to
- *  be filled for this cycle.  Also, any CAB (crap after beacon?) traffic will
- *  be added to the beacon frame at this point.
-*/
+/* Generate beacon frame and queue cab data for a vap */
 static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 {
 	struct ath_buf *bf;
@@ -275,14 +270,6 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
 		sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc);
 }
 
-/*
- *  Setup a h/w transmit queue for beacons.
- *
- *  This function allocates an information structure (struct ath9k_txq_info)
- *  on the stack, sets some specific parameters (zero out channel width
- *  min/max, and enable aifs). The info structure does not need to be
- *  persistant.
-*/
 int ath_beaconq_setup(struct ath_hal *ah)
 {
 	struct ath9k_tx_queue_info qi;
@@ -295,14 +282,6 @@ int ath_beaconq_setup(struct ath_hal *ah)
 	return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
 }
 
-
-/*
- *  Allocate and setup an initial beacon frame.
- *
- *  Allocate a beacon state variable for a specific VAP instance created on
- *  the ATH interface.  This routine also calculates the beacon "slot" for
- *  staggared beacons in the mBSSID case.
-*/
 int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 {
 	struct ieee80211_vif *vif;
@@ -321,7 +300,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 	if (!avp->av_bcbuf) {
 		/* Allocate beacon state for hostap/ibss.  We know
 		 * a buffer is available. */
-
 		avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
 						 struct ath_buf, list);
 		list_del(&avp->av_bcbuf->list);
@@ -427,12 +405,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 	return 0;
 }
 
-/*
- *  Reclaim beacon resources and return buffer to the pool.
- *
- *  Checks the VAP to put the beacon frame buffer back to the ATH object
- *  queue, and de-allocates any skbs that were sent as CAB traffic.
-*/
 void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
 {
 	if (avp->av_bcbuf != NULL) {
@@ -458,13 +430,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
 	}
 }
 
-/*
- * Tasklet for Sending Beacons
- *
- * Transmit one or more beacon frames at SWBA.  Dynamic updates to the frame
- * contents are done as needed and the slot time is also adjusted based on
- * current state.
-*/
 void ath9k_beacon_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
@@ -481,9 +446,7 @@ void ath9k_beacon_tasklet(unsigned long data)
 
 	if (sc->sc_flags & SC_OP_NO_RESET) {
 		show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
-							    &rx_clear,
-							    &rx_frame,
-							    &tx_frame);
+					    &rx_clear, &rx_frame, &tx_frame);
 	}
 
 	/*
@@ -605,9 +568,10 @@ void ath9k_beacon_tasklet(unsigned long data)
 	if (sc->sc_updateslot == UPDATE) {
 		sc->sc_updateslot = COMMIT; /* commit next beacon */
 		sc->sc_slotupdate = slot;
-	} else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
-		ath_setslottime(sc);        /* commit change to hardware */
-
+	} else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) {
+		ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
+		sc->sc_updateslot = OK;
+	}
 	if (bfaddr != 0) {
 		/*
 		 * Stop any current dma and put the new frame(s) on the queue.
@@ -629,20 +593,6 @@ void ath9k_beacon_tasklet(unsigned long data)
 	}
 }
 
-/*
- *  Tasklet for Beacon Stuck processing
- *
- *  Processing for Beacon Stuck.
- *  Basically resets the chip.
-*/
-void ath_bstuck_process(struct ath_softc *sc)
-{
-	DPRINTF(sc, ATH_DBG_BEACON,
-		"%s: stuck beacon; resetting (bmiss count %u)\n",
-		__func__, sc->sc_bmisscount);
-	ath_reset(sc, false);
-}
-
 /*
  * Configure the beacon and sleep timers.
  *
@@ -886,8 +836,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
 	}
 }
 
-/* Function to collect beacon rssi data and resync beacon if necessary */
-
 void ath_beacon_sync(struct ath_softc *sc, int if_id)
 {
 	/*

+ 2 - 2
drivers/net/wireless/ath9k/calib.c

@@ -176,14 +176,14 @@ static bool getNoiseFloorThresh(struct ath_hal *ah,
 	case CHANNEL_A_HT20:
 	case CHANNEL_A_HT40PLUS:
 	case CHANNEL_A_HT40MINUS:
-		*nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
+		*nft = (int8_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);
+		*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
 		break;
 	default:
 		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,

+ 0 - 1652
drivers/net/wireless/ath9k/core.c

@@ -1,1652 +0,0 @@
-/*
- * 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 "regd.h"
-
-static u32 ath_chainmask_sel_up_rssi_thres =
-	ATH_CHAINMASK_SEL_UP_RSSI_THRES;
-static u32 ath_chainmask_sel_down_rssi_thres =
-	ATH_CHAINMASK_SEL_DOWN_RSSI_THRES;
-static u32 ath_chainmask_sel_period =
-	ATH_CHAINMASK_SEL_TIMEOUT;
-
-/* return bus cachesize in 4B word units */
-
-static void bus_read_cachesize(struct ath_softc *sc, int *csz)
-{
-	u8 u8tmp;
-
-	pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
-	*csz = (int)u8tmp;
-
-	/*
-	 * This check was put in to avoid "unplesant" consequences if
-	 * the bootrom has not fully initialized all PCI devices.
-	 * Sometimes the cache line size register is not set
-	 */
-
-	if (*csz == 0)
-		*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
- *
- *  This function initializes and fills the rate table in the ATH object based
- *  on the operating mode.
-*/
-static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
-{
-	const struct ath9k_rate_table *rt;
-	int i;
-
-	memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
-	rt = ath9k_hw_getratetable(sc->sc_ah, mode);
-	BUG_ON(!rt);
-
-	for (i = 0; i < rt->rateCount; i++)
-		sc->sc_rixmap[rt->info[i].rateCode] = (u8) i;
-
-	memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
-	for (i = 0; i < 256; i++) {
-		u8 ix = rt->rateCodeToIndex[i];
-
-		if (ix == 0xff)
-			continue;
-
-		sc->sc_hwmap[i].ieeerate =
-		    rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
-		sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps;
-
-		if (rt->info[ix].shortPreamble ||
-		    rt->info[ix].phy == PHY_OFDM) {
-			/* XXX: Handle this */
-		}
-
-		/* NB: this uses the last entry if the rate isn't found */
-		/* XXX beware of overlow */
-	}
-	sc->sc_currates = rt;
-	sc->sc_curmode = mode;
-	/*
-	 * All protection frames are transmited at 2Mb/s for
-	 * 11g, otherwise at 1Mb/s.
-	 * XXX select protection rate index from rate table.
-	 */
-	sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0);
-}
-
-/*
- * Set up rate table (legacy rates)
- */
-static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	const struct ath9k_rate_table *rt = NULL;
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_rate *rate;
-	int i, maxrates;
-
-	switch (band) {
-	case IEEE80211_BAND_2GHZ:
-		rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G);
-		break;
-	case IEEE80211_BAND_5GHZ:
-		rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A);
-		break;
-	default:
-		break;
-	}
-
-	if (rt == NULL)
-		return;
-
-	sband = &sc->sbands[band];
-	rate = sc->rates[band];
-
-	if (rt->rateCount > ATH_RATE_MAX)
-		maxrates = ATH_RATE_MAX;
-	else
-		maxrates = rt->rateCount;
-
-	for (i = 0; i < maxrates; i++) {
-		rate[i].bitrate = rt->info[i].rateKbps / 100;
-		rate[i].hw_value = rt->info[i].rateCode;
-		sband->n_bitrates++;
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: Rate: %2dMbps, ratecode: %2d\n",
-			__func__,
-			rate[i].bitrate / 10,
-			rate[i].hw_value);
-	}
-}
-
-/*
- *  Set up channel list
- */
-static int ath_setup_channels(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int nchan, i, a = 0, b = 0;
-	u8 regclassids[ATH_REGCLASSIDS_MAX];
-	u32 nregclass = 0;
-	struct ieee80211_supported_band *band_2ghz;
-	struct ieee80211_supported_band *band_5ghz;
-	struct ieee80211_channel *chan_2ghz;
-	struct ieee80211_channel *chan_5ghz;
-	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)) {
-		u32 rd = ah->ah_currentRD;
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to collect channel list; "
-			"regdomain likely %u country code %u\n",
-			__func__, rd, CTRY_DEFAULT);
-		return -EINVAL;
-	}
-
-	band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
-	band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
-	chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
-	chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
-
-	for (i = 0; i < nchan; i++) {
-		c = &ah->ah_channels[i];
-		if (IS_CHAN_2GHZ(c)) {
-			chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
-			chan_2ghz[a].center_freq = c->channel;
-			chan_2ghz[a].max_power = c->maxTxPower;
-
-			if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
-				chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
-			if (c->channelFlags & CHANNEL_PASSIVE)
-				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);
-		} 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;
-			if (c->channelFlags & CHANNEL_PASSIVE)
-				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);
-		}
-	}
-
-	return 0;
-}
-
-/*
- *  Determine mode from channel flags
- *
- *  This routine will provide the enumerated WIRELESSS_MODE value based
- *  on the settings of the channel flags.  If no valid set of flags
- *  exist, the lowest mode (11b) is selected.
-*/
-
-static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
-{
-	if (chan->chanmode == CHANNEL_A)
-		return ATH9K_MODE_11A;
-	else if (chan->chanmode == CHANNEL_G)
-		return ATH9K_MODE_11G;
-	else if (chan->chanmode == CHANNEL_B)
-		return ATH9K_MODE_11B;
-	else if (chan->chanmode == CHANNEL_A_HT20)
-		return ATH9K_MODE_11NA_HT20;
-	else if (chan->chanmode == CHANNEL_G_HT20)
-		return ATH9K_MODE_11NG_HT20;
-	else if (chan->chanmode == CHANNEL_A_HT40PLUS)
-		return ATH9K_MODE_11NA_HT40PLUS;
-	else if (chan->chanmode == CHANNEL_A_HT40MINUS)
-		return ATH9K_MODE_11NA_HT40MINUS;
-	else if (chan->chanmode == CHANNEL_G_HT40PLUS)
-		return ATH9K_MODE_11NG_HT40PLUS;
-	else if (chan->chanmode == CHANNEL_G_HT40MINUS)
-		return ATH9K_MODE_11NG_HT40MINUS;
-
-	WARN_ON(1); /* should not get here */
-
-	return ATH9K_MODE_11B;
-}
-
-/*
- * Set the current channel
- *
- * Set/change channels.  If the channel is really being changed, it's done
- * by reseting the chip.  To accomplish this we must first cleanup any pending
- * DMA, then restart stuff after a la ath_init.
-*/
-int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	bool fastcc = true, stopped;
-
-	if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */
-		return -EIO;
-
-	DPRINTF(sc, ATH_DBG_CONFIG,
-		"%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n",
-		__func__,
-		ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel,
-				  sc->sc_ah->ah_curchan->channelFlags),
-		sc->sc_ah->ah_curchan->channel,
-		ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags),
-		hchan->channel, hchan->channelFlags);
-
-	if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
-	    hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
-	    (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
-	    (sc->sc_flags & SC_OP_FULL_RESET)) {
-		int status;
-		/*
-		 * This is only performed if the channel settings have
-		 * actually changed.
-		 *
-		 * To switch channels clear any pending DMA operations;
-		 * wait long enough for the RX fifo to drain, reset the
-		 * hardware at the new frequency, and then re-enable
-		 * the relevant bits of the h/w.
-		 */
-		ath9k_hw_set_interrupts(ah, 0);	/* disable interrupts */
-		ath_draintxq(sc, false);	/* clear pending tx frames */
-		stopped = ath_stoprecv(sc);	/* turn off frame recv */
-
-		/* XXX: do not flush receive queue here. We don't want
-		 * to flush data frames already in queue because of
-		 * changing channel. */
-
-		if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
-			fastcc = false;
-
-		spin_lock_bh(&sc->sc_resetlock);
-		if (!ath9k_hw_reset(ah, hchan,
-				    sc->sc_ht_info.tx_chan_width,
-				    sc->sc_tx_chainmask,
-				    sc->sc_rx_chainmask,
-				    sc->sc_ht_extprotspacing,
-				    fastcc, &status)) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: unable to reset channel %u (%uMhz) "
-				"flags 0x%x hal status %u\n", __func__,
-				ath9k_hw_mhz2ieee(ah, hchan->channel,
-						  hchan->channelFlags),
-				hchan->channel, hchan->channelFlags, status);
-			spin_unlock_bh(&sc->sc_resetlock);
-			return -EIO;
-		}
-		spin_unlock_bh(&sc->sc_resetlock);
-
-		sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
-		sc->sc_flags &= ~SC_OP_FULL_RESET;
-
-		/* Re-enable rx framework */
-		if (ath_startrecv(sc) != 0) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: unable to restart recv logic\n", __func__);
-			return -EIO;
-		}
-		/*
-		 * Change channels and update the h/w rate map
-		 * if we're switching; e.g. 11a to 11b/g.
-		 */
-		ath_setcurmode(sc, ath_chan2mode(hchan));
-
-		ath_update_txpow(sc);	/* update tx power state */
-		/*
-		 * Re-enable interrupts.
-		 */
-		ath9k_hw_set_interrupts(ah, sc->sc_imask);
-	}
-	return 0;
-}
-
-/**********************/
-/* Chainmask Handling */
-/**********************/
-
-static void ath_chainmask_sel_timertimeout(unsigned long data)
-{
-	struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data;
-	cm->switch_allowed = 1;
-}
-
-/* Start chainmask select timer */
-static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm)
-{
-	cm->switch_allowed = 0;
-	mod_timer(&cm->timer, ath_chainmask_sel_period);
-}
-
-/* Stop chainmask select timer */
-static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm)
-{
-	cm->switch_allowed = 0;
-	del_timer_sync(&cm->timer);
-}
-
-static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an)
-{
-	struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
-	memset(cm, 0, sizeof(struct ath_chainmask_sel));
-
-	cm->cur_tx_mask = sc->sc_tx_chainmask;
-	cm->cur_rx_mask = sc->sc_rx_chainmask;
-	cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER;
-	setup_timer(&cm->timer,
-		ath_chainmask_sel_timertimeout, (unsigned long) cm);
-}
-
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an)
-{
-	struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
-	/*
-	 * Disable auto-swtiching in one of the following if conditions.
-	 * sc_chainmask_auto_sel is used for internal global auto-switching
-	 * enabled/disabled setting
-	 */
-	if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) {
-		cm->cur_tx_mask = sc->sc_tx_chainmask;
-		return cm->cur_tx_mask;
-	}
-
-	if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER)
-		return cm->cur_tx_mask;
-
-	if (cm->switch_allowed) {
-		/* Switch down from tx 3 to tx 2. */
-		if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 &&
-		    ATH_RSSI_OUT(cm->tx_avgrssi) >=
-		    ath_chainmask_sel_down_rssi_thres) {
-			cm->cur_tx_mask = sc->sc_tx_chainmask;
-
-			/* Don't let another switch happen until
-			 * this timer expires */
-			ath_chainmask_sel_timerstart(cm);
-		}
-		/* Switch up from tx 2 to 3. */
-		else if (cm->cur_tx_mask == sc->sc_tx_chainmask &&
-			 ATH_RSSI_OUT(cm->tx_avgrssi) <=
-			 ath_chainmask_sel_up_rssi_thres) {
-			cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3;
-
-			/* Don't let another switch happen
-			 * until this timer expires */
-			ath_chainmask_sel_timerstart(cm);
-		}
-	}
-
-	return cm->cur_tx_mask;
-}
-
-/*
- * Update tx/rx chainmask. For legacy association,
- * hard code chainmask to 1x1, for 11n association, use
- * the chainmask configuration.
- */
-
-void ath_update_chainmask(struct ath_softc *sc, int is_ht)
-{
-	sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
-	if (is_ht) {
-		sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
-		sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
-	} else {
-		sc->sc_tx_chainmask = 1;
-		sc->sc_rx_chainmask = 1;
-	}
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n",
-		__func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask);
-}
-
-/*******/
-/* ANI */
-/*******/
-
-/*
- *  This routine performs the periodic noise floor calibration function
- *  that is used to adjust and optimize the chip performance.  This
- *  takes environmental changes (location, temperature) into account.
- *  When the task is complete, it reschedules itself depending on the
- *  appropriate interval that was calculated.
- */
-
-static void ath_ani_calibrate(unsigned long data)
-{
-	struct ath_softc *sc;
-	struct ath_hal *ah;
-	bool longcal = false;
-	bool shortcal = false;
-	bool aniflag = false;
-	unsigned int timestamp = jiffies_to_msecs(jiffies);
-	u32 cal_interval;
-
-	sc = (struct ath_softc *)data;
-	ah = sc->sc_ah;
-
-	/*
-	* don't calibrate when we're scanning.
-	* we are most likely not on our home channel.
-	*/
-	if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)
-		return;
-
-	/* Long calibration runs independently of short calibration. */
-	if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
-		longcal = true;
-		DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n",
-			__func__, jiffies);
-		sc->sc_ani.sc_longcal_timer = timestamp;
-	}
-
-	/* Short calibration applies only while sc_caldone is false */
-	if (!sc->sc_ani.sc_caldone) {
-		if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
-		    ATH_SHORT_CALINTERVAL) {
-			shortcal = true;
-			DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n",
-			       __func__, jiffies);
-			sc->sc_ani.sc_shortcal_timer = timestamp;
-			sc->sc_ani.sc_resetcal_timer = timestamp;
-		}
-	} else {
-		if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
-		    ATH_RESTART_CALINTERVAL) {
-			ath9k_hw_reset_calvalid(ah, ah->ah_curchan,
-						&sc->sc_ani.sc_caldone);
-			if (sc->sc_ani.sc_caldone)
-				sc->sc_ani.sc_resetcal_timer = timestamp;
-		}
-	}
-
-	/* Verify whether we must check ANI */
-	if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
-	   ATH_ANI_POLLINTERVAL) {
-		aniflag = true;
-		sc->sc_ani.sc_checkani_timer = timestamp;
-	}
-
-	/* Skip all processing if there's nothing to do. */
-	if (longcal || shortcal || aniflag) {
-		/* Call ANI routine if necessary */
-		if (aniflag)
-			ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
-					     ah->ah_curchan);
-
-		/* Perform calibration if necessary */
-		if (longcal || shortcal) {
-			bool iscaldone = false;
-
-			if (ath9k_hw_calibrate(ah, ah->ah_curchan,
-					       sc->sc_rx_chainmask, longcal,
-					       &iscaldone)) {
-				if (longcal)
-					sc->sc_ani.sc_noise_floor =
-						ath9k_hw_getchan_noise(ah,
-							       ah->ah_curchan);
-
-				DPRINTF(sc, ATH_DBG_ANI,
-					"%s: calibrate chan %u/%x nf: %d\n",
-					 __func__,
-					ah->ah_curchan->channel,
-					ah->ah_curchan->channelFlags,
-					sc->sc_ani.sc_noise_floor);
-			} else {
-				DPRINTF(sc, ATH_DBG_ANY,
-					"%s: calibrate chan %u/%x failed\n",
-					 __func__,
-					ah->ah_curchan->channel,
-					ah->ah_curchan->channelFlags);
-			}
-			sc->sc_ani.sc_caldone = iscaldone;
-		}
-	}
-
-	/*
-	* Set timer interval based on previous results.
-	* The interval must be the shortest necessary to satisfy ANI,
-	* short calibration and long calibration.
-	*/
-
-	cal_interval = ATH_ANI_POLLINTERVAL;
-	if (!sc->sc_ani.sc_caldone)
-		cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
-
-	mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-}
-
-/********/
-/* Core */
-/********/
-
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int status;
-	int error = 0;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
-		__func__, sc->sc_ah->ah_opmode);
-
-	/* Reset SERDES registers */
-	ath9k_hw_configpcipowersave(ah, 0);
-
-	/*
-	 * The basic interface to setting the hardware in a good
-	 * state is ``reset''.  On return the hardware is known to
-	 * be powered up and with interrupts disabled.  This must
-	 * be followed by initialization of the appropriate bits
-	 * and then setup of the interrupt mask.
-	 */
-
-	spin_lock_bh(&sc->sc_resetlock);
-	if (!ath9k_hw_reset(ah, initial_chan,
-			    sc->sc_ht_info.tx_chan_width,
-			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
-			    sc->sc_ht_extprotspacing, false, &status)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to reset hardware; hal status %u "
-			"(freq %u flags 0x%x)\n", __func__, status,
-			initial_chan->channel, initial_chan->channelFlags);
-		error = -EIO;
-		spin_unlock_bh(&sc->sc_resetlock);
-		goto done;
-	}
-	spin_unlock_bh(&sc->sc_resetlock);
-
-	/*
-	 * This is needed only to setup initial state
-	 * but it's best done after a reset.
-	 */
-	ath_update_txpow(sc);
-
-	/*
-	 * Setup the hardware after reset:
-	 * The receive engine is set going.
-	 * Frame transmit is handled entirely
-	 * in the frame output path; there's nothing to do
-	 * here except setup the interrupt mask.
-	 */
-	if (ath_startrecv(sc) != 0) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to start recv logic\n", __func__);
-		error = -EIO;
-		goto done;
-	}
-
-	/* Setup our intr mask. */
-	sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
-		| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
-		| ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
-
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
-		sc->sc_imask |= ATH9K_INT_GTT;
-
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-		sc->sc_imask |= ATH9K_INT_CST;
-
-	/*
-	 * Enable MIB interrupts when there are hardware phy counters.
-	 * Note we only do this (at the moment) for station mode.
-	 */
-	if (ath9k_hw_phycounters(ah) &&
-	    ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
-	     (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)))
-		sc->sc_imask |= ATH9K_INT_MIB;
-	/*
-	 * Some hardware processes the TIM IE and fires an
-	 * interrupt when the TIM bit is set.  For hardware
-	 * that does, if not overridden by configuration,
-	 * enable the TIM interrupt when operating as station.
-	 */
-	if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
-	    (sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
-	    !sc->sc_config.swBeaconProcess)
-		sc->sc_imask |= ATH9K_INT_TIM;
-
-	ath_setcurmode(sc, ath_chan2mode(initial_chan));
-
-	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);
-	ath_draintxq(sc, retry_tx);
-	ath_stoprecv(sc);
-	ath_flushrecv(sc);
-
-	/* Reset chip */
-	spin_lock_bh(&sc->sc_resetlock);
-	if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
-			    sc->sc_ht_info.tx_chan_width,
-			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
-			    sc->sc_ht_extprotspacing, false, &status)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to reset hardware; hal status %u\n",
-			__func__, status);
-		error = -EIO;
-	}
-	spin_unlock_bh(&sc->sc_resetlock);
-
-	if (ath_startrecv(sc) != 0)
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to start recv logic\n", __func__);
-
-	/*
-	 * We may be doing a reset in response to a request
-	 * that changes the channel so update any state that
-	 * might change as a result.
-	 */
-	ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
-
-	ath_update_txpow(sc);
-
-	if (sc->sc_flags & SC_OP_BEACONS)
-		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
-
-	ath9k_hw_set_interrupts(ah, sc->sc_imask);
-
-	/* Restart the txq */
-	if (retry_tx) {
-		int i;
-		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-			if (ATH_TXQ_SETUP(sc, i)) {
-				spin_lock_bh(&sc->sc_txq[i].axq_lock);
-				ath_txq_schedule(sc, &sc->sc_txq[i]);
-				spin_unlock_bh(&sc->sc_txq[i].axq_lock);
-			}
-		}
-	}
-
-	return error;
-}
-
-/* Interrupt handler.  Most of the actual processing is deferred.
- * It's the caller's responsibility to ensure the chip is awake. */
-
-irqreturn_t ath_isr(int irq, void *dev)
-{
-	struct ath_softc *sc = dev;
-	struct ath_hal *ah = sc->sc_ah;
-	enum ath9k_int status;
-	bool sched = false;
-
-	do {
-		if (sc->sc_flags & SC_OP_INVALID) {
-			/*
-			 * The hardware is not ready/present, don't
-			 * touch anything. Note this can happen early
-			 * on if the IRQ is shared.
-			 */
-			return IRQ_NONE;
-		}
-		if (!ath9k_hw_intrpend(ah)) {	/* shared irq, not for us */
-			return IRQ_NONE;
-		}
-
-		/*
-		 * Figure out the reason(s) for the interrupt.  Note
-		 * that the hal returns a pseudo-ISR that may include
-		 * bits we haven't explicitly enabled so we mask the
-		 * value to insure we only process bits we requested.
-		 */
-		ath9k_hw_getisr(ah, &status);	/* NB: clears ISR too */
-
-		status &= sc->sc_imask;	/* discard unasked-for bits */
-
-		/*
-		 * If there are no status bits set, then this interrupt was not
-		 * for me (should have been caught above).
-		 */
-
-		if (!status)
-			return IRQ_NONE;
-
-		sc->sc_intrstatus = status;
-
-		if (status & ATH9K_INT_FATAL) {
-			/* need a chip reset */
-			sched = true;
-		} else if (status & ATH9K_INT_RXORN) {
-			/* need a chip reset */
-			sched = true;
-		} else {
-			if (status & ATH9K_INT_SWBA) {
-				/* schedule a tasklet for beacon handling */
-				tasklet_schedule(&sc->bcon_tasklet);
-			}
-			if (status & ATH9K_INT_RXEOL) {
-				/*
-				 * NB: the hardware should re-read the link when
-				 *     RXE bit is written, but it doesn't work
-				 *     at least on older hardware revs.
-				 */
-				sched = true;
-			}
-
-			if (status & ATH9K_INT_TXURN)
-				/* bump tx trigger level */
-				ath9k_hw_updatetxtriglevel(ah, true);
-			/* XXX: optimize this */
-			if (status & ATH9K_INT_RX)
-				sched = true;
-			if (status & ATH9K_INT_TX)
-				sched = true;
-			if (status & ATH9K_INT_BMISS)
-				sched = true;
-			/* carrier sense timeout */
-			if (status & ATH9K_INT_CST)
-				sched = true;
-			if (status & ATH9K_INT_MIB) {
-				/*
-				 * Disable interrupts until we service the MIB
-				 * interrupt; otherwise it will continue to
-				 * fire.
-				 */
-				ath9k_hw_set_interrupts(ah, 0);
-				/*
-				 * Let the hal handle the event. We assume
-				 * it will clear whatever condition caused
-				 * the interrupt.
-				 */
-				ath9k_hw_procmibevent(ah, &sc->sc_halstats);
-				ath9k_hw_set_interrupts(ah, sc->sc_imask);
-			}
-			if (status & ATH9K_INT_TIM_TIMER) {
-				if (!(ah->ah_caps.hw_caps &
-				      ATH9K_HW_CAP_AUTOSLEEP)) {
-					/* Clear RxAbort bit so that we can
-					 * receive frames */
-					ath9k_hw_setrxabort(ah, 0);
-					sched = true;
-				}
-			}
-		}
-	} while (0);
-
-	if (sched) {
-		/* turn off every interrupt except SWBA */
-		ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
-		tasklet_schedule(&sc->intr_tq);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/* Deferred interrupt processing  */
-
-static void ath9k_tasklet(unsigned long data)
-{
-	struct ath_softc *sc = (struct ath_softc *)data;
-	u32 status = sc->sc_intrstatus;
-
-	if (status & ATH9K_INT_FATAL) {
-		/* need a chip reset */
-		ath_reset(sc, false);
-		return;
-	} else {
-
-		if (status &
-		    (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
-			/* XXX: fill me in */
-			/*
-			if (status & ATH9K_INT_RXORN) {
-			}
-			if (status & ATH9K_INT_RXEOL) {
-			}
-			*/
-			spin_lock_bh(&sc->sc_rxflushlock);
-			ath_rx_tasklet(sc, 0);
-			spin_unlock_bh(&sc->sc_rxflushlock);
-		}
-		/* XXX: optimize this */
-		if (status & ATH9K_INT_TX)
-			ath_tx_tasklet(sc);
-		/* XXX: fill me in */
-		/*
-		if (status & ATH9K_INT_BMISS) {
-		}
-		if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) {
-			if (status & ATH9K_INT_TIM) {
-			}
-			if (status & ATH9K_INT_DTIMSYNC) {
-			}
-		}
-		*/
-	}
-
-	/* re-enable hardware interrupt */
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
-}
-
-int ath_init(u16 devid, struct ath_softc *sc)
-{
-	struct ath_hal *ah = NULL;
-	int status;
-	int error = 0, i;
-	int csz = 0;
-
-	/* XXX: hardware will not be ready until ath_open() being called */
-	sc->sc_flags |= SC_OP_INVALID;
-	sc->sc_debug = DBG_DEFAULT;
-
-	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);
-
-	/*
-	 * Cache line size is used to size and align various
-	 * structures used to communicate with the hardware.
-	 */
-	bus_read_cachesize(sc, &csz);
-	/* XXX assert csz is non-zero */
-	sc->sc_cachelsz = csz << 2;	/* convert to bytes */
-
-	ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
-	if (ah == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to attach hardware; HAL status %u\n",
-			__func__, status);
-		error = -ENXIO;
-		goto bad;
-	}
-	sc->sc_ah = ah;
-
-	/* Get the hardware key cache size. */
-	sc->sc_keymax = ah->ah_caps.keycache_size;
-	if (sc->sc_keymax > ATH_KEYMAX) {
-		DPRINTF(sc, ATH_DBG_KEYCACHE,
-			"%s: Warning, using only %u entries in %u key cache\n",
-			__func__, ATH_KEYMAX, sc->sc_keymax);
-		sc->sc_keymax = ATH_KEYMAX;
-	}
-
-	/*
-	 * Reset the key cache since some parts do not
-	 * reset the contents on initial power up.
-	 */
-	for (i = 0; i < sc->sc_keymax; i++)
-		ath9k_hw_keyreset(ah, (u16) i);
-	/*
-	 * Mark key cache slots associated with global keys
-	 * as in use.  If we knew TKIP was not to be used we
-	 * could leave the +32, +64, and +32+64 slots free.
-	 * XXX only for splitmic.
-	 */
-	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
-		set_bit(i, sc->sc_keymap);
-		set_bit(i + 32, sc->sc_keymap);
-		set_bit(i + 64, sc->sc_keymap);
-		set_bit(i + 32 + 64, sc->sc_keymap);
-	}
-
-	/* Collect the channel list using the default country code */
-
-	error = ath_setup_channels(sc);
-	if (error)
-		goto bad;
-
-	/* default to MONITOR mode */
-	sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
-
-	/* Setup rate tables */
-
-	ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
-	ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
-
-	/* NB: setup here so ath_rate_update is happy */
-	ath_setcurmode(sc, ATH9K_MODE_11A);
-
-	/*
-	 * Allocate hardware transmit queues: one queue for
-	 * beacon frames and one data queue for each QoS
-	 * priority.  Note that the hal handles reseting
-	 * these queues at the needed time.
-	 */
-	sc->sc_bhalq = ath_beaconq_setup(ah);
-	if (sc->sc_bhalq == -1) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup a beacon xmit queue\n", __func__);
-		error = -EIO;
-		goto bad2;
-	}
-	sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
-	if (sc->sc_cabq == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup CAB xmit queue\n", __func__);
-		error = -EIO;
-		goto bad2;
-	}
-
-	sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
-	ath_cabq_update(sc);
-
-	for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++)
-		sc->sc_haltype2q[i] = -1;
-
-	/* Setup data queues */
-	/* NB: ensure BK queue is the lowest priority h/w queue */
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for BK traffic\n",
-			__func__);
-		error = -EIO;
-		goto bad2;
-	}
-
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for BE traffic\n",
-			__func__);
-		error = -EIO;
-		goto bad2;
-	}
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for VI traffic\n",
-			__func__);
-		error = -EIO;
-		goto bad2;
-	}
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for VO traffic\n",
-			__func__);
-		error = -EIO;
-		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);
-	if (sc->sc_rc == NULL) {
-		error = -EIO;
-		goto bad2;
-	}
-
-	if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-				   ATH9K_CIPHER_TKIP, NULL)) {
-		/*
-		 * Whether we should enable h/w TKIP MIC.
-		 * XXX: if we don't support WME TKIP MIC, then we wouldn't
-		 * report WMM capable, so it's always safe to turn on
-		 * TKIP MIC in this case.
-		 */
-		ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
-				       0, 1, NULL);
-	}
-
-	/*
-	 * Check whether the separate key cache entries
-	 * are required to handle both tx+rx MIC keys.
-	 * With split mic keys the number of stations is limited
-	 * to 27 otherwise 59.
-	 */
-	if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-				   ATH9K_CIPHER_TKIP, NULL)
-	    && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-				      ATH9K_CIPHER_MIC, NULL)
-	    && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
-				      0, NULL))
-		sc->sc_splitmic = 1;
-
-	/* turn on mcast key search if possible */
-	if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
-		(void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
-					     1, NULL);
-
-	sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
-	sc->sc_config.txpowlimit_override = 0;
-
-	/* 11n Capabilities */
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
-		sc->sc_flags |= SC_OP_TXAGGR;
-		sc->sc_flags |= SC_OP_RXAGGR;
-	}
-
-	sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
-	sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
-
-	ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
-	sc->sc_defant = ath9k_hw_getdefantenna(ah);
-
-	ath9k_hw_getmac(ah, sc->sc_myaddr);
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
-		ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
-		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 */
-	for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++)
-		sc->sc_bslot[i] = ATH_IF_ID_ANY;
-
-	/* save MISC configurations */
-	sc->sc_config.swBeaconProcess = 1;
-
-#ifdef CONFIG_SLOW_ANT_DIV
-	/* range is 40 - 255, we use something in the middle */
-	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 */
-	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-		if (ATH_TXQ_SETUP(sc, i))
-			ath_tx_cleanupq(sc, &sc->sc_txq[i]);
-bad:
-	if (ah)
-		ath9k_hw_detach(ah);
-
-	return error;
-}
-
-/*******************/
-/* Node Management */
-/*******************/
-
-void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
-{
-	struct ath_node *an;
-
-	an = (struct ath_node *)sta->drv_priv;
-
-	if (sc->sc_flags & SC_OP_TXAGGR)
-		ath_tx_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);
-}
-
-void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
-{
-	struct ath_node *an = (struct ath_node *)sta->drv_priv;
-
-	ath_chainmask_sel_timerstop(&an->an_chainmask_sel);
-
-	if (sc->sc_flags & SC_OP_TXAGGR)
-		ath_tx_node_cleanup(sc, an);
-}
-
-/*
- * Set up New Node
- *
- * Setup driver-specific state for a newly associated node.  This routine
- * really only applies if compression or XR are enabled, there is no code
- * covering any other cases.
-*/
-
-void ath_newassoc(struct ath_softc *sc,
-	struct ath_node *an, int isnew, int isuapsd)
-{
-	int tidno;
-
-	/* if station reassociates, tear down the aggregation state. */
-	if (!isnew) {
-		for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
-			if (sc->sc_flags & SC_OP_TXAGGR)
-				ath_tx_aggr_teardown(sc, an, tidno);
-		}
-	}
-}
-
-/**************/
-/* Encryption */
-/**************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
-{
-	ath9k_hw_keyreset(sc->sc_ah, keyix);
-	if (freeslot)
-		clear_bit(keyix, sc->sc_keymap);
-}
-
-int ath_keyset(struct ath_softc *sc,
-	       u16 keyix,
-	       struct ath9k_keyval *hk,
-	       const u8 mac[ETH_ALEN])
-{
-	bool status;
-
-	status = ath9k_hw_set_keycache_entry(sc->sc_ah,
-		keyix, hk, mac, false);
-
-	return status != false;
-}
-
-/***********************/
-/* TX Power/Regulatory */
-/***********************/
-
-/*
- *  Set Transmit power in HAL
- *
- *  This routine makes the actual HAL calls to set the new transmit power
- *  limit.
-*/
-
-void ath_update_txpow(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	u32 txpow;
-
-	if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
-		ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
-		/* read back in case value is clamped */
-		ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
-		sc->sc_curtxpow = txpow;
-	}
-}
-
-/**************************/
-/* Slow Antenna Diversity */
-/**************************/
-
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
-			   struct ath_softc *sc,
-			   int32_t rssitrig)
-{
-	int trig;
-
-	/* antdivf_rssitrig can range from 40 - 0xff */
-	trig = (rssitrig > 0xff) ? 0xff : rssitrig;
-	trig = (rssitrig < 40) ? 40 : rssitrig;
-
-	antdiv->antdiv_sc = sc;
-	antdiv->antdivf_rssitrig = trig;
-}
-
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
-			    u8 num_antcfg,
-			    const u8 *bssid)
-{
-	antdiv->antdiv_num_antcfg =
-		num_antcfg < ATH_ANT_DIV_MAX_CFG ?
-		num_antcfg : ATH_ANT_DIV_MAX_CFG;
-	antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
-	antdiv->antdiv_curcfg = 0;
-	antdiv->antdiv_bestcfg = 0;
-	antdiv->antdiv_laststatetsf = 0;
-
-	memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid));
-
-	antdiv->antdiv_start = 1;
-}
-
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv)
-{
-	antdiv->antdiv_start = 0;
-}
-
-static int32_t ath_find_max_val(int32_t *val,
-	u8 num_val, u8 *max_index)
-{
-	u32 MaxVal = *val++;
-	u32 cur_index = 0;
-
-	*max_index = 0;
-	while (++cur_index < num_val) {
-		if (*val > MaxVal) {
-			MaxVal = *val;
-			*max_index = cur_index;
-		}
-
-		val++;
-	}
-
-	return MaxVal;
-}
-
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
-		      struct ieee80211_hdr *hdr,
-		      struct ath_rx_status *rx_stats)
-{
-	struct ath_softc *sc = antdiv->antdiv_sc;
-	struct ath_hal *ah = sc->sc_ah;
-	u64 curtsf = 0;
-	u8 bestcfg, curcfg = antdiv->antdiv_curcfg;
-	__le16 fc = hdr->frame_control;
-
-	if (antdiv->antdiv_start && ieee80211_is_beacon(fc)
-	    && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) {
-		antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi;
-		antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah);
-		curtsf = antdiv->antdiv_lastbtsf[curcfg];
-	} else {
-		return;
-	}
-
-	switch (antdiv->antdiv_state) {
-	case ATH_ANT_DIV_IDLE:
-		if ((antdiv->antdiv_lastbrssi[curcfg] <
-		     antdiv->antdivf_rssitrig)
-		    && ((curtsf - antdiv->antdiv_laststatetsf) >
-			ATH_ANT_DIV_MIN_IDLE_US)) {
-
-			curcfg++;
-			if (curcfg == antdiv->antdiv_num_antcfg)
-				curcfg = 0;
-
-			if (!ath9k_hw_select_antconfig(ah, curcfg)) {
-				antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg;
-				antdiv->antdiv_curcfg = curcfg;
-				antdiv->antdiv_laststatetsf = curtsf;
-				antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
-			}
-		}
-		break;
-
-	case ATH_ANT_DIV_SCAN:
-		if ((curtsf - antdiv->antdiv_laststatetsf) <
-		    ATH_ANT_DIV_MIN_SCAN_US)
-			break;
-
-		curcfg++;
-		if (curcfg == antdiv->antdiv_num_antcfg)
-			curcfg = 0;
-
-		if (curcfg == antdiv->antdiv_bestcfg) {
-			ath_find_max_val(antdiv->antdiv_lastbrssi,
-				   antdiv->antdiv_num_antcfg, &bestcfg);
-			if (!ath9k_hw_select_antconfig(ah, bestcfg)) {
-				antdiv->antdiv_bestcfg = bestcfg;
-				antdiv->antdiv_curcfg = bestcfg;
-				antdiv->antdiv_laststatetsf = curtsf;
-				antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
-			}
-		} else {
-			if (!ath9k_hw_select_antconfig(ah, curcfg)) {
-				antdiv->antdiv_curcfg = curcfg;
-				antdiv->antdiv_laststatetsf = curtsf;
-				antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
-			}
-		}
-
-		break;
-	}
-}
-
-/***********************/
-/* Descriptor Handling */
-/***********************/
-
-/*
- *  Set up DMA descriptors
- *
- *  This function will allocate both the DMA descriptor structure, and the
- *  buffers it contains.  These are used to contain the descriptors used
- *  by the system.
-*/
-
-int ath_descdma_setup(struct ath_softc *sc,
-		      struct ath_descdma *dd,
-		      struct list_head *head,
-		      const char *name,
-		      int nbuf,
-		      int ndesc)
-{
-#define	DS2PHYS(_dd, _ds)						\
-	((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
-#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
-#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
-
-	struct ath_desc *ds;
-	struct ath_buf *bf;
-	int i, bsize, error;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n",
-		__func__, name, nbuf, ndesc);
-
-	/* ath_desc must be a multiple of DWORDs */
-	if ((sizeof(struct ath_desc) % 4) != 0) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n",
-			__func__);
-		ASSERT((sizeof(struct ath_desc) % 4) == 0);
-		error = -ENOMEM;
-		goto fail;
-	}
-
-	dd->dd_name = name;
-	dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
-
-	/*
-	 * Need additional DMA memory because we can't use
-	 * descriptors that cross the 4K page boundary. Assume
-	 * one skipped descriptor per 4K page.
-	 */
-	if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
-		u32 ndesc_skipped =
-			ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
-		u32 dma_len;
-
-		while (ndesc_skipped) {
-			dma_len = ndesc_skipped * sizeof(struct ath_desc);
-			dd->dd_desc_len += dma_len;
-
-			ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
-		};
-	}
-
-	/* allocate descriptors */
-	dd->dd_desc = pci_alloc_consistent(sc->pdev,
-			      dd->dd_desc_len,
-			      &dd->dd_desc_paddr);
-	if (dd->dd_desc == NULL) {
-		error = -ENOMEM;
-		goto fail;
-	}
-	ds = dd->dd_desc;
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n",
-		__func__, dd->dd_name, ds, (u32) dd->dd_desc_len,
-		ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
-
-	/* allocate buffers */
-	bsize = sizeof(struct ath_buf) * nbuf;
-	bf = kmalloc(bsize, GFP_KERNEL);
-	if (bf == NULL) {
-		error = -ENOMEM;
-		goto fail2;
-	}
-	memset(bf, 0, bsize);
-	dd->dd_bufptr = bf;
-
-	INIT_LIST_HEAD(head);
-	for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
-		bf->bf_desc = ds;
-		bf->bf_daddr = DS2PHYS(dd, ds);
-
-		if (!(sc->sc_ah->ah_caps.hw_caps &
-		      ATH9K_HW_CAP_4KB_SPLITTRANS)) {
-			/*
-			 * Skip descriptor addresses which can cause 4KB
-			 * boundary crossing (addr + length) with a 32 dword
-			 * descriptor fetch.
-			 */
-			while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
-				ASSERT((caddr_t) bf->bf_desc <
-				       ((caddr_t) dd->dd_desc +
-					dd->dd_desc_len));
-
-				ds += ndesc;
-				bf->bf_desc = ds;
-				bf->bf_daddr = DS2PHYS(dd, ds);
-			}
-		}
-		list_add_tail(&bf->list, head);
-	}
-	return 0;
-fail2:
-	pci_free_consistent(sc->pdev,
-		dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-fail:
-	memset(dd, 0, sizeof(*dd));
-	return error;
-#undef ATH_DESC_4KB_BOUND_CHECK
-#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
-#undef DS2PHYS
-}
-
-/*
- *  Cleanup DMA descriptors
- *
- *  This function will free the DMA block that was allocated for the descriptor
- *  pool.  Since this was allocated as one "chunk", it is freed in the same
- *  manner.
-*/
-
-void ath_descdma_cleanup(struct ath_softc *sc,
-			 struct ath_descdma *dd,
-			 struct list_head *head)
-{
-	/* Free memory associated with descriptors */
-	pci_free_consistent(sc->pdev,
-		dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-
-	INIT_LIST_HEAD(head);
-	kfree(dd->dd_bufptr);
-	memset(dd, 0, sizeof(*dd));
-}
-
-/*************/
-/* Utilities */
-/*************/
-
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
-{
-	int qnum;
-
-	switch (queue) {
-	case 0:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO];
-		break;
-	case 1:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI];
-		break;
-	case 2:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
-		break;
-	case 3:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK];
-		break;
-	default:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
-		break;
-	}
-
-	return qnum;
-}
-
-int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
-{
-	int qnum;
-
-	switch (queue) {
-	case ATH9K_WME_AC_VO:
-		qnum = 0;
-		break;
-	case ATH9K_WME_AC_VI:
-		qnum = 1;
-		break;
-	case ATH9K_WME_AC_BE:
-		qnum = 2;
-		break;
-	case ATH9K_WME_AC_BK:
-		qnum = 3;
-		break;
-	default:
-		qnum = -1;
-		break;
-	}
-
-	return qnum;
-}
-
-
-/*
- *  Expand time stamp to TSF
- *
- *  Extend 15-bit time stamp from rx descriptor to
- *  a full 64-bit TSF using the current h/w TSF.
-*/
-
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
-{
-	u64 tsf;
-
-	tsf = ath9k_hw_gettsf64(sc->sc_ah);
-	if ((tsf & 0x7fff) < rstamp)
-		tsf -= 0x8000;
-	return (tsf & ~0x7fff) | rstamp;
-}
-
-/*
- *  Set Default Antenna
- *
- *  Call into the HAL to set the default antenna to use.  Not really valid for
- *  MIMO technology.
-*/
-
-void ath_setdefantenna(void *context, u32 antenna)
-{
-	struct ath_softc *sc = (struct ath_softc *)context;
-	struct ath_hal *ah = sc->sc_ah;
-
-	/* XXX block beacon interrupts */
-	ath9k_hw_setantenna(ah, antenna);
-	sc->sc_defant = antenna;
-	sc->sc_rxotherant = 0;
-}
-
-/*
- * Set Slot Time
- *
- * This will wake up the chip if required, and set the slot time for the
- * frame (maximum transmit time).  Slot time is assumed to be already set
- * in the ATH object member sc_slottime
-*/
-
-void ath_setslottime(struct ath_softc *sc)
-{
-	ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
-	sc->sc_updateslot = OK;
-}

+ 36 - 244
drivers/net/wireless/ath9k/core.h

@@ -47,10 +47,6 @@
 
 struct ath_node;
 
-/******************/
-/* Utility macros */
-/******************/
-
 /* Macro to expand scalars to 64-bit objects */
 
 #define	ito64(x) (sizeof(x) == 8) ?			\
@@ -86,11 +82,6 @@ struct ath_node;
 
 #define	ATH_TXQ_SETUP(sc, i)        ((sc)->sc_txqsetup & (1<<i))
 
-static inline unsigned long get_timestamp(void)
-{
-	return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
-}
-
 static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 /*************/
@@ -141,34 +132,6 @@ struct ath_config {
 	u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */
 };
 
-/***********************/
-/* Chainmask Selection */
-/***********************/
-
-#define ATH_CHAINMASK_SEL_TIMEOUT	   6000
-/* Default - Number of last RSSI values that is used for
- * chainmask selection */
-#define ATH_CHAINMASK_SEL_RSSI_CNT	   10
-/* Means use 3x3 chainmask instead of configured chainmask */
-#define ATH_CHAINMASK_SEL_3X3		   7
-/* Default - Rssi threshold below which we have to switch to 3x3 */
-#define ATH_CHAINMASK_SEL_UP_RSSI_THRES	   20
-/* Default - Rssi threshold above which we have to switch to
- * user configured values */
-#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES  35
-/* Struct to store the chainmask select related info */
-struct ath_chainmask_sel {
-	struct timer_list timer;
-	int cur_tx_mask; 	/* user configured or 3x3 */
-	int cur_rx_mask; 	/* user configured or 3x3 */
-	int tx_avgrssi;
-	u8 switch_allowed:1, 	/* timer will set this */
-	   cm_sel_enabled : 1;
-};
-
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an);
-void ath_update_chainmask(struct ath_softc *sc, int is_ht);
-
 /*************************/
 /* Descriptor Management */
 /*************************/
@@ -203,7 +166,6 @@ struct ath_buf_state {
 	int bfs_seqno;				/* sequence number */
 	int bfs_tidno;				/* tid of this frame */
 	int bfs_retries;			/* current retries */
-	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;
@@ -241,7 +203,6 @@ struct ath_buf {
 					   an aggregate) */
 	struct ath_buf *bf_lastfrm;	/* last buf of this frame */
 	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 */
 	struct ath_desc *bf_desc;	/* virtual addr of desc */
 	dma_addr_t bf_daddr;		/* physical addr of desc */
@@ -279,80 +240,27 @@ struct ath_descdma {
 	dma_addr_t dd_dmacontext;
 };
 
-/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */
-
-struct ath_rx_context {
-	struct ath_buf *ctx_rxbuf;	/* associated ath_buf for rx */
-};
-#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb)
-
-int ath_descdma_setup(struct ath_softc *sc,
-		      struct ath_descdma *dd,
-		      struct list_head *head,
-		      const char *name,
-		      int nbuf,
-		      int ndesc);
-int ath_desc_alloc(struct ath_softc *sc);
-void ath_desc_free(struct ath_softc *sc);
-void ath_descdma_cleanup(struct ath_softc *sc,
-			 struct ath_descdma *dd,
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+		      struct list_head *head, const char *name,
+		      int nbuf, int ndesc);
+void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 			 struct list_head *head);
 
-/******/
-/* RX */
-/******/
+/***********/
+/* RX / TX */
+/***********/
 
 #define ATH_MAX_ANTENNA          3
 #define ATH_RXBUF                512
 #define WME_NUM_TID              16
 
-/* per frame rx status block */
-struct ath_recv_status {
-	u64 tsf;		/* mac tsf */
-	int8_t rssi;		/* RSSI (noise floor ajusted) */
-	int8_t rssictl[ATH_MAX_ANTENNA];	/* RSSI (noise floor ajusted) */
-	int8_t rssiextn[ATH_MAX_ANTENNA];	/* RSSI (noise floor ajusted) */
-	int8_t abs_rssi;	/* absolute RSSI */
-	u8 rateieee;		/* data rate received (IEEE rate code) */
-	u8 ratecode;		/* phy rate code */
-	int rateKbps;		/* data rate received (Kbps) */
-	int antenna;		/* rx antenna */
-	int flags;		/* status of associated skb */
-#define ATH_RX_FCS_ERROR        0x01
-#define ATH_RX_MIC_ERROR        0x02
-#define ATH_RX_DECRYPT_ERROR    0x04
-#define ATH_RX_RSSI_VALID       0x08
-/* if any of ctl,extn chainrssis are valid */
-#define ATH_RX_CHAIN_RSSI_VALID 0x10
-/* if extn chain rssis are valid */
-#define ATH_RX_RSSI_EXTN_VALID  0x20
-/* set if 40Mhz, clear if 20Mhz */
-#define ATH_RX_40MHZ            0x40
-/* set if short GI, clear if full GI */
-#define ATH_RX_SHORT_GI         0x80
-};
-
-struct ath_rxbuf {
-	struct sk_buff *rx_wbuf;
-	unsigned long rx_time;			/* system time when received */
-	struct ath_recv_status rx_status;	/* cached rx status */
-};
-
 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_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_indicate(struct ath_softc *sc,
-		     struct sk_buff *skb,
-		     struct ath_recv_status *status,
-		     u16 keyix);
-/******/
-/* TX */
-/******/
 
 #define ATH_TXBUF               512
 /* max number of transmit attempts (tries) */
@@ -500,9 +408,6 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
 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);
 void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
 
 /**********************/
@@ -567,25 +472,41 @@ struct ath_node_aggr {
 /* driver-specific node state */
 struct ath_node {
 	struct ath_softc *an_sc;
-	struct ath_chainmask_sel an_chainmask_sel;
 	struct ath_node_aggr an_aggr;
 	u16 maxampdu;
 	u8 mpdudensity;
 };
 
-void ath_tx_resume_tid(struct ath_softc *sc,
-	struct ath_atx_tid *tid);
+void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
 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_tx_aggr_teardown(struct ath_softc *sc,	struct ath_node *an, u8 tidno);
 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);
-void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta);
-void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta);
+
+/********/
+/* VAPs */
+/********/
+
+/*
+ * Define the scheme that we select MAC address for multiple
+ * BSS on the same radio. The very first VAP will just use the MAC
+ * address from the EEPROM. For the next 3 VAPs, we set the
+ * U/L bit (bit 1) in MAC address, and use the next two bits as the
+ * index of the VAP.
+ */
+
+#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
+	((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
+
+/* driver-specific vap state */
+struct ath_vap {
+	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 */
+};
 
 /*******************/
 /* Beacon Handling */
@@ -620,80 +541,8 @@ void ath9k_beacon_tasklet(unsigned long data);
 void ath_beacon_config(struct ath_softc *sc, int if_id);
 int ath_beaconq_setup(struct ath_hal *ah);
 int ath_beacon_alloc(struct ath_softc *sc, int if_id);
-void ath_bstuck_process(struct ath_softc *sc);
 void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
 void ath_beacon_sync(struct ath_softc *sc, int if_id);
-void ath_get_beaconconfig(struct ath_softc *sc,
-			  int if_id,
-			  struct ath_beacon_config *conf);
-/********/
-/* VAPs */
-/********/
-
-/*
- * Define the scheme that we select MAC address for multiple
- * BSS on the same radio. The very first VAP will just use the MAC
- * address from the EEPROM. For the next 3 VAPs, we set the
- * U/L bit (bit 1) in MAC address, and use the next two bits as the
- * index of the VAP.
- */
-
-#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
-	((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
-
-/* VAP configuration (from protocol layer) */
-struct ath_vap_config {
-	u32 av_fixed_rateset;
-	u32 av_fixed_retryset;
-};
-
-/* driver-specific vap state */
-struct ath_vap {
-	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 */
-	struct ath_vap_config av_config;/* vap configuration parameters*/
-	struct ath_rate_node *rc_node;
-};
-
-/*********************/
-/* Antenna diversity */
-/*********************/
-
-#define ATH_ANT_DIV_MAX_CFG      2
-#define ATH_ANT_DIV_MIN_IDLE_US  1000000  /* us */
-#define ATH_ANT_DIV_MIN_SCAN_US  50000	  /* us */
-
-enum ATH_ANT_DIV_STATE{
-	ATH_ANT_DIV_IDLE,
-	ATH_ANT_DIV_SCAN,	/* evaluating antenna */
-};
-
-struct ath_antdiv {
-	struct ath_softc *antdiv_sc;
-	u8 antdiv_start;
-	enum ATH_ANT_DIV_STATE antdiv_state;
-	u8 antdiv_num_antcfg;
-	u8 antdiv_curcfg;
-	u8 antdiv_bestcfg;
-	int32_t antdivf_rssitrig;
-	int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG];
-	u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG];
-	u64 antdiv_laststatetsf;
-	u8 antdiv_bssid[ETH_ALEN];
-};
-
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
-	struct ath_softc *sc, int32_t rssitrig);
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
-			    u8 num_antcfg,
-			    const u8 *bssid);
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv);
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
-		      struct ieee80211_hdr *wh,
-		      struct ath_rx_status *rx_stats);
-void ath_setdefantenna(void *sc, u32 antenna);
 
 /*******/
 /* ANI */
@@ -775,30 +624,8 @@ struct ath_rfkill {
 
 #define ATH_IF_ID_ANY   	0xff
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
-
-#define RSSI_LPF_THRESHOLD         -20
-#define ATH_RSSI_EP_MULTIPLIER     (1<<7)  /* pow2 to optimize out * and / */
-#define ATH_RATE_DUMMY_MARKER      0
-#define ATH_RSSI_LPF_LEN           10
-#define ATH_RSSI_DUMMY_MARKER      0x127
-
-#define ATH_EP_MUL(x, mul)         ((x) * (mul))
-#define ATH_EP_RND(x, mul)						\
-	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-#define ATH_RSSI_OUT(x)							\
-	(((x) != ATH_RSSI_DUMMY_MARKER) ?				\
-	 (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER)
-#define ATH_RSSI_IN(x)					\
-	(ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
-#define ATH_LPF_RSSI(x, y, len)						\
-	((x != ATH_RSSI_DUMMY_MARKER) ? \
-		(((x) * ((len) - 1) + (y)) / (len)) : (y))
-#define ATH_RSSI_LPF(x, y) do {						\
-		if ((y) >= RSSI_LPF_THRESHOLD)				\
-			x = ATH_LPF_RSSI((x), \
-				ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
-	} while (0)
-
+#define ATH_RSSI_DUMMY_MARKER   0x127
+#define ATH_RATE_DUMMY_MARKER   0
 
 enum PROT_MODE {
 	PROT_M_NONE = 0,
@@ -806,17 +633,6 @@ enum PROT_MODE {
 	PROT_M_CTSONLY
 };
 
-enum RATE_TYPE {
-	NORMAL_RATE = 0,
-	HALF_RATE,
-	QUARTER_RATE
-};
-
-struct ath_ht_info {
-	enum ath9k_ht_macmode tx_chan_width;
-	u8 ext_chan_offset;
-};
-
 #define SC_OP_INVALID		BIT(0)
 #define SC_OP_BEACONS		BIT(1)
 #define SC_OP_RXAGGR		BIT(2)
@@ -839,7 +655,6 @@ struct ath_softc {
 	struct tasklet_struct bcon_tasklet;
 	struct ath_config sc_config;
 	struct ath_hal *sc_ah;
-	struct ath_rate_softc *sc_rc;
 	void __iomem *mem;
 
 	u8 sc_curbssid[ETH_ALEN];
@@ -871,8 +686,8 @@ struct ath_softc {
 	u8 sc_rxotherant;		/* rx's on non-default antenna */
 
 	struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
-	struct ath_ht_info sc_ht_info;
 	enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
+	enum ath9k_ht_macmode tx_chan_width;
 
 #ifdef CONFIG_SLOW_ANT_DIV
 	struct ath_antdiv sc_antdiv;
@@ -914,13 +729,8 @@ struct ath_softc {
 
 	/* Rate */
 	struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
-	const struct ath9k_rate_table *sc_currates;
-	u8 sc_rixmap[256];	/* IEEE to h/w rate table ix */
+	struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
 	u8 sc_protrix;		/* protection rate index */
-	struct {
-		u32 rateKbps;	/* transfer rate in kbs */
-		u8 ieeerate;	/* IEEE rate */
-	} sc_hwmap[256];	/* h/w rate ix mappings */
 
 	/* Channel, Band */
 	struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
@@ -945,27 +755,9 @@ struct ath_softc {
 	struct ath_ani sc_ani;
 };
 
-int ath_init(u16 devid, struct ath_softc *sc);
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
-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);
-
-/*********************/
-/* Utility Functions */
-/*********************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot);
-int ath_keyset(struct ath_softc *sc,
-	       u16 keyix,
-	       struct ath9k_keyval *hk,
-	       const u8 mac[ETH_ALEN]);
 int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
 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 *);
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
 
 #endif /* CORE_H */

+ 8 - 3
drivers/net/wireless/ath9k/eeprom.c

@@ -1244,7 +1244,7 @@ bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
 
 	txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
 
-	ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 1, &ant_config);
+	ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config);
 	REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
 
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
@@ -1551,9 +1551,9 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
 
 	switch (param) {
 	case EEP_NFTHRESH_5:
-		return -pModal[0].noiseFloorThreshCh[0];
+		return pModal[0].noiseFloorThreshCh[0];
 	case EEP_NFTHRESH_2:
-		return -pModal[1].noiseFloorThreshCh[0];
+		return pModal[1].noiseFloorThreshCh[0];
 	case AR_EEPROM_MAC(0):
 		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
 	case AR_EEPROM_MAC(1):
@@ -1584,6 +1584,11 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
 		return pBase->txMask;
 	case EEP_RX_MASK:
 		return pBase->rxMask;
+	case EEP_RXGAIN_TYPE:
+		return pBase->rxGainType;
+	case EEP_TXGAIN_TYPE:
+		return pBase->txGainType;
+
 	default:
 		return 0;
 	}

+ 77 - 199
drivers/net/wireless/ath9k/hw.c

@@ -86,10 +86,11 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
 enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
 			       const struct ath9k_channel *chan)
 {
-	if (IS_CHAN_CCK(chan))
-		return ATH9K_MODE_11A;
+	if (IS_CHAN_B(chan))
+		return ATH9K_MODE_11B;
 	if (IS_CHAN_G(chan))
 		return ATH9K_MODE_11G;
+
 	return ATH9K_MODE_11A;
 }
 
@@ -142,27 +143,27 @@ bool ath9k_get_channel_edges(struct ath_hal *ah,
 }
 
 u16 ath9k_hw_computetxtime(struct ath_hal *ah,
-			   const struct ath9k_rate_table *rates,
+			   struct ath_rate_table *rates,
 			   u32 frameLen, u16 rateix,
 			   bool shortPreamble)
 {
 	u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
 	u32 kbps;
 
-	kbps = rates->info[rateix].rateKbps;
+	kbps = rates->info[rateix].ratekbps;
 
 	if (kbps == 0)
 		return 0;
 
 	switch (rates->info[rateix].phy) {
-	case PHY_CCK:
+	case WLAN_RC_PHY_CCK:
 		phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
-		if (shortPreamble && rates->info[rateix].shortPreamble)
+		if (shortPreamble && rates->info[rateix].short_preamble)
 			phyTime >>= 1;
 		numBits = frameLen << 3;
 		txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
 		break;
-	case PHY_OFDM:
+	case WLAN_RC_PHY_OFDM:
 		if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
 			bitsPerSymbol =	(kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
 			numBits = OFDM_PLCP_BITS + (frameLen << 3);
@@ -557,6 +558,54 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah)
 	return 0;
 }
 
+static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah)
+{
+	u32 rxgain_type;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
+		rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE);
+
+		if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
+			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_backoff_13db_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
+		else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
+			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_backoff_23db_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
+		else
+			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_original_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+	} else
+		INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_original_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+}
+
+static void ath9k_hw_init_txgain_ini(struct ath_hal *ah)
+{
+	u32 txgain_type;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
+		txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE);
+
+		if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
+			INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+			ar9280Modes_high_power_tx_gain_9280_2,
+			ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
+		else
+			INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+			ar9280Modes_original_tx_gain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+	} else
+		INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+		ar9280Modes_original_tx_gain_9280_2,
+		ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+}
+
 static int ath9k_hw_post_attach(struct ath_hal *ah)
 {
 	int ecode;
@@ -800,6 +849,14 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 	if (ecode != 0)
 		goto bad;
 
+	/* rxgain table */
+	if (AR_SREV_9280_20_OR_LATER(ah))
+		ath9k_hw_init_rxgain_ini(ah);
+
+	/* txgain table */
+	if (AR_SREV_9280_20_OR_LATER(ah))
+		ath9k_hw_init_txgain_ini(ah);
+
 #ifndef CONFIG_SLOW_ANT_DIV
 	if (ah->ah_devid == AR9280_DEVID_PCI) {
 		for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
@@ -853,7 +910,7 @@ static void ath9k_hw_init_bb(struct ath_hal *ah,
 	u32 synthDelay;
 
 	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
-	if (IS_CHAN_CCK(chan))
+	if (IS_CHAN_B(chan))
 		synthDelay = (4 * synthDelay) / 22;
 	else
 		synthDelay /= 10;
@@ -1258,6 +1315,12 @@ static int ath9k_hw_process_ini(struct ath_hal *ah,
 		DO_DELAY(regWrites);
 	}
 
+	if (AR_SREV_9280_20_OR_LATER(ah))
+		REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites);
+
+	if (AR_SREV_9280_20_OR_LATER(ah))
+		REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites);
+
 	for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
 		u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
 		u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
@@ -1585,7 +1648,7 @@ static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
 	}
 
 	if (!IS_CHAN_OFDM(chan) &&
-	    !IS_CHAN_CCK(chan) &&
+	    !IS_CHAN_B(chan) &&
 	    !IS_CHAN_HT20(chan) &&
 	    !IS_CHAN_HT40(chan)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
@@ -1649,7 +1712,7 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah,
 	}
 
 	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
-	if (IS_CHAN_CCK(chan))
+	if (IS_CHAN_B(chan))
 		synthDelay = (4 * synthDelay) / 22;
 	else
 		synthDelay /= 10;
@@ -2169,8 +2232,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 	    ((chan->channelFlags & CHANNEL_ALL) ==
 	     (ah->ah_curchan->channelFlags & CHANNEL_ALL)) &&
 	    (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
-				   !IS_CHAN_A_5MHZ_SPACED(ah->
-							  ah_curchan)))) {
+				   !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) {
 
 		if (ath9k_hw_channel_change(ah, chan, macmode)) {
 			ath9k_hw_loadnf(ah, ah->ah_curchan);
@@ -2278,7 +2340,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 	ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
 	ath9k_hw_init_qos(ah);
 
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		ath9k_enable_rfkill(ah);
 #endif
@@ -3128,190 +3190,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
 
 }
 
-/***************/
-/* Rate tables */
-/***************/
-
-static struct ath9k_rate_table ar5416_11a_table = {
-	8,
-	{0},
-	{
-		{true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
-		{true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}
-	},
-};
-
-static struct ath9k_rate_table ar5416_11b_table = {
-	4,
-	{0},
-	{
-		{true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-		{true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-		{true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1},
-		{true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1}
-	},
-};
-
-static struct ath9k_rate_table ar5416_11g_table = {
-	12,
-	{0},
-	{
-		{true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-		{true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-		{true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
-		{true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
-		{false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
-		{false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}
-	},
-};
-
-static struct ath9k_rate_table ar5416_11ng_table = {
-	28,
-	{0},
-	{
-		{true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-		{true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-		{true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
-		{true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
-		{false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
-		{false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8},
-		{true, PHY_HT, 6500, 0x80, 0x00, 0, 4},
-		{true, PHY_HT, 13000, 0x81, 0x00, 1, 6},
-		{true, PHY_HT, 19500, 0x82, 0x00, 2, 6},
-		{true, PHY_HT, 26000, 0x83, 0x00, 3, 8},
-		{true, PHY_HT, 39000, 0x84, 0x00, 4, 8},
-		{true, PHY_HT, 52000, 0x85, 0x00, 5, 8},
-		{true, PHY_HT, 58500, 0x86, 0x00, 6, 8},
-		{true, PHY_HT, 65000, 0x87, 0x00, 7, 8},
-		{true, PHY_HT, 13000, 0x88, 0x00, 8, 4},
-		{true, PHY_HT, 26000, 0x89, 0x00, 9, 6},
-		{true, PHY_HT, 39000, 0x8a, 0x00, 10, 6},
-		{true, PHY_HT, 52000, 0x8b, 0x00, 11, 8},
-		{true, PHY_HT, 78000, 0x8c, 0x00, 12, 8},
-		{true, PHY_HT, 104000, 0x8d, 0x00, 13, 8},
-		{true, PHY_HT, 117000, 0x8e, 0x00, 14, 8},
-		{true, PHY_HT, 130000, 0x8f, 0x00, 15, 8},
-	},
-};
-
-static struct ath9k_rate_table ar5416_11na_table = {
-	24,
-	{0},
-	{
-		{true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
-		{true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4},
-		{true, PHY_HT, 6500, 0x80, 0x00, 0, 0},
-		{true, PHY_HT, 13000, 0x81, 0x00, 1, 2},
-		{true, PHY_HT, 19500, 0x82, 0x00, 2, 2},
-		{true, PHY_HT, 26000, 0x83, 0x00, 3, 4},
-		{true, PHY_HT, 39000, 0x84, 0x00, 4, 4},
-		{true, PHY_HT, 52000, 0x85, 0x00, 5, 4},
-		{true, PHY_HT, 58500, 0x86, 0x00, 6, 4},
-		{true, PHY_HT, 65000, 0x87, 0x00, 7, 4},
-		{true, PHY_HT, 13000, 0x88, 0x00, 8, 0},
-		{true, PHY_HT, 26000, 0x89, 0x00, 9, 2},
-		{true, PHY_HT, 39000, 0x8a, 0x00, 10, 2},
-		{true, PHY_HT, 52000, 0x8b, 0x00, 11, 4},
-		{true, PHY_HT, 78000, 0x8c, 0x00, 12, 4},
-		{true, PHY_HT, 104000, 0x8d, 0x00, 13, 4},
-		{true, PHY_HT, 117000, 0x8e, 0x00, 14, 4},
-		{true, PHY_HT, 130000, 0x8f, 0x00, 15, 4},
-	},
-};
-
-static void ath9k_hw_setup_rate_table(struct ath_hal *ah,
-				      struct ath9k_rate_table *rt)
-{
-	int i;
-
-	if (rt->rateCodeToIndex[0] != 0)
-		return;
-
-	for (i = 0; i < 256; i++)
-		rt->rateCodeToIndex[i] = (u8) -1;
-
-	for (i = 0; i < rt->rateCount; i++) {
-		u8 code = rt->info[i].rateCode;
-		u8 cix = rt->info[i].controlRate;
-
-		rt->rateCodeToIndex[code] = i;
-		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
-
-		rt->info[i].lpAckDuration =
-			ath9k_hw_computetxtime(ah, rt,
-					       WLAN_CTRL_FRAME_SIZE,
-					       cix,
-					       false);
-		rt->info[i].spAckDuration =
-			ath9k_hw_computetxtime(ah, rt,
-					       WLAN_CTRL_FRAME_SIZE,
-					       cix,
-					       true);
-	}
-}
-
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
-						     u32 mode)
-{
-	struct ath9k_rate_table *rt;
-
-	switch (mode) {
-	case ATH9K_MODE_11A:
-		rt = &ar5416_11a_table;
-		break;
-	case ATH9K_MODE_11B:
-		rt = &ar5416_11b_table;
-		break;
-	case ATH9K_MODE_11G:
-		rt = &ar5416_11g_table;
-		break;
-	case ATH9K_MODE_11NG_HT20:
-	case ATH9K_MODE_11NG_HT40PLUS:
-	case ATH9K_MODE_11NG_HT40MINUS:
-		rt = &ar5416_11ng_table;
-		break;
-	case ATH9K_MODE_11NA_HT20:
-	case ATH9K_MODE_11NA_HT40PLUS:
-	case ATH9K_MODE_11NA_HT40MINUS:
-		rt = &ar5416_11na_table;
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n",
-			__func__, mode);
-		return NULL;
-	}
-
-	ath9k_hw_setup_rate_table(ah, rt);
-
-	return rt;
-}
-
 /*******************/
 /* HW Capabilities */
 /*******************/
@@ -3453,7 +3331,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
 
 	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
 
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT);
 	if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
 		ah->ah_rfkill_gpio =
@@ -3710,7 +3588,7 @@ void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
 		AR_GPIO_BIT(gpio));
 }
 
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 void ath9k_enable_rfkill(struct ath_hal *ah)
 {
 	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,

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

@@ -415,6 +415,9 @@ struct ar5416Stats {
 #define AR5416_EEP_MINOR_VER_3       0x3
 #define AR5416_EEP_MINOR_VER_7       0x7
 #define AR5416_EEP_MINOR_VER_9       0x9
+#define AR5416_EEP_MINOR_VER_16      0x10
+#define AR5416_EEP_MINOR_VER_17      0x11
+#define AR5416_EEP_MINOR_VER_19      0x13
 
 #define AR5416_NUM_5G_CAL_PIERS         8
 #define AR5416_NUM_2G_CAL_PIERS         4
@@ -436,6 +439,16 @@ struct ar5416Stats {
 #define AR5416_MAX_CHAINS               3
 #define AR5416_PWR_TABLE_OFFSET         -5
 
+/* Rx gain type values */
+#define AR5416_EEP_RXGAIN_23DB_BACKOFF     0
+#define AR5416_EEP_RXGAIN_13DB_BACKOFF     1
+#define AR5416_EEP_RXGAIN_ORIG             2
+
+/* Tx gain type values */
+#define AR5416_EEP_TXGAIN_ORIGINAL         0
+#define AR5416_EEP_TXGAIN_HIGH_POWER       1
+
+
 enum eeprom_param {
 	EEP_NFTHRESH_5,
 	EEP_NFTHRESH_2,
@@ -454,6 +467,8 @@ enum eeprom_param {
 	EEP_MINOR_REV,
 	EEP_TX_MASK,
 	EEP_RX_MASK,
+	EEP_RXGAIN_TYPE,
+	EEP_TXGAIN_TYPE,
 };
 
 enum ar5416_rates {
@@ -485,7 +500,11 @@ struct base_eep_header {
 	u32 binBuildNumber;
 	u8 deviceType;
 	u8 pwdclkind;
-	u8 futureBase[32];
+	u8 futureBase_1[2];
+	u8 rxGainType;
+	u8 futureBase_2[3];
+	u8 txGainType;
+	u8 futureBase_3[25];
 } __packed;
 
 struct spur_chan {
@@ -792,6 +811,8 @@ struct ath_hal_5416 {
 	struct ar5416IniArray ah_iniAddac;
 	struct ar5416IniArray ah_iniPcieSerdes;
 	struct ar5416IniArray ah_iniModesAdditional;
+	struct ar5416IniArray ah_iniModesRxGain;
+	struct ar5416IniArray ah_iniModesTxGain;
 };
 #define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
 

+ 497 - 204
drivers/net/wireless/ath9k/initvals.h

@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+/* AR5416 to Fowl ar5146.ini */
 static const u32 ar5416Modes_9100[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -31,17 +32,17 @@ static const u32 ar5416Modes_9100[][6] = {
     { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de },
+    { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de },
     { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
     { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
     { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
     { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
     { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
     { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
     { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
-    { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
     { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
     { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
     { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
@@ -207,7 +208,7 @@ static const u32 ar5416Common_9100[][2] = {
     { 0x00008134, 0x00000000 },
     { 0x00008138, 0x00000000 },
     { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0x00000000 },
+    { 0x00008144, 0xffffffff },
     { 0x00008168, 0x00000000 },
     { 0x0000816c, 0x00000000 },
     { 0x00008170, 0x32143320 },
@@ -266,7 +267,7 @@ static const u32 ar5416Common_9100[][2] = {
     { 0x0000832c, 0x00000007 },
     { 0x00008330, 0x00000302 },
     { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
+    { 0x00008338, 0x00070000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x000107ff },
     { 0x00009808, 0x00000000 },
@@ -661,6 +662,7 @@ static const u32 ar5416Addac_9100[][2] = {
     {0x000098c4,  0x00000000 },
 };
 
+/* ar5416 - howl ar5416_howl.ini */
 static const u32 ar5416Modes[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -952,7 +954,7 @@ static const u32 ar5416Common[][2] = {
     { 0x0000994c, 0x00020028 },
     { 0x0000c95c, 0x004b6a8e },
     { 0x0000c968, 0x000003ce },
-    { 0x00009970, 0x190fb514 },
+    { 0x00009970, 0x190fb515 },
     { 0x00009974, 0x00000000 },
     { 0x00009978, 0x00000001 },
     { 0x0000997c, 0x00000000 },
@@ -1311,7 +1313,7 @@ static const u32 ar5416Addac[][2] = {
     {0x000098cc, 0x00000000 },
 };
 
-
+/* AR5416 9160 Sowl ar5416_sowl.ini */
 static const u32 ar5416Modes_9160[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -1329,21 +1331,22 @@ static const u32 ar5416Modes_9160[][6] = {
     { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
+    { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
     { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
     { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
     { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
     { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
     { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
     { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
     { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
     { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
     { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
     { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
     { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+    { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
     { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
     { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
     { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
@@ -1505,7 +1508,7 @@ static const u32 ar5416Common_9160[][2] = {
     { 0x00008134, 0x00000000 },
     { 0x00008138, 0x00000000 },
     { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0x00000000 },
+    { 0x00008144, 0xffffffff },
     { 0x00008168, 0x00000000 },
     { 0x0000816c, 0x00000000 },
     { 0x00008170, 0x32143320 },
@@ -1564,7 +1567,7 @@ static const u32 ar5416Common_9160[][2] = {
     { 0x0000832c, 0x00000007 },
     { 0x00008330, 0x00000302 },
     { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
+    { 0x00008338, 0x00ff0000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x000107ff },
     { 0x00009808, 0x00000000 },
@@ -1597,7 +1600,6 @@ static const u32 ar5416Common_9160[][2] = {
     { 0x00009958, 0x2108ecff },
     { 0x00009940, 0x00750604 },
     { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
     { 0x00009970, 0x190fb515 },
     { 0x00009974, 0x00000000 },
     { 0x00009978, 0x00000001 },
@@ -1699,7 +1701,7 @@ static const u32 ar5416Common_9160[][2] = {
     { 0x0000a244, 0x00007bb6 },
     { 0x0000a248, 0x0fff3ffc },
     { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000a000 },
+    { 0x0000a250, 0x0000e000 },
     { 0x0000a254, 0x00000000 },
     { 0x0000a258, 0x0cc75380 },
     { 0x0000a25c, 0x0f0f0f01 },
@@ -1719,7 +1721,7 @@ static const u32 ar5416Common_9160[][2] = {
     { 0x0000a34c, 0x3fffffff },
     { 0x0000a350, 0x3fffffff },
     { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79a8aa33 },
+    { 0x0000a358, 0x79bfaa03 },
     { 0x0000d35c, 0x07ffffef },
     { 0x0000d360, 0x0fffffe7 },
     { 0x0000d364, 0x17ffffe5 },
@@ -1842,7 +1844,6 @@ static const u32 ar5416Bank3_9160[][3] = {
 };
 
 static const u32 ar5416Bank6_9160[][3] = {
-
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
@@ -1920,7 +1921,6 @@ static const u32 ar5416Bank7_9160[][2] = {
     { 0x000098cc, 0x0000000e },
 };
 
-
 static u32 ar5416Addac_9160[][2] = {
     {0x0000989c,  0x00000000 },
     {0x0000989c,  0x00000000 },
@@ -1956,7 +1956,6 @@ static u32 ar5416Addac_9160[][2] = {
     {0x000098cc,  0x00000000 },
 };
 
-
 static u32 ar5416Addac_91601_1[][2] = {
     {0x0000989c,  0x00000000 },
     {0x0000989c,  0x00000000 },
@@ -1992,8 +1991,7 @@ static u32 ar5416Addac_91601_1[][2] = {
     {0x000098cc,  0x00000000 },
 };
 
-
-
+/* XXX 9280 1 */
 static const u32 ar9280Modes_9280[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2543,9 +2541,7 @@ static const u32 ar9280Common_9280[][2] = {
     { 0x00007898, 0x2a850160 },
 };
 
-
-
-
+/* XXX 9280 2 */
 static const u32 ar9280Modes_9280_2[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2560,26 +2556,24 @@ static const u32 ar9280Modes_9280_2[][6] = {
     { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
     { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
     { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e },
+    { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
     { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
-    { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
-    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
-    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+    { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+    { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e },
     { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
-    { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+    { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
     { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
     { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
     { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
+    { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+    { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
     { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
     { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
     { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
-    { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c },
-    { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
+    { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
     { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
     { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
     { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
@@ -2587,164 +2581,13 @@ static const u32 ar9280Modes_9280_2[][6] = {
     { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
     { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
-    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
-    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
-    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
-    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
-    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
-    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
-    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
-    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
-    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
-    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
-    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
-    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
-    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
-    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
-    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
-    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
-    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
-    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
-    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
-    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
-    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
-    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
-    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
-    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
-    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
-    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
-    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
-    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
-    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
-    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
-    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
-    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
-    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
-    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
-    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
-    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
-    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
-    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
-    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
-    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
-    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
-    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
-    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
-    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
-    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
-    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
-    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
-    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
-    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
-    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
-    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
-    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
-    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
-    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
-    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
-    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
-    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
-    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
-    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
-    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
-    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
-    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
-    { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
-    { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
-    { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
-    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
-    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
-    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
-    { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
-    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
-    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
-    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
-    { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
-    { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
-    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
-    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
-    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
-    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
-    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
-    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
-    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
-    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
-    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
-    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
-    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
-    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
-    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
-    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
-    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
-    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
-    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
-    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
-    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
-    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
-    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
-    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
-    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
-    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
-    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
     { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
-    { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
     { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
     { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
-    { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a },
+    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
     { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 },
+    { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
     { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
-    { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
-    { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
-    { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
-    { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
-    { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
-    { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
-    { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
-    { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
-    { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
-    { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
-    { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
-    { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
-    { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
-    { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
-    { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
-    { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
-    { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
-    { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
-    { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
-    { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
     { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
     { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
@@ -2884,7 +2727,7 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x00008134, 0x00000000 },
     { 0x00008138, 0x00000000 },
     { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0x00000000 },
+    { 0x00008144, 0xffffffff },
     { 0x00008168, 0x00000000 },
     { 0x0000816c, 0x00000000 },
     { 0x00008170, 0x32143320 },
@@ -2923,6 +2766,7 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
+    { 0x00008264, 0xa8a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -2939,7 +2783,7 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x0000832c, 0x00000007 },
     { 0x00008330, 0x00000302 },
     { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
+    { 0x00008338, 0x00ff0000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x000107ff },
     { 0x00008344, 0x00581043 },
@@ -2973,7 +2817,7 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x00009958, 0x2108ecff },
     { 0x00009940, 0x14750604 },
     { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
+    { 0x00009968, 0x000003ce },
     { 0x00009970, 0x190fb515 },
     { 0x00009974, 0x00000000 },
     { 0x00009978, 0x00000001 },
@@ -2999,13 +2843,14 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x000099ec, 0x0cc80caa },
     { 0x000099f0, 0x00000000 },
     { 0x000099fc, 0x00001042 },
+    { 0x0000a208, 0x803e4788 },
     { 0x0000a210, 0x4080a333 },
     { 0x0000a214, 0x40206c10 },
     { 0x0000a218, 0x009c4060 },
     { 0x0000a220, 0x01834061 },
     { 0x0000a224, 0x00000400 },
     { 0x0000a228, 0x000003b5 },
-    { 0x0000a22c, 0x233f71c0 },
+    { 0x0000a22c, 0x233f7180 },
     { 0x0000a234, 0x20202020 },
     { 0x0000a238, 0x20202020 },
     { 0x0000a23c, 0x13c88000 },
@@ -3022,7 +2867,6 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x0000b26c, 0x0ebae9c6 },
     { 0x0000d270, 0x00820820 },
     { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
     { 0x0000d35c, 0x07ffffef },
     { 0x0000d360, 0x0fffffe7 },
     { 0x0000d364, 0x17ffffe5 },
@@ -3064,7 +2908,6 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x00007808, 0x04924914 },
     { 0x0000780c, 0x21084210 },
     { 0x00007810, 0x6d801300 },
-    { 0x00007814, 0x0019beff },
     { 0x00007818, 0x07e41000 },
     { 0x0000781c, 0x00392000 },
     { 0x00007820, 0x92592480 },
@@ -3073,7 +2916,6 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x0000782c, 0x04924914 },
     { 0x00007830, 0x21084210 },
     { 0x00007834, 0x6d801300 },
-    { 0x00007838, 0x0019beff },
     { 0x0000783c, 0x07e40000 },
     { 0x00007840, 0x00392000 },
     { 0x00007844, 0x92592480 },
@@ -3110,12 +2952,465 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
     { 0x00009828, 0x0b020001, 0x0b020001 },
     { 0x00009834, 0x00000f0f, 0x00000f0f },
     { 0x00009844, 0x03721821, 0x03721821 },
-    { 0x00009914, 0x00000898, 0x00000898 },
+    { 0x00009914, 0x00000898, 0x00001130 },
     { 0x00009918, 0x0000000b, 0x00000016 },
     { 0x00009944, 0xdfbc1210, 0xdfbc1210 },
 };
 
+static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = {
+    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 },
+    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 },
+    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 },
+    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 },
+    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 },
+    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d },
+    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 },
+    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 },
+    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 },
+    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 },
+    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a },
+    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e },
+    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 },
+    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 },
+    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 },
+    { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 },
+    { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b },
+    { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f },
+    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 },
+    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 },
+    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 },
+    { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 },
+    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b },
+    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f },
+    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 },
+    { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 },
+    { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 },
+    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 },
+    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b },
+    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f },
+    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 },
+    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 },
+    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+    { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+};
+
+static const u32 ar9280Modes_original_rxgain_9280_2[][6] = {
+    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
+    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
+    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
+    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
+    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
+    { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
+    { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
+    { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
+    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
+    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
+    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
+    { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
+    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
+    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
+    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
+    { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
+    { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
+    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
+    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
+    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
+    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
+    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
+    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
+    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
+    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
+    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
+    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
+    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
+    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
+    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
+    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
+    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
+    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
+    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
+    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
+    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
+    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
+    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
+    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
+    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
+    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
+    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+    { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+};
 
+static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
+    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 },
+    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 },
+    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 },
+    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 },
+    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 },
+    { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c },
+    { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 },
+    { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 },
+    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 },
+    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 },
+    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 },
+    { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d },
+    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 },
+    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 },
+    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 },
+    { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 },
+    { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a },
+    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e },
+    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 },
+    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 },
+    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 },
+    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 },
+    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b },
+    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f },
+    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 },
+    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 },
+    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 },
+    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 },
+    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b },
+    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f },
+    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 },
+    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 },
+    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+    { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+};
+
+static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 },
+    { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 },
+    { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 },
+    { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 },
+    { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 },
+    { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a },
+    { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 },
+    { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+    { 0x0000a324, 0x00020092, 0x00020092, 0x00022411, 0x00022411, 0x00022411 },
+    { 0x0000a328, 0x0002410a, 0x0002410a, 0x00025413, 0x00025413, 0x00025413 },
+    { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00029811, 0x00029811, 0x00029811 },
+    { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002c813, 0x0002c813, 0x0002c813 },
+    { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030a14, 0x00030a14, 0x00030a14 },
+    { 0x0000a338, 0x000321ec, 0x000321ec, 0x00035a50, 0x00035a50, 0x00035a50 },
+    { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00039c4c, 0x00039c4c, 0x00039c4c },
+    { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003de8a, 0x0003de8a, 0x0003de8a },
+    { 0x0000a344, 0x000321ec, 0x000321ec, 0x00042e92, 0x00042e92, 0x00042e92 },
+    { 0x0000a348, 0x000321ec, 0x000321ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 },
+    { 0x0000a34c, 0x000321ec, 0x000321ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 },
+    { 0x0000a350, 0x000321ec, 0x000321ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 },
+    { 0x0000a354, 0x000321ec, 0x000321ec, 0x00053fd5, 0x00053fd5, 0x00053fd5 },
+    { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+    { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+    { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
+};
+
+static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
+    { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
+    { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
+    { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
+    { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
+    { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
+    { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
+    { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+    { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
+    { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
+    { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
+    { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
+    { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
+    { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
+    { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
+    { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
+    { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
+    { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
+    { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
+    { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
+    { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
+    { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+    { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+    { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
+};
 
 static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
     {0x00004040,  0x9248fd00 },
@@ -3123,23 +3418,21 @@ static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
     {0x00004040,  0xa8000019 },
     {0x00004040,  0x13160820 },
     {0x00004040,  0xe5980560 },
-    {0x00004040,  0x401dcffc },
-    {0x00004040,  0x1aaabe40 },
+    {0x00004040,  0xc01dcffc },
+    {0x00004040,  0x1aaabe41 },
     {0x00004040,  0xbe105554 },
     {0x00004040,  0x00043007 },
     {0x00004044,  0x00000000 },
 };
 
-
-
 static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
     {0x00004040,  0x13160820 },
     {0x00004040,  0xe5980560 },
-    {0x00004040,  0x401dcffd },
-    {0x00004040,  0x1aaabe40 },
+    {0x00004040,  0xc01dcffd },
+    {0x00004040,  0x1aaabe41 },
     {0x00004040,  0xbe105554 },
     {0x00004040,  0x00043007 },
     {0x00004044,  0x00000000 },

+ 3 - 1
drivers/net/wireless/ath9k/mac.c

@@ -293,8 +293,10 @@ int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
 		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)
+	if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
 		ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+		ath9k_hw_updatetxtriglevel(ah, true);
+	}
 	if (ads->ds_txstatus9 & AR_TxOpExceeded)
 		ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
 	if (ads->ds_txstatus1 & AR_TxTimerExpired)

File diff suppressed because it is too large
+ 908 - 231
drivers/net/wireless/ath9k/main.c


File diff suppressed because it is too large
+ 205 - 442
drivers/net/wireless/ath9k/rc.c


+ 48 - 171
drivers/net/wireless/ath9k/rc.h

@@ -20,83 +20,24 @@
 #define RC_H
 
 #include "ath9k.h"
-/*
- * Interface definitions for transmit rate control modules for the
- * Atheros driver.
- *
- * A rate control module is responsible for choosing the transmit rate
- * for each data frame.  Management+control frames are always sent at
- * a fixed rate.
- *
- * Only one module may be present at a time; the driver references
- * rate control interfaces by symbol name.  If multiple modules are
- * to be supported we'll need to switch to a registration-based scheme
- * as is currently done, for example, for authentication modules.
- *
- * An instance of the rate control module is attached to each device
- * at attach time and detached when the device is destroyed.  The module
- * may associate data with each device and each node (station).  Both
- * sets of storage are opaque except for the size of the per-node storage
- * which must be provided when the module is attached.
- *
- * The rate control module is notified for each state transition and
- * station association/reassociation.  Otherwise it is queried for a
- * rate for each outgoing frame and provided status from each transmitted
- * frame.  Any ancillary processing is the responsibility of the module
- * (e.g. if periodic processing is required then the module should setup
- * it's own timer).
- *
- * In addition to the transmit rate for each frame the module must also
- * indicate the number of attempts to make at the specified rate.  If this
- * number is != ATH_TXMAXTRY then an additional callback is made to setup
- * additional transmit state.  The rate control code is assumed to write
- * this additional data directly to the transmit descriptor.
- */
 
 struct ath_softc;
 
-#define TRUE 1
-#define FALSE 0
+#define ATH_RATE_MAX     30
+#define RATE_TABLE_SIZE  64
+#define MAX_TX_RATE_PHY  48
 
-#define ATH_RATE_MAX	30
+/* VALID_ALL - valid for 20/40/Legacy,
+ * VALID - Legacy only,
+ * VALID_20 - HT 20 only,
+ * VALID_40 - HT 40 only */
 
-enum ieee80211_fixed_rate_mode {
-	IEEE80211_FIXED_RATE_NONE  = 0,
-	IEEE80211_FIXED_RATE_MCS   = 1  /* HT rates */
-};
-
-/*
- * Use the hal os glue code to get ms time
- */
-#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
-
-#define WLAN_PHY_HT_20_SS       WLAN_RC_PHY_HT_20_SS
-#define WLAN_PHY_HT_20_DS       WLAN_RC_PHY_HT_20_DS
-#define WLAN_PHY_HT_20_DS_HGI   WLAN_RC_PHY_HT_20_DS_HGI
-#define WLAN_PHY_HT_40_SS       WLAN_RC_PHY_HT_40_SS
-#define WLAN_PHY_HT_40_SS_HGI   WLAN_RC_PHY_HT_40_SS_HGI
-#define WLAN_PHY_HT_40_DS       WLAN_RC_PHY_HT_40_DS
-#define WLAN_PHY_HT_40_DS_HGI   WLAN_RC_PHY_HT_40_DS_HGI
-
-#define WLAN_PHY_OFDM	PHY_OFDM
-#define WLAN_PHY_CCK	PHY_CCK
-
-#define TRUE_20		0x2
-#define TRUE_40		0x4
-#define TRUE_2040	(TRUE_20|TRUE_40)
-#define TRUE_ALL	(TRUE_2040|TRUE)
-
-enum {
-	WLAN_RC_PHY_HT_20_SS = 4,
-	WLAN_RC_PHY_HT_20_DS,
-	WLAN_RC_PHY_HT_40_SS,
-	WLAN_RC_PHY_HT_40_DS,
-	WLAN_RC_PHY_HT_20_SS_HGI,
-	WLAN_RC_PHY_HT_20_DS_HGI,
-	WLAN_RC_PHY_HT_40_SS_HGI,
-	WLAN_RC_PHY_HT_40_DS_HGI,
-	WLAN_RC_PHY_MAX
-};
+#define INVALID    0x0
+#define VALID      0x1
+#define VALID_20   0x2
+#define VALID_40   0x4
+#define VALID_2040 (VALID_20|VALID_40)
+#define VALID_ALL  (VALID_2040|VALID)
 
 #define WLAN_RC_PHY_DS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_DS)		\
 				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\
@@ -113,26 +54,22 @@ enum {
 
 #define WLAN_RC_PHY_HT(_phy)    (_phy >= WLAN_RC_PHY_HT_20_SS)
 
-/* Returns the capflag mode */
 #define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ?	\
-		(capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE))
+		(capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID))
 
 /* Return TRUE if flag supports HT20 && client supports HT20 or
  * return TRUE if flag supports HT40 && client supports HT40.
  * This is used becos some rates overlap between HT20/HT40.
  */
-
-#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \
-				& WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \
-				  (capflag & WLAN_RC_40_FLAG)))
+#define WLAN_RC_PHY_HT_VALID(flag, capflag)			\
+	(((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \
+	 ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG)))
 
 #define WLAN_RC_DS_FLAG         (0x01)
 #define WLAN_RC_40_FLAG         (0x02)
 #define WLAN_RC_SGI_FLAG        (0x04)
 #define WLAN_RC_HT_FLAG         (0x08)
 
-#define RATE_TABLE_SIZE		64
-
 /**
  * struct ath_rate_table - Rate Control table
  * @valid: valid for use in rate control
@@ -149,10 +86,11 @@ enum {
  * @max_4ms_framelen: maximum frame length(bytes) for tx duration
  * @probe_interval: interval for rate control to probe for other rates
  * @rssi_reduce_interval: interval for rate control to reduce rssi
- * @initial_ratemax: initial ratemax value used in ath_rc_sib_update()
+ * @initial_ratemax: initial ratemax value
  */
 struct ath_rate_table {
 	int rate_cnt;
+	u8 rateCodeToIndex[256];
 	struct {
 		int valid;
 		int valid_single_stream;
@@ -170,42 +108,26 @@ struct ath_rate_table {
 		u8 sgi_index;
 		u8 ht_index;
 		u32 max_4ms_framelen;
+		u16 lpAckDuration;
+		u16 spAckDuration;
 	} info[RATE_TABLE_SIZE];
 	u32 probe_interval;
 	u32 rssi_reduce_interval;
 	u8 initial_ratemax;
 };
 
-#define ATH_RC_PROBE_ALLOWED            0x00000001
-#define ATH_RC_MINRATE_LASTRATE         0x00000002
-
-struct ath_rc_series {
-	u8 rix;
-	u8 tries;
-	u8 flags;
-	u32 max_4ms_framelen;
-};
-
-/* rcs_flags definition */
-#define ATH_RC_DS_FLAG               0x01
-#define ATH_RC_CW40_FLAG             0x02    /* CW 40 */
-#define ATH_RC_SGI_FLAG              0x04    /* Short Guard Interval */
-#define ATH_RC_HT_FLAG               0x08    /* HT */
-#define ATH_RC_RTSCTS_FLAG           0x10    /* RTS-CTS */
-
-/*
- * State structures for new rate adaptation code
- */
-#define	MAX_TX_RATE_TBL	        64
-#define MAX_TX_RATE_PHY         48
-
 struct ath_tx_ratectrl_state {
 	int8_t rssi_thres;	/* required rssi for this rate (dB) */
 	u8 per;			/* recent estimate of packet error rate (%) */
 };
 
+struct ath_rateset {
+	u8 rs_nrates;
+	u8 rs_rates[ATH_RATE_MAX];
+};
+
 /**
- * struct ath_tx_ratectrl - TX Rate control Information
+ * struct ath_rate_priv - Rate Control priv data
  * @state: RC state
  * @rssi_last: last ACK rssi
  * @rssi_last_lookup: last ACK rssi used for lookup
@@ -224,9 +146,13 @@ struct ath_tx_ratectrl_state {
  * @valid_phy_ratecnt: valid rate count
  * @rate_max_phy: phy index for the max rate
  * @probe_interval: interval for ratectrl to probe for other rates
+ * @prev_data_rix: rate idx of last data frame
+ * @ht_cap: HT capabilities
+ * @single_stream: When TRUE, only single TX stream possible
+ * @neg_rates: Negotatied rates
+ * @neg_ht_rates: Negotiated HT rates
  */
-struct ath_tx_ratectrl {
-	struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL];
+struct ath_rate_priv {
 	int8_t rssi_last;
 	int8_t rssi_last_lookup;
 	int8_t rssi_last_prev;
@@ -236,89 +162,40 @@ struct ath_tx_ratectrl {
 	int32_t rssi_sum;
 	u8 rate_table_size;
 	u8 probe_rate;
-	u32 rssi_time;
-	u32 rssi_down_time;
-	u32 probe_time;
 	u8 hw_maxretry_pktcnt;
 	u8 max_valid_rate;
-	u8 valid_rate_index[MAX_TX_RATE_TBL];
-	u32 per_down_time;
-
-	/* 11n state */
+	u8 valid_rate_index[RATE_TABLE_SIZE];
+	u8 ht_cap;
+	u8 single_stream;
 	u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
-	u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
+	u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
 	u8 rc_phy_mode;
 	u8 rate_max_phy;
+	u32 rssi_time;
+	u32 rssi_down_time;
+	u32 probe_time;
+	u32 per_down_time;
 	u32 probe_interval;
-};
-
-struct ath_rateset {
-	u8 rs_nrates;
-	u8 rs_rates[ATH_RATE_MAX];
-};
-
-/* per-device state */
-struct ath_rate_softc {
-	/* phy tables that contain rate control data */
-	const void *hw_rate_table[ATH9K_MODE_MAX];
-
-	/* -1 or index of fixed rate */
-	int fixedrix;
-};
-
-/* per-node state */
-struct ath_rate_node {
-	struct ath_tx_ratectrl tx_ratectrl;
-
-	/* rate idx of last data frame */
 	u32 prev_data_rix;
-
-	/* ht capabilities */
-	u8 ht_cap;
-
-	/* When TRUE, only single stream Tx possible */
-	u8 single_stream;
-
-	/* Negotiated rates */
+	u32 tx_triglevel_max;
+	struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
 	struct ath_rateset neg_rates;
-
-	/* Negotiated HT rates */
 	struct ath_rateset neg_ht_rates;
-
 	struct ath_rate_softc *asc;
-	struct ath_vap *avp;
 };
 
-/* Driver data of ieee80211_tx_info */
 struct ath_tx_info_priv {
-	struct ath_rc_series rcs[4];
 	struct ath_tx_status tx;
 	int n_frames;
 	int n_bad_frames;
-	u8 min_rate;
+	bool update_rc;
 };
 
-/*
- * Attach/detach a rate control module.
- */
-struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah);
-void ath_rate_detach(struct ath_rate_softc *asc);
-
-/*
- * Update/reset rate control state for 802.11 state transitions.
- * Important mostly as the analog to ath_rate_newassoc when operating
- * in station mode.
- */
-void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv);
-void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
-
-/*
- * Return rate index for given Dot11 Rate.
- */
-u8 ath_rate_findrateix(struct ath_softc *sc,
-		       u8 dot11_rate);
+#define ATH_TX_INFO_PRIV(tx_info) \
+	((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
 
-/* Routines to register/unregister rate control algorithm */
+void ath_rate_attach(struct ath_softc *sc);
+u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
 int ath_rate_control_register(void);
 void ath_rate_control_unregister(void);
 

+ 228 - 372
drivers/net/wireless/ath9k/recv.c

@@ -14,10 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/*
- * Implementation of receive path.
- */
-
 #include "core.h"
 
 /*
@@ -27,10 +23,7 @@
  * MAC acknowledges BA status as long as it copies frames to host
  * buffer (or rx fifo). This can incorrectly acknowledge packets
  * to a sender if last desc is self-linked.
- *
- * NOTE: Caller should hold the rxbuf lock.
  */
-
 static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
 {
 	struct ath_hal *ah = sc->sc_ah;
@@ -40,19 +33,17 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
 	ATH_RXBUF_RESET(bf);
 
 	ds = bf->bf_desc;
-	ds->ds_link = 0;    /* link to null */
+	ds->ds_link = 0; /* link to null */
 	ds->ds_data = bf->bf_buf_addr;
 
-	/* XXX For RADAR?
-	 * virtual addr of the beginning of the buffer. */
+	/* virtual addr of the beginning of the buffer. */
 	skb = bf->bf_mpdu;
 	ASSERT(skb != NULL);
 	ds->ds_vdata = skb->data;
 
 	/* setup rx descriptors */
-	ath9k_hw_setuprxdesc(ah,
-			     ds,
-			     skb_tailroom(skb),   /* buffer size */
+	ath9k_hw_setuprxdesc(ah, ds,
+			     skb_tailroom(skb), /* buffer size */
 			     0);
 
 	if (sc->sc_rxlink == NULL)
@@ -64,8 +55,29 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
 	ath9k_hw_rxena(ah);
 }
 
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
-	u32 len)
+static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
+{
+	/* XXX block beacon interrupts */
+	ath9k_hw_setantenna(sc->sc_ah, antenna);
+	sc->sc_defant = antenna;
+	sc->sc_rxotherant = 0;
+}
+
+/*
+ *  Extend 15-bit time stamp from rx descriptor to
+ *  a full 64-bit TSF using the current h/w TSF.
+*/
+static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
+{
+	u64 tsf;
+
+	tsf = ath9k_hw_gettsf64(sc->sc_ah);
+	if ((tsf & 0x7fff) < rstamp)
+		tsf -= 0x8000;
+	return (tsf & ~0x7fff) | rstamp;
+}
+
+static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
 {
 	struct sk_buff *skb;
 	u32 off;
@@ -91,59 +103,133 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
 	return skb;
 }
 
-static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb)
+static int ath_rate2idx(struct ath_softc *sc, int rate)
 {
-	struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
+	int i = 0, cur_band, n_rates;
+	struct ieee80211_hw *hw = sc->hw;
 
-	ASSERT(bf != NULL);
+	cur_band = hw->conf.channel->band;
+	n_rates = sc->sbands[cur_band].n_bitrates;
 
-	spin_lock_bh(&sc->sc_rxbuflock);
-	if (bf->bf_status & ATH_BUFSTATUS_STALE) {
-		/*
-		 * This buffer is still held for hw acess.
-		 * Mark it as free to be re-queued it later.
-		 */
-		bf->bf_status |= ATH_BUFSTATUS_FREE;
-	} else {
-		/* XXX: we probably never enter here, remove after
-		 * verification */
-		list_add_tail(&bf->list, &sc->sc_rxbuf);
-		ath_rx_buf_link(sc, bf);
+	for (i = 0; i < n_rates; i++) {
+		if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
+			break;
 	}
-	spin_unlock_bh(&sc->sc_rxbuflock);
+
+	/*
+	 * NB:mac80211 validates rx rate index against the supported legacy rate
+	 * index only (should be done against ht rates also), return the highest
+	 * legacy rate index for rx rate which does not match any one of the
+	 * supported basic and extended rates to make mac80211 happy.
+	 * The following hack will be cleaned up once the issue with
+	 * the rx rate index validation in mac80211 is fixed.
+	 */
+	if (i == n_rates)
+		return n_rates - 1;
+
+	return i;
 }
 
 /*
- * The skb indicated to upper stack won't be returned to us.
- * So we have to allocate a new one and queue it by ourselves.
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
  */
-static int ath_rx_indicate(struct ath_softc *sc,
-			   struct sk_buff *skb,
-			   struct ath_recv_status *status,
-			   u16 keyix)
+static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
+			  struct ieee80211_rx_status *rx_status, bool *decrypt_error,
+			  struct ath_softc *sc)
 {
-	struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
-	struct sk_buff *nskb;
-	int type;
-
-	/* indicate frame to the stack, which will free the old skb. */
-	type = _ath_rx_indicate(sc, skb, status, keyix);
-
-	/* allocate a new skb and queue it to for H/W processing */
-	nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
-	if (nskb != NULL) {
-		bf->bf_mpdu = nskb;
-		bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data,
-					 skb_end_pointer(nskb) - nskb->head,
-					 PCI_DMA_FROMDEVICE);
-		bf->bf_dmacontext = bf->bf_buf_addr;
-		ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf;
+	struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
+	struct ieee80211_hdr *hdr;
+	int ratekbps, rix;
+	u8 ratecode;
+	__le16 fc;
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	fc = hdr->frame_control;
+	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
 
-		/* queue the new wbuf to H/W */
-		ath_rx_requeue(sc, nskb);
+	if (ds->ds_rxstat.rs_more) {
+		/*
+		 * Frame spans multiple descriptors; this cannot happen yet
+		 * as we don't support jumbograms. If not in monitor mode,
+		 * discard the frame. Enable this if you want to see
+		 * error frames in Monitor mode.
+		 */
+		if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
+			goto rx_next;
+	} else if (ds->ds_rxstat.rs_status != 0) {
+		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY)
+			goto rx_next;
+
+		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
+			*decrypt_error = true;
+		} else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
+			if (ieee80211_is_ctl(fc))
+				/*
+				 * Sometimes, we get invalid
+				 * MIC failures on valid control frames.
+				 * Remove these mic errors.
+				 */
+				ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC;
+			else
+				rx_status->flag |= RX_FLAG_MMIC_ERROR;
+		}
+		/*
+		 * Reject error frames with the exception of
+		 * decryption and MIC failures. For monitor mode,
+		 * we also ignore the CRC error.
+		 */
+		if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
+			if (ds->ds_rxstat.rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+			      ATH9K_RXERR_CRC))
+				goto rx_next;
+		} else {
+			if (ds->ds_rxstat.rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+				goto rx_next;
+			}
+		}
 	}
 
-	return type;
+	ratecode = ds->ds_rxstat.rs_rate;
+	rix = rate_table->rateCodeToIndex[ratecode];
+	ratekbps = rate_table->info[rix].ratekbps;
+
+	/* HT rate */
+	if (ratecode & 0x80) {
+		if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
+			ratekbps = (ratekbps * 27) / 13;
+		if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
+			ratekbps = (ratekbps * 10) / 9;
+	}
+
+	rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
+	rx_status->band = sc->hw->conf.channel->band;
+	rx_status->freq =  sc->hw->conf.channel->center_freq;
+	rx_status->noise = sc->sc_ani.sc_noise_floor;
+	rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+	rx_status->rate_idx = ath_rate2idx(sc, (ratekbps / 100));
+	rx_status->antenna = ds->ds_rxstat.rs_antenna;
+
+	/* at 45 you will be able to use MCS 15 reliably. A more elaborate
+	 * scheme can be used here but it requires tables of SNR/throughput for
+	 * each possible mode used. */
+	rx_status->qual =  ds->ds_rxstat.rs_rssi * 100 / 45;
+
+	/* rssi can be more than 45 though, anything above that
+	 * should be considered at 100% */
+	if (rx_status->qual > 100)
+		rx_status->qual = 100;
+
+	rx_status->flag |= RX_FLAG_TSFT;
+
+	return 1;
+rx_next:
+	return 0;
 }
 
 static void ath_opmode_init(struct ath_softc *sc)
@@ -185,12 +271,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
 		sc->sc_flags &= ~SC_OP_RXFLUSH;
 		spin_lock_init(&sc->sc_rxbuflock);
 
-		/*
-		 * Cisco's VPN software requires that drivers be able to
-		 * receive encapsulated frames that are larger than the MTU.
-		 * Since we can't be sure how large a frame we'll get, setup
-		 * to handle the larges on possible.
-		 */
 		sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN,
 					   min(sc->sc_cachelsz,
 					       (u16)64));
@@ -209,8 +289,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
 			break;
 		}
 
-		/* Pre-allocate a wbuf for each rx buffer */
-
 		list_for_each_entry(bf, &sc->sc_rxbuf, list) {
 			skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
 			if (skb == NULL) {
@@ -223,7 +301,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
 					 skb_end_pointer(skb) - skb->head,
 					 PCI_DMA_FROMDEVICE);
 			bf->bf_dmacontext = bf->bf_buf_addr;
-			ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
 		}
 		sc->sc_rxlink = NULL;
 
@@ -235,8 +312,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
 	return error;
 }
 
-/* Reclaim all rx queue resources */
-
 void ath_rx_cleanup(struct ath_softc *sc)
 {
 	struct sk_buff *skb;
@@ -248,8 +323,6 @@ void ath_rx_cleanup(struct ath_softc *sc)
 			dev_kfree_skb(skb);
 	}
 
-	/* cleanup rx descriptors */
-
 	if (sc->sc_rxdma.dd_desc_len != 0)
 		ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
 }
@@ -297,20 +370,19 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
 	}
 
 	if (sc->sc_ah->ah_opmode == ATH9K_M_STA ||
-			sc->sc_ah->ah_opmode == ATH9K_M_IBSS)
+	    sc->sc_ah->ah_opmode == ATH9K_M_IBSS)
 		rfilt |= ATH9K_RX_FILTER_BEACON;
 
 	/* If in HOSTAP mode, want to enable reception of PSPOLL frames
 	   & beacon frames */
 	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
 		rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
+
 	return rfilt;
 
 #undef RX_FILTER_PRESERVE
 }
 
-/* Enable the receive h/w following a reset. */
-
 int ath_startrecv(struct ath_softc *sc)
 {
 	struct ath_hal *ah = sc->sc_ah;
@@ -322,21 +394,6 @@ int ath_startrecv(struct ath_softc *sc)
 
 	sc->sc_rxlink = NULL;
 	list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) {
-		if (bf->bf_status & ATH_BUFSTATUS_STALE) {
-			/* restarting h/w, no need for holding descriptors */
-			bf->bf_status &= ~ATH_BUFSTATUS_STALE;
-			/*
-			 * Upper layer may not be done with the frame yet so
-			 * we can't just re-queue it to hardware. Remove it
-			 * from h/w queue. It'll be re-queued when upper layer
-			 * returns the frame and ath_rx_requeue_mpdu is called.
-			 */
-			if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) {
-				list_del(&bf->list);
-				continue;
-			}
-		}
-		/* chain descriptors */
 		ath_rx_buf_link(sc, bf);
 	}
 
@@ -346,120 +403,69 @@ int ath_startrecv(struct ath_softc *sc)
 
 	bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
 	ath9k_hw_putrxbuf(ah, bf->bf_daddr);
-	ath9k_hw_rxena(ah);      /* enable recv descriptors */
+	ath9k_hw_rxena(ah);
 
 start_recv:
 	spin_unlock_bh(&sc->sc_rxbuflock);
-	ath_opmode_init(sc);        /* set filters, etc. */
-	ath9k_hw_startpcureceive(ah);	/* re-enable PCU/DMA engine */
+	ath_opmode_init(sc);
+	ath9k_hw_startpcureceive(ah);
+
 	return 0;
 }
 
-/* Disable the receive h/w in preparation for a reset. */
-
 bool ath_stoprecv(struct ath_softc *sc)
 {
 	struct ath_hal *ah = sc->sc_ah;
-	u64 tsf;
 	bool stopped;
 
-	ath9k_hw_stoppcurecv(ah);	/* disable PCU */
-	ath9k_hw_setrxfilter(ah, 0);	/* clear recv filter */
-	stopped = ath9k_hw_stopdmarecv(ah);	/* disable DMA engine */
-	mdelay(3);			/* 3ms is long enough for 1 frame */
-	tsf = ath9k_hw_gettsf64(ah);
-	sc->sc_rxlink = NULL;		/* just in case */
+	ath9k_hw_stoppcurecv(ah);
+	ath9k_hw_setrxfilter(ah, 0);
+	stopped = ath9k_hw_stopdmarecv(ah);
+	mdelay(3); /* 3ms is long enough for 1 frame */
+	sc->sc_rxlink = NULL;
+
 	return stopped;
 }
 
-/* Flush receive queue */
-
 void ath_flushrecv(struct ath_softc *sc)
 {
-	/*
-	 * ath_rx_tasklet may be used to handle rx interrupt and flush receive
-	 * queue at the same time. Use a lock to serialize the access of rx
-	 * queue.
-	 * ath_rx_tasklet cannot hold the spinlock while indicating packets.
-	 * Instead, do not claim the spinlock but check for a flush in
-	 * progress (see references to sc_rxflush)
-	 */
 	spin_lock_bh(&sc->sc_rxflushlock);
 	sc->sc_flags |= SC_OP_RXFLUSH;
-
 	ath_rx_tasklet(sc, 1);
-
 	sc->sc_flags &= ~SC_OP_RXFLUSH;
 	spin_unlock_bh(&sc->sc_rxflushlock);
 }
 
-/* Process receive queue, as well as LED, etc. */
-
 int ath_rx_tasklet(struct ath_softc *sc, int flush)
 {
 #define PA2DESC(_sc, _pa)                                               \
 	((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc +		\
 			     ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
 
-	struct ath_buf *bf, *bf_held = NULL;
+	struct ath_buf *bf;
 	struct ath_desc *ds;
-	struct ieee80211_hdr *hdr;
-	struct sk_buff *skb = NULL;
-	struct ath_recv_status rx_status;
+	struct sk_buff *skb = NULL, *requeue_skb;
+	struct ieee80211_rx_status rx_status;
 	struct ath_hal *ah = sc->sc_ah;
-	int type, rx_processed = 0;
-	u32 phyerr;
-	u8 chainreset = 0;
-	int retval;
-	__le16 fc;
+	struct ieee80211_hdr *hdr;
+	int hdrlen, padsize, retval;
+	bool decrypt_error = false;
+	u8 keyix;
+
+	spin_lock_bh(&sc->sc_rxbuflock);
 
 	do {
 		/* If handling rx interrupt and flush is in progress => exit */
 		if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
 			break;
 
-		spin_lock_bh(&sc->sc_rxbuflock);
 		if (list_empty(&sc->sc_rxbuf)) {
 			sc->sc_rxlink = NULL;
-			spin_unlock_bh(&sc->sc_rxbuflock);
 			break;
 		}
 
 		bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
-
-		/*
-		 * There is a race condition that BH gets scheduled after sw
-		 * writes RxE and before hw re-load the last descriptor to get
-		 * the newly chained one. Software must keep the last DONE
-		 * descriptor as a holding descriptor - software does so by
-		 * marking it with the STALE flag.
-		 */
-		if (bf->bf_status & ATH_BUFSTATUS_STALE) {
-			bf_held = bf;
-			if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) {
-				/*
-				 * The holding descriptor is the last
-				 * descriptor in queue. It's safe to
-				 * remove the last holding descriptor
-				 * in BH context.
-				 */
-				list_del(&bf_held->list);
-				bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
-				sc->sc_rxlink = NULL;
-
-				if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
-					list_add_tail(&bf_held->list,
-						&sc->sc_rxbuf);
-					ath_rx_buf_link(sc, bf_held);
-				}
-				spin_unlock_bh(&sc->sc_rxbuflock);
-				break;
-			}
-			bf = list_entry(bf->list.next, struct ath_buf, list);
-		}
-
 		ds = bf->bf_desc;
-		++rx_processed;
 
 		/*
 		 * Must provide the virtual address of the current
@@ -472,8 +478,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		 * on.  All this is necessary because of our use of
 		 * a self-linked list to avoid rx overruns.
 		 */
-		retval = ath9k_hw_rxprocdesc(ah,
-					     ds,
+		retval = ath9k_hw_rxprocdesc(ah, ds,
 					     bf->bf_daddr,
 					     PA2DESC(sc, ds->ds_link),
 					     0);
@@ -482,7 +487,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 			struct ath_desc *tds;
 
 			if (list_is_last(&bf->list, &sc->sc_rxbuf)) {
-				spin_unlock_bh(&sc->sc_rxbuflock);
+				sc->sc_rxlink = NULL;
 				break;
 			}
 
@@ -500,215 +505,87 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 			 */
 
 			tds = tbf->bf_desc;
-			retval = ath9k_hw_rxprocdesc(ah,
-				tds, tbf->bf_daddr,
-				PA2DESC(sc, tds->ds_link), 0);
+			retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
+					     PA2DESC(sc, tds->ds_link), 0);
 			if (retval == -EINPROGRESS) {
-				spin_unlock_bh(&sc->sc_rxbuflock);
 				break;
 			}
 		}
 
-		/* XXX: we do not support frames spanning
-		 * multiple descriptors */
-		bf->bf_status |= ATH_BUFSTATUS_DONE;
-
 		skb = bf->bf_mpdu;
-		if (skb == NULL) {		/* XXX ??? can this happen */
-			spin_unlock_bh(&sc->sc_rxbuflock);
+		if (!skb)
 			continue;
-		}
-		/*
-		 * Now we know it's a completed frame, we can indicate the
-		 * frame. Remove the previous holding descriptor and leave
-		 * this one in the queue as the new holding descriptor.
-		 */
-		if (bf_held) {
-			list_del(&bf_held->list);
-			bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
-			if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
-				list_add_tail(&bf_held->list, &sc->sc_rxbuf);
-				/* try to requeue this descriptor */
-				ath_rx_buf_link(sc, bf_held);
-			}
-		}
 
-		bf->bf_status |= ATH_BUFSTATUS_STALE;
-		bf_held = bf;
 		/*
-		 * Release the lock here in case ieee80211_input() return
-		 * the frame immediately by calling ath_rx_mpdu_requeue().
+		 * If we're asked to flush receive queue, directly
+		 * chain it back at the queue without processing it.
 		 */
-		spin_unlock_bh(&sc->sc_rxbuflock);
+		if (flush)
+			goto requeue;
 
-		if (flush) {
-			/*
-			 * If we're asked to flush receive queue, directly
-			 * chain it back at the queue without processing it.
-			 */
-			goto rx_next;
-		}
+		if (!ds->ds_rxstat.rs_datalen)
+			goto requeue;
 
-		hdr = (struct ieee80211_hdr *)skb->data;
-		fc = hdr->frame_control;
-		memset(&rx_status, 0, sizeof(struct ath_recv_status));
+		/* The status portion of the descriptor could get corrupted. */
+		if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
+			goto requeue;
 
-		if (ds->ds_rxstat.rs_more) {
-			/*
-			 * Frame spans multiple descriptors; this
-			 * cannot happen yet as we don't support
-			 * jumbograms.  If not in monitor mode,
-			 * discard the frame.
-			 */
-#ifndef ERROR_FRAMES
-			/*
-			 * Enable this if you want to see
-			 * error frames in Monitor mode.
-			 */
-			if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
-				goto rx_next;
-#endif
-			/* fall thru for monitor mode handling... */
-		} else if (ds->ds_rxstat.rs_status != 0) {
-			if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
-				rx_status.flags |= ATH_RX_FCS_ERROR;
-			if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
-				phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
-				goto rx_next;
-			}
+		if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
+			goto requeue;
 
-			if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
-				/*
-				 * Decrypt error. We only mark packet status
-				 * here and always push up the frame up to let
-				 * mac80211 handle the actual error case, be
-				 * it no decryption key or real decryption
-				 * error. This let us keep statistics there.
-				 */
-				rx_status.flags |= ATH_RX_DECRYPT_ERROR;
-			} else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
-				/*
-				 * Demic error. We only mark frame status here
-				 * and always push up the frame up to let
-				 * mac80211 handle the actual error case. This
-				 * let us keep statistics there. Hardware may
-				 * post a false-positive MIC error.
-				 */
-				if (ieee80211_is_ctl(fc))
-					/*
-					 * Sometimes, we get invalid
-					 * MIC failures on valid control frames.
-					 * Remove these mic errors.
-					 */
-					ds->ds_rxstat.rs_status &=
-						~ATH9K_RXERR_MIC;
-				else
-					rx_status.flags |= ATH_RX_MIC_ERROR;
-			}
-			/*
-			 * Reject error frames with the exception of
-			 * decryption and MIC failures. For monitor mode,
-			 * we also ignore the CRC error.
-			 */
-			if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
-				if (ds->ds_rxstat.rs_status &
-				    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
-					ATH9K_RXERR_CRC))
-					goto rx_next;
-			} else {
-				if (ds->ds_rxstat.rs_status &
-				    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
-					goto rx_next;
-				}
-			}
-		}
-		/*
-		 * The status portion of the descriptor could get corrupted.
-		 */
-		if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
-			goto rx_next;
-		/*
-		 * Sync and unmap the frame.  At this point we're
-		 * committed to passing the sk_buff somewhere so
-		 * clear buf_skb; this means a new sk_buff must be
-		 * allocated when the rx descriptor is setup again
-		 * to receive another frame.
-		 */
-		skb_put(skb, ds->ds_rxstat.rs_datalen);
-		skb->protocol = cpu_to_be16(ETH_P_CONTROL);
-		rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
-		rx_status.rateieee =
-			sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate;
-		rx_status.rateKbps =
-			sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps;
-		rx_status.ratecode = ds->ds_rxstat.rs_rate;
-
-		/* HT rate */
-		if (rx_status.ratecode & 0x80) {
-			/* TODO - add table to avoid division */
-			if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
-				rx_status.flags |= ATH_RX_40MHZ;
-				rx_status.rateKbps =
-					(rx_status.rateKbps * 27) / 13;
-			}
-			if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
-				rx_status.rateKbps =
-					(rx_status.rateKbps * 10) / 9;
-			else
-				rx_status.flags |= ATH_RX_SHORT_GI;
-		}
+		/* Ensure we always have an skb to requeue once we are done
+		 * processing the current buffer's skb */
+		requeue_skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
 
-		/* sc_noise_floor is only available when the station
-		   attaches to an AP, so we use a default value
-		   if we are not yet attached. */
-		rx_status.abs_rssi =
-			ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor;
+		/* If there is no memory we ignore the current RX'd frame,
+		 * tell hardware it can give us a new frame using the old
+		 * skb and put it at the tail of the sc->sc_rxbuf list for
+		 * processing. */
+		if (!requeue_skb)
+			goto requeue;
 
-		pci_dma_sync_single_for_cpu(sc->pdev,
-					    bf->bf_buf_addr,
+		/* Sync and unmap the frame */
+		pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
 					    skb_tailroom(skb),
 					    PCI_DMA_FROMDEVICE);
-		pci_unmap_single(sc->pdev,
-				 bf->bf_buf_addr,
+		pci_unmap_single(sc->pdev, bf->bf_buf_addr,
 				 sc->sc_rxbufsize,
 				 PCI_DMA_FROMDEVICE);
 
-		/* XXX: Ah! make me more readable, use a helper */
-		if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
-			if (ds->ds_rxstat.rs_moreaggr == 0) {
-				rx_status.rssictl[0] =
-					ds->ds_rxstat.rs_rssi_ctl0;
-				rx_status.rssictl[1] =
-					ds->ds_rxstat.rs_rssi_ctl1;
-				rx_status.rssictl[2] =
-					ds->ds_rxstat.rs_rssi_ctl2;
-				rx_status.rssi = ds->ds_rxstat.rs_rssi;
-				if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
-					rx_status.rssiextn[0] =
-						ds->ds_rxstat.rs_rssi_ext0;
-					rx_status.rssiextn[1] =
-						ds->ds_rxstat.rs_rssi_ext1;
-					rx_status.rssiextn[2] =
-						ds->ds_rxstat.rs_rssi_ext2;
-					rx_status.flags |=
-						ATH_RX_RSSI_EXTN_VALID;
-				}
-				rx_status.flags |= ATH_RX_RSSI_VALID |
-					ATH_RX_CHAIN_RSSI_VALID;
-			}
-		} else {
-			/*
-			 * Need to insert the "combined" rssi into the
-			 * status structure for upper layer processing
-			 */
-			rx_status.rssi = ds->ds_rxstat.rs_rssi;
-			rx_status.flags |= ATH_RX_RSSI_VALID;
+		skb_put(skb, ds->ds_rxstat.rs_datalen);
+		skb->protocol = cpu_to_be16(ETH_P_CONTROL);
+
+		/* see if any padding is done by the hw and remove it */
+		hdr = (struct ieee80211_hdr *)skb->data;
+		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+		if (hdrlen & 3) {
+			padsize = hdrlen % 4;
+			memmove(skb->data + padsize, skb->data, hdrlen);
+			skb_pull(skb, padsize);
 		}
 
-		/* Pass frames up to the stack. */
+		keyix = ds->ds_rxstat.rs_keyix;
 
-		type = ath_rx_indicate(sc, skb,
-			&rx_status, ds->ds_rxstat.rs_keyix);
+		if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
+			rx_status.flag |= RX_FLAG_DECRYPTED;
+		} else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+			   && !decrypt_error && skb->len >= hdrlen + 4) {
+			keyix = skb->data[hdrlen + 3] >> 6;
+
+			if (test_bit(keyix, sc->sc_keymap))
+				rx_status.flag |= RX_FLAG_DECRYPTED;
+		}
+
+		/* Send the frame to mac80211 */
+		__ieee80211_rx(sc->hw, skb, &rx_status);
+
+		/* We will now give hardware our shiny new allocated skb */
+		bf->bf_mpdu = requeue_skb;
+		bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data,
+					 sc->sc_rxbufsize,
+					 PCI_DMA_FROMDEVICE);
+		bf->bf_dmacontext = bf->bf_buf_addr;
 
 		/*
 		 * change the default rx antenna if rx diversity chooses the
@@ -716,37 +593,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		 */
 		if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
 			if (++sc->sc_rxotherant >= 3)
-				ath_setdefantenna(sc,
-						ds->ds_rxstat.rs_antenna);
+				ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
 		} else {
 			sc->sc_rxotherant = 0;
 		}
+requeue:
+		list_move_tail(&bf->list, &sc->sc_rxbuf);
+		ath_rx_buf_link(sc, bf);
+	} while (1);
 
-#ifdef CONFIG_SLOW_ANT_DIV
-		if ((rx_status.flags & ATH_RX_RSSI_VALID) &&
-		    ieee80211_is_beacon(fc)) {
-			ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat);
-		}
-#endif
-		/*
-		 * For frames successfully indicated, the buffer will be
-		 * returned to us by upper layers by calling
-		 * ath_rx_mpdu_requeue, either synchronusly or asynchronously.
-		 * So we don't want to do it here in this loop.
-		 */
-		continue;
-
-rx_next:
-		bf->bf_status |= ATH_BUFSTATUS_FREE;
-	} while (TRUE);
-
-	if (chainreset) {
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: Reset rx chain mask. "
-			"Do internal reset\n", __func__);
-		ASSERT(flush == 0);
-		ath_reset(sc, false);
-	}
+	spin_unlock_bh(&sc->sc_rxbuflock);
 
 	return 0;
 #undef PA2DESC

+ 164 - 301
drivers/net/wireless/ath9k/xmit.c

@@ -14,10 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/*
- * Implementation of transmit path.
- */
-
 #include "core.h"
 
 #define BITS_PER_BYTE           8
@@ -106,21 +102,35 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 	ath9k_hw_txstart(ah, txq->axq_qnum);
 }
 
-/* Get transmit rate index using rate in Kbps */
-
-static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate)
+static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+			    struct ath_xmit_status *tx_status)
 {
-	int i;
-	int ndx = 0;
+	struct ieee80211_hw *hw = sc->hw;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
 
-	for (i = 0; i < rt->rateCount; i++) {
-		if (rt->info[i].rateKbps == rate) {
-			ndx = i;
-			break;
-		}
+	DPRINTF(sc, ATH_DBG_XMIT,
+		"%s: TX complete: skb: %p\n", __func__, skb);
+
+	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
+	    tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+		kfree(tx_info_priv);
+		tx_info->rate_driver_data[0] = NULL;
 	}
 
-	return ndx;
+	if (tx_status->flags & ATH_TX_BAR) {
+		tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+		tx_status->flags &= ~ATH_TX_BAR;
+	}
+
+	if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
+		/* Frame was ACKed */
+		tx_info->flags |= IEEE80211_TX_STAT_ACK;
+	}
+
+	tx_info->status.rates[0].count = tx_status->retries + 1;
+
+	ieee80211_tx_status(hw, skb);
 }
 
 /* Check if it's okay to send out aggregates */
@@ -137,6 +147,19 @@ static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 		return 0;
 }
 
+static void ath_get_beaconconfig(struct ath_softc *sc, int if_id,
+				 struct ath_beacon_config *conf)
+{
+	struct ieee80211_hw *hw = sc->hw;
+
+	/* fill in beacon config data */
+
+	conf->beacon_interval = hw->conf.beacon_int;
+	conf->listen_interval = 100;
+	conf->dtim_count = 1;
+	conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
+}
+
 /* Calculate Atheros packet type from IEEE80211 packet header */
 
 static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
@@ -162,26 +185,23 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
 	return htype;
 }
 
-static bool check_min_rate(struct sk_buff *skb)
+static bool is_pae(struct sk_buff *skb)
 {
 	struct ieee80211_hdr *hdr;
-	bool use_minrate = false;
 	__le16 fc;
 
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
 
-	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
-		use_minrate = true;
-	} else if (ieee80211_is_data(fc)) {
+	if (ieee80211_is_data(fc)) {
 		if (ieee80211_is_nullfunc(fc) ||
 		    /* Port Access Entity (IEEE 802.1X) */
 		    (skb->protocol == cpu_to_be16(ETH_P_PAE))) {
-			use_minrate = true;
+			return true;
 		}
 	}
 
-	return use_minrate;
+	return false;
 }
 
 static int get_hw_crypto_keytype(struct sk_buff *skb)
@@ -200,56 +220,6 @@ static int get_hw_crypto_keytype(struct sk_buff *skb)
 	return ATH9K_KEY_TYPE_CLEAR;
 }
 
-static void setup_rate_retries(struct ath_softc *sc, struct sk_buff *skb)
-{
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ath_tx_info_priv *tx_info_priv;
-	struct ath_rc_series *rcs;
-	struct ieee80211_hdr *hdr;
-	const struct ath9k_rate_table *rt;
-	bool use_minrate;
-	__le16 fc;
-	u8 rix;
-
-	rt = sc->sc_currates;
-	BUG_ON(!rt);
-
-	hdr = (struct ieee80211_hdr *)skb->data;
-	fc = hdr->frame_control;
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; /* HACK */
-	rcs = tx_info_priv->rcs;
-
-	/* Check if min rates have to be used */
-	use_minrate = check_min_rate(skb);
-
-	if (ieee80211_is_data(fc) && !use_minrate) {
-		if (is_multicast_ether_addr(hdr->addr1)) {
-			rcs[0].rix =
-				ath_tx_findindex(rt, tx_info_priv->min_rate);
-			/* mcast packets are not re-tried */
-			rcs[0].tries = 1;
-		}
-	} else {
-		/* for management and control frames,
-		   or for NULL and EAPOL frames */
-		if (use_minrate)
-			rcs[0].rix = ath_rate_findrateix(sc, tx_info_priv->min_rate);
-		else
-			rcs[0].rix = 0;
-		rcs[0].tries = ATH_MGT_TXMAXTRY;
-	}
-
-	rix = rcs[0].rix;
-
-	if (ieee80211_has_morefrags(fc) ||
-	    (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
-		rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
-		rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
-		/* reset tries but keep rate index */
-		rcs[0].tries = ATH_TXMAXTRY;
-	}
-}
-
 /* Called only when tx aggregation is enabled and HT is supported */
 
 static void assign_aggr_tid_seqno(struct sk_buff *skb,
@@ -278,7 +248,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb,
 
 	/* Get seqno */
 
-	if (ieee80211_is_data(fc) && !check_min_rate(skb)) {
+	if (ieee80211_is_data(fc) && !is_pae(skb)) {
 		/* For HT capable stations, we save tidno for later use.
 		 * We also override seqno set by upper layer with the one
 		 * in tx aggregation state.
@@ -523,27 +493,23 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
  * width  - 0 for 20 MHz, 1 for 40 MHz
  * half_gi - to use 4us v/s 3.6 us for symbol time
  */
-
 static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 			    int width, int half_gi, bool shortPreamble)
 {
-	const struct ath9k_rate_table *rt = sc->sc_currates;
+	struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
 	u32 nbits, nsymbits, duration, nsymbols;
 	u8 rc;
 	int streams, pktlen;
 
 	pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
-	rc = rt->info[rix].rateCode;
+	rc = rate_table->info[rix].ratecode;
 
-	/*
-	 * for legacy rates, use old function to compute packet duration
-	 */
+	/* for legacy rates, use old function to compute packet duration */
 	if (!IS_HT_RATE(rc))
-		return ath9k_hw_computetxtime(sc->sc_ah, rt, pktlen, rix,
-					      shortPreamble);
-	/*
-	 * find number of symbols: PLCP + data
-	 */
+		return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen,
+					      rix, shortPreamble);
+
+	/* find number of symbols: PLCP + data */
 	nbits = (pktlen << 3) + OFDM_PLCP_BITS;
 	nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
 	nsymbols = (nbits + nsymbits - 1) / nsymbits;
@@ -553,9 +519,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 	else
 		duration = SYMBOL_TIME_HALFGI(nsymbols);
 
-	/*
-	 * addup duration for legacy/ht training and signal fields
-	 */
+	/* addup duration for legacy/ht training and signal fields */
 	streams = HT_RC_2_STREAMS(rc);
 	duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
 
@@ -567,179 +531,125 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 {
 	struct ath_hal *ah = sc->sc_ah;
-	const struct ath9k_rate_table *rt;
+	struct ath_rate_table *rt;
 	struct ath_desc *ds = bf->bf_desc;
 	struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
 	struct ath9k_11n_rate_series series[4];
+	struct sk_buff *skb;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_tx_rate *rates;
+	struct ieee80211_hdr *hdr;
 	int i, flags, rtsctsena = 0;
 	u32 ctsduration = 0;
 	u8 rix = 0, cix, ctsrate = 0;
-	struct ath_node *an = NULL;
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *tx_info;
+	__le16 fc;
+
+	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
 
 	skb = (struct sk_buff *)bf->bf_mpdu;
+	hdr = (struct ieee80211_hdr *)skb->data;
+	fc = hdr->frame_control;
 	tx_info = IEEE80211_SKB_CB(skb);
+	rates = tx_info->control.rates;
 
-	if (tx_info->control.sta)
-		an = (struct ath_node *)tx_info->control.sta->drv_priv;
+	if (ieee80211_has_morefrags(fc) ||
+	    (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
+		rates[1].count = rates[2].count = rates[3].count = 0;
+		rates[1].idx = rates[2].idx = rates[3].idx = 0;
+		rates[0].count = ATH_TXMAXTRY;
+	}
 
-	/*
-	 * get the cix for the lowest valid rix.
-	 */
-	rt = sc->sc_currates;
-	for (i = 4; i--;) {
-		if (bf->bf_rcs[i].tries) {
-			rix = bf->bf_rcs[i].rix;
+	/* get the cix for the lowest valid rix */
+	rt = sc->hw_rate_table[sc->sc_curmode];
+	for (i = 3; i >= 0; i--) {
+		if (rates[i].count && (rates[i].idx >= 0)) {
+			rix = rates[i].idx;
 			break;
 		}
 	}
+
 	flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA));
-	cix = rt->info[rix].controlRate;
+	cix = rt->info[rix].ctrl_rate;
 
 	/*
-	 * If 802.11g protection is enabled, determine whether
-	 * to use RTS/CTS or just CTS.  Note that this is only
-	 * done for OFDM/HT unicast frames.
+	 * If 802.11g protection is enabled, determine whether to use RTS/CTS or
+	 * just CTS.  Note that this is only done for OFDM/HT unicast frames.
 	 */
-	if (sc->sc_protmode != PROT_M_NONE &&
-	    (rt->info[rix].phy == PHY_OFDM ||
-	     rt->info[rix].phy == PHY_HT) &&
-	    (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+	if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK)
+	    && (rt->info[rix].phy == WLAN_RC_PHY_OFDM ||
+		WLAN_RC_PHY_HT(rt->info[rix].phy))) {
 		if (sc->sc_protmode == PROT_M_RTSCTS)
 			flags = ATH9K_TXDESC_RTSENA;
 		else if (sc->sc_protmode == PROT_M_CTSONLY)
 			flags = ATH9K_TXDESC_CTSENA;
 
-		cix = rt->info[sc->sc_protrix].controlRate;
+		cix = rt->info[sc->sc_protrix].ctrl_rate;
 		rtsctsena = 1;
 	}
 
-	/* For 11n, the default behavior is to enable RTS for
-	 * hw retried frames. We enable the global flag here and
-	 * let rate series flags determine which rates will actually
-	 * use RTS.
+	/* For 11n, the default behavior is to enable RTS for hw retried frames.
+	 * We enable the global flag here and let rate series flags determine
+	 * which rates will actually use RTS.
 	 */
 	if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
-		/*
-		 * 802.11g protection not needed, use our default behavior
-		 */
+		/* 802.11g protection not needed, use our default behavior */
 		if (!rtsctsena)
 			flags = ATH9K_TXDESC_RTSENA;
 	}
 
-	/*
-	 * Set protection if aggregate protection on
-	 */
+	/* Set protection if aggregate protection on */
 	if (sc->sc_config.ath_aggr_prot &&
 	    (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
 		flags = ATH9K_TXDESC_RTSENA;
-		cix = rt->info[sc->sc_protrix].controlRate;
+		cix = rt->info[sc->sc_protrix].ctrl_rate;
 		rtsctsena = 1;
 	}
 
-	/*
-	 *  For AR5416 - RTS cannot be followed by a frame larger than 8K.
-	 */
-	if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) {
-		/*
-		 * Ensure that in the case of SM Dynamic power save
-		 * while we are bursting the second aggregate the
-		 * RTS is cleared.
-		 */
+	/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
+	if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit))
 		flags &= ~(ATH9K_TXDESC_RTSENA);
-	}
-
-	/*
-	 * CTS transmit rate is derived from the transmit rate
-	 * by looking in the h/w rate table.  We must also factor
-	 * in whether or not a short preamble is to be used.
-	 * NB: cix is set above where RTS/CTS is enabled
-	 */
-	BUG_ON(cix == 0xff);
-	ctsrate = rt->info[cix].rateCode |
-		(bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
 
 	/*
-	 * Setup HAL rate series
+	 * CTS transmit rate is derived from the transmit rate by looking in the
+	 * h/w rate table.  We must also factor in whether or not a short
+	 * preamble is to be used. NB: cix is set above where RTS/CTS is enabled
 	 */
-	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+	ctsrate = rt->info[cix].ratecode |
+		(bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0);
 
 	for (i = 0; i < 4; i++) {
-		if (!bf->bf_rcs[i].tries)
+		if (!rates[i].count || (rates[i].idx < 0))
 			continue;
 
-		rix = bf->bf_rcs[i].rix;
+		rix = rates[i].idx;
 
-		series[i].Rate = rt->info[rix].rateCode |
-			(bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0);
+		series[i].Rate = rt->info[rix].ratecode |
+			(bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0);
 
-		series[i].Tries = bf->bf_rcs[i].tries;
+		series[i].Tries = rates[i].count;
 
 		series[i].RateFlags = (
-			(bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ?
+			(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ?
 				ATH9K_RATESERIES_RTS_CTS : 0) |
-			((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ?
+			((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ?
 				ATH9K_RATESERIES_2040 : 0) |
-			((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ?
+			((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ?
 				ATH9K_RATESERIES_HALFGI : 0);
 
 		series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
-			 (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
-			 (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
+			 (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
+			 (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
 			 bf_isshpreamble(bf));
 
-		if (bf_isht(bf) && an)
-			series[i].ChSel = ath_chainmask_sel_logic(sc, an);
-		else
-			series[i].ChSel = sc->sc_tx_chainmask;
+		series[i].ChSel = sc->sc_tx_chainmask;
 
 		if (rtsctsena)
 			series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
 	}
 
-	/*
-	 * For non-HT devices, calculate RTS/CTS duration in software
-	 * and disable multi-rate retry.
-	 */
-	if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) {
-		/*
-		 * Compute the transmit duration based on the frame
-		 * size and the size of an ACK frame.  We call into the
-		 * HAL to do the computation since it depends on the
-		 * characteristics of the actual PHY being used.
-		 *
-		 * NB: CTS is assumed the same size as an ACK so we can
-		 *     use the precalculated ACK durations.
-		 */
-		if (flags & ATH9K_TXDESC_RTSENA) {    /* SIFS + CTS */
-			ctsduration += bf_isshpreamble(bf) ?
-				rt->info[cix].spAckDuration :
-				rt->info[cix].lpAckDuration;
-		}
-
-		ctsduration += series[0].PktDuration;
-
-		if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */
-			ctsduration += bf_isshpreamble(bf) ?
-				rt->info[rix].spAckDuration :
-				rt->info[rix].lpAckDuration;
-		}
-
-		/*
-		 * Disable multi-rate retry when using RTS/CTS by clearing
-		 * series 1, 2 and 3.
-		 */
-		memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3);
-	}
-
-	/*
-	 * set dur_update_en for l-sig computation except for PS-Poll frames
-	 */
-	ath9k_hw_set11n_ratescenario(ah, ds, lastds,
-				     !bf_ispspoll(bf),
-				     ctsrate,
-				     ctsduration,
+	/* set dur_update_en for l-sig computation except for PS-Poll frames */
+	ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf),
+				     ctsrate, ctsduration,
 				     series, 4, flags);
 
 	if (sc->sc_config.ath_aggr_prot && flags)
@@ -750,29 +660,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
  * Function to send a normal HT (non-AMPDU) frame
  * NB: must be called with txq lock held
  */
-
 static int ath_tx_send_normal(struct ath_softc *sc,
 			      struct ath_txq *txq,
 			      struct ath_atx_tid *tid,
 			      struct list_head *bf_head)
 {
 	struct ath_buf *bf;
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *tx_info;
-	struct ath_tx_info_priv *tx_info_priv;
 
 	BUG_ON(list_empty(bf_head));
 
 	bf = list_first_entry(bf_head, struct ath_buf, list);
 	bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */
 
-	skb = (struct sk_buff *)bf->bf_mpdu;
-	tx_info = IEEE80211_SKB_CB(skb);
-
-	/* XXX: HACK! */
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
-	memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
 	/* update starting sequence number for subsequent ADDBA request */
 	INCR(tid->seq_start, IEEE80211_SEQ_MAX);
 
@@ -1051,18 +950,37 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
 	return;
 }
 
+static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad)
+{
+	struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+
+	tx_info_priv->update_rc = false;
+	if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+
+	if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+	    (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+		if (bf_isdata(bf)) {
+			memcpy(&tx_info_priv->tx, &ds->ds_txstat,
+			       sizeof(tx_info_priv->tx));
+			tx_info_priv->n_frames = bf->bf_nframes;
+			tx_info_priv->n_bad_frames = nbad;
+			tx_info_priv->update_rc = true;
+		}
+	}
+}
+
 /* Process completed xmit descriptors from the specified queue */
 
-static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 {
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf, *lastbf, *bf_held = NULL;
 	struct list_head bf_head;
-	struct ath_desc *ds, *tmp_ds;
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *tx_info;
-	struct ath_tx_info_priv *tx_info_priv;
-	int nacked, txok, nbad = 0, isrifs = 0;
+	struct ath_desc *ds;
+	int txok, nbad = 0;
 	int status;
 
 	DPRINTF(sc, ATH_DBG_QUEUE,
@@ -1070,7 +988,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 		txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
 		txq->axq_link);
 
-	nacked = 0;
 	for (;;) {
 		spin_lock_bh(&txq->axq_lock);
 		if (list_empty(&txq->axq_q)) {
@@ -1160,30 +1077,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 		} else {
 			nbad = ath_tx_num_badfrms(sc, bf, txok);
 		}
-		skb = bf->bf_mpdu;
-		tx_info = IEEE80211_SKB_CB(skb);
-
-		/* XXX: HACK! */
-		tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif;
-		if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
-			tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
-		if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
-				(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
-			if (ds->ds_txstat.ts_status == 0)
-				nacked++;
-
-			if (bf_isdata(bf)) {
-				if (isrifs)
-					tmp_ds = bf->bf_rifslast->bf_desc;
-				else
-					tmp_ds = ds;
-				memcpy(&tx_info_priv->tx,
-					&tmp_ds->ds_txstat,
-					sizeof(tx_info_priv->tx));
-				tx_info_priv->n_frames = bf->bf_nframes;
-				tx_info_priv->n_bad_frames = nbad;
-			}
-		}
+
+		ath_tx_rc_status(bf, ds, nbad);
 
 		/*
 		 * Complete this transmit unit
@@ -1214,7 +1109,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 			ath_txq_schedule(sc, txq);
 		spin_unlock_bh(&txq->axq_lock);
 	}
-	return nacked;
 }
 
 static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
@@ -1254,7 +1148,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
 		spin_lock_bh(&sc->sc_resetlock);
 		if (!ath9k_hw_reset(ah,
 				    sc->sc_ah->ah_curchan,
-				    sc->sc_ht_info.tx_chan_width,
+				    sc->tx_chan_width,
 				    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
 				    sc->sc_ht_extprotspacing, true, &status)) {
 
@@ -1307,9 +1201,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
 			     struct ath_tx_control *txctl)
 {
 	struct ath_buf *bf;
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *tx_info;
-	struct ath_tx_info_priv *tx_info_priv;
 
 	BUG_ON(list_empty(bf_head));
 
@@ -1335,12 +1226,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
 		return 0;
 	}
 
-	skb = (struct sk_buff *)bf->bf_mpdu;
-	tx_info = IEEE80211_SKB_CB(skb);
-	/* XXX: HACK! */
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
-	memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
 	/* Add sub-frame to BAW */
 	ath_tx_addto_baw(sc, tid, bf);
 
@@ -1362,9 +1247,10 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
 			   struct ath_buf *bf,
 			   struct ath_atx_tid *tid)
 {
-	const struct ath9k_rate_table *rt = sc->sc_currates;
+	struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_tx_rate *rates;
 	struct ath_tx_info_priv *tx_info_priv;
 	u32 max_4ms_framelen, frame_length;
 	u16 aggr_limit, legacy = 0, maxampdu;
@@ -1372,10 +1258,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
 
 	skb = (struct sk_buff *)bf->bf_mpdu;
 	tx_info = IEEE80211_SKB_CB(skb);
-	tx_info_priv = (struct ath_tx_info_priv *)
-		tx_info->control.vif; /* XXX: HACK! */
-	memcpy(bf->bf_rcs,
-		tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+	rates = tx_info->control.rates;
+	tx_info_priv =
+		(struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
 
 	/*
 	 * Find the lowest frame length among the rate series that will have a
@@ -1385,14 +1270,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
 	max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
 
 	for (i = 0; i < 4; i++) {
-		if (bf->bf_rcs[i].tries) {
-			frame_length = bf->bf_rcs[i].max_4ms_framelen;
-
-			if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) {
+		if (rates[i].count) {
+			if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
 				legacy = 1;
 				break;
 			}
 
+			frame_length =
+				rate_table->info[rates[i].idx].max_4ms_framelen;
 			max_4ms_framelen = min(max_4ms_framelen, frame_length);
 		}
 	}
@@ -1431,7 +1316,9 @@ static int ath_compute_num_delims(struct ath_softc *sc,
 				  struct ath_buf *bf,
 				  u16 frmlen)
 {
-	const struct ath9k_rate_table *rt = sc->sc_currates;
+	struct ath_rate_table *rt = sc->hw_rate_table[sc->sc_curmode];
+	struct sk_buff *skb = bf->bf_mpdu;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	u32 nsymbits, nsymbols, mpdudensity;
 	u16 minlen;
 	u8 rc, flags, rix;
@@ -1464,11 +1351,11 @@ static int ath_compute_num_delims(struct ath_softc *sc,
 	if (mpdudensity == 0)
 		return ndelim;
 
-	rix = bf->bf_rcs[0].rix;
-	flags = bf->bf_rcs[0].flags;
-	rc = rt->info[rix].rateCode;
-	width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0;
-	half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0;
+	rix = tx_info->control.rates[0].idx;
+	flags = tx_info->control.rates[0].flags;
+	rc = rt->info[rix].ratecode;
+	width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
+	half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
 
 	if (half_gi)
 		nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
@@ -1510,7 +1397,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 	u16 aggr_limit = 0, al = 0, bpad = 0,
 		al_delta, h_baw = tid->baw_size / 2;
 	enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
-	int prev_al = 0, is_ds_rate = 0;
+	int prev_al = 0;
 	INIT_LIST_HEAD(&bf_head);
 
 	BUG_ON(list_empty(&tid->buf_q));
@@ -1531,11 +1418,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		if (!rl) {
 			aggr_limit = ath_lookup_rate(sc, bf, tid);
 			rl = 1;
-			/*
-			 * Is rate dual stream
-			 */
-			is_ds_rate =
-				(bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0;
 		}
 
 		/*
@@ -1772,20 +1654,19 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
 }
 
 static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
-				struct sk_buff *skb, struct scatterlist *sg,
+				struct sk_buff *skb,
 				struct ath_tx_control *txctl)
 {
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ath_tx_info_priv *tx_info_priv;
-	struct ath_rc_series *rcs;
 	int hdrlen;
 	__le16 fc;
 
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+	tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_KERNEL);
+	tx_info->rate_driver_data[0] = tx_info_priv;
 	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 	fc = hdr->frame_control;
-	rcs = tx_info_priv->rcs;
 
 	ATH_TXBUF_RESET(bf);
 
@@ -1805,7 +1686,7 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
 	(sc->sc_flags & SC_OP_PREAMBLE_SHORT) ?
 		(bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) :
 		(bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE);
-	(sc->hw->conf.ht.enabled &&
+	(sc->hw->conf.ht.enabled && !is_pae(skb) &&
 	 (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ?
 		(bf->bf_state.bf_type |= BUF_HT) :
 		(bf->bf_state.bf_type &= ~BUF_HT);
@@ -1823,15 +1704,6 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
 		bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
 	}
 
-	/* Rate series */
-
-	setup_rate_retries(sc, skb);
-
-	bf->bf_rcs[0] = rcs[0];
-	bf->bf_rcs[1] = rcs[1];
-	bf->bf_rcs[2] = rcs[2];
-	bf->bf_rcs[3] = rcs[3];
-
 	/* Assign seqno, tidno */
 
 	if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR))
@@ -1847,7 +1719,6 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
 
 /* FIXME: tx power */
 static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
-			     struct scatterlist *sg, u32 n_sg,
 			     struct ath_tx_control *txctl)
 {
 	struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
@@ -1876,10 +1747,10 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 			       bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
 
 	ath9k_hw_filltxdesc(ah, ds,
-			    sg_dma_len(sg),		/* segment length */
-			    true,			/* first segment */
-			    (n_sg == 1) ? true : false,	/* last segment */
-			    ds);			/* first descriptor */
+			    skb->len,	/* segment length */
+			    true,	/* first segment */
+			    true,	/* last segment */
+			    ds);	/* first descriptor */
 
 	bf->bf_lastfrm = bf;
 
@@ -1919,7 +1790,6 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
 		 struct ath_tx_control *txctl)
 {
 	struct ath_buf *bf;
-	struct scatterlist sg;
 
 	/* Check if a tx buffer is available */
 
@@ -1930,15 +1800,8 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
 		return -1;
 	}
 
-	ath_tx_setup_buffer(sc, bf, skb, &sg, txctl);
-
-	/* Setup S/G */
-
-	memset(&sg, 0, sizeof(struct scatterlist));
-	sg_dma_address(&sg) = bf->bf_dmacontext;
-	sg_dma_len(&sg) = skb->len;
-
-	ath_tx_start_dma(sc, bf, &sg, 1, txctl);
+	ath_tx_setup_buffer(sc, bf, skb, txctl);
+	ath_tx_start_dma(sc, bf, txctl);
 
 	return 0;
 }

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

@@ -107,7 +107,7 @@ static inline int __iwl3945_poll_bit(const char *f, u32 l,
 	int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout);
 	IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
 		      addr, bits, mask,
-		      unlikely(ret  == -ETIMEDOUT)?"timeout":"", f, l);
+		      unlikely(ret  == -ETIMEDOUT) ? "timeout" : "", f, l);
 	return ret;
 }
 #define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \

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

@@ -886,7 +886,6 @@ struct iwl3945_priv {
 	struct work_struct report_work;
 	struct work_struct request_scan;
 	struct work_struct beacon_update;
-	struct work_struct set_monitor;
 
 	struct tasklet_struct irq_tasklet;
 

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

@@ -53,6 +53,7 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
  *   is not compatible with earlier drivers.
  * This number will also appear in << 8 position of 1st dword of uCode file */
 #define IWL4965_UCODE_API "-2"
+#define IWL4965_MODULE_FIRMWARE "iwlwifi-4965" IWL4965_UCODE_API ".ucode"
 
 
 /* module parameters */
@@ -661,7 +662,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
 	int txq_id = txq->q.id;
 
 	/* Find out whether to activate Tx queue */
-	int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+	int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
 
 	/* Set up and activate */
 	iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
@@ -691,9 +692,10 @@ static const u16 default_queue_to_tx_fifo[] = {
 static int iwl4965_alive_notify(struct iwl_priv *priv)
 {
 	u32 a;
-	int i = 0;
 	unsigned long flags;
 	int ret;
+	int i, chan;
+	u32 reg_val;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -717,6 +719,17 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
 	iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR,
 			priv->scd_bc_tbls.dma >> 10);
 
+	/* Enable DMA channel */
+	for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++)
+		iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+	/* Update FH chicken bits */
+	reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+	iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+			   reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
 	/* Disable chain mode for all queues */
 	iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0);
 
@@ -747,7 +760,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
 				 (1 << priv->hw_params.max_txq_num) - 1);
 
 	/* Activate all Tx DMA/FIFO channels */
-	priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+	priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6));
 
 	iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
 
@@ -1909,7 +1922,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
 	/* Modify device's station table to Tx this TID */
-	iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	ret = iwl_grab_nic_access(priv);
@@ -2025,7 +2038,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
 		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
 		info->status.rates[0].count = tx_resp->failure_frame + 1;
 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-		info->flags |= iwl_is_tx_success(status)?
+		info->flags |= iwl_is_tx_success(status) ?
 			IEEE80211_TX_STAT_ACK : 0;
 		iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
 		/* FIXME: code repetition end */
@@ -2322,7 +2335,7 @@ static struct iwl_ops iwl4965_ops = {
 
 struct iwl_cfg iwl4965_agn_cfg = {
 	.name = "4965AGN",
-	.fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
+	.fw_name = IWL4965_MODULE_FIRMWARE,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.eeprom_size = IWL4965_EEPROM_IMG_SIZE,
 	.eeprom_ver = EEPROM_4965_EEPROM_VERSION,
@@ -2332,7 +2345,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
 };
 
 /* Module firmware */
-MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode");
+MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE);
 
 module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");

+ 22 - 5
drivers/net/wireless/iwlwifi/iwl-5000.c

@@ -475,6 +475,9 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
 	case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
 		index = IWL_CALIB_TX_IQ_PERD;
 		break;
+	case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
+		index = IWL_CALIB_BASE_BAND;
+		break;
 	default:
 		IWL_ERROR("Unknown calibration notification %d\n",
 			  hdr->op_code);
@@ -697,9 +700,10 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
 static int iwl5000_alive_notify(struct iwl_priv *priv)
 {
 	u32 a;
-	int i = 0;
 	unsigned long flags;
 	int ret;
+	int i, chan;
+	u32 reg_val;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -722,6 +726,18 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
 
 	iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
 		       priv->scd_bc_tbls.dma >> 10);
+
+	/* Enable DMA channel */
+	for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
+		iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+	/* Update FH chicken bits */
+	reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+	iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+			   reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
 	iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
 		IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
 	iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
@@ -841,8 +857,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 		priv->hw_params.calib_init_cfg =
 			BIT(IWL_CALIB_XTAL)		|
 			BIT(IWL_CALIB_LO)		|
-			BIT(IWL_CALIB_TX_IQ) 	|
-			BIT(IWL_CALIB_TX_IQ_PERD);
+			BIT(IWL_CALIB_TX_IQ) 		|
+			BIT(IWL_CALIB_TX_IQ_PERD)	|
+			BIT(IWL_CALIB_BASE_BAND);
 		break;
 	case CSR_HW_REV_TYPE_5150:
 		priv->hw_params.calib_init_cfg = 0;
@@ -969,7 +986,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
 	/* Modify device's station table to Tx this TID */
-	iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	ret = iwl_grab_nic_access(priv);
@@ -1111,7 +1128,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
 		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
 		info->status.rates[0].count = tx_resp->failure_frame + 1;
 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-		info->flags |= iwl_is_tx_success(status)?
+		info->flags |= iwl_is_tx_success(status) ?
 					IEEE80211_TX_STAT_ACK : 0;
 		iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
 

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

@@ -281,10 +281,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
 	u32 time_diff;
 	s32 index;
 	struct iwl_traffic_load *tl = NULL;
-	__le16 fc = hdr->frame_control;
 	u8 tid;
 
-	if (ieee80211_is_data_qos(fc)) {
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
 		u8 *qc = ieee80211_get_qos_ctl(hdr);
 		tid = qc[0] & 0xf;
 	} else
@@ -773,7 +772,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
 	int status;
 	u8 retries;
 	int rs_index, index = 0;
-	struct iwl_lq_sta *lq_sta;
+	struct iwl_lq_sta *lq_sta = priv_sta;
 	struct iwl_link_quality_cmd *table;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
@@ -785,12 +784,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
 	struct iwl_scale_tbl_info tbl_type;
 	struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
 	u8 active_index = 0;
-	__le16 fc = hdr->frame_control;
 	s32 tpt = 0;
 
 	IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
 
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    is_multicast_ether_addr(hdr->addr1))
 		return;
 
 	/* This packet was aggregated but doesn't carry rate scale info */
@@ -803,8 +802,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
 	if (retries > 15)
 		retries = 15;
 
-	lq_sta = (struct iwl_lq_sta *)priv_sta;
-
 	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !lq_sta->ibss_sta_added)
 		goto out;
@@ -1675,7 +1672,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	int high_tpt = IWL_INVALID_VALUE;
 	u32 fail_count;
 	s8 scale_action = 0;
-	__le16 fc;
 	u16 rate_mask;
 	u8 update_lq = 0;
 	struct iwl_scale_tbl_info *tbl, *tbl1;
@@ -1690,13 +1686,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
 	IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
 
-	fc = hdr->frame_control;
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
-		/* Send management frames and broadcast/multicast data using
-		 * lowest rate. */
-		/* TODO: this could probably be improved.. */
+	/* Send management frames and broadcast/multicast data using
+	 * lowest rate. */
+	/* TODO: this could probably be improved.. */
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    is_multicast_ether_addr(hdr->addr1))
 		return;
-	}
 
 	if (!sta || !lq_sta)
 		return;
@@ -2095,29 +2090,26 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 			struct ieee80211_tx_rate_control *txrc)
 {
 
-	int i;
 	struct sk_buff *skb = txrc->skb;
 	struct ieee80211_supported_band *sband = txrc->sband;
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
 	struct ieee80211_conf *conf = &priv->hw->conf;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	__le16 fc;
-	struct iwl_lq_sta *lq_sta;
+	struct iwl_lq_sta *lq_sta = priv_sta;
+	int rate_idx;
 
 	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
 
 	/* Send management frames and broadcast/multicast data using lowest
 	 * rate. */
-	fc = hdr->frame_control;
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
-	    !sta || !priv_sta) {
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) {
 		info->control.rates[0].idx = rate_lowest_index(sband, sta);
 		return;
 	}
 
-	lq_sta = (struct iwl_lq_sta *)priv_sta;
-	i = lq_sta->last_txrate_idx;
+	rate_idx  = lq_sta->last_txrate_idx;
 
 	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !lq_sta->ibss_sta_added) {
@@ -2137,14 +2129,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 		}
 	}
 
-	if ((i < 0) || (i > IWL_RATE_COUNT)) {
-		info->control.rates[0].idx = rate_lowest_index(sband, sta);
-		return;
-	}
+	if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
+		rate_idx = rate_lowest_index(sband, sta);
+	else if (sband->band == IEEE80211_BAND_5GHZ)
+		rate_idx -= IWL_FIRST_OFDM_RATE;
 
-	if (sband->band == IEEE80211_BAND_5GHZ)
-		i -= IWL_FIRST_OFDM_RATE;
-	info->control.rates[0].idx = i;
+	info->control.rates[0].idx = rate_idx;
 }
 
 static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
@@ -2525,7 +2515,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
 	for (i = 0; i < LQ_SIZE; i++) {
 		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
 				"rate=0x%X\n",
-				lq_sta->active_tbl == i?"*":"x",
+				lq_sta->active_tbl == i ? "*" : "x",
 				lq_sta->lq_info[i].lq_type,
 				lq_sta->lq_info[i].is_SGI,
 				lq_sta->lq_info[i].is_fat,

+ 45 - 76
drivers/net/wireless/iwlwifi/iwl-agn.c

@@ -466,9 +466,9 @@ static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
 
 	/* Set rate mask*/
 	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
-		rate_mask = priv->active_rate_basic & 0xF;
+		rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
 	else
-		rate_mask = priv->active_rate_basic & 0xFF0;
+		rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
 
 	/* Find lowest valid rate */
 	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
@@ -1492,7 +1492,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 			hw_rf_kill = 1;
 
 		IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n",
-				hw_rf_kill ? "disable radio":"enable radio");
+				hw_rf_kill ? "disable radio" : "enable radio");
 
 		/* driver only loads ucode once setting the interface up.
 		 * the driver as well won't allow loading if RFKILL is set
@@ -2224,27 +2224,6 @@ static void iwl_bg_rf_kill(struct work_struct *work)
 	iwl_rfkill_set_hw_state(priv);
 }
 
-static void iwl_bg_set_monitor(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work,
-				struct iwl_priv, set_monitor);
-	int ret;
-
-	IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
-	mutex_lock(&priv->mutex);
-
-	ret = iwl_set_mode(priv, NL80211_IFTYPE_MONITOR);
-	if (ret) {
-		if (ret == -EAGAIN)
-			IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
-		else
-			IWL_ERROR("iwl_set_mode() failed ret = %d\n", ret);
-	}
-
-	mutex_unlock(&priv->mutex);
-}
-
 static void iwl_bg_run_time_calib_work(struct work_struct *work)
 {
 	struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -2890,16 +2869,43 @@ static void iwl_configure_filter(struct ieee80211_hw *hw,
 				 int mc_count, struct dev_addr_list *mc_list)
 {
 	struct iwl_priv *priv = hw->priv;
+	__le32 *filter_flags = &priv->staging_rxon.filter_flags;
+
+	IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+			changed_flags, *total_flags);
 
-	if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
-		IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
-				   NL80211_IFTYPE_MONITOR,
-				   changed_flags, *total_flags);
-		/* queue work 'cuz mac80211 is holding a lock which
-		 * prevents us from issuing (synchronous) f/w cmds */
-		queue_work(priv->workqueue, &priv->set_monitor);
+	if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+		if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+			*filter_flags |= RXON_FILTER_PROMISC_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_PROMISC_MSK;
+	}
+	if (changed_flags & FIF_ALLMULTI) {
+		if (*total_flags & FIF_ALLMULTI)
+			*filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
+	}
+	if (changed_flags & FIF_CONTROL) {
+		if (*total_flags & FIF_CONTROL)
+			*filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
+	}
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+			*filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
 	}
-	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+
+	/* We avoid iwl_commit_rxon here to commit the new filter flags
+	 * since mac80211 will call ieee80211_hw_config immediately.
+	 * (mc_list is not supported at this time). Otherwise, we need to
+	 * queue a background iwl_commit_rxon work.
+	 */
+
+	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
 			FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
@@ -3058,49 +3064,11 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
 			struct ieee80211_key_conf *keyconf, const u8 *addr,
 			u32 iv32, u16 *phase1key)
 {
-	struct iwl_priv *priv = hw->priv;
-	u8 sta_id = IWL_INVALID_STATION;
-	unsigned long flags;
-	__le16 key_flags = 0;
-	int i;
 
+	struct iwl_priv *priv = hw->priv;
 	IWL_DEBUG_MAC80211("enter\n");
 
-	sta_id = iwl_find_station(priv, addr);
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
-				   addr);
-		return;
-	}
-
-	if (iwl_scan_cancel(priv)) {
-		/* cancel scan failed, just live w/ bad key and rely
-		   briefly on SW decryption */
-		return;
-	}
-
-	key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
-	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-	key_flags &= ~STA_KEY_FLG_INVALID;
-
-	if (sta_id == priv->hw_params.bcast_sta_id)
-		key_flags |= STA_KEY_MULTICAST_MSK;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-
-	priv->stations[sta_id].sta.key.key_flags = key_flags;
-	priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
-
-	for (i = 0; i < 5; i++)
-		priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
-			cpu_to_le16(phase1key[i]);
-
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
-	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key);
 
 	IWL_DEBUG_MAC80211("leave\n");
 }
@@ -3239,10 +3207,10 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
 		IWL_DEBUG_HT("start Rx\n");
-		return iwl_rx_agg_start(priv, sta->addr, tid, *ssn);
+		return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn);
 	case IEEE80211_AMPDU_RX_STOP:
 		IWL_DEBUG_HT("stop Rx\n");
-		return iwl_rx_agg_stop(priv, sta->addr, tid);
+		return iwl_sta_rx_agg_stop(priv, sta->addr, tid);
 	case IEEE80211_AMPDU_TX_START:
 		IWL_DEBUG_HT("start Tx\n");
 		return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
@@ -3256,6 +3224,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 	}
 	return 0;
 }
+
 static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 				struct ieee80211_tx_queue_stats *stats)
 {
@@ -3694,7 +3663,8 @@ static ssize_t show_power_level(struct device *d,
 		break;
 	}
 
-	p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto");
+	p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
+			"fixed" : "auto");
 	p += sprintf(p, "\tINDEX:%d", level);
 	p += sprintf(p, "\n");
 	return p - buf + 1;
@@ -3832,7 +3802,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
 	INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
 	INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
-	INIT_WORK(&priv->set_monitor, iwl_bg_set_monitor);
 	INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);

+ 4 - 22
drivers/net/wireless/iwlwifi/iwl-core.c

@@ -37,6 +37,7 @@
 #include "iwl-io.h"
 #include "iwl-rfkill.h"
 #include "iwl-power.h"
+#include "iwl-sta.h"
 
 
 MODULE_DESCRIPTION("iwl core");
@@ -237,28 +238,6 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_hw_nic_init);
 
-/**
- * iwl_clear_stations_table - Clear the driver's station table
- *
- * NOTE:  This does not clear or otherwise alter the device's station table.
- */
-void iwl_clear_stations_table(struct iwl_priv *priv)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-
-	if (iwl_is_alive(priv) &&
-	   !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
-	   iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
-		IWL_ERROR("Couldn't clear the station table\n");
-
-	priv->num_stations = 0;
-	memset(priv->stations, 0, sizeof(priv->stations));
-
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-EXPORT_SYMBOL(iwl_clear_stations_table);
 
 void iwl_reset_qos(struct iwl_priv *priv)
 {
@@ -832,6 +811,9 @@ int iwl_setup_mac(struct iwl_priv *priv)
 		BIT(NL80211_IFTYPE_AP) |
 		BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC);
+
+	hw->wiphy->fw_handles_regulatory = true;
+
 	/* Default value; 4 EDCA QOS priorities */
 	hw->queues = 4;
 	/* queues to support 11n aggregation */

+ 0 - 3
drivers/net/wireless/iwlwifi/iwl-core.h

@@ -182,7 +182,6 @@ struct iwl_cfg {
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
 		struct ieee80211_ops *hw_ops);
 void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_clear_stations_table(struct iwl_priv *priv);
 void iwl_reset_qos(struct iwl_priv *priv);
 void iwl_set_rxon_chain(struct iwl_priv *priv);
 int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
@@ -206,8 +205,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
 void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 void iwl_rx_replenish(struct iwl_priv *priv);
 int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn);
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
 int iwl_rx_queue_restock(struct iwl_priv *priv);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
 void iwl_rx_allocate(struct iwl_priv *priv);

+ 1 - 6
drivers/net/wireless/iwlwifi/iwl-dev.h

@@ -574,11 +574,6 @@ struct iwl_hw_params {
  * iwl4965_mac_     <-- mac80211 callback
  *
  ****************************************************************************/
-struct iwl_addsta_cmd;
-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 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];
@@ -700,6 +695,7 @@ enum iwl_calib {
 	IWL_CALIB_LO,
 	IWL_CALIB_TX_IQ,
 	IWL_CALIB_TX_IQ_PERD,
+	IWL_CALIB_BASE_BAND,
 	IWL_CALIB_MAX
 };
 
@@ -990,7 +986,6 @@ struct iwl_priv {
 	struct work_struct report_work;
 	struct work_struct request_scan;
 	struct work_struct beacon_update;
-	struct work_struct set_monitor;
 
 	struct tasklet_struct irq_tasklet;
 

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

@@ -72,7 +72,7 @@
  * Addresses are offsets from device's PCI hardware base address.
  */
 #define FH_MEM_LOWER_BOUND                   (0x1000)
-#define FH_MEM_UPPER_BOUND                   (0x1EF0)
+#define FH_MEM_UPPER_BOUND                   (0x2000)
 
 /**
  * Keep-Warm (KW) buffer base address.
@@ -268,6 +268,8 @@
 
 #define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME	(0x00008000)
 
+#define FH_RSCSR_FRAME_SIZE_MSK	(0x00003FFF)	/* bits 0-13 */
+
 
 /**
  * Rx Shared Status Registers (RSSR)
@@ -294,6 +296,13 @@
 
 #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT	28
 
+/* TFDB  Area - TFDs buffer table */
+#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
+#define FH_TFDIB_LOWER_BOUND       (FH_MEM_LOWER_BOUND + 0x900)
+#define FH_TFDIB_UPPER_BOUND       (FH_MEM_LOWER_BOUND + 0x958)
+#define FH_TFDIB_CTRL0_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
+#define FH_TFDIB_CTRL1_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
+
 /**
  * Transmit DMA Channel Control/Status Registers (TCSR)
  *
@@ -323,6 +332,7 @@
 #define FH49_TCSR_CHNL_NUM                            (7)
 #define FH50_TCSR_CHNL_NUM                            (8)
 
+/* TCSR: tx_config register values */
 #define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl)	\
 		(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
 #define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl)	\
@@ -379,31 +389,18 @@
 	(FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
 	FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
 
-
-
-#define FH_REGS_LOWER_BOUND		     (0x1000)
-#define FH_REGS_UPPER_BOUND		     (0x2000)
-
 /* Tx service channels */
-#define FH_SRVC_CHNL                                (9)
-#define FH_SRVC_LOWER_BOUND          (FH_REGS_LOWER_BOUND + 0x9C8)
-#define FH_SRVC_UPPER_BOUND          (FH_REGS_LOWER_BOUND + 0x9D0)
+#define FH_SRVC_CHNL		(9)
+#define FH_SRVC_LOWER_BOUND	(FH_MEM_LOWER_BOUND + 0x9C8)
+#define FH_SRVC_UPPER_BOUND	(FH_MEM_LOWER_BOUND + 0x9D0)
 #define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
 		(FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
 
-/* TFDB  Area - TFDs buffer table */
-#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
-#define FH_TFDIB_LOWER_BOUND       (FH_REGS_LOWER_BOUND + 0x900)
-#define FH_TFDIB_UPPER_BOUND       (FH_REGS_LOWER_BOUND + 0x958)
-#define FH_TFDIB_CTRL0_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
-#define FH_TFDIB_CTRL1_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
-
-/* TCSR: tx_config register values */
-#define FH_RSCSR_FRAME_SIZE_MSK	(0x00003FFF)	/* bits 0-13 */
-
-#define TFD_QUEUE_SIZE_MAX      (256)
-#define TFD_QUEUE_SIZE_BC_DUP	(64)
-#define TFD_QUEUE_BC_SIZE	(TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
+#define FH_TX_CHICKEN_BITS_REG	(FH_MEM_LOWER_BOUND + 0xE98)
+/* Instruct FH to increment the retry count of a packet when
+ * it is brought from the memory to TX-FIFO
+ */
+#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN	(0x00000002)
 
 /**
  * struct iwl_rb_status - reseve buffer status
@@ -423,9 +420,10 @@ struct iwl_rb_status {
 } __attribute__ ((packed));
 
 
-
+#define TFD_QUEUE_SIZE_MAX      (256)
+#define TFD_QUEUE_SIZE_BC_DUP	(64)
+#define TFD_QUEUE_BC_SIZE	(TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
 #define IWL_TX_DMA_MASK        DMA_BIT_MASK(36)
-
 #define IWL_NUM_OF_TBS		20
 
 static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
@@ -440,7 +438,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
  * @lo: low [31:0] portion of the dma address of TX buffer
  * 	every even is unaligned on 16 bit boundary
  * @hi_n_len 0-3 [35:32] portion of dma
- *	     4-16 length of the tx buffer
+ *	     4-15 length of the tx buffer
  */
 struct iwl_tfd_tb {
 	__le32 lo;
@@ -453,7 +451,8 @@ struct iwl_tfd_tb {
  * Transmit Frame Descriptor (TFD)
  *
  * @ __reserved1[3] reserved
- * @ num_tbs 0-5 number of active tbs
+ * @ num_tbs 0-4 number of active tbs
+ *	     5   reserved
  * 	     6-7 padding (not used)
  * @ tbs[20]	transmit frame buffer descriptors
  * @ __pad 	padding
@@ -473,8 +472,6 @@ struct iwl_tfd_tb {
  * Tx frame, up to 8 KBytes in size.
  *
  * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
- *
- * Bit fields in the control dword (val0):
  */
 struct iwl_tfd {
 	u8 __reserved1[3];
@@ -485,6 +482,6 @@ struct iwl_tfd {
 
 
 /* Keep Warm Size */
-#define IWL_KW_SIZE 0x1000	/*4k */
+#define IWL_KW_SIZE 0x1000	/* 4k */
 
 #endif /* !__iwl_fh_h__ */

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

@@ -36,7 +36,7 @@
 #include "iwl-core.h"
 
 
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
 
 const char *get_cmd_string(u8 cmd)
 {

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

@@ -109,7 +109,7 @@ static inline int __iwl_poll_bit(const char *f, u32 l,
 	int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout);
 	IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
 		     addr, bits, mask,
-		     unlikely(ret  == -ETIMEDOUT)?"timeout":"", f, l);
+		     unlikely(ret  == -ETIMEDOUT) ? "timeout" : "", f, l);
 	return ret;
 }
 #define iwl_poll_bit(priv, addr, bits, mask, timeout) \

+ 0 - 75
drivers/net/wireless/iwlwifi/iwl-rx.c

@@ -499,49 +499,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
 
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn)
-{
-	unsigned long flags;
-	int sta_id;
-
-	sta_id = iwl_find_station(priv, addr);
-	if (sta_id == IWL_INVALID_STATION)
-		return -ENXIO;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	priv->stations[sta_id].sta.station_flags_msk = 0;
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
-	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
-	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-					CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_start);
-
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
-{
-	unsigned long flags;
-	int sta_id;
-
-	sta_id = iwl_find_station(priv, addr);
-	if (sta_id == IWL_INVALID_STATION)
-		return -ENXIO;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	priv->stations[sta_id].sta.station_flags_msk = 0;
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
-	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-					CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_stop);
-
 
 /* Calculate noise level, based on measurements during network silence just
  *   before arriving beacon.  This measurement can be done only if we know
@@ -1017,38 +974,6 @@ static inline int iwl_calc_rssi(struct iwl_priv *priv,
 }
 
 
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
-	priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
-	priv->stations[sta_id].sta.sta.modify_mask = 0;
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
-{
-	/* FIXME: need locking over ps_status ??? */
-	u8 sta_id = iwl_find_station(priv, addr);
-
-	if (sta_id != IWL_INVALID_STATION) {
-		u8 sta_awake = priv->stations[sta_id].
-				ps_status == STA_PS_STATUS_WAKE;
-
-		if (sta_awake && ps_bit)
-			priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
-		else if (!sta_awake && !ps_bit) {
-			iwl_sta_modify_ps_wake(priv, sta_id);
-			priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
-		}
-	}
-}
-
 /* This is necessary only for a number of statistics, see the caller. */
 static int iwl_is_network_packet(struct iwl_priv *priv,
 		struct ieee80211_hdr *header)

+ 152 - 5
drivers/net/wireless/iwlwifi/iwl-sta.c

@@ -132,7 +132,7 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
 	return 1;
 }
 
-int iwl_send_add_sta(struct iwl_priv *priv,
+static int iwl_send_add_sta(struct iwl_priv *priv,
 		     struct iwl_addsta_cmd *sta, u8 flags)
 {
 	struct iwl_rx_packet *res = NULL;
@@ -180,7 +180,6 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 
 	return ret;
 }
-EXPORT_SYMBOL(iwl_send_add_sta);
 
 static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
 				   struct ieee80211_sta_ht_cap *sta_ht_inf)
@@ -464,6 +463,29 @@ out:
 }
 EXPORT_SYMBOL(iwl_remove_station);
 
+/**
+ * iwl_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
+void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	if (iwl_is_alive(priv) &&
+	   !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
+	   iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
+		IWL_ERROR("Couldn't clear the station table\n");
+
+	priv->num_stations = 0;
+	memset(priv->stations, 0, sizeof(priv->stations));
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+EXPORT_SYMBOL(iwl_clear_stations_table);
+
 static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
 	int i;
@@ -703,6 +725,55 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
 	return ret;
 }
 
+void iwl_update_tkip_key(struct iwl_priv *priv,
+			struct ieee80211_key_conf *keyconf,
+			const u8 *addr, u32 iv32, u16 *phase1key)
+{
+	u8 sta_id = IWL_INVALID_STATION;
+	unsigned long flags;
+	__le16 key_flags = 0;
+	int i;
+	DECLARE_MAC_BUF(mac);
+
+	sta_id = iwl_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+				   addr);
+		return;
+	}
+
+	if (iwl_scan_cancel(priv)) {
+		/* cancel scan failed, just live w/ bad key and rely
+		   briefly on SW decryption */
+		return;
+	}
+
+	key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
+	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+	key_flags &= ~STA_KEY_FLG_INVALID;
+
+	if (sta_id == priv->hw_params.bcast_sta_id)
+		key_flags |= STA_KEY_MULTICAST_MSK;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	priv->stations[sta_id].sta.key.key_flags = key_flags;
+	priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
+
+	for (i = 0; i < 5; i++)
+		priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
+			cpu_to_le16(phase1key[i]);
+
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+}
+EXPORT_SYMBOL(iwl_update_tkip_key);
+
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
 				struct ieee80211_key_conf *keyconf,
 				u8 sta_id)
@@ -989,9 +1060,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 EXPORT_SYMBOL(iwl_get_sta_id);
 
 /**
- * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
  */
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
+void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 {
 	unsigned long flags;
 
@@ -1004,5 +1075,81 @@ void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
 
 	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
-EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx);
+EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
+
+int iwl_sta_rx_agg_start(struct iwl_priv *priv,
+			 const u8 *addr, int tid, u16 ssn)
+{
+	unsigned long flags;
+	int sta_id;
+
+	sta_id = iwl_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+					CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_start);
+
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
+{
+	unsigned long flags;
+	int sta_id;
+
+	sta_id = iwl_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+					CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+	priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+	priv->stations[sta_id].sta.sta.modify_mask = 0;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+{
+	/* FIXME: need locking over ps_status ??? */
+	u8 sta_id = iwl_find_station(priv, addr);
+
+	if (sta_id != IWL_INVALID_STATION) {
+		u8 sta_awake = priv->stations[sta_id].
+				ps_status == STA_PS_STATUS_WAKE;
+
+		if (sta_awake && ps_bit)
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+		else if (!sta_awake && !ps_bit) {
+			iwl_sta_modify_ps_wake(priv, sta_id);
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+		}
+	}
+}
 

+ 13 - 1
drivers/net/wireless/iwlwifi/iwl-sta.h

@@ -47,9 +47,21 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
 			struct ieee80211_key_conf *key, u8 sta_id);
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
 			   struct ieee80211_key_conf *key, u8 sta_id);
+void iwl_update_tkip_key(struct iwl_priv *priv,
+			struct ieee80211_key_conf *keyconf,
+			const u8 *addr, u32 iv32, u16 *phase1key);
+
 int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
 int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+void iwl_clear_stations_table(struct iwl_priv *priv);
 int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid);
 int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
+u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
+			int is_ap, u8 flags,
+			struct ieee80211_sta_ht_cap *ht_info);
+void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int iwl_sta_rx_agg_start(struct iwl_priv *priv,
+			 const u8 *addr, int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr);
 #endif /* __iwl_sta_h__ */

+ 1 - 10
drivers/net/wireless/iwlwifi/iwl-tx.c

@@ -449,11 +449,6 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 	iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
 			     txq->q.dma_addr >> 8);
 
-	/* 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);
-
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -587,8 +582,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-
-
 	/* Alloc and init all Tx queues, including the command queue (#4) */
 	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
 		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
@@ -618,11 +611,9 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
  */
 void iwl_txq_ctx_stop(struct iwl_priv *priv)
 {
-
 	int txq_id;
 	unsigned long flags;
 
-
 	/* Turn off all Tx DMA fifos */
 	spin_lock_irqsave(&priv->lock, flags);
 	if (iwl_grab_nic_access(priv)) {
@@ -1498,7 +1489,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
 		ack = bitmap & (1ULL << i);
 		successes += !!ack;
 		IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
-			ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
+			ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
 			agg->start_idx + i);
 	}
 

+ 159 - 113
drivers/net/wireless/iwlwifi/iwl3945-base.c

@@ -519,7 +519,7 @@ static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
 
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
 
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
 
 static const char *get_cmd_string(u8 cmd)
 {
@@ -1425,9 +1425,9 @@ static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv)
 
 	/* Set rate mask*/
 	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
-		rate_mask = priv->active_rate_basic & 0xF;
+		rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
 	else
-		rate_mask = priv->active_rate_basic & 0xFF0;
+		rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
 
 	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
 	     i = iwl3945_rates[i].next_ieee) {
@@ -4320,7 +4320,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
 
 		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
 				"RF_KILL bit toggled to %s.\n",
-				hw_rf_kill ? "disable radio":"enable radio");
+				hw_rf_kill ? "disable radio" : "enable radio");
 
 		/* Queue restart only if RF_KILL switch was set to "kill"
 		 *   when we loaded driver, and is now set to "enable".
@@ -5996,24 +5996,6 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
 	iwl3945_rfkill_set_hw_state(priv);
 }
 
-static void iwl3945_bg_set_monitor(struct work_struct *work)
-{
-	struct iwl3945_priv *priv = container_of(work,
-				struct iwl3945_priv, set_monitor);
-
-	IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
-	mutex_lock(&priv->mutex);
-
-	if (!iwl3945_is_ready(priv))
-		IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
-	else
-		if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0)
-			IWL_ERROR("iwl3945_set_mode() failed\n");
-
-	mutex_unlock(&priv->mutex);
-}
-
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
 static void iwl3945_bg_scan_check(struct work_struct *data)
@@ -6339,10 +6321,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
 
 	case NL80211_IFTYPE_ADHOC:
 
-		/* clear out the station table */
-		iwl3945_clear_stations_table(priv);
-
-		iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
+		priv->assoc_id = 1;
 		iwl3945_add_station(priv, priv->bssid, 0, 0);
 		iwl3945_sync_sta(priv, IWL_STA_ID,
 				 (priv->band == IEEE80211_BAND_5GHZ) ?
@@ -6830,16 +6809,43 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
 				 int mc_count, struct dev_addr_list *mc_list)
 {
 	struct iwl3945_priv *priv = hw->priv;
+	__le32 *filter_flags = &priv->staging_rxon.filter_flags;
+
+	IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+			changed_flags, *total_flags);
 
-	if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
-		IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
-				   NL80211_IFTYPE_MONITOR,
-				   changed_flags, *total_flags);
-		/* queue work 'cuz mac80211 is holding a lock which
-		 * prevents us from issuing (synchronous) f/w cmds */
-		queue_work(priv->workqueue, &priv->set_monitor);
+	if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+		if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+			*filter_flags |= RXON_FILTER_PROMISC_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_PROMISC_MSK;
+	}
+	if (changed_flags & FIF_ALLMULTI) {
+		if (*total_flags & FIF_ALLMULTI)
+			*filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
 	}
-	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+	if (changed_flags & FIF_CONTROL) {
+		if (*total_flags & FIF_CONTROL)
+			*filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
+	}
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+			*filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
+	}
+
+	/* We avoid iwl_commit_rxon here to commit the new filter flags
+	 * since mac80211 will call ieee80211_hw_config immediately.
+	 * (mc_list is not supported at this time). Otherwise, we need to
+	 * queue a background iwl_commit_rxon work.
+	 */
+
+	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
 			FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
@@ -7715,7 +7721,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
 	INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
 	INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
 	INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
-	INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
 	INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
@@ -7787,6 +7792,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 	struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
 	unsigned long flags;
 
+	/***********************
+	 * 1. Allocating HW data
+	 * ********************/
+
 	/* Disabling hardware scan means that mac80211 will perform scans
 	 * "the hard way", rather than using device's scan. */
 	if (iwl3945_param_disable_hw_scan) {
@@ -7810,27 +7819,24 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 		err = -ENOMEM;
 		goto out;
 	}
-	SET_IEEE80211_DEV(hw, &pdev->dev);
 
-	hw->rate_control_algorithm = "iwl-3945-rs";
-	hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+	SET_IEEE80211_DEV(hw, &pdev->dev);
 
-	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
 	priv = hw->priv;
 	priv->hw = hw;
-
 	priv->pci_dev = pdev;
 	priv->cfg = cfg;
 
+	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+	hw->rate_control_algorithm = "iwl-3945-rs";
+	hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+
 	/* Select antenna (may be helpful if only one antenna is connected) */
 	priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
 #ifdef CONFIG_IWL3945_DEBUG
 	iwl3945_debug_level = iwl3945_param_debug;
 	atomic_set(&priv->restrict_refcnt, 0);
 #endif
-	priv->retry_rate = 1;
-
-	priv->ibss_beacon = NULL;
 
 	/* Tell mac80211 our characteristics */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
@@ -7841,17 +7847,14 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 		BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC);
 
+	hw->wiphy->fw_handles_regulatory = true;
+
 	/* 4 EDCA QOS priorities */
 	hw->queues = 4;
 
-	spin_lock_init(&priv->lock);
-	spin_lock_init(&priv->power_data.lock);
-	spin_lock_init(&priv->sta_lock);
-	spin_lock_init(&priv->hcmd_lock);
-
-	INIT_LIST_HEAD(&priv->free_frames);
-
-	mutex_init(&priv->mutex);
+	/***************************
+	 * 2. Initializing PCI bus
+	 * *************************/
 	if (pci_enable_device(pdev)) {
 		err = -ENODEV;
 		goto out_ieee80211_free_hw;
@@ -7859,14 +7862,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
 	pci_set_master(pdev);
 
-	/* Clear the driver's (not device's) station table */
-	iwl3945_clear_stations_table(priv);
-
-	priv->data_retry_limit = -1;
-	priv->ieee_channels = NULL;
-	priv->ieee_rates = NULL;
-	priv->band = IEEE80211_BAND_2GHZ;
-
 	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 	if (!err)
 		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
@@ -7880,10 +7875,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 	if (err)
 		goto out_pci_disable_device;
 
-	/* We disable the RETRY_TIMEOUT register (0x41) to keep
-	 * PCI Tx retries from interfering with C3 CPU state */
-	pci_write_config_byte(pdev, 0x41, 0x00);
-
+	/***********************
+	 * 3. Read REV Register
+	 * ********************/
 	priv->hw_base = pci_iomap(pdev, 0, 0);
 	if (!priv->hw_base) {
 		err = -ENODEV;
@@ -7894,25 +7888,70 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 			(unsigned long long) pci_resource_len(pdev, 0));
 	IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
 
-	/* Initialize module parameter values here */
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, 0x41, 0x00);
 
-	/* Disable radio (SW RF KILL) via parameter when loading driver */
-	if (iwl3945_param_disable) {
-		set_bit(STATUS_RF_KILL_SW, &priv->status);
-		IWL_DEBUG_INFO("Radio disabled.\n");
-	}
+	/* nic init */
+	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+			CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
 
-	priv->iw_mode = NL80211_IFTYPE_STATION;
+	iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	if (err < 0) {
+		IWL_DEBUG_INFO("Failed to init the card\n");
+		goto out_remove_sysfs;
+	}
 
-	printk(KERN_INFO DRV_NAME
-		": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+	/***********************
+	 * 4. Read EEPROM
+	 * ********************/
+	/* Read the EEPROM */
+	err = iwl3945_eeprom_init(priv);
+	if (err) {
+		IWL_ERROR("Unable to init EEPROM\n");
+		goto out_remove_sysfs;
+	}
+	/* MAC Address location in EEPROM same for 3945/4965 */
+	get_eeprom_mac(priv, priv->mac_addr);
+	IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
+	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
+	/***********************
+	 * 5. Setup HW Constants
+	 * ********************/
 	/* Device-specific setup */
 	if (iwl3945_hw_set_hw_setting(priv)) {
 		IWL_ERROR("failed to set hw settings\n");
 		goto out_iounmap;
 	}
 
+	/***********************
+	 * 6. Setup priv
+	 * ********************/
+	priv->retry_rate = 1;
+	priv->ibss_beacon = NULL;
+
+	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->power_data.lock);
+	spin_lock_init(&priv->sta_lock);
+	spin_lock_init(&priv->hcmd_lock);
+
+	INIT_LIST_HEAD(&priv->free_frames);
+	mutex_init(&priv->mutex);
+
+	/* Clear the driver's (not device's) station table */
+	iwl3945_clear_stations_table(priv);
+
+	priv->data_retry_limit = -1;
+	priv->ieee_channels = NULL;
+	priv->ieee_rates = NULL;
+	priv->band = IEEE80211_BAND_2GHZ;
+
+	priv->iw_mode = NL80211_IFTYPE_STATION;
+
 	if (iwl3945_param_qos_enable)
 		priv->qos_data.qos_enable = 1;
 
@@ -7921,70 +7960,76 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 	priv->qos_data.qos_active = 0;
 	priv->qos_data.qos_cap.val = 0;
 
-	iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
-	iwl3945_setup_deferred_work(priv);
-	iwl3945_setup_rx_handlers(priv);
 
 	priv->rates_mask = IWL_RATES_MASK;
 	/* If power management is turned on, default to AC mode */
 	priv->power_mode = IWL_POWER_AC;
 	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
 
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl3945_disable_interrupts(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+	err = iwl3945_init_channel_map(priv);
 	if (err) {
-		IWL_ERROR("failed to create sysfs device attributes\n");
+		IWL_ERROR("initializing regulatory failed: %d\n", err);
 		goto out_release_irq;
 	}
 
-	/* nic init */
-	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-			CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
-	iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
-			       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-	if (err < 0) {
-		IWL_DEBUG_INFO("Failed to init the card\n");
-		goto out_remove_sysfs;
-	}
-	/* Read the EEPROM */
-	err = iwl3945_eeprom_init(priv);
+	err = iwl3945_init_geos(priv);
 	if (err) {
-		IWL_ERROR("Unable to init EEPROM\n");
-		goto out_remove_sysfs;
+		IWL_ERROR("initializing geos failed: %d\n", err);
+		goto out_free_channel_map;
 	}
-	/* MAC Address location in EEPROM same for 3945/4965 */
-	get_eeprom_mac(priv, priv->mac_addr);
-	IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
-	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
-	err = iwl3945_init_channel_map(priv);
-	if (err) {
-		IWL_ERROR("initializing regulatory failed: %d\n", err);
-		goto out_remove_sysfs;
+	printk(KERN_INFO DRV_NAME
+		": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+
+	/***********************************
+	 * 7. Initialize Module Parameters
+	 * **********************************/
+
+	/* Initialize module parameter values here */
+	/* Disable radio (SW RF KILL) via parameter when loading driver */
+	if (iwl3945_param_disable) {
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+		IWL_DEBUG_INFO("Radio disabled.\n");
 	}
 
-	err = iwl3945_init_geos(priv);
+
+	/***********************
+	 * 8. Setup Services
+	 * ********************/
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl3945_disable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 	if (err) {
-		IWL_ERROR("initializing geos failed: %d\n", err);
-		goto out_free_channel_map;
+		IWL_ERROR("failed to create sysfs device attributes\n");
+		goto out_free_geos;
 	}
 
+	iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+	iwl3945_setup_deferred_work(priv);
+	iwl3945_setup_rx_handlers(priv);
+
+	/***********************
+	 * 9. Conclude
+	 * ********************/
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+
+	/*********************************
+	 * 10. Setup and Register mac80211
+	 * *******************************/
+
 	err = ieee80211_register_hw(priv->hw);
 	if (err) {
 		IWL_ERROR("Failed to register network device (error %d)\n", err);
-		goto out_free_geos;
+		goto  out_remove_sysfs;
 	}
 
 	priv->hw->conf.beacon_int = 100;
 	priv->mac80211_registered = 1;
-	pci_save_state(pdev);
-	pci_disable_device(pdev);
+
 
 	err = iwl3945_rfkill_init(priv);
 	if (err)
@@ -7993,12 +8038,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
 	return 0;
 
+ out_remove_sysfs:
+	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
  out_free_geos:
 	iwl3945_free_geos(priv);
  out_free_channel_map:
 	iwl3945_free_channel_map(priv);
- out_remove_sysfs:
-	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+
 
  out_release_irq:
 	destroy_workqueue(priv->workqueue);

+ 6 - 8
drivers/net/wireless/mac80211_hwsim.c

@@ -452,9 +452,9 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
 	hwsim_check_magic(vif);
 	if (conf->changed & IEEE80211_IFCC_BSSID) {
 		DECLARE_MAC_BUF(mac);
-		printk(KERN_DEBUG "%s:%s: BSSID changed: %s\n",
+		printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n",
 		       wiphy_name(hw->wiphy), __func__,
-		       print_mac(mac, conf->bssid));
+		       conf->bssid);
 		memcpy(vp->bssid, conf->bssid, ETH_ALEN);
 	}
 	return 0;
@@ -612,9 +612,8 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
 	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);
+	printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n",
+	       wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid);
 
 	skb = dev_alloc_skb(sizeof(*pspoll));
 	if (!skb)
@@ -644,9 +643,8 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
 	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);
+	printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n",
+	       wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps);
 
 	skb = dev_alloc_skb(sizeof(*hdr));
 	if (!skb)

+ 129 - 31
drivers/net/wireless/orinoco/orinoco.c

@@ -84,6 +84,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/firmware.h>
+#include <linux/suspend.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
@@ -431,9 +432,9 @@ struct fw_info {
 };
 
 const static struct fw_info orinoco_fw[] = {
-	{ "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
-	{ "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
-	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
+	{ NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+	{ NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
 };
 
 /* Structure used to access fields in FW
@@ -487,18 +488,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 	if (err)
 		goto free;
 
-	if (priv->cached_fw)
-		fw_entry = priv->cached_fw;
-	else {
+	if (!priv->cached_fw) {
 		err = request_firmware(&fw_entry, firmware, priv->dev);
+
 		if (err) {
 			printk(KERN_ERR "%s: Cannot find firmware %s\n",
 			       dev->name, firmware);
 			err = -ENOENT;
 			goto free;
 		}
-		priv->cached_fw = fw_entry;
-	}
+	} else
+		fw_entry = priv->cached_fw;
 
 	hdr = (const struct orinoco_fw_header *) fw_entry->data;
 
@@ -540,11 +540,9 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 	       dev->name, hermes_present(hw));
 
 abort:
-	/* In case of error, assume firmware was bogus and release it */
-	if (err) {
-		priv->cached_fw = NULL;
+	/* If we requested the firmware, release it. */
+	if (!priv->cached_fw)
 		release_firmware(fw_entry);
-	}
 
 free:
 	kfree(pda);
@@ -648,34 +646,41 @@ symbol_dl_firmware(struct orinoco_private *priv,
 	int ret;
 	const struct firmware *fw_entry;
 
-	if (request_firmware(&fw_entry, fw->pri_fw,
-			     priv->dev) != 0) {
-		printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-		       dev->name, fw->pri_fw);
-		return -ENOENT;
-	}
+	if (!priv->cached_pri_fw) {
+		if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
+			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+			       dev->name, fw->pri_fw);
+			return -ENOENT;
+		}
+	} else
+		fw_entry = priv->cached_pri_fw;
 
 	/* Load primary firmware */
 	ret = symbol_dl_image(priv, fw, fw_entry->data,
 			      fw_entry->data + fw_entry->size, 0);
-	release_firmware(fw_entry);
+
+	if (!priv->cached_pri_fw)
+		release_firmware(fw_entry);
 	if (ret) {
 		printk(KERN_ERR "%s: Primary firmware download failed\n",
 		       dev->name);
 		return ret;
 	}
 
-	if (request_firmware(&fw_entry, fw->sta_fw,
-			     priv->dev) != 0) {
-		printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-		       dev->name, fw->sta_fw);
-		return -ENOENT;
-	}
+	if (!priv->cached_fw) {
+		if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
+			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+			       dev->name, fw->sta_fw);
+			return -ENOENT;
+		}
+	} else
+		fw_entry = priv->cached_fw;
 
 	/* Load secondary firmware */
 	ret = symbol_dl_image(priv, fw, fw_entry->data,
 			      fw_entry->data + fw_entry->size, 1);
-	release_firmware(fw_entry);
+	if (!priv->cached_fw)
+		release_firmware(fw_entry);
 	if (ret) {
 		printk(KERN_ERR "%s: Secondary firmware download failed\n",
 		       dev->name);
@@ -708,6 +713,45 @@ static int orinoco_download(struct orinoco_private *priv)
 	return err;
 }
 
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
+static void orinoco_cache_fw(struct orinoco_private *priv, int ap)
+{
+	const struct firmware *fw_entry = NULL;
+	const char *pri_fw;
+	const char *fw;
+
+	pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
+	if (ap)
+		fw = orinoco_fw[priv->firmware_type].ap_fw;
+	else
+		fw = orinoco_fw[priv->firmware_type].sta_fw;
+
+	if (pri_fw) {
+		if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
+			priv->cached_pri_fw = fw_entry;
+	}
+
+	if (fw) {
+		if (request_firmware(&fw_entry, fw, priv->dev) == 0)
+			priv->cached_fw = fw_entry;
+	}
+}
+
+static void orinoco_uncache_fw(struct orinoco_private *priv)
+{
+	if (priv->cached_pri_fw)
+		release_firmware(priv->cached_pri_fw);
+	if (priv->cached_fw)
+		release_firmware(priv->cached_fw);
+
+	priv->cached_pri_fw = NULL;
+	priv->cached_fw = NULL;
+}
+#else
+#define orinoco_cache_fw(priv, ap)
+#define orinoco_uncache_fw(priv)
+#endif
+
 /********************************************************************/
 /* Device methods                                                   */
 /********************************************************************/
@@ -809,7 +853,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
 			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
 			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
-			wstats->qual.updated = 7;
+			wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 		}
 	}
 
@@ -1168,7 +1212,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
 	wstats.level = level - 0x95;
 	wstats.noise = noise - 0x95;
 	wstats.qual = (level > noise) ? (level - noise) : 0;
-	wstats.updated = 7;
+	wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 	/* Update spy records */
 	wireless_spy_update(dev, mac, &wstats);
 }
@@ -3061,6 +3105,50 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/********************************************************************/
+/* Power management                                                 */
+/********************************************************************/
+#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
+static int orinoco_pm_notifier(struct notifier_block *notifier,
+			       unsigned long pm_event,
+			       void *unused)
+{
+	struct orinoco_private *priv = container_of(notifier,
+						    struct orinoco_private,
+						    pm_notifier);
+
+	/* All we need to do is cache the firmware before suspend, and
+	 * release it when we come out.
+	 *
+	 * Only need to do this if we're downloading firmware. */
+	if (!priv->do_fw_download)
+		return NOTIFY_DONE;
+
+	switch (pm_event) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		orinoco_cache_fw(priv, 0);
+		break;
+
+	case PM_POST_RESTORE:
+		/* Restore from hibernation failed. We need to clean
+		 * up in exactly the same way, so fall through. */
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		orinoco_uncache_fw(priv);
+		break;
+
+	case PM_RESTORE_PREPARE:
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
+#define orinoco_pm_notifier NULL
+#endif
+
 /********************************************************************/
 /* Initialization                                                   */
 /********************************************************************/
@@ -3304,6 +3392,10 @@ static int orinoco_init(struct net_device *dev)
 	}
 
 	if (priv->do_fw_download) {
+#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
+		orinoco_cache_fw(priv, 0);
+#endif
+
 		err = orinoco_download(priv);
 		if (err)
 			priv->do_fw_download = 0;
@@ -3540,8 +3632,13 @@ struct net_device
 	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
 
+	priv->cached_pri_fw = NULL;
 	priv->cached_fw = NULL;
 
+	/* Register PM notifiers */
+	priv->pm_notifier.notifier_call = orinoco_pm_notifier;
+	register_pm_notifier(&priv->pm_notifier);
+
 	return dev;
 }
 
@@ -3553,9 +3650,10 @@ void free_orinocodev(struct net_device *dev)
 	 * when we call tasklet_kill it will run one final time,
 	 * emptying the list */
 	tasklet_kill(&priv->rx_tasklet);
-	if (priv->cached_fw)
-		release_firmware(priv->cached_fw);
-	priv->cached_fw = NULL;
+
+	unregister_pm_notifier(&priv->pm_notifier);
+	orinoco_uncache_fw(priv);
+
 	priv->wpa_ie_len = 0;
 	kfree(priv->wpa_ie);
 	orinoco_mic_free(priv);

+ 5 - 1
drivers/net/wireless/orinoco/orinoco.h

@@ -10,6 +10,7 @@
 #define DRIVER_VERSION "0.15"
 
 #include <linux/interrupt.h>
+#include <linux/suspend.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
@@ -167,8 +168,11 @@ struct orinoco_private {
 	unsigned int tkip_cm_active:1;
 	unsigned int key_mgmt:3;
 
-	/* Cached in memory firmware to use in ->resume */
+	/* Cached in memory firmware to use during ->resume. */
+	const struct firmware *cached_pri_fw;
 	const struct firmware *cached_fw;
+
+	struct notifier_block pm_notifier;
 };
 
 #ifdef ORINOCO_DEBUG

+ 20 - 1
drivers/net/wireless/orinoco/spectrum_cs.c

@@ -450,10 +450,29 @@ spectrum_cs_resume(struct pcmcia_device *link)
 {
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	int err;
+
+	err = orinoco_reinit_firmware(dev);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+		       dev->name, err);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
 
 	netif_device_attach(dev);
 	priv->hw_unavailable--;
-	schedule_work(&priv->reset_work);
+
+	if (priv->open && !priv->hw_unavailable) {
+		err = __orinoco_up(dev);
+		if (err)
+			printk(KERN_ERR "%s: Error %d restarting card\n",
+			       dev->name, err);
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }

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

@@ -102,6 +102,9 @@ struct p54_common {
 	unsigned int output_power;
 	u32 tsf_low32;
 	u32 tsf_high32;
+	u64 basic_rate_mask;
+	u16 wakeup_timer;
+	u16 aid;
 	struct ieee80211_tx_queue_stats tx_stats[8];
 	struct p54_edcf_queue_param qos_params[8];
 	struct ieee80211_low_level_stats stats;

+ 52 - 17
drivers/net/wireless/p54/p54common.c

@@ -530,6 +530,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 	rx_status.noise = priv->noise;
 	/* XX correct? */
 	rx_status.qual = (100 * hdr->rssi) / 127;
+	if (hdr->rate & 0x10)
+		rx_status.flag |= RX_FLAG_SHORTPRE;
 	rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
 			hdr->rate : (hdr->rate - 4)) & 0xf;
 	rx_status.freq = freq;
@@ -576,7 +578,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
 	unsigned long flags;
 	u32 freed = 0, last_addr = priv->rx_start;
 
-	if (!skb || !dev)
+	if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
 		return;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
@@ -1058,6 +1060,7 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
 		break;
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
 		if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
 			*aid = 0;
 			*queue = 3;
@@ -1198,7 +1201,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	txhdr->key_type = 0;
 	txhdr->key_len = 0;
 	txhdr->hw_queue = queue;
-	txhdr->backlog = 32;
+	if (current_queue)
+		txhdr->backlog = current_queue->len;
+	else
+		txhdr->backlog = 0;
 	memset(txhdr->durations, 0, sizeof(txhdr->durations));
 	txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
 		2 : info->antenna_sel_tx - 1;
@@ -1243,20 +1249,20 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid)
 	setup->rx_antenna = priv->rx_antenna;
 	setup->rx_align = 0;
 	if (priv->fw_var < 0x500) {
-		setup->v1.basic_rate_mask = cpu_to_le32(0x15f);
+		setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
 		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);
-		setup->v1.wakeup_timer = cpu_to_le16(500);
+		setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
 		setup->v1.unalloc0 = cpu_to_le16(0);
 	} else {
 		setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
 		setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
 		setup->v2.rxhw = cpu_to_le16(priv->rxhw);
-		setup->v2.timer = cpu_to_le16(1000);
+		setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
 		setup->v2.truncate = cpu_to_le16(48896);
-		setup->v2.basic_rate_mask = cpu_to_le32(0x15f);
+		setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
 		setup->v2.sbss_offset = 0;
 		setup->v2.mcast_window = 0;
 		setup->v2.rx_rssi_threshold = 0;
@@ -1342,7 +1348,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency)
 	} else {
 		chan->v2.rssical_mul = cpu_to_le16(130);
 		chan->v2.rssical_add = cpu_to_le16(0xfe70);
-		chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
+		chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
 		memset(chan->v2.rts_rates, 0, 8);
 	}
 	priv->tx(dev, skb, 1);
@@ -1518,16 +1524,24 @@ static int p54_start(struct ieee80211_hw *dev)
 
 	mutex_lock(&priv->conf_mutex);
 	err = priv->open(dev);
-	if (!err)
-		priv->mode = NL80211_IFTYPE_MONITOR;
+	if (err)
+		goto out;
 	P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
 	P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
 	P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
 	P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
 	err = p54_set_edcf(dev);
-	if (!err)
-		err = p54_init_stats(dev);
+	if (err)
+		goto out;
+	err = p54_init_stats(dev);
+	if (err)
+		goto out;
+	err = p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL);
+	if (err)
+		goto out;
+	priv->mode = NL80211_IFTYPE_MONITOR;
 
+out:
 	mutex_unlock(&priv->conf_mutex);
 	return err;
 }
@@ -1547,7 +1561,6 @@ static void p54_stop(struct ieee80211_hw *dev)
 	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;
@@ -1570,6 +1583,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_MESH_POINT:
 		priv->mode = conf->type;
 		break;
 	default:
@@ -1589,6 +1603,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 		p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr);
 		break;
 	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
 		p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL);
 		break;
 	default:
@@ -1653,6 +1668,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
 		break;
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 		ret = p54_set_freq(dev, dev->conf.channel->center_freq);
 		if (ret)
@@ -1712,10 +1728,9 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
 	if ((params) && !(queue > 4)) {
 		P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
 			params->cw_min, params->cw_max, params->txop);
+		ret = p54_set_edcf(dev);
 	} else
 		ret = -EINVAL;
-	if (!ret)
-		ret = p54_set_edcf(dev);
 	mutex_unlock(&priv->conf_mutex);
 	return ret;
 }
@@ -1792,6 +1807,24 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
 		priv->use_short_slot = info->use_short_slot;
 		p54_set_edcf(dev);
 	}
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+			priv->basic_rate_mask = (info->basic_rates << 4);
+		else
+			priv->basic_rate_mask = info->basic_rates;
+		p54_setup_mac(dev, priv->mac_mode, priv->bssid);
+		if (priv->fw_var >= 0x500)
+			p54_set_freq(dev, dev->conf.channel->center_freq);
+	}
+	if (changed & BSS_CHANGED_ASSOC) {
+		if (info->assoc) {
+			priv->aid = info->aid;
+			priv->wakeup_timer = info->beacon_int *
+					     info->dtim_period * 5;
+			p54_setup_mac(dev, priv->mac_mode, priv->bssid);
+		}
+	}
+
 }
 
 static const struct ieee80211_ops p54_ops = {
@@ -1821,14 +1854,16 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 
 	priv = dev->priv;
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+	priv->basic_rate_mask = 0x15f;
 	skb_queue_head_init(&priv->tx_queue);
 	dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		     IEEE80211_HW_SIGNAL_DBM |
 		     IEEE80211_HW_NOISE_DBM;
 
-	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION |
-					  NL80211_IFTYPE_ADHOC |
-					  NL80211_IFTYPE_AP);
+	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+				      BIT(NL80211_IFTYPE_ADHOC) |
+				      BIT(NL80211_IFTYPE_AP) |
+				      BIT(NL80211_IFTYPE_MESH_POINT);
 
 	dev->channel_change_time = 1000;	/* TODO: find actual value */
 	priv->tx_stats[0].limit = 1;		/* Beacon queue */

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

@@ -259,7 +259,7 @@ enum p54_rx_decrypt_status {
 	P54_DECRYPT_NOCKIPMIC,
 	P54_DECRYPT_FAIL_WEP,
 	P54_DECRYPT_FAIL_TKIP,
-	P54_DECRYPT_FAIL_MICAHEL,
+	P54_DECRYPT_FAIL_MICHAEL,
 	P54_DECRYPT_FAIL_CKIPKP,
 	P54_DECRYPT_FAIL_CKIPMIC,
 	P54_DECRYPT_FAIL_AESCCMP

+ 22 - 20
drivers/net/wireless/p54/p54pci.c

@@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table);
 static int p54p_upload_firmware(struct ieee80211_hw *dev)
 {
 	struct p54p_priv *priv = dev->priv;
-	const struct firmware *fw_entry = NULL;
 	__le32 reg;
 	int err;
 	__le32 *data;
@@ -73,23 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
 	P54P_WRITE(ctrl_stat, reg);
 	wmb();
 
-	err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev);
-	if (err) {
-		printk(KERN_ERR "%s (p54pci): cannot find firmware "
-		       "(isl3886pci)\n", pci_name(priv->pdev));
-		err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
-		if (err)
-			return err;
-	}
+	/* wait for the firmware to reset properly */
+	mdelay(10);
 
-	err = p54_parse_firmware(dev, fw_entry);
-	if (err) {
-		release_firmware(fw_entry);
+	err = p54_parse_firmware(dev, priv->firmware);
+	if (err)
 		return err;
-	}
 
-	data = (__le32 *) fw_entry->data;
-	remains = fw_entry->size;
+	data = (__le32 *) priv->firmware->data;
+	remains = priv->firmware->size;
 	device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
 	while (remains) {
 		u32 i = 0;
@@ -107,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
 		P54P_READ(int_enable);
 	}
 
-	release_firmware(fw_entry);
-
 	reg = P54P_READ(ctrl_stat);
 	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
 	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
@@ -500,15 +489,14 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 	if (mem_len < sizeof(struct p54p_csr)) {
 		printk(KERN_ERR "%s (p54pci): Too short PCI resources\n",
 		       pci_name(pdev));
-		pci_disable_device(pdev);
-		return err;
+		goto err_disable_dev;
 	}
 
 	err = pci_request_regions(pdev, "p54pci");
 	if (err) {
 		printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n",
 		       pci_name(pdev));
-		return err;
+		goto err_disable_dev;
 	}
 
 	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
@@ -561,6 +549,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 	spin_lock_init(&priv->lock);
 	tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
 
+	err = request_firmware(&priv->firmware, "isl3886pci",
+			       &priv->pdev->dev);
+	if (err) {
+		printk(KERN_ERR "%s (p54pci): cannot find firmware "
+			"(isl3886pci)\n", pci_name(priv->pdev));
+		err = request_firmware(&priv->firmware, "isl3886",
+				       &priv->pdev->dev);
+		if (err)
+			goto err_free_common;
+	}
+
 	err = p54p_open(dev);
 	if (err)
 		goto err_free_common;
@@ -579,6 +578,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 	return 0;
 
  err_free_common:
+	release_firmware(priv->firmware);
 	p54_free_common(dev);
 	pci_free_consistent(pdev, sizeof(*priv->ring_control),
 			    priv->ring_control, priv->ring_control_dma);
@@ -592,6 +592,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 
  err_free_reg:
 	pci_release_regions(pdev);
+ err_disable_dev:
 	pci_disable_device(pdev);
 	return err;
 }
@@ -606,6 +607,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
 
 	ieee80211_unregister_hw(dev);
 	priv = dev->priv;
+	release_firmware(priv->firmware);
 	pci_free_consistent(pdev, sizeof(*priv->ring_control),
 			    priv->ring_control, priv->ring_control_dma);
 	p54_free_common(dev);

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

@@ -93,7 +93,7 @@ struct p54p_priv {
 	struct pci_dev *pdev;
 	struct p54p_csr __iomem *map;
 	struct tasklet_struct rx_tasklet;
-
+	const struct firmware *firmware;
 	spinlock_t lock;
 	struct p54p_ring_control *ring_control;
 	dma_addr_t ring_control_dma;

+ 42 - 83
drivers/net/wireless/rt2x00/rt2400pci.c

@@ -49,20 +49,10 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
-		if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
 
 static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
@@ -72,31 +62,20 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt2400pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY))
-		goto exit_fail;
-
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
-
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+	}
 
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
 }
 
 static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -107,74 +86,54 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = rt2400pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
 
-	/*
-	 * Write the request into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2400pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY))
-		goto exit_fail;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
+	}
 
 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
 
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return;
-
-exit_fail:
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
-	*value = 0xff;
 }
 
 static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
 	mutex_lock(&rt2x00dev->csr_mutex);
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
-		if (!rt2x00_get_field32(reg, RFCSR_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+		rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+		rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+		rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
 	}
 
-	mutex_unlock(&rt2x00dev->csr_mutex);
-	ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, RFCSR_VALUE, value);
-	rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
-	rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
-
-	rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
-
 	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 

+ 42 - 83
drivers/net/wireless/rt2x00/rt2500pci.c

@@ -49,20 +49,10 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
-		if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
 
 static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
@@ -72,31 +62,20 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt2500pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY))
-		goto exit_fail;
-
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
-
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+	}
 
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
 }
 
 static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -107,74 +86,54 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = rt2500pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
 
-	/*
-	 * Write the request into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2500pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY))
-		goto exit_fail;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
+	}
 
 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
 
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return;
-
-exit_fail:
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
-	*value = 0xff;
 }
 
 static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
 	mutex_lock(&rt2x00dev->csr_mutex);
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
-		if (!rt2x00_get_field32(reg, RFCSR_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+		rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+		rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+		rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
 	}
 
-	mutex_unlock(&rt2x00dev->csr_mutex);
-	ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, RFCSR_VALUE, value);
-	rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
-	rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
-
-	rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
-
 	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 

+ 65 - 86
drivers/net/wireless/rt2x00/rt2500usb.c

@@ -57,7 +57,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
 	__le16 reg;
 	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
 				      USB_VENDOR_REQUEST_IN, offset,
-				      &reg, sizeof(u16), REGISTER_TIMEOUT);
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
 	*value = le16_to_cpu(reg);
 }
 
@@ -68,7 +68,7 @@ static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
 	__le16 reg;
 	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
 				       USB_VENDOR_REQUEST_IN, offset,
-				       &reg, sizeof(u16), REGISTER_TIMEOUT);
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
 	*value = le16_to_cpu(reg);
 }
 
@@ -89,7 +89,7 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
 	__le16 reg = cpu_to_le16(value);
 	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
 				      USB_VENDOR_REQUEST_OUT, offset,
-				      &reg, sizeof(u16), REGISTER_TIMEOUT);
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
 }
 
 static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
@@ -99,7 +99,7 @@ static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
 	__le16 reg = cpu_to_le16(value);
 	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
 				       USB_VENDOR_REQUEST_OUT, offset,
-				       &reg, sizeof(u16), REGISTER_TIMEOUT);
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
 }
 
 static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
@@ -112,21 +112,32 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
 				      REGISTER_TIMEOUT16(length));
 }
 
-static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
+static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+				  const unsigned int offset,
+				  struct rt2x00_field16 field,
+				  u16 *reg)
 {
-	u16 reg;
 	unsigned int i;
 
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg);
-		if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-			break;
+		rt2500usb_register_read_lock(rt2x00dev, offset, reg);
+		if (!rt2x00_get_field16(*reg, field))
+			return 1;
 		udelay(REGISTER_BUSY_DELAY);
 	}
 
-	return reg;
+	ERROR(rt2x00dev, "Indirect register access failed: "
+	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+	*reg = ~0;
+
+	return 0;
 }
 
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2500usb_regbusy_read((__dev), PHY_CSR8, PHY_CSR8_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2500usb_regbusy_read((__dev), PHY_CSR10, PHY_CSR10_RF_BUSY, (__reg))
+
 static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
 {
@@ -135,30 +146,19 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-		goto exit_fail;
-
-	/*
-	 * Write the data into the BBP.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
-	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
-	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
-
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
+		rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+		rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
 
-	return;
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+	}
 
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
 }
 
 static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -169,77 +169,57 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-		goto exit_fail;
-
-	/*
-	 * Write the request into the BBP.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
-	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+		rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
 
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-		goto exit_fail;
+		if (WAIT_FOR_BBP(rt2x00dev, &reg))
+			rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
+	}
 
-	rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
 	*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
 
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return;
-
-exit_fail:
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-	*value = 0xff;
 }
 
 static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u16 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
 	mutex_lock(&rt2x00dev->csr_mutex);
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
-		if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
-	ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
 
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
 
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
+	}
 
 	mutex_unlock(&rt2x00dev->csr_mutex);
 }
@@ -1128,7 +1108,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
 	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
 	struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-	int pipe = usb_sndbulkpipe(usb_dev, 1);
+	int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
 	int length;
 	u16 reg;
 
@@ -1154,7 +1134,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
 	 * length of the data to usb_fill_bulk_urb. Pass the skb
 	 * to the driver to determine what the length should be.
 	 */
-	length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+	length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
 	usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
 			  entry->skb->data, length, rt2500usb_beacondone,
@@ -1176,8 +1156,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
 	usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
 }
 
-static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
-				     struct sk_buff *skb)
+static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
 {
 	int length;
 
@@ -1185,8 +1164,8 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 	 * The length _must_ be a multiple of 2,
 	 * but it must _not_ be a multiple of the USB packet size.
 	 */
-	length = roundup(skb->len, 2);
-	length += (2 * !(length % rt2x00dev->usb_maxpacket));
+	length = roundup(entry->skb->len, 2);
+	length += (2 * !(length % entry->queue->usb_maxpacket));
 
 	return length;
 }

+ 1 - 7
drivers/net/wireless/rt2x00/rt2x00.h

@@ -555,8 +555,7 @@ struct rt2x00lib_ops {
 			       struct txentry_desc *txdesc);
 	int (*write_tx_data) (struct queue_entry *entry);
 	void (*write_beacon) (struct queue_entry *entry);
-	int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
-				struct sk_buff *skb);
+	int (*get_tx_data_len) (struct queue_entry *entry);
 	void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
 			       const enum data_queue_qid queue);
 
@@ -798,11 +797,6 @@ struct rt2x00_dev {
 	 */
 	short lna_gain;
 
-	/*
-	 * USB Max frame size (for rt2500usb & rt73usb).
-	 */
-	u16 usb_maxpacket;
-
 	/*
 	 * Current TX power value.
 	 */

+ 0 - 6
drivers/net/wireless/rt2x00/rt2x00leds.c

@@ -111,12 +111,6 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
 	led->led_dev.name = name;
 	led->led_dev.brightness = LED_OFF;
 
-	/*
-	 * Ensure the LED is off, it might have been enabled
-	 * by the hardware when the device was powered on.
-	 */
-	led->led_dev.brightness_set(&led->led_dev, LED_OFF);
-
 	retval = led_classdev_register(device, &led->led_dev);
 	if (retval) {
 		ERROR(rt2x00dev, "Failed to register led handler.\n");

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

@@ -132,8 +132,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		ERROR(rt2x00dev,
 		      "Attempt to send packet over invalid queue %d.\n"
 		      "Please file bug report to %s.\n", qid, DRV_PROJECT);
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
+		goto exit_fail;
 	}
 
 	/*

+ 25 - 0
drivers/net/wireless/rt2x00/rt2x00pci.c

@@ -31,6 +31,31 @@
 #include "rt2x00.h"
 #include "rt2x00pci.h"
 
+/*
+ * Register access.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   const struct rt2x00_field32 field,
+			   u32 *reg)
+{
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, offset, reg);
+		if (!rt2x00_get_field32(*reg, field))
+			return 1;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "Indirect register access failed: "
+	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+	*reg = ~0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
+
 /*
  * TX data handlers.
  */

+ 18 - 0
drivers/net/wireless/rt2x00/rt2x00pci.h

@@ -76,6 +76,24 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
 	memcpy_toio(rt2x00dev->csr.base + offset, value, length);
 }
 
+/**
+ * rt2x00pci_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   const struct rt2x00_field32 field,
+			   u32 *reg);
+
 /**
  * rt2x00pci_write_tx_data - Initialize data for TX operation
  * @entry: The entry where the frame is located

+ 6 - 8
drivers/net/wireless/rt2x00/rt2x00queue.c

@@ -386,7 +386,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 	u8 rate_idx, rate_flags;
 
 	if (unlikely(rt2x00queue_full(queue)))
-		return -EINVAL;
+		return -ENOBUFS;
 
 	if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
 		ERROR(queue->rt2x00dev,
@@ -415,7 +415,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 	tx_info = IEEE80211_SKB_CB(skb);
 	rate_idx = tx_info->control.rates[0].idx;
 	rate_flags = tx_info->control.rates[0].flags;
-	skbdesc = get_skb_frame_desc(entry->skb);
+	skbdesc = get_skb_frame_desc(skb);
 	memset(skbdesc, 0, sizeof(*skbdesc));
 	skbdesc->entry = entry;
 	skbdesc->tx_rate_idx = rate_idx;
@@ -427,20 +427,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 	 * the frame so we can provide it to the driver seperately.
 	 */
 	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
-	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
+	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags))
 		rt2x00crypto_tx_remove_iv(skb, iv_len);
-	}
 
 	/*
 	 * It could be possible that the queue was corrupted and this
-	 * call failed. Just drop the frame, we cannot rollback and pass
-	 * the frame to mac80211 because the skb->cb has now been tainted.
+	 * call failed. Since we always return NETDEV_TX_OK to mac80211,
+	 * this frame will simply be dropped.
 	 */
 	if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
 		clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-		dev_kfree_skb_any(entry->skb);
 		entry->skb = NULL;
-		return 0;
+		return -EIO;
 	}
 
 	if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))

+ 20 - 2
drivers/net/wireless/rt2x00/rt2x00queue.h

@@ -380,6 +380,8 @@ enum queue_index {
  * @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
  * @data_size: Maximum data size for the frames in this queue.
  * @desc_size: Hardware descriptor size for the data in this queue.
+ * @usb_endpoint: Device endpoint used for communication (USB only)
+ * @usb_maxpacket: Max packet size for given endpoint (USB only)
  */
 struct data_queue {
 	struct rt2x00_dev *rt2x00dev;
@@ -401,6 +403,9 @@ struct data_queue {
 
 	unsigned short data_size;
 	unsigned short desc_size;
+
+	unsigned short usb_endpoint;
+	unsigned short usb_maxpacket;
 };
 
 /**
@@ -443,6 +448,19 @@ struct data_queue_desc {
 #define tx_queue_end(__dev) \
 	&(__dev)->tx[(__dev)->ops->tx_queues]
 
+/**
+ * queue_next - Return pointer to next queue in list (HELPER MACRO).
+ * @__queue: Current queue for which we need the next queue
+ *
+ * Using the current queue address we take the address directly
+ * after the queue to take the next queue. Note that this macro
+ * should be used carefully since it does not protect against
+ * moving past the end of the list. (See macros &queue_end and
+ * &tx_queue_end for determining the end of the queue).
+ */
+#define queue_next(__queue) \
+	&(__queue)[1]
+
 /**
  * queue_loop - Loop through the queues within a specific range (HELPER MACRO).
  * @__entry: Pointer where the current queue entry will be stored in.
@@ -453,8 +471,8 @@ struct data_queue_desc {
  */
 #define queue_loop(__entry, __start, __end)			\
 	for ((__entry) = (__start);				\
-	     prefetch(&(__entry)[1]), (__entry) != (__end);	\
-	     (__entry) = &(__entry)[1])
+	     prefetch(queue_next(__entry)), (__entry) != (__end);\
+	     (__entry) = queue_next(__entry))
 
 /**
  * queue_for_each - Loop through all queues

+ 104 - 9
drivers/net/wireless/rt2x00/rt2x00usb.c

@@ -154,6 +154,28 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
 
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   struct rt2x00_field32 field,
+			   u32 *reg)
+{
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00usb_register_read_lock(rt2x00dev, offset, reg);
+		if (!rt2x00_get_field32(*reg, field))
+			return 1;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "Indirect register access failed: "
+	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+	*reg = ~0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
+
 /*
  * TX data handlers.
  */
@@ -212,10 +234,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
 	 * length of the data to usb_fill_bulk_urb. Pass the skb
 	 * to the driver to determine what the length should be.
 	 */
-	length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+	length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
 	usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-			  usb_sndbulkpipe(usb_dev, 1),
+			  usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
 			  entry->skb->data, length,
 			  rt2x00usb_interrupt_txdone, entry);
 
@@ -356,10 +378,11 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
 	struct usb_device *usb_dev =
 	    to_usb_device_intf(entry->queue->rt2x00dev->dev);
 	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+	int pipe;
 
 	if (entry->queue->qid == QID_RX) {
-		usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-				usb_rcvbulkpipe(usb_dev, 1),
+		pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
+		usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
 				entry->skb->data, entry->skb->len,
 				rt2x00usb_interrupt_rxdone, entry);
 
@@ -371,6 +394,76 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
 
+static void rt2x00usb_assign_endpoint(struct data_queue *queue,
+				      struct usb_endpoint_descriptor *ep_desc)
+{
+	struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
+	int pipe;
+
+	queue->usb_endpoint = usb_endpoint_num(ep_desc);
+
+	if (queue->qid == QID_RX) {
+		pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
+		queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
+	} else {
+		pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
+		queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
+	}
+
+	if (!queue->usb_maxpacket)
+		queue->usb_maxpacket = 1;
+}
+
+static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
+{
+	struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
+	struct usb_host_interface *intf_desc = intf->cur_altsetting;
+	struct usb_endpoint_descriptor *ep_desc;
+	struct data_queue *queue = rt2x00dev->tx;
+	struct usb_endpoint_descriptor *tx_ep_desc = NULL;
+	unsigned int i;
+
+	/*
+	 * Walk through all available endpoints to search for "bulk in"
+	 * and "bulk out" endpoints. When we find such endpoints collect
+	 * the information we need from the descriptor and assign it
+	 * to the queue.
+	 */
+	for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+		ep_desc = &intf_desc->endpoint[i].desc;
+
+		if (usb_endpoint_is_bulk_in(ep_desc)) {
+			rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
+		} else if (usb_endpoint_is_bulk_out(ep_desc)) {
+			rt2x00usb_assign_endpoint(queue, ep_desc);
+
+			if (queue != queue_end(rt2x00dev))
+				queue = queue_next(queue);
+			tx_ep_desc = ep_desc;
+		}
+	}
+
+	/*
+	 * At least 1 endpoint for RX and 1 endpoint for TX must be available.
+	 */
+	if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
+		ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
+		return -EPIPE;
+	}
+
+	/*
+	 * It might be possible not all queues have a dedicated endpoint.
+	 * Loop through all TX queues and copy the endpoint information
+	 * which we have gathered from already assigned endpoints.
+	 */
+	txall_queue_for_each(rt2x00dev, queue) {
+		if (!queue->usb_endpoint)
+			rt2x00usb_assign_endpoint(queue, tx_ep_desc);
+	}
+
+	return 0;
+}
+
 static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
 			       struct data_queue *queue)
 {
@@ -441,6 +534,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
 	struct data_queue *queue;
 	int status;
 
+	/*
+	 * Find endpoints for each queue
+	 */
+	status = rt2x00usb_find_endpoints(rt2x00dev);
+	if (status)
+		goto exit;
+
 	/*
 	 * Allocate DMA
 	 */
@@ -532,11 +632,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
 	rt2x00dev->ops = ops;
 	rt2x00dev->hw = hw;
 
-	rt2x00dev->usb_maxpacket =
-	    usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
-	if (!rt2x00dev->usb_maxpacket)
-		rt2x00dev->usb_maxpacket = 1;
-
 	retval = rt2x00usb_alloc_reg(rt2x00dev);
 	if (retval)
 		goto exit_free_device;

+ 136 - 0
drivers/net/wireless/rt2x00/rt2x00usb.h

@@ -231,6 +231,142 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
 					REGISTER_TIMEOUT16(length));
 }
 
+/**
+ * rt2x00usb_regbusy_read - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev,
+					   const unsigned int offset,
+					   u32 *value)
+{
+	__le32 reg;
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
+	*value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_read_lock - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+						const unsigned int offset,
+						u32 *value)
+{
+	__le32 reg;
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+				       USB_VENDOR_REQUEST_IN, offset,
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
+	*value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_multiread - Read 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev,
+						const unsigned int offset,
+						void *value, const u32 length)
+{
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      value, length,
+				      REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_register_write - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev,
+					    const unsigned int offset,
+					    u32 value)
+{
+	__le32 reg = cpu_to_le32(value);
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_write_lock - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+						 const unsigned int offset,
+						 u32 value)
+{
+	__le32 reg = cpu_to_le32(value);
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+				       USB_VENDOR_REQUEST_OUT, offset,
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_multiwrite - Write 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
+					       const unsigned int offset,
+					       void *value, const u32 length)
+{
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      value, length,
+				      REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   struct rt2x00_field32 field,
+			   u32 *reg);
+
 /*
  * Radio handlers
  */

+ 59 - 102
drivers/net/wireless/rt2x00/rt61pci.c

@@ -55,20 +55,13 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
+#define WAIT_FOR_MCU(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
+			       H2M_MAILBOX_CSR_OWNER, (__reg))
 
 static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, const u8 value)
@@ -78,30 +71,20 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt61pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
-
-	/*
-	 * Write the data into the BBP.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
-
-	rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
-	mutex_unlock(&rt2x00dev->csr_mutex);
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
 
-	return;
+		rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+	}
 
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
 }
 
 static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -112,72 +95,53 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = rt61pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
 
-	/*
-	 * Write the request into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+		rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
 
-	rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
-
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt61pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
+	}
 
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return;
 
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-	*value = 0xff;
 }
 
 static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
 	mutex_lock(&rt2x00dev->csr_mutex);
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
-	ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
-	rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
-	rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+		rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
+		rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
 
-	rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
+		rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
+	}
 
 	mutex_unlock(&rt2x00dev->csr_mutex);
 }
@@ -196,32 +160,25 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
 
 	mutex_lock(&rt2x00dev->csr_mutex);
 
-	rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
-
-	if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER))
-		goto exit_fail;
-
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
-	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
-
-	rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
-	rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
-	rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
-	rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
+	/*
+	 * Wait until the MCU becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+		rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
 
-	return;
+		rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+		rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+		rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
+		rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+	}
 
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
 
-	ERROR(rt2x00dev,
-	      "mcu request error. Request 0x%02x failed for token 0x%02x.\n",
-	      command, token);
 }
 #endif /* CONFIG_RT2X00_LIB_LEDS */
 

+ 167 - 266
drivers/net/wireless/rt2x00/rt73usb.c

@@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 /*
  * Register access.
  * All access to the CSR registers will go through the methods
- * rt73usb_register_read and rt73usb_register_write.
+ * rt2x00usb_register_read and rt2x00usb_register_write.
  * BBP and RF register require indirect register access,
  * and use the CSR registers BBPCSR and RFCSR to achieve this.
  * These indirect registers work with busy bits,
@@ -57,78 +57,10 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
  * and we will print an error.
  * The _lock versions must be used if you already hold the csr_mutex
  */
-static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev,
-					 const unsigned int offset, u32 *value)
-{
-	__le32 reg;
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
-				      USB_VENDOR_REQUEST_IN, offset,
-				      &reg, sizeof(u32), REGISTER_TIMEOUT);
-	*value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
-					      const unsigned int offset, u32 *value)
-{
-	__le32 reg;
-	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
-				       USB_VENDOR_REQUEST_IN, offset,
-				       &reg, sizeof(u32), REGISTER_TIMEOUT);
-	*value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev,
-					      const unsigned int offset,
-					      void *value, const u32 length)
-{
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
-				      USB_VENDOR_REQUEST_IN, offset,
-				      value, length,
-				      REGISTER_TIMEOUT32(length));
-}
-
-static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev,
-					  const unsigned int offset, u32 value)
-{
-	__le32 reg = cpu_to_le32(value);
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
-				      USB_VENDOR_REQUEST_OUT, offset,
-				      &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
-					       const unsigned int offset, u32 value)
-{
-	__le32 reg = cpu_to_le32(value);
-	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
-				       USB_VENDOR_REQUEST_OUT, offset,
-				      &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
-					       const unsigned int offset,
-					       void *value, const u32 length)
-{
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
-				      USB_VENDOR_REQUEST_OUT, offset,
-				      value, length,
-				      REGISTER_TIMEOUT32(length));
-}
-
-static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
 
 static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, const u8 value)
@@ -138,30 +70,20 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
-
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
-
-	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
-	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	return;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+		rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
+	}
 
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
 }
 
 static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -172,79 +94,59 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
 
-	/*
-	 * Write the request into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+		rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
 
-	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
-
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
+	}
 
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
-	mutex_unlock(&rt2x00dev->csr_mutex);
 
-	return;
-
-exit_fail:
 	mutex_unlock(&rt2x00dev->csr_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-	*value = 0xff;
 }
 
 static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
 	mutex_lock(&rt2x00dev->csr_mutex);
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	mutex_unlock(&rt2x00dev->csr_mutex);
-	ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
-
 	/*
-	 * RF5225 and RF2527 contain 21 bits per RF register value,
-	 * all others contain 20 bits.
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
-			   20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-				 rt2x00_rf(&rt2x00dev->chip, RF2527)));
-	rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
-
-	rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+		/*
+		 * RF5225 and RF2527 contain 21 bits per RF register value,
+		 * all others contain 20 bits.
+		 */
+		rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
+				   20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+					 rt2x00_rf(&rt2x00dev->chip, RF2527)));
+		rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+		rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
+	}
 
 	mutex_unlock(&rt2x00dev->csr_mutex);
 }
@@ -253,8 +155,8 @@ rf_write:
 static const struct rt2x00debug rt73usb_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt73usb_register_read,
-		.write		= rt73usb_register_write,
+		.read		= rt2x00usb_register_read,
+		.write		= rt2x00usb_register_write,
 		.flags		= RT2X00DEBUGFS_OFFSET,
 		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
@@ -333,10 +235,10 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev,
 	    container_of(led_cdev, struct rt2x00_led, led_dev);
 	u32 reg;
 
-	rt73usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
+	rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, *delay_on);
 	rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, *delay_off);
-	rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
+	rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
 
 	return 0;
 }
@@ -379,7 +281,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
 		 */
 		mask = (0xf << crypto->bssidx);
 
-		rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
 		reg &= mask;
 
 		if (reg && reg == mask)
@@ -416,16 +318,16 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
 			field.bit_offset = (3 * key->hw_key_idx);
 			field.bit_mask = 0x7 << field.bit_offset;
 
-			rt73usb_register_read(rt2x00dev, SEC_CSR1, &reg);
+			rt2x00usb_register_read(rt2x00dev, SEC_CSR1, &reg);
 			rt2x00_set_field32(&reg, field, crypto->cipher);
-			rt73usb_register_write(rt2x00dev, SEC_CSR1, reg);
+			rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg);
 		} else {
 			field.bit_offset = (3 * (key->hw_key_idx - 8));
 			field.bit_mask = 0x7 << field.bit_offset;
 
-			rt73usb_register_read(rt2x00dev, SEC_CSR5, &reg);
+			rt2x00usb_register_read(rt2x00dev, SEC_CSR5, &reg);
 			rt2x00_set_field32(&reg, field, crypto->cipher);
-			rt73usb_register_write(rt2x00dev, SEC_CSR5, reg);
+			rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg);
 		}
 
 		/*
@@ -448,12 +350,12 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
 	 */
 	mask = 1 << key->hw_key_idx;
 
-	rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
 	if (crypto->cmd == SET_KEY)
 		reg |= mask;
 	else if (crypto->cmd == DISABLE_KEY)
 		reg &= ~mask;
-	rt73usb_register_write(rt2x00dev, SEC_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg);
 
 	return 0;
 }
@@ -478,10 +380,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
 		 * When both registers are full, we drop the key,
 		 * otherwise we use the first invalid entry.
 		 */
-		rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
 		if (reg && reg == ~0) {
 			key->hw_key_idx = 32;
-			rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+			rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
 			if (reg && reg == ~0)
 				return -ENOSPC;
 		}
@@ -509,14 +411,14 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
 		/*
 		 * Send the address and cipher type to the hardware register.
 		 * This data fits within the CSR cache size, so we can use
-		 * rt73usb_register_multiwrite() directly.
+		 * rt2x00usb_register_multiwrite() directly.
 		 */
 		memset(&addr_entry, 0, sizeof(addr_entry));
 		memcpy(&addr_entry, crypto->address, ETH_ALEN);
 		addr_entry.cipher = crypto->cipher;
 
 		reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
-		rt73usb_register_multiwrite(rt2x00dev, reg,
+		rt2x00usb_register_multiwrite(rt2x00dev, reg,
 					    &addr_entry, sizeof(addr_entry));
 
 		/*
@@ -524,9 +426,9 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
 		 * without this received frames will not be decrypted
 		 * by the hardware.
 		 */
-		rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR4, &reg);
 		reg |= (1 << crypto->bssidx);
-		rt73usb_register_write(rt2x00dev, SEC_CSR4, reg);
+		rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg);
 
 		/*
 		 * The driver does not support the IV/EIV generation
@@ -549,21 +451,21 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
 	if (key->hw_key_idx < 32) {
 		mask = 1 << key->hw_key_idx;
 
-		rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
 		if (crypto->cmd == SET_KEY)
 			reg |= mask;
 		else if (crypto->cmd == DISABLE_KEY)
 			reg &= ~mask;
-		rt73usb_register_write(rt2x00dev, SEC_CSR2, reg);
+		rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg);
 	} else {
 		mask = 1 << (key->hw_key_idx - 32);
 
-		rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
 		if (crypto->cmd == SET_KEY)
 			reg |= mask;
 		else if (crypto->cmd == DISABLE_KEY)
 			reg &= ~mask;
-		rt73usb_register_write(rt2x00dev, SEC_CSR3, reg);
+		rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg);
 	}
 
 	return 0;
@@ -580,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
 	 * and broadcast frames will always be accepted since
 	 * there is no filter for it at this time.
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
 			   !(filter_flags & FIF_FCSFAIL));
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
@@ -598,7 +500,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS,
 			   !(filter_flags & FIF_CONTROL));
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 }
 
 static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
@@ -617,16 +519,16 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
 		 * bits which (when set to 0) will invalidate the entire beacon.
 		 */
 		beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
-		rt73usb_register_write(rt2x00dev, beacon_base, 0);
+		rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
 
 		/*
 		 * Enable synchronisation.
 		 */
-		rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+		rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-		rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+		rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 	}
 
 	if (flags & CONFIG_UPDATE_MAC) {
@@ -634,7 +536,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
 		rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
 		conf->mac[1] = cpu_to_le32(reg);
 
-		rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2,
+		rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2,
 					    conf->mac, sizeof(conf->mac));
 	}
 
@@ -643,7 +545,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
 		rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
 		conf->bssid[1] = cpu_to_le32(reg);
 
-		rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4,
+		rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4,
 					    conf->bssid, sizeof(conf->bssid));
 	}
 }
@@ -653,26 +555,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 
-	rt73usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
-	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00usb_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);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg);
 }
 
 static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -818,14 +720,14 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
 	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
 		rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
 
-	rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, PHY_CSR0, &reg);
 
 	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
 			   (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ));
 	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
 			   (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ));
 
-	rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
 	    rt2x00_rf(&rt2x00dev->chip, RF5225))
@@ -915,12 +817,12 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00usb_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);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 }
 
 static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -928,18 +830,18 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
 			   libconf->conf->beacon_int * 16);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 }
 
 static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
@@ -972,13 +874,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Update FCS error count from register.
 	 */
-	rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
 	qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
 
 	/*
 	 * Update False CCA count from register.
 	 */
-	rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
 	qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
 }
 
@@ -1138,7 +1040,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
 	 * Wait for stable hardware.
 	 */
 	for (i = 0; i < 100; i++) {
-		rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+		rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
 		if (reg)
 			break;
 		msleep(1);
@@ -1180,13 +1082,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
@@ -1195,12 +1097,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR1, reg);
 
 	/*
 	 * CCK TXD BBP registers
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
@@ -1209,77 +1111,77 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR2, reg);
 
 	/*
 	 * OFDM TXD BBP registers
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
-	rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR6, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR6_MAX_FRAME_UNIT, 0xfff);
-	rt73usb_register_write(rt2x00dev, MAC_CSR6, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg);
 
-	rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
 
 	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
 		return -EBUSY;
 
-	rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
 
 	/*
 	 * Invalidate all Shared Keys (SEC_CSR0),
 	 * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
 	 */
-	rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
-	rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
-	rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
 
 	reg = 0x000023b0;
 	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
 	    rt2x00_rf(&rt2x00dev->chip, RF2527))
 		rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
-	rt73usb_register_write(rt2x00dev, PHY_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
 
-	rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
-	rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
-	rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
-	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
 
 	/*
 	 * Clear all beacons
@@ -1287,36 +1189,36 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	 * the first byte since that byte contains the VALID and OWNER
 	 * bits which (when set to 0) will invalidate the entire beacon.
 	 */
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
 
 	/*
 	 * We must clear the error counters.
 	 * These registers are cleared on read,
 	 * so we may pass a useless variable to store the value.
 	 */
-	rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
-	rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
-	rt73usb_register_read(rt2x00dev, STA_CSR2, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR2, &reg);
 
 	/*
 	 * Reset MAC and BBP registers.
 	 */
-	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
 	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
-	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
 	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
-	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
-	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
 	return 0;
 }
@@ -1394,11 +1296,11 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
 			   (state == STATE_RADIO_RX_OFF) ||
 			   (state == STATE_RADIO_RX_OFF_LINK));
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 }
 
 static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -1415,12 +1317,12 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 
 static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
-	rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
 
 	/*
 	 * Disable synchronisation.
 	 */
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0);
 
 	rt2x00usb_disable_radio(rt2x00dev);
 }
@@ -1433,10 +1335,10 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
 
 	put_to_sleep = (state != STATE_AWAKE);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
 	rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
-	rt73usb_register_write(rt2x00dev, MAC_CSR12, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg);
 
 	/*
 	 * Device is not guaranteed to be in the requested state yet.
@@ -1444,7 +1346,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
 	 * device has entered the correct state.
 	 */
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+		rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
 		state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
 		if (state == !put_to_sleep)
 			return 0;
@@ -1584,11 +1486,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
 	 * Disable beaconing while we are reloading the beacon data,
 	 * otherwise we might be sending out invalid data.
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
 	/*
 	 * Write entire beacon with descriptor to register.
@@ -1606,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
 	entry->skb = NULL;
 }
 
-static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
-				   struct sk_buff *skb)
+static int rt73usb_get_tx_data_len(struct queue_entry *entry)
 {
 	int length;
 
@@ -1615,8 +1516,8 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 	 * The length _must_ be a multiple of 4,
 	 * but it must _not_ be a multiple of the USB packet size.
 	 */
-	length = roundup(skb->len, 4);
-	length += (4 * !(length % rt2x00dev->usb_maxpacket));
+	length = roundup(entry->skb->len, 4);
+	length += (4 * !(length % entry->queue->usb_maxpacket));
 
 	return length;
 }
@@ -1635,14 +1536,14 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 	 * For Wi-Fi faily generated beacons between participating stations.
 	 * Set TBTT phase adaptive adjustment step to 8us (default 16us)
 	 */
-	rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
 		rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-		rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+		rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 	}
 }
 
@@ -1881,7 +1782,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	 * Identify RF chipset.
 	 */
 	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
-	rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
 	rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
 
 	if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) {
@@ -2235,33 +2136,33 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
 		field.bit_offset = queue_idx * 16;
 		field.bit_mask = 0xffff << field.bit_offset;
 
-		rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+		rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
 		rt2x00_set_field32(&reg, field, queue->txop);
-		rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+		rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
 	} else if (queue_idx < 4) {
 		field.bit_offset = (queue_idx - 2) * 16;
 		field.bit_mask = 0xffff << field.bit_offset;
 
-		rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+		rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
 		rt2x00_set_field32(&reg, field, queue->txop);
-		rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+		rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
 	}
 
 	/* Update WMM registers */
 	field.bit_offset = queue_idx * 4;
 	field.bit_mask = 0xf << field.bit_offset;
 
-	rt73usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
+	rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
 	rt2x00_set_field32(&reg, field, queue->aifs);
-	rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg);
+	rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg);
 
-	rt73usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
+	rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
 	rt2x00_set_field32(&reg, field, queue->cw_min);
-	rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg);
+	rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg);
 
-	rt73usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
+	rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
 	rt2x00_set_field32(&reg, field, queue->cw_max);
-	rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg);
+	rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg);
 
 	return 0;
 }
@@ -2279,9 +2180,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
 	u64 tsf;
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
 	tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
-	rt73usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
 	tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
 
 	return tsf;

+ 7 - 0
drivers/net/wireless/rtl818x/rtl8187.h

@@ -111,6 +111,13 @@ struct rtl8187_priv {
 	u8 signal;
 	u8 quality;
 	u8 noise;
+	u8 slot_time;
+	u8 aifsn[4];
+	struct {
+		__le64 buf;
+		struct urb *urb;
+		struct sk_buff_head queue;
+	} b_tx_status;
 };
 
 void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);

+ 200 - 14
drivers/net/wireless/rtl818x/rtl8187_dev.c

@@ -176,8 +176,27 @@ static void rtl8187_tx_cb(struct urb *urb)
 	skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
 					  sizeof(struct rtl8187_tx_hdr));
 	ieee80211_tx_info_clear_status(info);
-	info->flags |= IEEE80211_TX_STAT_ACK;
-	ieee80211_tx_status_irqsafe(hw, skb);
+
+	if (!urb->status &&
+	    !(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+	    priv->is_rtl8187b) {
+		skb_queue_tail(&priv->b_tx_status.queue, skb);
+
+		/* queue is "full", discard last items */
+		while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
+			struct sk_buff *old_skb;
+
+			dev_dbg(&priv->udev->dev,
+				"transmit status queue full\n");
+
+			old_skb = skb_dequeue(&priv->b_tx_status.queue);
+			ieee80211_tx_status_irqsafe(hw, old_skb);
+		}
+	} else {
+		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status)
+			info->flags |= IEEE80211_TX_STAT_ACK;
+		ieee80211_tx_status_irqsafe(hw, skb);
+	}
 }
 
 static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
@@ -219,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 		hdr->flags = cpu_to_le32(flags);
 		hdr->len = 0;
 		hdr->rts_duration = rts_dur;
-		hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
+		hdr->retry = cpu_to_le32(info->control.rates[0].count << 8);
 		buf = hdr;
 
 		ep = 2;
@@ -237,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 		memset(hdr, 0, sizeof(*hdr));
 		hdr->flags = cpu_to_le32(flags);
 		hdr->rts_duration = rts_dur;
-		hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
+		hdr->retry = cpu_to_le32(info->control.rates[0].count << 8);
 		hdr->tx_duration =
 			ieee80211_generic_frame_duration(dev, priv->vif,
 							 skb->len, txrate);
@@ -403,6 +422,109 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
 	return 0;
 }
 
+static void rtl8187b_status_cb(struct urb *urb)
+{
+	struct ieee80211_hw *hw = (struct ieee80211_hw *)urb->context;
+	struct rtl8187_priv *priv = hw->priv;
+	u64 val;
+	unsigned int cmd_type;
+
+	if (unlikely(urb->status)) {
+		usb_free_urb(urb);
+		return;
+	}
+
+	/*
+	 * Read from status buffer:
+	 *
+	 * bits [30:31] = cmd type:
+	 * - 0 indicates tx beacon interrupt
+	 * - 1 indicates tx close descriptor
+	 *
+	 * In the case of tx beacon interrupt:
+	 * [0:9] = Last Beacon CW
+	 * [10:29] = reserved
+	 * [30:31] = 00b
+	 * [32:63] = Last Beacon TSF
+	 *
+	 * If it's tx close descriptor:
+	 * [0:7] = Packet Retry Count
+	 * [8:14] = RTS Retry Count
+	 * [15] = TOK
+	 * [16:27] = Sequence No
+	 * [28] = LS
+	 * [29] = FS
+	 * [30:31] = 01b
+	 * [32:47] = unused (reserved?)
+	 * [48:63] = MAC Used Time
+	 */
+	val = le64_to_cpu(priv->b_tx_status.buf);
+
+	cmd_type = (val >> 30) & 0x3;
+	if (cmd_type == 1) {
+		unsigned int pkt_rc, seq_no;
+		bool tok;
+		struct sk_buff *skb;
+		struct ieee80211_hdr *ieee80211hdr;
+		unsigned long flags;
+
+		pkt_rc = val & 0xFF;
+		tok = val & (1 << 15);
+		seq_no = (val >> 16) & 0xFFF;
+
+		spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
+		skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) {
+			ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+
+			/*
+			 * While testing, it was discovered that the seq_no
+			 * doesn't actually contains the sequence number.
+			 * Instead of returning just the 12 bits of sequence
+			 * number, hardware is returning entire sequence control
+			 * (fragment number plus sequence number) in a 12 bit
+			 * only field overflowing after some time. As a
+			 * workaround, just consider the lower bits, and expect
+			 * it's unlikely we wrongly ack some sent data
+			 */
+			if ((le16_to_cpu(ieee80211hdr->seq_ctrl)
+			    & 0xFFF) == seq_no)
+				break;
+		}
+		if (skb != (struct sk_buff *) &priv->b_tx_status.queue) {
+			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+			__skb_unlink(skb, &priv->b_tx_status.queue);
+			if (tok)
+				info->flags |= IEEE80211_TX_STAT_ACK;
+			info->status.rates[0].count = pkt_rc + 1;
+
+			ieee80211_tx_status_irqsafe(hw, skb);
+		}
+		spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
+	}
+
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int rtl8187b_init_status_urb(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	struct urb *entry;
+
+	entry = usb_alloc_urb(0, GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+	priv->b_tx_status.urb = entry;
+
+	usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9),
+			  &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf),
+			  rtl8187b_status_cb, dev);
+
+	usb_submit_urb(entry, GFP_KERNEL);
+
+	return 0;
+}
+
 static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
@@ -712,6 +834,13 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
 
 	rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1);
 
+	priv->slot_time = 0x9;
+	priv->aifsn[0] = 2; /* AIFSN[AC_VO] */
+	priv->aifsn[1] = 2; /* AIFSN[AC_VI] */
+	priv->aifsn[2] = 7; /* AIFSN[AC_BK] */
+	priv->aifsn[3] = 3; /* AIFSN[AC_BE] */
+	rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
+
 	return 0;
 }
 
@@ -748,6 +877,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
 				  (7 << 0  /* long retry limit */) |
 				  (7 << 21 /* MAX TX DMA */));
 		rtl8187_init_urbs(dev);
+		rtl8187b_init_status_urb(dev);
 		mutex_unlock(&priv->conf_mutex);
 		return 0;
 	}
@@ -824,6 +954,9 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
 		usb_kill_urb(info->urb);
 		kfree_skb(skb);
 	}
+	while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
+		dev_kfree_skb_any(skb);
+	usb_kill_urb(priv->b_tx_status.urb);
 	mutex_unlock(&priv->conf_mutex);
 }
 
@@ -919,24 +1052,38 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
 	return 0;
 }
 
+/*
+ * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for
+ * example. Thus we have to use raw values for AC_*_PARAM register addresses.
+ */
+static __le32 *rtl8187b_ac_addr[4] = {
+	(__le32 *) 0xFFF0, /* AC_VO */
+	(__le32 *) 0xFFF4, /* AC_VI */
+	(__le32 *) 0xFFFC, /* AC_BK */
+	(__le32 *) 0xFFF8, /* AC_BE */
+};
+
+#define SIFS_TIME 0xa
+
 static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot,
 			     bool use_short_preamble)
 {
 	if (priv->is_rtl8187b) {
-		u8 difs, eifs, slot_time;
+		u8 difs, eifs;
 		u16 ack_timeout;
+		int queue;
 
 		if (use_short_slot) {
-			slot_time = 0x9;
+			priv->slot_time = 0x9;
 			difs = 0x1c;
 			eifs = 0x53;
 		} else {
-			slot_time = 0x14;
+			priv->slot_time = 0x14;
 			difs = 0x32;
 			eifs = 0x5b;
 		}
-		rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa);
-		rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time);
+		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+		rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time);
 		rtl818x_iowrite8(priv, &priv->map->DIFS, difs);
 
 		/*
@@ -957,18 +1104,21 @@ static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot,
 			ack_timeout += 144;
 		rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER,
 				 DIV_ROUND_UP(ack_timeout, 4));
+
+		for (queue = 0; queue < 4; queue++)
+			rtl818x_iowrite8(priv, (u8 *) rtl8187b_ac_addr[queue],
+					 priv->aifsn[queue] * priv->slot_time +
+					 SIFS_TIME);
 	} else {
 		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
 		if (use_short_slot) {
 			rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
 			rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
 			rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
-			rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
 		} else {
 			rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
 			rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
 			rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
-			rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
 		}
 	}
 }
@@ -1017,6 +1167,42 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
 	rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
 }
 
+static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u8 cw_min, cw_max;
+
+	if (queue > 3)
+		return -EINVAL;
+
+	cw_min = fls(params->cw_min);
+	cw_max = fls(params->cw_max);
+
+	if (priv->is_rtl8187b) {
+		priv->aifsn[queue] = params->aifs;
+
+		/*
+		 * This is the structure of AC_*_PARAM registers in 8187B:
+		 * - TXOP limit field, bit offset = 16
+		 * - ECWmax, bit offset = 12
+		 * - ECWmin, bit offset = 8
+		 * - AIFS, bit offset = 0
+		 */
+		rtl818x_iowrite32(priv, rtl8187b_ac_addr[queue],
+				  (params->txop << 16) | (cw_max << 12) |
+				  (cw_min << 8) | (params->aifs *
+				  priv->slot_time + SIFS_TIME));
+	} else {
+		if (queue != 0)
+			return -EINVAL;
+
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL,
+				 cw_min | (cw_max << 4));
+	}
+	return 0;
+}
+
 static const struct ieee80211_ops rtl8187_ops = {
 	.tx			= rtl8187_tx,
 	.start			= rtl8187_start,
@@ -1027,6 +1213,7 @@ static const struct ieee80211_ops rtl8187_ops = {
 	.config_interface	= rtl8187_config_interface,
 	.bss_info_changed	= rtl8187_bss_info_changed,
 	.configure_filter	= rtl8187_configure_filter,
+	.conf_tx		= rtl8187_conf_tx
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1222,9 +1409,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 	}
 
 	if (priv->is_rtl8187b) {
-		printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
-			"is EXPERIMENTAL, and could damage your\n"
-			"         hardware, use at your own risk\n");
+		printk(KERN_WARNING "rtl8187: 8187B chip detected.\n");
 		dev->flags |= IEEE80211_HW_SIGNAL_DBM;
 	} else {
 		dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
@@ -1256,6 +1441,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 		goto err_free_dev;
 	}
 	mutex_init(&priv->conf_mutex);
+	skb_queue_head_init(&priv->b_tx_status.queue);
 
 	printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n",
 	       wiphy_name(dev->wiphy), dev->wiphy->perm_addr,

+ 0 - 6
drivers/net/wireless/rtl818x/rtl8187_rtl8225.c

@@ -878,12 +878,6 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
 	for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
 		rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
 
-	rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28);
-	rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28);
-	rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28);
-	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);
 	rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
 	rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);

+ 62 - 0
include/linux/ieee80211.h

@@ -1042,6 +1042,68 @@ enum ieee80211_spectrum_mgmt_actioncode {
 	WLAN_ACTION_SPCT_CHL_SWITCH = 4,
 };
 
+/*
+ * IEEE 802.11-2007 7.3.2.9 Country information element
+ *
+ * Minimum length is 8 octets, ie len must be evenly
+ * divisible by 2
+ */
+
+/* Although the spec says 8 I'm seeing 6 in practice */
+#define IEEE80211_COUNTRY_IE_MIN_LEN	6
+
+/*
+ * For regulatory extension stuff see IEEE 802.11-2007
+ * Annex I (page 1141) and Annex J (page 1147). Also
+ * review 7.3.2.9.
+ *
+ * When dot11RegulatoryClassesRequired is true and the
+ * first_channel/reg_extension_id is >= 201 then the IE
+ * compromises of the 'ext' struct represented below:
+ *
+ *  - Regulatory extension ID - when generating IE this just needs
+ *    to be monotonically increasing for each triplet passed in
+ *    the IE
+ *  - Regulatory class - index into set of rules
+ *  - Coverage class - index into air propagation time (Table 7-27),
+ *    in microseconds, you can compute the air propagation time from
+ *    the index by multiplying by 3, so index 10 yields a propagation
+ *    of 10 us. Valid values are 0-31, values 32-255 are not defined
+ *    yet. A value of 0 inicates air propagation of <= 1 us.
+ *
+ *  See also Table I.2 for Emission limit sets and table
+ *  I.3 for Behavior limit sets. Table J.1 indicates how to map
+ *  a reg_class to an emission limit set and behavior limit set.
+ */
+#define IEEE80211_COUNTRY_EXTENSION_ID 201
+
+/*
+ *  Channels numbers in the IE must be monotonically increasing
+ *  if dot11RegulatoryClassesRequired is not true.
+ *
+ *  If dot11RegulatoryClassesRequired is true consecutive
+ *  subband triplets following a regulatory triplet shall
+ *  have monotonically increasing first_channel number fields.
+ *
+ *  Channel numbers shall not overlap.
+ *
+ *  Note that max_power is signed.
+ */
+struct ieee80211_country_ie_triplet {
+	union {
+		struct {
+			u8 first_channel;
+			u8 num_channels;
+			s8 max_power;
+		} __attribute__ ((packed)) chans;
+		struct {
+			u8 reg_extension_id;
+			u8 reg_class;
+			u8 coverage_class;
+		} __attribute__ ((packed)) ext;
+	};
+} __attribute__ ((packed));
+
 /* BACK action code */
 enum ieee80211_back_actioncode {
 	WLAN_ACTION_ADDBA_REQ = 0,

+ 5 - 0
include/linux/nl80211.h

@@ -508,6 +508,8 @@ enum nl80211_band_attr {
  *	on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
  *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ *	(100 * dBm).
  */
 enum nl80211_frequency_attr {
 	__NL80211_FREQUENCY_ATTR_INVALID,
@@ -516,12 +518,15 @@ enum nl80211_frequency_attr {
 	NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
 	NL80211_FREQUENCY_ATTR_NO_IBSS,
 	NL80211_FREQUENCY_ATTR_RADAR,
+	NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
 
 	/* keep last */
 	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
 	NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
 };
 
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
  * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps

+ 1 - 0
include/linux/rfkill.h

@@ -108,6 +108,7 @@ struct rfkill {
 
 	struct device dev;
 	struct list_head node;
+	enum rfkill_state state_for_resume;
 };
 #define to_rfkill(d)	container_of(d, struct rfkill, dev)
 

+ 22 - 0
include/net/wireless.h

@@ -181,6 +181,11 @@ struct ieee80211_supported_band {
  * struct wiphy - wireless hardware description
  * @idx: the wiphy index assigned to this item
  * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ * @fw_handles_regulatory: tells us the firmware for this device
+ * 	has its own regulatory solution and cannot identify the
+ * 	ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ * 	we will disregard the first regulatory hint (when the
+ * 	initiator is %REGDOM_SET_BY_CORE).
  * @reg_notifier: the driver's regulatory notification callback
  */
 struct wiphy {
@@ -192,6 +197,8 @@ struct wiphy {
 	/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
 	u16 interface_modes;
 
+	bool fw_handles_regulatory;
+
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
 	 * know whether it points to a wiphy your driver has registered
@@ -373,4 +380,19 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
  * for a regulatory domain structure for the respective country.
  */
 extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
+
+/**
+ * regulatory_hint_11d - hints a country IE as a regulatory domain
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ *	conflicts)
+ * @country_ie: pointer to the country IE
+ * @country_ie_len: length of the country IE
+ *
+ * We will intersect the rd with the what CRDA tells us should apply
+ * for the alpha2 this country IE belongs to, this prevents APs from
+ * sending us incorrect or outdated information against a country.
+ */
+extern void regulatory_hint_11d(struct wiphy *wiphy,
+				u8 *country_ie,
+				u8 country_ie_len);
 #endif /* __NET_WIRELESS_H */

+ 4 - 4
net/mac80211/Kconfig

@@ -16,20 +16,20 @@ menu "Rate control algorithm selection"
 
 config MAC80211_RC_PID
 	bool "PID controller based rate control algorithm" if EMBEDDED
-	default y
 	---help---
 	  This option enables a TX rate control algorithm for
 	  mac80211 that uses a PID controller to select the TX
 	  rate.
 
 config MAC80211_RC_MINSTREL
-	bool "Minstrel"
+	bool "Minstrel" if EMBEDDED
+	default y
 	---help---
 	  This option enables the 'minstrel' TX rate control algorithm
 
 choice
 	prompt "Default rate control algorithm"
-	default MAC80211_RC_DEFAULT_PID
+	default MAC80211_RC_DEFAULT_MINSTREL
 	---help---
 	  This option selects the default rate control algorithm
 	  mac80211 will use. Note that this default can still be
@@ -55,8 +55,8 @@ endchoice
 
 config MAC80211_RC_DEFAULT
 	string
-	default "pid" if MAC80211_RC_DEFAULT_PID
 	default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
+	default "pid" if MAC80211_RC_DEFAULT_PID
 	default ""
 
 endmenu

+ 1 - 1
net/mac80211/ht.c

@@ -36,7 +36,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
 
 	ht_cap->ht_supported = true;
 
-	ht_cap->cap = ht_cap->cap & sband->ht_cap.cap;
+	ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap;
 	ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
 	ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
 

+ 2 - 3
net/mac80211/main.c

@@ -722,7 +722,6 @@ EXPORT_SYMBOL(ieee80211_alloc_hw);
 int ieee80211_register_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	const char *name;
 	int result;
 	enum ieee80211_band band;
 	struct net_device *mdev;
@@ -787,8 +786,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	mdev->header_ops = &ieee80211_header_ops;
 	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
-	name = wiphy_dev(local->hw.wiphy)->driver->name;
-	local->hw.workqueue = create_freezeable_workqueue(name);
+	local->hw.workqueue =
+		create_freezeable_workqueue(wiphy_name(local->hw.wiphy));
 	if (!local->hw.workqueue) {
 		result = -ENOMEM;
 		goto fail_workqueue;

+ 13 - 2
net/mac80211/mlme.c

@@ -802,6 +802,10 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
+/*
+ * The disassoc 'reason' argument can be either our own reason
+ * if self disconnected or a reason code from the AP.
+ */
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_if_sta *ifsta, bool deauth,
 				   bool self_disconnected, u16 reason)
@@ -848,7 +852,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
 	ieee80211_sta_send_apinfo(sdata, ifsta);
 
-	if (self_disconnected)
+	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 
 	sta_info_unlink(&sta);
@@ -1163,7 +1167,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
-	ieee80211_set_disassoc(sdata, ifsta, false, false, 0);
+	ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code);
 }
 
 
@@ -1736,6 +1740,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 					       ap_ht_cap_flags);
 	}
 
+	if (elems.country_elem) {
+		/* Note we are only reviewing this on beacons
+		 * for the BSSID we are associated to */
+		regulatory_hint_11d(local->hw.wiphy,
+			elems.country_elem, elems.country_elem_len);
+	}
+
 	ieee80211_bss_info_change_notify(sdata, changed);
 }
 

+ 1 - 1
net/mac80211/rc80211_pid_algo.c

@@ -256,7 +256,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba
 	if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
 		spinfo->tx_num_failed += 2;
 		spinfo->tx_num_xmit++;
-	} else if (info->status.rates[0].count) {
+	} else if (info->status.rates[0].count > 1) {
 		spinfo->tx_num_failed++;
 		spinfo->tx_num_xmit++;
 	}

+ 4 - 3
net/mac80211/wep.c

@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
+#include <asm/unaligned.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -125,10 +126,10 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 {
 	struct blkcipher_desc desc = { .tfm = tfm };
 	struct scatterlist sg;
-	__le32 *icv;
+	__le32 icv;
 
-	icv = (__le32 *)(data + data_len);
-	*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+	icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+	put_unaligned(icv, (__le32 *)(data + data_len));
 
 	crypto_blkcipher_setkey(tfm, rc4key, klen);
 	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);

+ 16 - 1
net/rfkill/rfkill.c

@@ -565,22 +565,37 @@ static void rfkill_release(struct device *dev)
 #ifdef CONFIG_PM
 static int rfkill_suspend(struct device *dev, pm_message_t state)
 {
+	struct rfkill *rfkill = to_rfkill(dev);
+
 	/* mark class device as suspended */
 	if (dev->power.power_state.event != state.event)
 		dev->power.power_state = state;
 
+	/* store state for the resume handler */
+	rfkill->state_for_resume = rfkill->state;
+
 	return 0;
 }
 
 static int rfkill_resume(struct device *dev)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
+	enum rfkill_state newstate;
 
 	if (dev->power.power_state.event != PM_EVENT_ON) {
 		mutex_lock(&rfkill->mutex);
 
 		dev->power.power_state.event = PM_EVENT_ON;
 
+		/*
+		 * rfkill->state could have been modified before we got
+		 * called, and won't be updated by rfkill_toggle_radio()
+		 * in force mode.  Sync it FIRST.
+		 */
+		if (rfkill->get_state &&
+		    !rfkill->get_state(rfkill->data, &newstate))
+			rfkill->state = newstate;
+
 		/*
 		 * If we are under EPO, kick transmitter offline,
 		 * otherwise restore to pre-suspend state.
@@ -590,7 +605,7 @@ static int rfkill_resume(struct device *dev)
 		rfkill_toggle_radio(rfkill,
 				rfkill_epo_lock_active ?
 					RFKILL_STATE_SOFT_BLOCKED :
-					rfkill->state,
+					rfkill->state_for_resume,
 				1);
 
 		mutex_unlock(&rfkill->mutex);

+ 11 - 0
net/wireless/Kconfig

@@ -1,6 +1,15 @@
 config CFG80211
         tristate "Improved wireless configuration API"
 
+config CFG80211_REG_DEBUG
+	bool "cfg80211 regulatory debugging"
+	depends on CFG80211
+	default n
+	---help---
+	  You can enable this if you want to debug regulatory changes.
+
+	  If unsure, say N.
+
 config NL80211
 	bool "nl80211 new netlink interface support"
 	depends on CFG80211
@@ -40,6 +49,8 @@ config WIRELESS_OLD_REGULATORY
 	  ieee80211_regdom module parameter. This is being phased out and you
 	  should stop using them ASAP.
 
+	  Note: You will need CRDA if you want 802.11d support
+
 	  Say Y unless you have installed a new userspace application.
 	  Also say Y if have one currently depending on the ieee80211_regdom
 	  module parameter and cannot port it to use the new userspace

+ 4 - 1
net/wireless/core.c

@@ -19,7 +19,6 @@
 #include "nl80211.h"
 #include "core.h"
 #include "sysfs.h"
-#include "reg.h"
 
 /* name for sysfs, %d is appended */
 #define PHY_NAME "phy"
@@ -348,6 +347,10 @@ void wiphy_unregister(struct wiphy *wiphy)
 	/* unlock again before freeing */
 	mutex_unlock(&drv->mtx);
 
+	/* If this device got a regulatory hint tell core its
+	 * free to listen now to a new shiny device regulatory hint */
+	reg_device_remove(wiphy);
+
 	list_del(&drv->list);
 	device_del(&drv->wiphy.dev);
 	debugfs_remove(drv->wiphy.debugfsdir);

+ 13 - 0
net/wireless/core.h

@@ -11,6 +11,7 @@
 #include <net/genetlink.h>
 #include <net/wireless.h>
 #include <net/cfg80211.h>
+#include "reg.h"
 
 struct cfg80211_registered_device {
 	struct cfg80211_ops *ops;
@@ -21,6 +22,18 @@ struct cfg80211_registered_device {
 	 * any call is in progress */
 	struct mutex mtx;
 
+	/* ISO / IEC 3166 alpha2 for which this device is receiving
+	 * country IEs on, this can help disregard country IEs from APs
+	 * on the same alpha2 quickly. The alpha2 may differ from
+	 * cfg80211_regdomain's alpha2 when an intersection has occurred.
+	 * If the AP is reconfigured this can also be used to tell us if
+	 * the country on the country IE changed. */
+	char country_ie_alpha2[2];
+
+	/* If a Country IE has been received this tells us the environment
+	 * which its telling us its in. This defaults to ENVIRON_ANY */
+	enum environment_cap env;
+
 	/* wiphy index, internal only */
 	int idx;
 

+ 4 - 1
net/wireless/nl80211.c

@@ -198,6 +198,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			if (chan->flags & IEEE80211_CHAN_RADAR)
 				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
 
+			NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+				    DBM_TO_MBM(chan->max_power));
+
 			nla_nest_end(msg, nl_freq);
 		}
 
@@ -1760,7 +1763,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 #endif
 	mutex_lock(&cfg80211_drv_mutex);
-	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data);
+	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
 	mutex_unlock(&cfg80211_drv_mutex);
 	return r;
 }

+ 516 - 70
net/wireless/reg.c

@@ -60,12 +60,18 @@
  * @intersect: indicates whether the wireless core should intersect
  * 	the requested regulatory domain with the presently set regulatory
  * 	domain.
+ * @country_ie_checksum: checksum of the last processed and accepted
+ * 	country IE
+ * @country_ie_env: lets us know if the AP is telling us we are outdoor,
+ * 	indoor, or if it doesn't matter
  */
 struct regulatory_request {
 	struct wiphy *wiphy;
 	enum reg_set_by initiator;
 	char alpha2[2];
 	bool intersect;
+	u32 country_ie_checksum;
+	enum environment_cap country_ie_env;
 };
 
 /* Receipt of information from last regulatory request */
@@ -85,6 +91,11 @@ static u32 supported_bandwidths[] = {
  * information to give us an alpha2 */
 static const struct ieee80211_regdomain *cfg80211_regdomain;
 
+/* We use this as a place for the rd structure built from the
+ * last parsed country IE to rest until CRDA gets back to us with
+ * what it thinks should apply for the same country */
+static const struct ieee80211_regdomain *country_ie_regdomain;
+
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
 	.n_reg_rules = 1,
@@ -264,6 +275,18 @@ static bool is_unknown_alpha2(const char *alpha2)
 	return false;
 }
 
+static bool is_intersected_alpha2(const char *alpha2)
+{
+	if (!alpha2)
+		return false;
+	/* Special case where regulatory domain is the
+	 * result of an intersection between two regulatory domain
+	 * structures */
+	if (alpha2[0] == '9' && alpha2[1] == '8')
+		return true;
+	return false;
+}
+
 static bool is_an_alpha2(const char *alpha2)
 {
 	if (!alpha2)
@@ -292,6 +315,25 @@ static bool regdom_changed(const char *alpha2)
 	return true;
 }
 
+/**
+ * country_ie_integrity_changes - tells us if the country IE has changed
+ * @checksum: checksum of country IE of fields we are interested in
+ *
+ * If the country IE has not changed you can ignore it safely. This is
+ * useful to determine if two devices are seeing two different country IEs
+ * even on the same alpha2. Note that this will return false if no IE has
+ * been set on the wireless core yet.
+ */
+static bool country_ie_integrity_changes(u32 checksum)
+{
+	/* If no IE has been set then the checksum doesn't change */
+	if (unlikely(!last_request->country_ie_checksum))
+		return false;
+	if (unlikely(last_request->country_ie_checksum != checksum))
+		return true;
+	return false;
+}
+
 /* This lets us keep regulatory code which is updated on a regulatory
  * basis in userspace. */
 static int call_crda(const char *alpha2)
@@ -330,7 +372,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
 	const struct ieee80211_freq_range *freq_range = &rule->freq_range;
 	u32 freq_diff;
 
-	if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
+	if (freq_range->start_freq_khz <= 0 || freq_range->end_freq_khz <= 0)
 		return false;
 
 	if (freq_range->start_freq_khz > freq_range->end_freq_khz)
@@ -352,6 +394,9 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd)
 	if (!rd->n_reg_rules)
 		return false;
 
+	if (WARN_ON(rd->n_reg_rules > NL80211_MAX_SUPP_REG_RULES))
+		return false;
+
 	for (i = 0; i < rd->n_reg_rules; i++) {
 		reg_rule = &rd->reg_rules[i];
 		if (!is_valid_reg_rule(reg_rule))
@@ -376,6 +421,174 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
 	return 0;
 }
 
+/* Converts a country IE to a regulatory domain. A regulatory domain
+ * structure has a lot of information which the IE doesn't yet have,
+ * so for the other values we use upper max values as we will intersect
+ * with our userspace regulatory agent to get lower bounds. */
+static struct ieee80211_regdomain *country_ie_2_rd(
+				u8 *country_ie,
+				u8 country_ie_len,
+				u32 *checksum)
+{
+	struct ieee80211_regdomain *rd = NULL;
+	unsigned int i = 0;
+	char alpha2[2];
+	u32 flags = 0;
+	u32 num_rules = 0, size_of_regd = 0;
+	u8 *triplets_start = NULL;
+	u8 len_at_triplet = 0;
+	/* the last channel we have registered in a subband (triplet) */
+	int last_sub_max_channel = 0;
+
+	*checksum = 0xDEADBEEF;
+
+	/* Country IE requirements */
+	BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN ||
+		country_ie_len & 0x01);
+
+	alpha2[0] = country_ie[0];
+	alpha2[1] = country_ie[1];
+
+	/*
+	 * Third octet can be:
+	 *    'I' - Indoor
+	 *    'O' - Outdoor
+	 *
+	 *  anything else we assume is no restrictions
+	 */
+	if (country_ie[2] == 'I')
+		flags = NL80211_RRF_NO_OUTDOOR;
+	else if (country_ie[2] == 'O')
+		flags = NL80211_RRF_NO_INDOOR;
+
+	country_ie += 3;
+	country_ie_len -= 3;
+
+	triplets_start = country_ie;
+	len_at_triplet = country_ie_len;
+
+	*checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);
+
+	/* We need to build a reg rule for each triplet, but first we must
+	 * calculate the number of reg rules we will need. We will need one
+	 * for each channel subband */
+	while (country_ie_len >= 3) {
+		struct ieee80211_country_ie_triplet *triplet =
+			(struct ieee80211_country_ie_triplet *) country_ie;
+		int cur_sub_max_channel = 0, cur_channel = 0;
+
+		if (triplet->ext.reg_extension_id >=
+				IEEE80211_COUNTRY_EXTENSION_ID) {
+			country_ie += 3;
+			country_ie_len -= 3;
+			continue;
+		}
+
+		cur_channel = triplet->chans.first_channel;
+		cur_sub_max_channel = ieee80211_channel_to_frequency(
+			cur_channel + triplet->chans.num_channels);
+
+		/* Basic sanity check */
+		if (cur_sub_max_channel < cur_channel)
+			return NULL;
+
+		/* Do not allow overlapping channels. Also channels
+		 * passed in each subband must be monotonically
+		 * increasing */
+		if (last_sub_max_channel) {
+			if (cur_channel <= last_sub_max_channel)
+				return NULL;
+			if (cur_sub_max_channel <= last_sub_max_channel)
+				return NULL;
+		}
+
+		/* When dot11RegulatoryClassesRequired is supported
+		 * we can throw ext triplets as part of this soup,
+		 * for now we don't care when those change as we
+		 * don't support them */
+		*checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |
+		  ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |
+		  ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);
+
+		last_sub_max_channel = cur_sub_max_channel;
+
+		country_ie += 3;
+		country_ie_len -= 3;
+		num_rules++;
+
+		/* Note: this is not a IEEE requirement but
+		 * simply a memory requirement */
+		if (num_rules > NL80211_MAX_SUPP_REG_RULES)
+			return NULL;
+	}
+
+	country_ie = triplets_start;
+	country_ie_len = len_at_triplet;
+
+	size_of_regd = sizeof(struct ieee80211_regdomain) +
+		(num_rules * sizeof(struct ieee80211_reg_rule));
+
+	rd = kzalloc(size_of_regd, GFP_KERNEL);
+	if (!rd)
+		return NULL;
+
+	rd->n_reg_rules = num_rules;
+	rd->alpha2[0] = alpha2[0];
+	rd->alpha2[1] = alpha2[1];
+
+	/* This time around we fill in the rd */
+	while (country_ie_len >= 3) {
+		struct ieee80211_country_ie_triplet *triplet =
+			(struct ieee80211_country_ie_triplet *) country_ie;
+		struct ieee80211_reg_rule *reg_rule = NULL;
+		struct ieee80211_freq_range *freq_range = NULL;
+		struct ieee80211_power_rule *power_rule = NULL;
+
+		/* Must parse if dot11RegulatoryClassesRequired is true,
+		 * we don't support this yet */
+		if (triplet->ext.reg_extension_id >=
+				IEEE80211_COUNTRY_EXTENSION_ID) {
+			country_ie += 3;
+			country_ie_len -= 3;
+			continue;
+		}
+
+		reg_rule = &rd->reg_rules[i];
+		freq_range = &reg_rule->freq_range;
+		power_rule = &reg_rule->power_rule;
+
+		reg_rule->flags = flags;
+
+		/* The +10 is since the regulatory domain expects
+		 * the actual band edge, not the center of freq for
+		 * its start and end freqs, assuming 20 MHz bandwidth on
+		 * the channels passed */
+		freq_range->start_freq_khz =
+			MHZ_TO_KHZ(ieee80211_channel_to_frequency(
+				triplet->chans.first_channel) - 10);
+		freq_range->end_freq_khz =
+			MHZ_TO_KHZ(ieee80211_channel_to_frequency(
+				triplet->chans.first_channel +
+					triplet->chans.num_channels) + 10);
+
+		/* Large arbitrary values, we intersect later */
+		/* Increment this if we ever support >= 40 MHz channels
+		 * in IEEE 802.11 */
+		freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
+		power_rule->max_antenna_gain = DBI_TO_MBI(100);
+		power_rule->max_eirp = DBM_TO_MBM(100);
+
+		country_ie += 3;
+		country_ie_len -= 3;
+		i++;
+
+		BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
+	}
+
+	return rd;
+}
+
+
 /* Helper for regdom_intersect(), this does the real
  * mathematical intersection fun */
 static int reg_rules_intersect(
@@ -603,12 +816,23 @@ static void handle_band(struct ieee80211_supported_band *sband)
 		handle_channel(&sband->channels[i]);
 }
 
+static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
+{
+	if (!last_request)
+		return true;
+	if (setby == REGDOM_SET_BY_CORE &&
+		  wiphy->fw_handles_regulatory)
+		return true;
+	return false;
+}
+
 static void update_all_wiphy_regulatory(enum reg_set_by setby)
 {
 	struct cfg80211_registered_device *drv;
 
 	list_for_each_entry(drv, &cfg80211_drv_list, list)
-		wiphy_update_regulatory(&drv->wiphy, setby);
+		if (!ignore_reg_update(&drv->wiphy, setby))
+			wiphy_update_regulatory(&drv->wiphy, setby);
 }
 
 void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
@@ -660,16 +884,14 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 					return -EOPNOTSUPP;
 				return -EALREADY;
 			}
-			/* Two consecutive Country IE hints on the same wiphy */
-			if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+			/* Two consecutive Country IE hints on the same wiphy.
+			 * This should be picked up early by the driver/stack */
+			if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
+				  alpha2)))
 				return 0;
 			return -EALREADY;
 		}
-		/*
-		 * Ignore Country IE hints for now, need to think about
-		 * what we need to do to support multi-domain operation.
-		 */
-		return -EOPNOTSUPP;
+		return REG_INTERSECT;
 	case REGDOM_SET_BY_DRIVER:
 		if (last_request->initiator == REGDOM_SET_BY_DRIVER)
 			return -EALREADY;
@@ -677,6 +899,11 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 	case REGDOM_SET_BY_USER:
 		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
 			return REG_INTERSECT;
+		/* If the user knows better the user should set the regdom
+		 * to their country before the IE is picked up */
+		if (last_request->initiator == REGDOM_SET_BY_USER &&
+			  last_request->intersect)
+			return -EOPNOTSUPP;
 		return 0;
 	}
 
@@ -685,7 +912,9 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 
 /* Caller must hold &cfg80211_drv_mutex */
 int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
-		      const char *alpha2)
+			const char *alpha2,
+			u32 country_ie_checksum,
+			enum environment_cap env)
 {
 	struct regulatory_request *request;
 	bool intersect = false;
@@ -698,36 +927,32 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
 	else if (r)
 		return r;
 
-	switch (set_by) {
-	case REGDOM_SET_BY_CORE:
-	case REGDOM_SET_BY_COUNTRY_IE:
-	case REGDOM_SET_BY_DRIVER:
-	case REGDOM_SET_BY_USER:
-		request = kzalloc(sizeof(struct regulatory_request),
-				  GFP_KERNEL);
-		if (!request)
-			return -ENOMEM;
-
-		request->alpha2[0] = alpha2[0];
-		request->alpha2[1] = alpha2[1];
-		request->initiator = set_by;
-		request->wiphy = wiphy;
-		request->intersect = intersect;
-
-		kfree(last_request);
-		last_request = request;
-		r = call_crda(alpha2);
-#ifndef CONFIG_WIRELESS_OLD_REGULATORY
-		if (r)
-			printk(KERN_ERR "cfg80211: Failed calling CRDA\n");
-#endif
-		break;
-	default:
-		r = -ENOTSUPP;
-		break;
-	}
+	request = kzalloc(sizeof(struct regulatory_request),
+			  GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
 
-	return r;
+	request->alpha2[0] = alpha2[0];
+	request->alpha2[1] = alpha2[1];
+	request->initiator = set_by;
+	request->wiphy = wiphy;
+	request->intersect = intersect;
+	request->country_ie_checksum = country_ie_checksum;
+	request->country_ie_env = env;
+
+	kfree(last_request);
+	last_request = request;
+	/*
+	 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
+	 * AND if CRDA is NOT present nothing will happen, if someone
+	 * wants to bother with 11d with OLD_REG you can add a timer.
+	 * If after x amount of time nothing happens you can call:
+	 *
+	 * return set_regdom(country_ie_regdomain);
+	 *
+	 * to intersect with the static rd
+	 */
+	return call_crda(alpha2);
 }
 
 void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
@@ -735,11 +960,120 @@ void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
 	BUG_ON(!alpha2);
 
 	mutex_lock(&cfg80211_drv_mutex);
-	__regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2);
+	__regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY);
 	mutex_unlock(&cfg80211_drv_mutex);
 }
 EXPORT_SYMBOL(regulatory_hint);
 
+static bool reg_same_country_ie_hint(struct wiphy *wiphy,
+			u32 country_ie_checksum)
+{
+	if (!last_request->wiphy)
+		return false;
+	if (likely(last_request->wiphy != wiphy))
+		return !country_ie_integrity_changes(country_ie_checksum);
+	/* We should not have let these through at this point, they
+	 * should have been picked up earlier by the first alpha2 check
+	 * on the device */
+	if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))
+		return true;
+	return false;
+}
+
+void regulatory_hint_11d(struct wiphy *wiphy,
+			u8 *country_ie,
+			u8 country_ie_len)
+{
+	struct ieee80211_regdomain *rd = NULL;
+	char alpha2[2];
+	u32 checksum = 0;
+	enum environment_cap env = ENVIRON_ANY;
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	/* IE len must be evenly divisible by 2 */
+	if (country_ie_len & 0x01)
+		goto out;
+
+	if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
+		goto out;
+
+	/* Pending country IE processing, this can happen after we
+	 * call CRDA and wait for a response if a beacon was received before
+	 * we were able to process the last regulatory_hint_11d() call */
+	if (country_ie_regdomain)
+		goto out;
+
+	alpha2[0] = country_ie[0];
+	alpha2[1] = country_ie[1];
+
+	if (country_ie[2] == 'I')
+		env = ENVIRON_INDOOR;
+	else if (country_ie[2] == 'O')
+		env = ENVIRON_OUTDOOR;
+
+	/* We will run this for *every* beacon processed for the BSSID, so
+	 * we optimize an early check to exit out early if we don't have to
+	 * do anything */
+	if (likely(last_request->wiphy)) {
+		struct cfg80211_registered_device *drv_last_ie;
+
+		drv_last_ie = wiphy_to_dev(last_request->wiphy);
+
+		/* Lets keep this simple -- we trust the first AP
+		 * after we intersect with CRDA */
+		if (likely(last_request->wiphy == wiphy)) {
+			/* Ignore IEs coming in on this wiphy with
+			 * the same alpha2 and environment cap */
+			if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+				  alpha2) &&
+				  env == drv_last_ie->env)) {
+				goto out;
+			}
+			/* the wiphy moved on to another BSSID or the AP
+			 * was reconfigured. XXX: We need to deal with the
+			 * case where the user suspends and goes to goes
+			 * to another country, and then gets IEs from an
+			 * AP with different settings */
+			goto out;
+		} else {
+			/* Ignore IEs coming in on two separate wiphys with
+			 * the same alpha2 and environment cap */
+			if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+				  alpha2) &&
+				  env == drv_last_ie->env)) {
+				goto out;
+			}
+			/* We could potentially intersect though */
+			goto out;
+		}
+	}
+
+	rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
+	if (!rd)
+		goto out;
+
+	/* This will not happen right now but we leave it here for the
+	 * the future when we want to add suspend/resume support and having
+	 * the user move to another country after doing so, or having the user
+	 * move to another AP. Right now we just trust the first AP. This is why
+	 * this is marked as likley(). If we hit this before we add this support
+	 * we want to be informed of it as it would indicate a mistake in the
+	 * current design  */
+	if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum))))
+		goto out;
+
+	/* We keep this around for when CRDA comes back with a response so
+	 * we can intersect with that */
+	country_ie_regdomain = rd;
+
+	__regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,
+		country_ie_regdomain->alpha2, checksum, env);
+
+out:
+	mutex_unlock(&cfg80211_drv_mutex);
+}
+EXPORT_SYMBOL(regulatory_hint_11d);
 
 static void print_rd_rules(const struct ieee80211_regdomain *rd)
 {
@@ -779,7 +1113,25 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
 static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
 
-	if (is_world_regdom(rd->alpha2))
+	if (is_intersected_alpha2(rd->alpha2)) {
+		struct wiphy *wiphy = NULL;
+		struct cfg80211_registered_device *drv;
+
+		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+			if (last_request->wiphy) {
+				wiphy = last_request->wiphy;
+				drv = wiphy_to_dev(wiphy);
+				printk(KERN_INFO "cfg80211: Current regulatory "
+					"domain updated by AP to: %c%c\n",
+					drv->country_ie_alpha2[0],
+					drv->country_ie_alpha2[1]);
+			} else
+				printk(KERN_INFO "cfg80211: Current regulatory "
+					"domain intersected: \n");
+		} else
+				printk(KERN_INFO "cfg80211: Current regulatory "
+					"intersected: \n");
+	} else if (is_world_regdom(rd->alpha2))
 		printk(KERN_INFO "cfg80211: World regulatory "
 			"domain updated:\n");
 	else {
@@ -802,10 +1154,39 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
 	print_rd_rules(rd);
 }
 
+#ifdef CONFIG_CFG80211_REG_DEBUG
+static void reg_country_ie_process_debug(
+	const struct ieee80211_regdomain *rd,
+	const struct ieee80211_regdomain *country_ie_regdomain,
+	const struct ieee80211_regdomain *intersected_rd)
+{
+	printk(KERN_DEBUG "cfg80211: Received country IE:\n");
+	print_regdomain_info(country_ie_regdomain);
+	printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n");
+	print_regdomain_info(rd);
+	if (intersected_rd) {
+		printk(KERN_DEBUG "cfg80211: We intersect both of these "
+			"and get:\n");
+		print_regdomain_info(rd);
+		return;
+	}
+	printk(KERN_DEBUG "cfg80211: Intersection between both failed\n");
+}
+#else
+static inline void reg_country_ie_process_debug(
+	const struct ieee80211_regdomain *rd,
+	const struct ieee80211_regdomain *country_ie_regdomain,
+	const struct ieee80211_regdomain *intersected_rd)
+{
+}
+#endif
+
 /* Takes ownership of rd only if it doesn't fail */
 static int __set_regdom(const struct ieee80211_regdomain *rd)
 {
 	const struct ieee80211_regdomain *intersected_rd = NULL;
+	struct cfg80211_registered_device *drv = NULL;
+	struct wiphy *wiphy = NULL;
 	/* Some basic sanity checks first */
 
 	if (is_world_regdom(rd->alpha2)) {
@@ -822,10 +1203,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 	if (!last_request)
 		return -EINVAL;
 
-	/* allow overriding the static definitions if CRDA is present */
-	if (!is_old_static_regdom(cfg80211_regdomain) &&
-	    !regdom_changed(rd->alpha2))
-		return -EINVAL;
+	/* Lets only bother proceeding on the same alpha2 if the current
+	 * rd is non static (it means CRDA was present and was used last)
+	 * and the pending request came in from a country IE */
+	if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+		/* If someone else asked us to change the rd lets only bother
+		 * checking if the alpha2 changes if CRDA was already called */
+		if (!is_old_static_regdom(cfg80211_regdomain) &&
+		    !regdom_changed(rd->alpha2))
+			return -EINVAL;
+	}
+
+	wiphy = last_request->wiphy;
 
 	/* Now lets set the regulatory domain, update all driver channels
 	 * and finally inform them of what we have done, in case they want
@@ -835,36 +1224,78 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 	if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
 		return -EINVAL;
 
-	reset_regdomains();
+	if (!is_valid_rd(rd)) {
+		printk(KERN_ERR "cfg80211: Invalid "
+			"regulatory domain detected:\n");
+		print_regdomain_info(rd);
+		return -EINVAL;
+	}
 
-	/* Country IE parsing coming soon */
-	switch (last_request->initiator) {
-	case REGDOM_SET_BY_CORE:
-	case REGDOM_SET_BY_DRIVER:
-	case REGDOM_SET_BY_USER:
-		if (!is_valid_rd(rd)) {
-			printk(KERN_ERR "cfg80211: Invalid "
-				"regulatory domain detected:\n");
-			print_regdomain_info(rd);
-			return -EINVAL;
-		}
-		break;
-	case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */
-		WARN_ON(1);
-	default:
-		return -EOPNOTSUPP;
+	if (!last_request->intersect) {
+		reset_regdomains();
+		cfg80211_regdomain = rd;
+		return 0;
 	}
 
-	if (unlikely(last_request->intersect)) {
+	/* Intersection requires a bit more work */
+
+	if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+
 		intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
 		if (!intersected_rd)
 			return -EINVAL;
+
+		/* We can trash what CRDA provided now */
 		kfree(rd);
-		rd = intersected_rd;
+		rd = NULL;
+
+		reset_regdomains();
+		cfg80211_regdomain = intersected_rd;
+
+		return 0;
 	}
 
-	/* Tada! */
-	cfg80211_regdomain = rd;
+	/*
+	 * Country IE requests are handled a bit differently, we intersect
+	 * the country IE rd with what CRDA believes that country should have
+	 */
+
+	BUG_ON(!country_ie_regdomain);
+
+	if (rd != country_ie_regdomain) {
+		/* Intersect what CRDA returned and our what we
+		 * had built from the Country IE received */
+
+		intersected_rd = regdom_intersect(rd, country_ie_regdomain);
+
+		reg_country_ie_process_debug(rd, country_ie_regdomain,
+			intersected_rd);
+
+		kfree(country_ie_regdomain);
+		country_ie_regdomain = NULL;
+	} else {
+		/* This would happen when CRDA was not present and
+		 * OLD_REGULATORY was enabled. We intersect our Country
+		 * IE rd and what was set on cfg80211 originally */
+		intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
+	}
+
+	if (!intersected_rd)
+		return -EINVAL;
+
+	drv = wiphy_to_dev(wiphy);
+
+	drv->country_ie_alpha2[0] = rd->alpha2[0];
+	drv->country_ie_alpha2[1] = rd->alpha2[1];
+	drv->env = last_request->country_ie_env;
+
+	BUG_ON(intersected_rd == rd);
+
+	kfree(rd);
+	rd = NULL;
+
+	reset_regdomains();
+	cfg80211_regdomain = intersected_rd;
 
 	return 0;
 }
@@ -885,16 +1316,28 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 	}
 
 	/* This would make this whole thing pointless */
-	BUG_ON(rd != cfg80211_regdomain);
+	if (!last_request->intersect)
+		BUG_ON(rd != cfg80211_regdomain);
 
 	/* update all wiphys now with the new established regulatory domain */
 	update_all_wiphy_regulatory(last_request->initiator);
 
-	print_regdomain(rd);
+	print_regdomain(cfg80211_regdomain);
 
 	return r;
 }
 
+/* Caller must hold cfg80211_drv_mutex */
+void reg_device_remove(struct wiphy *wiphy)
+{
+	if (!last_request->wiphy)
+		return;
+	if (last_request->wiphy != wiphy)
+		return;
+	last_request->wiphy = NULL;
+	last_request->country_ie_env = ENVIRON_ANY;
+}
+
 int regulatory_init(void)
 {
 	int err;
@@ -914,11 +1357,11 @@ int regulatory_init(void)
 	 * that is not a valid ISO / IEC 3166 alpha2 */
 	if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
 		err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
-					ieee80211_regdom);
+					ieee80211_regdom, 0, ENVIRON_ANY);
 #else
 	cfg80211_regdomain = cfg80211_world_regdom;
 
-	err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00");
+	err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY);
 	if (err)
 		printk(KERN_ERR "cfg80211: calling CRDA failed - "
 		       "unable to update world regulatory domain, "
@@ -934,6 +1377,9 @@ void regulatory_exit(void)
 
 	reset_regdomains();
 
+	kfree(country_ie_regdomain);
+	country_ie_regdomain = NULL;
+
 	kfree(last_request);
 
 	platform_device_unregister(reg_pdev);

+ 17 - 4
net/wireless/reg.h

@@ -4,28 +4,41 @@
 bool is_world_regdom(const char *alpha2);
 bool reg_is_valid_request(const char *alpha2);
 
+void reg_device_remove(struct wiphy *wiphy);
+
 int regulatory_init(void);
 void regulatory_exit(void);
 
 int set_regdom(const struct ieee80211_regdomain *rd);
 
+enum environment_cap {
+	ENVIRON_ANY,
+	ENVIRON_INDOOR,
+	ENVIRON_OUTDOOR,
+};
+
+
 /**
  * __regulatory_hint - hint to the wireless core a regulatory domain
  * @wiphy: if the hint comes from country information from an AP, this
  *	is required to be set to the wiphy that received the information
  * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
  *	should be in.
+ * @country_ie_checksum: checksum of processed country IE, set this to 0
+ * 	if the hint did not come from a country IE
+ * @country_ie_env: the environment the IE told us we are in, %ENVIRON_*
  *
  * The Wireless subsystem can use this function to hint to the wireless core
- * what it believes should be the current regulatory domain by
- * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
- * domain should be in.
+ * what it believes should be the current regulatory domain by giving it an
+ * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be
+ * in.
  *
  * Returns zero if all went fine, %-EALREADY if a regulatory domain had
  * already been set or other standard error codes.
  *
  */
 extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
-			     const char *alpha2);
+			     const char *alpha2, u32 country_ie_checksum,
+			     enum environment_cap country_ie_env);
 
 #endif  /* __NET_WIRELESS_REG_H */

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