diff --git a/MAINTAINERS b/MAINTAINERS
index 194095ac07ec3e6f78cfc8f94261e88f675a99c7..579713ef7cfb4e750944c584a599fc3874bf0b42 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1230,7 +1230,7 @@ F:	Documentation/aoe/
 F:	drivers/block/aoe/
 
 ATHEROS ATH GENERIC UTILITIES
-M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
+M:	"Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
 L:	linux-wireless@vger.kernel.org
 S:	Supported
 F:	drivers/net/wireless/ath/*
@@ -1238,7 +1238,7 @@ F:	drivers/net/wireless/ath/*
 ATHEROS ATH5K WIRELESS DRIVER
 M:	Jiri Slaby <jirislaby@gmail.com>
 M:	Nick Kossifidis <mickflemm@gmail.com>
-M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
+M:	"Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
 M:	Bob Copeland <me@bobcopeland.com>
 L:	linux-wireless@vger.kernel.org
 L:	ath5k-devel@lists.ath5k.org
@@ -1247,10 +1247,10 @@ S:	Maintained
 F:	drivers/net/wireless/ath/ath5k/
 
 ATHEROS ATH9K WIRELESS DRIVER
-M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
-M:	Jouni Malinen <jmalinen@atheros.com>
-M:	Vasanthakumar Thiagarajan <vasanth@atheros.com>
-M:	Senthil Balasubramanian <senthilkumar@atheros.com>
+M:	"Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
+M:	Jouni Malinen <jouni@qca.qualcomm.com>
+M:	Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
+M:	Senthil Balasubramanian <senthilb@qca.qualcomm.com>
 L:	linux-wireless@vger.kernel.org
 L:	ath9k-devel@lists.ath9k.org
 W:	http://wireless.kernel.org/en/users/Drivers/ath9k
@@ -1278,7 +1278,7 @@ F:	drivers/input/misc/ati_remote2.c
 ATLX ETHERNET DRIVERS
 M:	Jay Cliburn <jcliburn@gmail.com>
 M:	Chris Snook <chris.snook@gmail.com>
-M:	Jie Yang <jie.yang@atheros.com>
+M:	Jie Yang <yangjie@qca.qualcomm.com>
 L:	netdev@vger.kernel.org
 W:	http://sourceforge.net/projects/atl1
 W:	http://atl1.sourceforge.net
@@ -4503,6 +4503,17 @@ W:	http://www.qlogic.com
 S:	Supported
 F:	drivers/net/ethernet/qlogic/netxen/
 
+NFC SUBSYSTEM
+M:	Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+M:	Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+M:	Samuel Ortiz <sameo@linux.intel.com>
+L:	linux-wireless@vger.kernel.org
+S:	Maintained
+F:	net/nfc/
+F:	include/linux/nfc.h
+F:	include/net/nfc.h
+F:	drivers/nfc/
+
 NFS, SUNRPC, AND LOCKD CLIENTS
 M:	Trond Myklebust <Trond.Myklebust@netapp.com>
 L:	linux-nfs@vger.kernel.org
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index 5940c81e7e1274d3feca3eeff84d64b40acf727d..4bc10aa57bd425cf61cb0cb65f1e8f064b169e38 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -90,6 +90,24 @@ void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
 	}
 }
 
+/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
+{
+	struct bcma_bus *bus = cc->core->bus;
+	u32 val;
+
+	val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
+	if (enable) {
+		val |= BCMA_CHIPCTL_4331_EXTPA_EN;
+		if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
+			val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
+	} else {
+		val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
+		val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
+	}
+	bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
+}
+
 void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 {
 	struct bcma_bus *bus = cc->core->bus;
@@ -99,7 +117,7 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 		bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 		break;
 	case 0x4331:
-		pr_err("Enabling Ext PA lines not implemented\n");
+		/* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 		break;
 	case 43224:
 		if (bus->chipinfo.rev == 0) {
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 0ea390f9aa9e75e3dfb2d18139eb670eca7f01f5..cad9948576837a53373791179b388d59276c7596 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -281,7 +281,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 
 	/* get & parse master ports */
 	for (i = 0; i < ports[0]; i++) {
-		u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
+		s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
 		if (mst_port_d < 0)
 			return -EILSEQ;
 	}
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index 8b5b7856abe3314ceeb9526811267b9f7e3a2576..166ed13ec06685667aa00fe9cf381d08a2af71ed 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -152,6 +152,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
 	if (!sprom)
 		return -ENOMEM;
 
+	if (bus->chipinfo.id == 0x4331)
+		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
+
 	/* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 	 * According to brcm80211 this applies to cards with PCIe rev >= 6
 	 * TODO: understand this condition and use it */
@@ -159,6 +162,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
 		BCMA_CC_SPROM_PCIE6;
 	bcma_sprom_read(bus, offset, sprom);
 
+	if (bus->chipinfo.id == 0x4331)
+		bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
+
 	err = bcma_sprom_valid(sprom);
 	if (err)
 		goto out;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 44d9d8d56490c8a5bbe1b1fac4bc74c364ce92c1..b54ab78fb092231f16dc8f33039bad8f6f1f0435 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -303,17 +303,13 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
  * register as the other analog registers.  Hence the 9 writes.
  */
 static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
-					 int restore,
-					 int power_off)
+					 bool power_off)
 {
 	u8 i;
 	u32 val;
 
-	if (ah->is_pciexpress != true || ah->aspm_enabled != true)
-		return;
-
 	/* Nothing to do on restore for 11N */
-	if (!restore) {
+	if (!power_off /* !restore */) {
 		if (AR_SREV_9280_20_OR_LATER(ah)) {
 			/*
 			 * AR9280 2.0 or later chips use SerDes values from the
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index a0aadaddd0710691967564c59a01399245418634..f2c6f2316a3b5edad25f18604fe1200216598b19 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -636,7 +636,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
 	{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
 	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
 	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-	{0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
+	{0x0000a204, 0x000036c0, 0x000036c4, 0x000036c4, 0x000036c0},
 	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
 	{0x0000a22c, 0x01026a2f, 0x01026a2f, 0x01026a2f, 0x01026a2f},
 	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index f48051c50092f0d85a5babf97160621862c24b36..fa35a0235f44b2ef2e0ce267cc8099bc6e108a9f 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -839,20 +839,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 			       struct ath9k_channel *chan)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->caps;
-	int val;
 	bool txiqcal_done = false;
 
-	val = REG_READ(ah, AR_ENT_OTP);
-	ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val);
-
-	/* Configure rx/tx chains before running AGC/TxiQ cals */
-	if (val & AR_ENT_OTP_CHAIN2_DISABLE)
-		ar9003_hw_set_chain_masks(ah, 0x3, 0x3);
-	else
-		ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask,
-					  pCap->tx_chainmask);
-
 	/* Do Tx IQ Calibration */
 	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
 		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
@@ -887,9 +875,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 	if (txiqcal_done)
 		ar9003_hw_tx_iq_cal_post_proc(ah);
 
-	/* Revert chainmasks to their original values before NF cal */
-	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
-
 	ath9k_hw_start_nfcal(ah, true);
 
 	/* Initialize list pointers */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index ad2bb2bf4e8a8ff86242ee99bd4a92b8dbb395c2..b6839e695270999bcd1ef1665d3e533c80a444af 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -21,6 +21,7 @@
 #include "ar9340_initvals.h"
 #include "ar9330_1p1_initvals.h"
 #include "ar9330_1p2_initvals.h"
+#include "ar9580_1p0_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
 
@@ -253,6 +254,56 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
 				ar9485_1_1_pcie_phy_clkreq_disable_L1,
 				ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
 				2);
+	} else if (AR_SREV_9580(ah)) {
+		/* mac */
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+				ar9580_1p0_mac_core,
+				ARRAY_SIZE(ar9580_1p0_mac_core), 2);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+				ar9580_1p0_mac_postamble,
+				ARRAY_SIZE(ar9580_1p0_mac_postamble), 5);
+
+		/* bb */
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+				ar9580_1p0_baseband_core,
+				ARRAY_SIZE(ar9580_1p0_baseband_core), 2);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+				ar9580_1p0_baseband_postamble,
+				ARRAY_SIZE(ar9580_1p0_baseband_postamble), 5);
+
+		/* radio */
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+				ar9580_1p0_radio_core,
+				ARRAY_SIZE(ar9580_1p0_radio_core), 2);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+				ar9580_1p0_radio_postamble,
+				ARRAY_SIZE(ar9580_1p0_radio_postamble), 5);
+
+		/* soc */
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+				ar9580_1p0_soc_preamble,
+				ARRAY_SIZE(ar9580_1p0_soc_preamble), 2);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+				ar9580_1p0_soc_postamble,
+				ARRAY_SIZE(ar9580_1p0_soc_postamble), 5);
+
+		/* rx/tx gain */
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
+				ar9580_1p0_rx_gain_table,
+				ARRAY_SIZE(ar9580_1p0_rx_gain_table), 2);
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9580_1p0_low_ob_db_tx_gain_table,
+				ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table),
+				5);
+
+		INIT_INI_ARRAY(&ah->iniModesAdditional,
+				ar9580_1p0_modes_fast_clock,
+				ARRAY_SIZE(ar9580_1p0_modes_fast_clock),
+				3);
 	} else {
 		/* mac */
 		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -348,6 +399,11 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 				       ar9485_modes_lowest_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
 				       5);
+		else if (AR_SREV_9580(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+			      ar9580_1p0_lowest_ob_db_tx_gain_table,
+			      ARRAY_SIZE(ar9580_1p0_lowest_ob_db_tx_gain_table),
+			      5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
@@ -375,6 +431,11 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 				       ar9485Modes_high_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
 				       5);
+		else if (AR_SREV_9580(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9580_1p0_high_ob_db_tx_gain_table,
+				ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table),
+				       5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_high_ob_db_tx_gain_table_2p2,
@@ -402,6 +463,11 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 				       ar9485Modes_low_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
 				       5);
+		else if (AR_SREV_9580(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				 ar9580_1p0_low_ob_db_tx_gain_table,
+				 ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table),
+				 5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_low_ob_db_tx_gain_table_2p2,
@@ -429,6 +495,11 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 				       ar9485Modes_high_power_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
 				       5);
+		else if (AR_SREV_9580(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9580_1p0_high_power_tx_gain_table,
+				ARRAY_SIZE(ar9580_1p0_high_power_tx_gain_table),
+				5);
 		else
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9300Modes_high_power_tx_gain_table_2p2,
@@ -463,6 +534,11 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
 				       ar9485Common_wo_xlna_rx_gain_1_1,
 				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
 				       2);
+		else if (AR_SREV_9580(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9580_1p0_rx_gain_table,
+				       ARRAY_SIZE(ar9580_1p0_rx_gain_table),
+				       2);
 		else
 			INIT_INI_ARRAY(&ah->iniModesRxGain,
 				       ar9300Common_rx_gain_table_2p2,
@@ -490,6 +566,11 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
 				       ar9485Common_wo_xlna_rx_gain_1_1,
 				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
 				       2);
+		else if (AR_SREV_9580(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				   ar9580_1p0_wo_xlna_rx_gain_table,
+				   ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table),
+				   2);
 		else
 			INIT_INI_ARRAY(&ah->iniModesRxGain,
 				       ar9300Common_wo_xlna_rx_gain_table_2p2,
@@ -516,14 +597,10 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
  * register as the other analog registers.  Hence the 9 writes.
  */
 static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
-					 int restore,
-					 int power_off)
+					 bool power_off)
 {
-	if (ah->is_pciexpress != true || ah->aspm_enabled != true)
-		return;
-
 	/* Nothing to do on restore for 11N */
-	if (!restore) {
+	if (!power_off /* !restore */) {
 		/* set bit 19 to allow forcing of pcie core into L1 state */
 		REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 1aadc4757e672a1cf9b93eb502c4b6a527c0fb76..8ace36e77399137943510b95ad3f74a3575d4aba 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -253,8 +253,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
 		return -EIO;
 	}
 
-	if (status & AR_TxOpExceeded)
-		ts->ts_status |= ATH9K_TXERR_XTXOP;
 	ts->ts_rateindex = MS(status, AR_FinalTxIdx);
 	ts->ts_seqnum = MS(status, AR_SeqNum);
 	ts->tid = MS(status, AR_TxTid);
@@ -264,6 +262,8 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
 	ts->ts_status = 0;
 	ts->ts_flags  = 0;
 
+	if (status & AR_TxOpExceeded)
+		ts->ts_status |= ATH9K_TXERR_XTXOP;
 	status = ACCESS_ONCE(ads->status2);
 	ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00);
 	ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01);
@@ -415,36 +415,12 @@ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
 static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
 					u32 aggrLen)
 {
-#define FIRST_DESC_NDELIMS 60
 	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
 
 	ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
 
-	if (ah->ent_mode & AR_ENT_OTP_MPSD) {
-		u32 ctl17, ndelim;
-		/*
-		 * Add delimiter when using RTS/CTS with aggregation
-		 * and non enterprise AR9003 card
-		 */
-		ctl17 = ads->ctl17;
-		ndelim = MS(ctl17, AR_PadDelim);
-
-		if (ndelim < FIRST_DESC_NDELIMS) {
-			aggrLen += (FIRST_DESC_NDELIMS - ndelim) * 4;
-			ndelim = FIRST_DESC_NDELIMS;
-		}
-
-		ctl17 &= ~AR_AggrLen;
-		ctl17 |= SM(aggrLen, AR_AggrLen);
-
-		ctl17 &= ~AR_PadDelim;
-		ctl17 |= SM(ndelim, AR_PadDelim);
-
-		ads->ctl17 = ctl17;
-	} else {
-		ads->ctl17 &= ~AR_AggrLen;
-		ads->ctl17 |= SM(aggrLen, AR_AggrLen);
-	}
+	ads->ctl17 &= ~AR_AggrLen;
+	ads->ctl17 |= SM(aggrLen, AR_AggrLen);
 }
 
 static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index a0aaa6855486cb9914fa3445368fa48890a2db94..33edb5653ca6ab850f751b8e61b399efff13a62b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -482,7 +482,7 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
 		(REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO);
 
 	/* Enable 11n HT, 20 MHz */
-	phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_WALSH |
+	phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 |
 		  AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
 
 	/* Configure baseband for dynamic 20/40 operation */
@@ -540,7 +540,7 @@ static void ar9003_hw_init_bb(struct ath_hw *ah,
 	udelay(synthDelay + BASE_ACTIVATE_DELAY);
 }
 
-void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
+static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
 {
 	switch (rx) {
 	case 0x5:
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 5c590429f120c307688952206e997aef6832d066..80397de11e0d2c182e121ec0e01b486eb62d0a07 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -1124,6 +1124,4 @@
 #define AR_PHY_CL_TAB_CL_GAIN_MOD		0x1f
 #define AR_PHY_CL_TAB_CL_GAIN_MOD_S		0
 
-void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
-
 #endif  /* AR9003_PHY_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..06b3f0df9fad50f707c79fc8f71ec90f6a493129
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
@@ -0,0 +1,1673 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef INITVALS_9580_1P0_H
+#define INITVALS_9580_1P0_H
+
+/* AR9580 1.0 */
+
+static const u32 ar9580_1p0_modes_fast_clock[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00001030, 0x00000268, 0x000004d0},
+	{0x00001070, 0x0000018c, 0x00000318},
+	{0x000010b0, 0x00000fd0, 0x00001fa0},
+	{0x00008014, 0x044c044c, 0x08980898},
+	{0x0000801c, 0x148ec02b, 0x148ec057},
+	{0x00008318, 0x000044c0, 0x00008980},
+	{0x00009e00, 0x0372131c, 0x0372131c},
+	{0x0000a230, 0x0000000b, 0x00000016},
+	{0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9580_1p0_radio_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
+	{0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
+	{0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
+	{0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+	{0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+	{0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+};
+
+static const u32 ar9580_1p0_baseband_core[][2] = {
+	/* Addr      allmodes  */
+	{0x00009800, 0xafe68e30},
+	{0x00009804, 0xfd14e000},
+	{0x00009808, 0x9c0a9f6b},
+	{0x0000980c, 0x04900000},
+	{0x00009814, 0x3280c00a},
+	{0x00009818, 0x00000000},
+	{0x0000981c, 0x00020028},
+	{0x00009834, 0x6400a290},
+	{0x00009838, 0x0108ecff},
+	{0x0000983c, 0x0d000600},
+	{0x00009880, 0x201fff00},
+	{0x00009884, 0x00001042},
+	{0x000098a4, 0x00200400},
+	{0x000098b0, 0x32840bbe},
+	{0x000098d0, 0x004b6a8e},
+	{0x000098d4, 0x00000820},
+	{0x000098dc, 0x00000000},
+	{0x000098f0, 0x00000000},
+	{0x000098f4, 0x00000000},
+	{0x00009c04, 0xff55ff55},
+	{0x00009c08, 0x0320ff55},
+	{0x00009c0c, 0x00000000},
+	{0x00009c10, 0x00000000},
+	{0x00009c14, 0x00046384},
+	{0x00009c18, 0x05b6b440},
+	{0x00009c1c, 0x00b6b440},
+	{0x00009d00, 0xc080a333},
+	{0x00009d04, 0x40206c10},
+	{0x00009d08, 0x009c4060},
+	{0x00009d0c, 0x9883800a},
+	{0x00009d10, 0x01834061},
+	{0x00009d14, 0x00c0040b},
+	{0x00009d18, 0x00000000},
+	{0x00009e08, 0x0038230c},
+	{0x00009e24, 0x990bb515},
+	{0x00009e28, 0x0c6f0000},
+	{0x00009e30, 0x06336f77},
+	{0x00009e34, 0x6af6532f},
+	{0x00009e38, 0x0cc80c00},
+	{0x00009e40, 0x0d261820},
+	{0x00009e4c, 0x00001004},
+	{0x00009e50, 0x00ff03f1},
+	{0x00009e54, 0x00000000},
+	{0x00009fc0, 0x803e4788},
+	{0x00009fc4, 0x0001efb5},
+	{0x00009fcc, 0x40000014},
+	{0x00009fd0, 0x01193b93},
+	{0x0000a20c, 0x00000000},
+	{0x0000a220, 0x00000000},
+	{0x0000a224, 0x00000000},
+	{0x0000a228, 0x10002310},
+	{0x0000a23c, 0x00000000},
+	{0x0000a244, 0x0c000000},
+	{0x0000a2a0, 0x00000001},
+	{0x0000a2c0, 0x00000001},
+	{0x0000a2c8, 0x00000000},
+	{0x0000a2cc, 0x18c43433},
+	{0x0000a2d4, 0x00000000},
+	{0x0000a2ec, 0x00000000},
+	{0x0000a2f0, 0x00000000},
+	{0x0000a2f4, 0x00000000},
+	{0x0000a2f8, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a34c, 0x00000000},
+	{0x0000a350, 0x0000a000},
+	{0x0000a364, 0x00000000},
+	{0x0000a370, 0x00000000},
+	{0x0000a390, 0x00000001},
+	{0x0000a394, 0x00000444},
+	{0x0000a398, 0x001f0e0f},
+	{0x0000a39c, 0x0075393f},
+	{0x0000a3a0, 0xb79f6427},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0xaaaaaaaa},
+	{0x0000a3ac, 0x3c466478},
+	{0x0000a3c0, 0x20202020},
+	{0x0000a3c4, 0x22222220},
+	{0x0000a3c8, 0x20200020},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3d8, 0x20202020},
+	{0x0000a3dc, 0x20202020},
+	{0x0000a3e0, 0x20202020},
+	{0x0000a3e4, 0x20202020},
+	{0x0000a3e8, 0x20202020},
+	{0x0000a3ec, 0x20202020},
+	{0x0000a3f0, 0x00000000},
+	{0x0000a3f4, 0x00000000},
+	{0x0000a3f8, 0x0c9bd380},
+	{0x0000a3fc, 0x000f0f01},
+	{0x0000a400, 0x8fa91f01},
+	{0x0000a404, 0x00000000},
+	{0x0000a408, 0x0e79e5c6},
+	{0x0000a40c, 0x00820820},
+	{0x0000a414, 0x1ce739ce},
+	{0x0000a418, 0x2d001dce},
+	{0x0000a41c, 0x1ce739ce},
+	{0x0000a420, 0x000001ce},
+	{0x0000a424, 0x1ce739ce},
+	{0x0000a428, 0x000001ce},
+	{0x0000a42c, 0x1ce739ce},
+	{0x0000a430, 0x1ce739ce},
+	{0x0000a434, 0x00000000},
+	{0x0000a438, 0x00001801},
+	{0x0000a43c, 0x00100000},
+	{0x0000a440, 0x00000000},
+	{0x0000a444, 0x00000000},
+	{0x0000a448, 0x05000080},
+	{0x0000a44c, 0x00000001},
+	{0x0000a450, 0x00010000},
+	{0x0000a458, 0x00000000},
+	{0x0000a640, 0x00000000},
+	{0x0000a644, 0x3fad9d74},
+	{0x0000a648, 0x0048060a},
+	{0x0000a64c, 0x00003c37},
+	{0x0000a670, 0x03020100},
+	{0x0000a674, 0x09080504},
+	{0x0000a678, 0x0d0c0b0a},
+	{0x0000a67c, 0x13121110},
+	{0x0000a680, 0x31301514},
+	{0x0000a684, 0x35343332},
+	{0x0000a688, 0x00000036},
+	{0x0000a690, 0x00000838},
+	{0x0000a7c0, 0x00000000},
+	{0x0000a7c4, 0xfffffffc},
+	{0x0000a7c8, 0x00000000},
+	{0x0000a7cc, 0x00000000},
+	{0x0000a7d0, 0x00000000},
+	{0x0000a7d4, 0x00000004},
+	{0x0000a7dc, 0x00000000},
+	{0x0000a8d0, 0x004b6a8e},
+	{0x0000a8d4, 0x00000820},
+	{0x0000a8dc, 0x00000000},
+	{0x0000a8f0, 0x00000000},
+	{0x0000a8f4, 0x00000000},
+	{0x0000b2d0, 0x00000080},
+	{0x0000b2d4, 0x00000000},
+	{0x0000b2ec, 0x00000000},
+	{0x0000b2f0, 0x00000000},
+	{0x0000b2f4, 0x00000000},
+	{0x0000b2f8, 0x00000000},
+	{0x0000b408, 0x0e79e5c0},
+	{0x0000b40c, 0x00820820},
+	{0x0000b420, 0x00000000},
+	{0x0000b8d0, 0x004b6a8e},
+	{0x0000b8d4, 0x00000820},
+	{0x0000b8dc, 0x00000000},
+	{0x0000b8f0, 0x00000000},
+	{0x0000b8f4, 0x00000000},
+	{0x0000c2d0, 0x00000080},
+	{0x0000c2d4, 0x00000000},
+	{0x0000c2ec, 0x00000000},
+	{0x0000c2f0, 0x00000000},
+	{0x0000c2f4, 0x00000000},
+	{0x0000c2f8, 0x00000000},
+	{0x0000c408, 0x0e79e5c0},
+	{0x0000c40c, 0x00820820},
+	{0x0000c420, 0x00000000},
+};
+
+static const u32 ar9580_1p0_mac_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a398, 0x00000000},
+	{0x0000a39c, 0x6f7f0301},
+	{0x0000a3a0, 0xca9228ee},
+};
+
+static const u32 ar9580_1p0_mac_core[][2] = {
+	/* Addr      allmodes  */
+	{0x00000008, 0x00000000},
+	{0x00000030, 0x00020085},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000000},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x000010f0, 0x00000100},
+	{0x00001270, 0x00000000},
+	{0x000012b0, 0x00000000},
+	{0x000012f0, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00008000, 0x00000000},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000000},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008040, 0x00000000},
+	{0x00008044, 0x00000000},
+	{0x00008048, 0x00000000},
+	{0x0000804c, 0xffffffff},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000310},
+	{0x00008074, 0x00000020},
+	{0x00008078, 0x00000000},
+	{0x0000809c, 0x0000000f},
+	{0x000080a0, 0x00000000},
+	{0x000080a4, 0x02ff0000},
+	{0x000080a8, 0x0e070605},
+	{0x000080ac, 0x0000000d},
+	{0x000080b0, 0x00000000},
+	{0x000080b4, 0x00000000},
+	{0x000080b8, 0x00000000},
+	{0x000080bc, 0x00000000},
+	{0x000080c0, 0x2a800000},
+	{0x000080c4, 0x06900168},
+	{0x000080c8, 0x13881c22},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00252500},
+	{0x000080d4, 0x00a00000},
+	{0x000080d8, 0x00400000},
+	{0x000080dc, 0x00000000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x3f3f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00000000},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000000},
+	{0x00008114, 0x000007ff},
+	{0x00008118, 0x000000aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x0000ffff},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081c4, 0x33332210},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000800},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x40000000},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x9bc00010},
+	{0x00008268, 0xffffffff},
+	{0x0000826c, 0x0000ffff},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000004},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x000000ff},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000140},
+	{0x00008314, 0x00000000},
+	{0x0000831c, 0x0000010d},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000700},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x02400000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0xaa48105b},
+	{0x00008348, 0x008f0000},
+	{0x0000835c, 0x00000000},
+	{0x00008360, 0xffffffff},
+	{0x00008364, 0xffffffff},
+	{0x00008368, 0x00000000},
+	{0x00008370, 0x00000000},
+	{0x00008374, 0x000000ff},
+	{0x00008378, 0x00000000},
+	{0x0000837c, 0x00000000},
+	{0x00008380, 0xffffffff},
+	{0x00008384, 0xffffffff},
+	{0x00008390, 0xffffffff},
+	{0x00008394, 0xffffffff},
+	{0x00008398, 0x00000000},
+	{0x0000839c, 0x00000000},
+	{0x000083a0, 0x00000000},
+	{0x000083a4, 0x0000fa14},
+	{0x000083a8, 0x000f0c00},
+	{0x000083ac, 0x33332210},
+	{0x000083b0, 0x33332210},
+	{0x000083b4, 0x33332210},
+	{0x000083b8, 0x33332210},
+	{0x000083bc, 0x00000000},
+	{0x000083c0, 0x00000000},
+	{0x000083c4, 0x00000000},
+	{0x000083c8, 0x00000000},
+	{0x000083cc, 0x00000200},
+	{0x000083d0, 0x000301ff},
+};
+
+static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
+	{0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x7082708c, 0x7082708c, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+	{0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+	{0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+	{0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_wo_xlna_rx_gain_table[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a000, 0x00010000},
+	{0x0000a004, 0x00030002},
+	{0x0000a008, 0x00050004},
+	{0x0000a00c, 0x00810080},
+	{0x0000a010, 0x00830082},
+	{0x0000a014, 0x01810180},
+	{0x0000a018, 0x01830182},
+	{0x0000a01c, 0x01850184},
+	{0x0000a020, 0x01890188},
+	{0x0000a024, 0x018b018a},
+	{0x0000a028, 0x018d018c},
+	{0x0000a02c, 0x03820190},
+	{0x0000a030, 0x03840383},
+	{0x0000a034, 0x03880385},
+	{0x0000a038, 0x038a0389},
+	{0x0000a03c, 0x038c038b},
+	{0x0000a040, 0x0390038d},
+	{0x0000a044, 0x03920391},
+	{0x0000a048, 0x03940393},
+	{0x0000a04c, 0x03960395},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x29292929},
+	{0x0000a084, 0x29292929},
+	{0x0000a088, 0x29292929},
+	{0x0000a08c, 0x29292929},
+	{0x0000a090, 0x22292929},
+	{0x0000a094, 0x1d1d2222},
+	{0x0000a098, 0x0c111117},
+	{0x0000a09c, 0x00030303},
+	{0x0000a0a0, 0x00000000},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x001f0000},
+	{0x0000a0c4, 0x01000101},
+	{0x0000a0c8, 0x011e011f},
+	{0x0000a0cc, 0x011c011d},
+	{0x0000a0d0, 0x02030204},
+	{0x0000a0d4, 0x02010202},
+	{0x0000a0d8, 0x021f0200},
+	{0x0000a0dc, 0x0302021e},
+	{0x0000a0e0, 0x03000301},
+	{0x0000a0e4, 0x031e031f},
+	{0x0000a0e8, 0x0402031d},
+	{0x0000a0ec, 0x04000401},
+	{0x0000a0f0, 0x041e041f},
+	{0x0000a0f4, 0x0502041d},
+	{0x0000a0f8, 0x05000501},
+	{0x0000a0fc, 0x051e051f},
+	{0x0000a100, 0x06010602},
+	{0x0000a104, 0x061f0600},
+	{0x0000a108, 0x061d061e},
+	{0x0000a10c, 0x07020703},
+	{0x0000a110, 0x07000701},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x01000101},
+	{0x0000a148, 0x011e011f},
+	{0x0000a14c, 0x011c011d},
+	{0x0000a150, 0x02030204},
+	{0x0000a154, 0x02010202},
+	{0x0000a158, 0x021f0200},
+	{0x0000a15c, 0x0302021e},
+	{0x0000a160, 0x03000301},
+	{0x0000a164, 0x031e031f},
+	{0x0000a168, 0x0402031d},
+	{0x0000a16c, 0x04000401},
+	{0x0000a170, 0x041e041f},
+	{0x0000a174, 0x0502041d},
+	{0x0000a178, 0x05000501},
+	{0x0000a17c, 0x051e051f},
+	{0x0000a180, 0x06010602},
+	{0x0000a184, 0x061f0600},
+	{0x0000a188, 0x061d061e},
+	{0x0000a18c, 0x07020703},
+	{0x0000a190, 0x07000701},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000196},
+	{0x0000b000, 0x00010000},
+	{0x0000b004, 0x00030002},
+	{0x0000b008, 0x00050004},
+	{0x0000b00c, 0x00810080},
+	{0x0000b010, 0x00830082},
+	{0x0000b014, 0x01810180},
+	{0x0000b018, 0x01830182},
+	{0x0000b01c, 0x01850184},
+	{0x0000b020, 0x02810280},
+	{0x0000b024, 0x02830282},
+	{0x0000b028, 0x02850284},
+	{0x0000b02c, 0x02890288},
+	{0x0000b030, 0x028b028a},
+	{0x0000b034, 0x0388028c},
+	{0x0000b038, 0x038a0389},
+	{0x0000b03c, 0x038c038b},
+	{0x0000b040, 0x0390038d},
+	{0x0000b044, 0x03920391},
+	{0x0000b048, 0x03940393},
+	{0x0000b04c, 0x03960395},
+	{0x0000b050, 0x00000000},
+	{0x0000b054, 0x00000000},
+	{0x0000b058, 0x00000000},
+	{0x0000b05c, 0x00000000},
+	{0x0000b060, 0x00000000},
+	{0x0000b064, 0x00000000},
+	{0x0000b068, 0x00000000},
+	{0x0000b06c, 0x00000000},
+	{0x0000b070, 0x00000000},
+	{0x0000b074, 0x00000000},
+	{0x0000b078, 0x00000000},
+	{0x0000b07c, 0x00000000},
+	{0x0000b080, 0x32323232},
+	{0x0000b084, 0x2f2f3232},
+	{0x0000b088, 0x23282a2d},
+	{0x0000b08c, 0x1c1e2123},
+	{0x0000b090, 0x14171919},
+	{0x0000b094, 0x0e0e1214},
+	{0x0000b098, 0x03050707},
+	{0x0000b09c, 0x00030303},
+	{0x0000b0a0, 0x00000000},
+	{0x0000b0a4, 0x00000000},
+	{0x0000b0a8, 0x00000000},
+	{0x0000b0ac, 0x00000000},
+	{0x0000b0b0, 0x00000000},
+	{0x0000b0b4, 0x00000000},
+	{0x0000b0b8, 0x00000000},
+	{0x0000b0bc, 0x00000000},
+	{0x0000b0c0, 0x003f0020},
+	{0x0000b0c4, 0x00400041},
+	{0x0000b0c8, 0x0140005f},
+	{0x0000b0cc, 0x0160015f},
+	{0x0000b0d0, 0x017e017f},
+	{0x0000b0d4, 0x02410242},
+	{0x0000b0d8, 0x025f0240},
+	{0x0000b0dc, 0x027f0260},
+	{0x0000b0e0, 0x0341027e},
+	{0x0000b0e4, 0x035f0340},
+	{0x0000b0e8, 0x037f0360},
+	{0x0000b0ec, 0x04400441},
+	{0x0000b0f0, 0x0460045f},
+	{0x0000b0f4, 0x0541047f},
+	{0x0000b0f8, 0x055f0540},
+	{0x0000b0fc, 0x057f0560},
+	{0x0000b100, 0x06400641},
+	{0x0000b104, 0x0660065f},
+	{0x0000b108, 0x067e067f},
+	{0x0000b10c, 0x07410742},
+	{0x0000b110, 0x075f0740},
+	{0x0000b114, 0x077f0760},
+	{0x0000b118, 0x07800781},
+	{0x0000b11c, 0x07a0079f},
+	{0x0000b120, 0x07c107bf},
+	{0x0000b124, 0x000007c0},
+	{0x0000b128, 0x00000000},
+	{0x0000b12c, 0x00000000},
+	{0x0000b130, 0x00000000},
+	{0x0000b134, 0x00000000},
+	{0x0000b138, 0x00000000},
+	{0x0000b13c, 0x00000000},
+	{0x0000b140, 0x003f0020},
+	{0x0000b144, 0x00400041},
+	{0x0000b148, 0x0140005f},
+	{0x0000b14c, 0x0160015f},
+	{0x0000b150, 0x017e017f},
+	{0x0000b154, 0x02410242},
+	{0x0000b158, 0x025f0240},
+	{0x0000b15c, 0x027f0260},
+	{0x0000b160, 0x0341027e},
+	{0x0000b164, 0x035f0340},
+	{0x0000b168, 0x037f0360},
+	{0x0000b16c, 0x04400441},
+	{0x0000b170, 0x0460045f},
+	{0x0000b174, 0x0541047f},
+	{0x0000b178, 0x055f0540},
+	{0x0000b17c, 0x057f0560},
+	{0x0000b180, 0x06400641},
+	{0x0000b184, 0x0660065f},
+	{0x0000b188, 0x067e067f},
+	{0x0000b18c, 0x07410742},
+	{0x0000b190, 0x075f0740},
+	{0x0000b194, 0x077f0760},
+	{0x0000b198, 0x07800781},
+	{0x0000b19c, 0x07a0079f},
+	{0x0000b1a0, 0x07c107bf},
+	{0x0000b1a4, 0x000007c0},
+	{0x0000b1a8, 0x00000000},
+	{0x0000b1ac, 0x00000000},
+	{0x0000b1b0, 0x00000000},
+	{0x0000b1b4, 0x00000000},
+	{0x0000b1b8, 0x00000000},
+	{0x0000b1bc, 0x00000000},
+	{0x0000b1c0, 0x00000000},
+	{0x0000b1c4, 0x00000000},
+	{0x0000b1c8, 0x00000000},
+	{0x0000b1cc, 0x00000000},
+	{0x0000b1d0, 0x00000000},
+	{0x0000b1d4, 0x00000000},
+	{0x0000b1d8, 0x00000000},
+	{0x0000b1dc, 0x00000000},
+	{0x0000b1e0, 0x00000000},
+	{0x0000b1e4, 0x00000000},
+	{0x0000b1e8, 0x00000000},
+	{0x0000b1ec, 0x00000000},
+	{0x0000b1f0, 0x00000396},
+	{0x0000b1f4, 0x00000396},
+	{0x0000b1f8, 0x00000396},
+	{0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9580_1p0_soc_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9580_1p0_high_ob_db_tx_gain_table[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
+	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
+	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+	{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+	{0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+	{0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_soc_preamble[][2] = {
+	/* Addr      allmodes  */
+	{0x000040a4, 0x00a0c1c9},
+	{0x00007008, 0x00000000},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00007048, 0x00000008},
+};
+
+static const u32 ar9580_1p0_rx_gain_table[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a000, 0x00010000},
+	{0x0000a004, 0x00030002},
+	{0x0000a008, 0x00050004},
+	{0x0000a00c, 0x00810080},
+	{0x0000a010, 0x00830082},
+	{0x0000a014, 0x01810180},
+	{0x0000a018, 0x01830182},
+	{0x0000a01c, 0x01850184},
+	{0x0000a020, 0x01890188},
+	{0x0000a024, 0x018b018a},
+	{0x0000a028, 0x018d018c},
+	{0x0000a02c, 0x01910190},
+	{0x0000a030, 0x01930192},
+	{0x0000a034, 0x01950194},
+	{0x0000a038, 0x038a0196},
+	{0x0000a03c, 0x038c038b},
+	{0x0000a040, 0x0390038d},
+	{0x0000a044, 0x03920391},
+	{0x0000a048, 0x03940393},
+	{0x0000a04c, 0x03960395},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x22222229},
+	{0x0000a084, 0x1d1d1d1d},
+	{0x0000a088, 0x1d1d1d1d},
+	{0x0000a08c, 0x1d1d1d1d},
+	{0x0000a090, 0x171d1d1d},
+	{0x0000a094, 0x11111717},
+	{0x0000a098, 0x00030311},
+	{0x0000a09c, 0x00000000},
+	{0x0000a0a0, 0x00000000},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x001f0000},
+	{0x0000a0c4, 0x01000101},
+	{0x0000a0c8, 0x011e011f},
+	{0x0000a0cc, 0x011c011d},
+	{0x0000a0d0, 0x02030204},
+	{0x0000a0d4, 0x02010202},
+	{0x0000a0d8, 0x021f0200},
+	{0x0000a0dc, 0x0302021e},
+	{0x0000a0e0, 0x03000301},
+	{0x0000a0e4, 0x031e031f},
+	{0x0000a0e8, 0x0402031d},
+	{0x0000a0ec, 0x04000401},
+	{0x0000a0f0, 0x041e041f},
+	{0x0000a0f4, 0x0502041d},
+	{0x0000a0f8, 0x05000501},
+	{0x0000a0fc, 0x051e051f},
+	{0x0000a100, 0x06010602},
+	{0x0000a104, 0x061f0600},
+	{0x0000a108, 0x061d061e},
+	{0x0000a10c, 0x07020703},
+	{0x0000a110, 0x07000701},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x01000101},
+	{0x0000a148, 0x011e011f},
+	{0x0000a14c, 0x011c011d},
+	{0x0000a150, 0x02030204},
+	{0x0000a154, 0x02010202},
+	{0x0000a158, 0x021f0200},
+	{0x0000a15c, 0x0302021e},
+	{0x0000a160, 0x03000301},
+	{0x0000a164, 0x031e031f},
+	{0x0000a168, 0x0402031d},
+	{0x0000a16c, 0x04000401},
+	{0x0000a170, 0x041e041f},
+	{0x0000a174, 0x0502041d},
+	{0x0000a178, 0x05000501},
+	{0x0000a17c, 0x051e051f},
+	{0x0000a180, 0x06010602},
+	{0x0000a184, 0x061f0600},
+	{0x0000a188, 0x061d061e},
+	{0x0000a18c, 0x07020703},
+	{0x0000a190, 0x07000701},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000196},
+	{0x0000b000, 0x00010000},
+	{0x0000b004, 0x00030002},
+	{0x0000b008, 0x00050004},
+	{0x0000b00c, 0x00810080},
+	{0x0000b010, 0x00830082},
+	{0x0000b014, 0x01810180},
+	{0x0000b018, 0x01830182},
+	{0x0000b01c, 0x01850184},
+	{0x0000b020, 0x02810280},
+	{0x0000b024, 0x02830282},
+	{0x0000b028, 0x02850284},
+	{0x0000b02c, 0x02890288},
+	{0x0000b030, 0x028b028a},
+	{0x0000b034, 0x0388028c},
+	{0x0000b038, 0x038a0389},
+	{0x0000b03c, 0x038c038b},
+	{0x0000b040, 0x0390038d},
+	{0x0000b044, 0x03920391},
+	{0x0000b048, 0x03940393},
+	{0x0000b04c, 0x03960395},
+	{0x0000b050, 0x00000000},
+	{0x0000b054, 0x00000000},
+	{0x0000b058, 0x00000000},
+	{0x0000b05c, 0x00000000},
+	{0x0000b060, 0x00000000},
+	{0x0000b064, 0x00000000},
+	{0x0000b068, 0x00000000},
+	{0x0000b06c, 0x00000000},
+	{0x0000b070, 0x00000000},
+	{0x0000b074, 0x00000000},
+	{0x0000b078, 0x00000000},
+	{0x0000b07c, 0x00000000},
+	{0x0000b080, 0x2a2d2f32},
+	{0x0000b084, 0x21232328},
+	{0x0000b088, 0x19191c1e},
+	{0x0000b08c, 0x12141417},
+	{0x0000b090, 0x07070e0e},
+	{0x0000b094, 0x03030305},
+	{0x0000b098, 0x00000003},
+	{0x0000b09c, 0x00000000},
+	{0x0000b0a0, 0x00000000},
+	{0x0000b0a4, 0x00000000},
+	{0x0000b0a8, 0x00000000},
+	{0x0000b0ac, 0x00000000},
+	{0x0000b0b0, 0x00000000},
+	{0x0000b0b4, 0x00000000},
+	{0x0000b0b8, 0x00000000},
+	{0x0000b0bc, 0x00000000},
+	{0x0000b0c0, 0x003f0020},
+	{0x0000b0c4, 0x00400041},
+	{0x0000b0c8, 0x0140005f},
+	{0x0000b0cc, 0x0160015f},
+	{0x0000b0d0, 0x017e017f},
+	{0x0000b0d4, 0x02410242},
+	{0x0000b0d8, 0x025f0240},
+	{0x0000b0dc, 0x027f0260},
+	{0x0000b0e0, 0x0341027e},
+	{0x0000b0e4, 0x035f0340},
+	{0x0000b0e8, 0x037f0360},
+	{0x0000b0ec, 0x04400441},
+	{0x0000b0f0, 0x0460045f},
+	{0x0000b0f4, 0x0541047f},
+	{0x0000b0f8, 0x055f0540},
+	{0x0000b0fc, 0x057f0560},
+	{0x0000b100, 0x06400641},
+	{0x0000b104, 0x0660065f},
+	{0x0000b108, 0x067e067f},
+	{0x0000b10c, 0x07410742},
+	{0x0000b110, 0x075f0740},
+	{0x0000b114, 0x077f0760},
+	{0x0000b118, 0x07800781},
+	{0x0000b11c, 0x07a0079f},
+	{0x0000b120, 0x07c107bf},
+	{0x0000b124, 0x000007c0},
+	{0x0000b128, 0x00000000},
+	{0x0000b12c, 0x00000000},
+	{0x0000b130, 0x00000000},
+	{0x0000b134, 0x00000000},
+	{0x0000b138, 0x00000000},
+	{0x0000b13c, 0x00000000},
+	{0x0000b140, 0x003f0020},
+	{0x0000b144, 0x00400041},
+	{0x0000b148, 0x0140005f},
+	{0x0000b14c, 0x0160015f},
+	{0x0000b150, 0x017e017f},
+	{0x0000b154, 0x02410242},
+	{0x0000b158, 0x025f0240},
+	{0x0000b15c, 0x027f0260},
+	{0x0000b160, 0x0341027e},
+	{0x0000b164, 0x035f0340},
+	{0x0000b168, 0x037f0360},
+	{0x0000b16c, 0x04400441},
+	{0x0000b170, 0x0460045f},
+	{0x0000b174, 0x0541047f},
+	{0x0000b178, 0x055f0540},
+	{0x0000b17c, 0x057f0560},
+	{0x0000b180, 0x06400641},
+	{0x0000b184, 0x0660065f},
+	{0x0000b188, 0x067e067f},
+	{0x0000b18c, 0x07410742},
+	{0x0000b190, 0x075f0740},
+	{0x0000b194, 0x077f0760},
+	{0x0000b198, 0x07800781},
+	{0x0000b19c, 0x07a0079f},
+	{0x0000b1a0, 0x07c107bf},
+	{0x0000b1a4, 0x000007c0},
+	{0x0000b1a8, 0x00000000},
+	{0x0000b1ac, 0x00000000},
+	{0x0000b1b0, 0x00000000},
+	{0x0000b1b4, 0x00000000},
+	{0x0000b1b8, 0x00000000},
+	{0x0000b1bc, 0x00000000},
+	{0x0000b1c0, 0x00000000},
+	{0x0000b1c4, 0x00000000},
+	{0x0000b1c8, 0x00000000},
+	{0x0000b1cc, 0x00000000},
+	{0x0000b1d0, 0x00000000},
+	{0x0000b1d4, 0x00000000},
+	{0x0000b1d8, 0x00000000},
+	{0x0000b1dc, 0x00000000},
+	{0x0000b1e0, 0x00000000},
+	{0x0000b1e4, 0x00000000},
+	{0x0000b1e8, 0x00000000},
+	{0x0000b1ec, 0x00000000},
+	{0x0000b1f0, 0x00000396},
+	{0x0000b1f4, 0x00000396},
+	{0x0000b1f8, 0x00000396},
+	{0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9580_1p0_radio_core[][2] = {
+	/* Addr      allmodes  */
+	{0x00016000, 0x36db6db6},
+	{0x00016004, 0x6db6db40},
+	{0x00016008, 0x73f00000},
+	{0x0001600c, 0x00000000},
+	{0x00016040, 0x7f80fff8},
+	{0x0001604c, 0x76d005b5},
+	{0x00016050, 0x556cf031},
+	{0x00016054, 0x13449440},
+	{0x00016058, 0x0c51c92c},
+	{0x0001605c, 0x3db7fffc},
+	{0x00016060, 0xfffffffc},
+	{0x00016064, 0x000f0278},
+	{0x0001606c, 0x6db60000},
+	{0x00016080, 0x00000000},
+	{0x00016084, 0x0e48048c},
+	{0x00016088, 0x54214514},
+	{0x0001608c, 0x119f481e},
+	{0x00016090, 0x24926490},
+	{0x00016098, 0xd2888888},
+	{0x000160a0, 0x0a108ffe},
+	{0x000160a4, 0x812fc370},
+	{0x000160a8, 0x423c8000},
+	{0x000160b4, 0x92480080},
+	{0x000160c0, 0x00adb6d0},
+	{0x000160c4, 0x6db6db60},
+	{0x000160c8, 0x6db6db6c},
+	{0x000160cc, 0x01e6c000},
+	{0x00016100, 0x3fffbe01},
+	{0x00016104, 0xfff80000},
+	{0x00016108, 0x00080010},
+	{0x00016144, 0x02084080},
+	{0x00016148, 0x00000000},
+	{0x00016280, 0x058a0001},
+	{0x00016284, 0x3d840208},
+	{0x00016288, 0x05a20408},
+	{0x0001628c, 0x00038c07},
+	{0x00016290, 0x00000004},
+	{0x00016294, 0x458aa14f},
+	{0x00016380, 0x00000000},
+	{0x00016384, 0x00000000},
+	{0x00016388, 0x00800700},
+	{0x0001638c, 0x00800700},
+	{0x00016390, 0x00800700},
+	{0x00016394, 0x00000000},
+	{0x00016398, 0x00000000},
+	{0x0001639c, 0x00000000},
+	{0x000163a0, 0x00000001},
+	{0x000163a4, 0x00000001},
+	{0x000163a8, 0x00000000},
+	{0x000163ac, 0x00000000},
+	{0x000163b0, 0x00000000},
+	{0x000163b4, 0x00000000},
+	{0x000163b8, 0x00000000},
+	{0x000163bc, 0x00000000},
+	{0x000163c0, 0x000000a0},
+	{0x000163c4, 0x000c0000},
+	{0x000163c8, 0x14021402},
+	{0x000163cc, 0x00001402},
+	{0x000163d0, 0x00000000},
+	{0x000163d4, 0x00000000},
+	{0x00016400, 0x36db6db6},
+	{0x00016404, 0x6db6db40},
+	{0x00016408, 0x73f00000},
+	{0x0001640c, 0x00000000},
+	{0x00016440, 0x7f80fff8},
+	{0x0001644c, 0x76d005b5},
+	{0x00016450, 0x556cf031},
+	{0x00016454, 0x13449440},
+	{0x00016458, 0x0c51c92c},
+	{0x0001645c, 0x3db7fffc},
+	{0x00016460, 0xfffffffc},
+	{0x00016464, 0x000f0278},
+	{0x0001646c, 0x6db60000},
+	{0x00016500, 0x3fffbe01},
+	{0x00016504, 0xfff80000},
+	{0x00016508, 0x00080010},
+	{0x00016544, 0x02084080},
+	{0x00016548, 0x00000000},
+	{0x00016780, 0x00000000},
+	{0x00016784, 0x00000000},
+	{0x00016788, 0x00800700},
+	{0x0001678c, 0x00800700},
+	{0x00016790, 0x00800700},
+	{0x00016794, 0x00000000},
+	{0x00016798, 0x00000000},
+	{0x0001679c, 0x00000000},
+	{0x000167a0, 0x00000001},
+	{0x000167a4, 0x00000001},
+	{0x000167a8, 0x00000000},
+	{0x000167ac, 0x00000000},
+	{0x000167b0, 0x00000000},
+	{0x000167b4, 0x00000000},
+	{0x000167b8, 0x00000000},
+	{0x000167bc, 0x00000000},
+	{0x000167c0, 0x000000a0},
+	{0x000167c4, 0x000c0000},
+	{0x000167c8, 0x14021402},
+	{0x000167cc, 0x00001402},
+	{0x000167d0, 0x00000000},
+	{0x000167d4, 0x00000000},
+	{0x00016800, 0x36db6db6},
+	{0x00016804, 0x6db6db40},
+	{0x00016808, 0x73f00000},
+	{0x0001680c, 0x00000000},
+	{0x00016840, 0x7f80fff8},
+	{0x0001684c, 0x76d005b5},
+	{0x00016850, 0x556cf031},
+	{0x00016854, 0x13449440},
+	{0x00016858, 0x0c51c92c},
+	{0x0001685c, 0x3db7fffc},
+	{0x00016860, 0xfffffffc},
+	{0x00016864, 0x000f0278},
+	{0x0001686c, 0x6db60000},
+	{0x00016900, 0x3fffbe01},
+	{0x00016904, 0xfff80000},
+	{0x00016908, 0x00080010},
+	{0x00016944, 0x02084080},
+	{0x00016948, 0x00000000},
+	{0x00016b80, 0x00000000},
+	{0x00016b84, 0x00000000},
+	{0x00016b88, 0x00800700},
+	{0x00016b8c, 0x00800700},
+	{0x00016b90, 0x00800700},
+	{0x00016b94, 0x00000000},
+	{0x00016b98, 0x00000000},
+	{0x00016b9c, 0x00000000},
+	{0x00016ba0, 0x00000001},
+	{0x00016ba4, 0x00000001},
+	{0x00016ba8, 0x00000000},
+	{0x00016bac, 0x00000000},
+	{0x00016bb0, 0x00000000},
+	{0x00016bb4, 0x00000000},
+	{0x00016bb8, 0x00000000},
+	{0x00016bbc, 0x00000000},
+	{0x00016bc0, 0x000000a0},
+	{0x00016bc4, 0x000c0000},
+	{0x00016bc8, 0x14021402},
+	{0x00016bcc, 0x00001402},
+	{0x00016bd0, 0x00000000},
+	{0x00016bd4, 0x00000000},
+};
+
+static const u32 ar9580_1p0_baseband_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+	{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+	{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+	{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+	{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
+	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
+	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
+	{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+	{0x0000a204, 0x000036c0, 0x000036c4, 0x000036c4, 0x000036c0},
+	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+	{0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
+	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+	{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+	{0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
+	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+	{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+	{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+	{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+	{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
+	{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
+	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+	{0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+	{0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+	{0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+	{0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9580_1p0_pcie_phy_clkreq_enable_L1[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x0835365e},
+	{0x00004040, 0x0008003b},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9580_1p0_pcie_phy_clkreq_disable_L1[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x0831365e},
+	{0x00004040, 0x0008003b},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9580_1p0_pcie_phy_pll_on_clkreq[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x0831265e},
+	{0x00004040, 0x0008003b},
+	{0x00004044, 0x00000000},
+};
+
+#endif /* INITVALS_9580_1P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index c03949eb37c893ea102879484d486ac7a4ea9be0..3a893e19d6c366056c2ca6a30f51d4974170e7b3 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -558,8 +558,7 @@ struct ath_ant_comb {
 #define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
 #define SC_OP_BT_SCAN		     BIT(13)
 #define SC_OP_ANI_RUN		     BIT(14)
-#define SC_OP_ENABLE_APM	     BIT(15)
-#define SC_OP_PRIM_STA_VIF	     BIT(16)
+#define SC_OP_PRIM_STA_VIF	     BIT(15)
 
 /* Powersave flags */
 #define PS_WAIT_FOR_BEACON        BIT(0)
@@ -664,7 +663,6 @@ extern int led_blink;
 extern bool is_ath9k_unloaded;
 
 irqreturn_t ath_isr(int irq, void *dev);
-void ath9k_init_crypto(struct ath_softc *sc);
 int ath9k_init_device(u16 devid, struct ath_softc *sc,
 		    const struct ath_bus_ops *bus_ops);
 void ath9k_deinit_device(struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index ac2da3cce7889f0430837660314a1d92073c26e8..ebaf304f464bc2aa0efc58bd1997251acfee90c7 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -82,7 +82,6 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
 					      int16_t *nfarray)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ieee80211_conf *conf = &common->hw->conf;
 	struct ath_nf_limits *limit;
 	struct ath9k_nfcal_hist *h;
 	bool high_nf_mid = false;
@@ -94,7 +93,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
 
 	for (i = 0; i < NUM_NF_READINGS; i++) {
 		if (!(chainmask & (1 << i)) ||
-		    ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
+		    ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(ah->curchan)))
 			continue;
 
 		h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index fa6bd2d189e573516e2ab7cac919ab3109dbe52f..dc705a224952658ecc9202b65e8d39b1748ef0da 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -169,6 +169,32 @@ void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
 }
 EXPORT_SYMBOL(ath9k_cmn_update_txpow);
 
+void ath9k_cmn_init_crypto(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	int i = 0;
+
+	/* Get the hardware key cache size. */
+	common->keymax = AR_KEYTABLE_SIZE;
+
+	/*
+	 * 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 (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
+		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
+
+	/*
+	 * Reset the key cache since some parts do not
+	 * reset the contents on initial power up.
+	 */
+	for (i = 0; i < common->keymax; i++)
+		ath_hw_keyreset(common, (u16) i);
+}
+EXPORT_SYMBOL(ath9k_cmn_init_crypto);
+
 static int __init ath9k_cmn_init(void)
 {
 	return 0;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index 77ec288b5a70557efc233e53c03b31b95d822bb4..ad14fecc76c6e1eb1405448a2b1179f2a4f234b0 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -62,3 +62,4 @@ void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
 				  enum ath_stomp_type stomp_type);
 void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
 			    u16 new_txpow, u16 *txpower);
+void ath9k_cmn_init_crypto(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 9bec3b89fb684030087f502270143b6b5c9047ec..da45f325be7da2fb8cc9a692633aec0b7d76d041 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1163,6 +1163,59 @@ static const struct file_operations fops_regdump = {
 	.llseek = default_llseek,/* read accesses f_pos */
 };
 
+static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_nfcal_hist *h = sc->caldata.nfCalHist;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ieee80211_conf *conf = &common->hw->conf;
+	u32 len = 0, size = 1500;
+	u32 i, j;
+	ssize_t retval = 0;
+	char *buf;
+	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+	u8 nread;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	len += snprintf(buf + len, size - len,
+			"Channel Noise Floor : %d\n", ah->noise);
+	len += snprintf(buf + len, size - len,
+			"Chain | privNF | # Readings | NF Readings\n");
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (!(chainmask & (1 << i)) ||
+		    ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
+			continue;
+
+		nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - h[i].invalidNFcount;
+		len += snprintf(buf + len, size - len, " %d\t %d\t %d\t\t",
+				i, h[i].privNF, nread);
+		for (j = 0; j < nread; j++)
+			len += snprintf(buf + len, size - len,
+					" %d", h[i].nfCalBuffer[j]);
+		len += snprintf(buf + len, size - len, "\n");
+	}
+
+	if (len > size)
+		len = size;
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+}
+
+static const struct file_operations fops_dump_nfcal = {
+	.read = read_file_dump_nfcal,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
 				     size_t count, loff_t *ppos)
 {
@@ -1262,6 +1315,8 @@ int ath9k_init_debug(struct ath_hw *ah)
 			    &ah->config.cwm_ignore_extcca);
 	debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_regdump);
+	debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc,
+			    &fops_dump_nfcal);
 	debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_base_eeprom);
 	debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 19aa5b7248875f0169d68898d07db4b4b0644746..9cf42f6973aaffe80170301add79c0f29c055730 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -572,25 +572,6 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
 	return -EINVAL;
 }
 
-static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
-{
-	struct ath_common *common = ath9k_hw_common(priv->ah);
-	int i = 0;
-
-	/* Get the hardware key cache size. */
-	common->keymax = AR_KEYTABLE_SIZE;
-
-	if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
-		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
-
-	/*
-	 * Reset the key cache since some parts do not
-	 * reset the contents on initial power up.
-	 */
-	for (i = 0; i < common->keymax; i++)
-		ath_hw_keyreset(common, (u16) i);
-}
-
 static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
 {
 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
@@ -720,7 +701,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
 		priv->cur_beacon_conf.bslot[i] = NULL;
 
-	ath9k_init_crypto(priv);
+	ath9k_cmn_init_crypto(ah);
 	ath9k_init_channels_rates(priv);
 	ath9k_init_misc(priv);
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 7212acb2bd6ccfb2f09caf858e0b13c48998a504..0248024da56aa927d070053e2f71b6b8027dc34f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1736,6 +1736,22 @@ static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw,
 	return ret;
 }
 
+
+static int ath9k_htc_get_stats(struct ieee80211_hw *hw,
+			       struct ieee80211_low_level_stats *stats)
+{
+	struct ath9k_htc_priv *priv = hw->priv;
+	struct ath_hw *ah = priv->ah;
+	struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
+
+	stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
+	stats->dot11RTSFailureCount = mib_stats->rts_bad;
+	stats->dot11FCSErrorCount = mib_stats->fcs_bad;
+	stats->dot11RTSSuccessCount = mib_stats->rts_good;
+
+	return 0;
+}
+
 struct ieee80211_ops ath9k_htc_ops = {
 	.tx                 = ath9k_htc_tx,
 	.start              = ath9k_htc_start,
@@ -1759,4 +1775,5 @@ struct ieee80211_ops ath9k_htc_ops = {
 	.rfkill_poll        = ath9k_htc_rfkill_poll_state,
 	.set_coverage_class = ath9k_htc_set_coverage_class,
 	.set_bitrate_mask   = ath9k_htc_set_bitrate_mask,
+	.get_stats	    = ath9k_htc_get_stats,
 };
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index cb29e8875386d7966334273748f2e7c97abab69d..dd9003ee123bfbe6701eedd519cdb749c643960a 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -22,10 +22,12 @@
 /* Hardware core and driver accessible callbacks */
 
 static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah,
-					       int restore,
-					       int power_off)
+					       bool power_off)
 {
-	ath9k_hw_ops(ah)->config_pci_powersave(ah, restore, power_off);
+	if (ah->aspm_enabled != true)
+		return;
+
+	ath9k_hw_ops(ah)->config_pci_powersave(ah, power_off);
 }
 
 static inline void ath9k_hw_rxena(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index db44e5b0c98b53cf75cb93f5b1cb1ff98b371c5c..a0d1147844fba7211c8b2cf0a45f915b50e9f0a8 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -603,10 +603,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 
 	ath9k_hw_init_mode_regs(ah);
 
-
-	if (ah->is_pciexpress)
-		ath9k_hw_aspm_init(ah);
-	else
+	if (!ah->is_pciexpress)
 		ath9k_hw_disablepcie(ah);
 
 	if (!AR_SREV_9300_20_OR_LATER(ah))
@@ -621,6 +618,9 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	if (r)
 		return r;
 
+	if (ah->is_pciexpress)
+		ath9k_hw_aspm_init(ah);
+
 	r = ath9k_hw_init_macaddr(ah);
 	if (r) {
 		ath_err(common, "Failed to initialize MAC address\n");
@@ -663,6 +663,7 @@ int ath9k_hw_init(struct ath_hw *ah)
 	case AR9300_DEVID_AR9485_PCIE:
 	case AR9300_DEVID_AR9330:
 	case AR9300_DEVID_AR9340:
+	case AR9300_DEVID_AR9580:
 		break;
 	default:
 		if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -996,7 +997,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
 		slottime = 21;
 		sifstime = 64;
 	} else {
-		eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS);
+		eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS)/common->clockrate;
 		reg = REG_READ(ah, AR_USEC);
 		rx_lat = MS(reg, AR_USEC_RX_LAT);
 		tx_lat = MS(reg, AR_USEC_TX_LAT);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 4fbcced2828cf7a454e3aa01012d14091312485c..3aa3fb1917758cb8ff916dbc6236fb8bd9f67f08 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -45,6 +45,7 @@
 #define AR9300_DEVID_PCIE	0x0030
 #define AR9300_DEVID_AR9340	0x0031
 #define AR9300_DEVID_AR9485_PCIE 0x0032
+#define AR9300_DEVID_AR9580	0x0033
 #define AR9300_DEVID_AR9330	0x0035
 
 #define AR5416_AR9100_DEVID	0x000b
@@ -606,8 +607,7 @@ struct ath_hw_private_ops {
  */
 struct ath_hw_ops {
 	void (*config_pci_powersave)(struct ath_hw *ah,
-				     int restore,
-				     int power_off);
+				     bool power_off);
 	void (*rx_enable)(struct ath_hw *ah);
 	void (*set_desc_link)(void *ds, u32 link);
 	bool (*calibrate)(struct ath_hw *ah,
@@ -1037,10 +1037,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
 void ath9k_hw_proc_mib_event(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
-#define ATH_PCIE_CAP_LINK_CTRL	0x70
-#define ATH_PCIE_CAP_LINK_L0S	1
-#define ATH_PCIE_CAP_LINK_L1	2
-
 #define ATH9K_CLOCK_RATE_CCK		22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM	40
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM	44
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index db38a58e752d4a001ffd9b22a909b6f3c55669cd..d7761d1fc5ba7c4813c4808488d6f2fd29735dbc 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -404,31 +404,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 	return error;
 }
 
-void ath9k_init_crypto(struct ath_softc *sc)
-{
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	int i = 0;
-
-	/* Get the hardware key cache size. */
-	common->keymax = AR_KEYTABLE_SIZE;
-
-	/*
-	 * Reset the key cache since some parts do not
-	 * reset the contents on initial power up.
-	 */
-	for (i = 0; i < common->keymax; i++)
-		ath_hw_keyreset(common, (u16) i);
-
-	/*
-	 * 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 (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
-		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
-}
-
 static int ath9k_init_btcoex(struct ath_softc *sc)
 {
 	struct ath_txq *txq;
@@ -630,7 +605,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 	if (ret)
 		goto err_btcoex;
 
-	ath9k_init_crypto(sc);
+	ath9k_cmn_init_crypto(sc->sc_ah);
 	ath9k_init_misc(sc);
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 0f90e1521ffeb61865ed8ee1ce473aea5c255349..7ce9b320f0d9758a7c8c6c393e98e9546f9078bd 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -345,21 +345,8 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
 	}
 	memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
 	qi->tqi_type = type;
-	if (qinfo == NULL) {
-		qi->tqi_qflags =
-			TXQ_FLAG_TXOKINT_ENABLE
-			| TXQ_FLAG_TXERRINT_ENABLE
-			| TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
-		qi->tqi_aifs = INIT_AIFS;
-		qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
-		qi->tqi_cwmax = INIT_CWMAX;
-		qi->tqi_shretry = INIT_SH_RETRY;
-		qi->tqi_lgretry = INIT_LG_RETRY;
-		qi->tqi_physCompBuf = 0;
-	} else {
-		qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
-		(void) ath9k_hw_set_txq_props(ah, q, qinfo);
-	}
+	qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+	(void) ath9k_hw_set_txq_props(ah, q, qinfo);
 
 	return q;
 }
@@ -564,7 +551,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 EXPORT_SYMBOL(ath9k_hw_resettxqueue);
 
 int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
-			struct ath_rx_status *rs, u64 tsf)
+			struct ath_rx_status *rs)
 {
 	struct ar5416_desc ads;
 	struct ar5416_desc *adsp = AR5416DESC(ds);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 8e848c4d16baf536834231633795e3c1c9382abe..153859ccc2a1a08c88907398c3a22b248d3483e6 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -687,7 +687,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
 bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
 bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
 int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
-			struct ath_rx_status *rs, u64 tsf);
+			struct ath_rx_status *rs);
 void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
 			  u32 size, u32 flags);
 bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1e7fe8c0e11915352f02319bee55fb36e83748cb..5ac4f3f2ad60e0200bcb49f3e464330d50ea37b5 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -565,7 +565,6 @@ void ath_ani_calibrate(unsigned long data)
 static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
 	struct ath_node *an;
-	struct ath_hw *ah = sc->sc_ah;
 	an = (struct ath_node *)sta->drv_priv;
 
 #ifdef CONFIG_ATH9K_DEBUGFS
@@ -574,9 +573,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
 	spin_unlock(&sc->nodes_lock);
 	an->sta = sta;
 #endif
-	if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
-		sc->sc_flags |= SC_OP_ENABLE_APM;
-
 	if (sc->sc_flags & SC_OP_TXAGGR) {
 		ath_tx_node_init(sc, an);
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
@@ -826,11 +822,9 @@ irqreturn_t ath_isr(int irq, void *dev)
 	if (status & ATH9K_INT_TXURN)
 		ath9k_hw_updatetxtriglevel(ah, true);
 
-	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
-		if (status & ATH9K_INT_RXEOL) {
-			ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
-			ath9k_hw_set_interrupts(ah, ah->imask);
-		}
+	if (status & ATH9K_INT_RXEOL) {
+		ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+		ath9k_hw_set_interrupts(ah, ah->imask);
 	}
 
 	if (status & ATH9K_INT_MIB) {
@@ -888,7 +882,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	spin_lock_bh(&sc->sc_pcu_lock);
 	atomic_set(&ah->intr_ref_cnt, -1);
 
-	ath9k_hw_configpcipowersave(ah, 0, 0);
+	ath9k_hw_configpcipowersave(ah, false);
 
 	if (!ah->curchan)
 		ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah);
@@ -969,7 +963,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	ath9k_hw_phy_disable(ah);
 
-	ath9k_hw_configpcipowersave(ah, 1, 1);
+	ath9k_hw_configpcipowersave(ah, true);
 
 	spin_unlock_bh(&sc->sc_pcu_lock);
 	ath9k_ps_restore(sc);
@@ -1069,7 +1063,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	init_channel = ath9k_cmn_get_curchannel(hw, ah);
 
 	/* Reset SERDES registers */
-	ath9k_hw_configpcipowersave(ah, 0, 0);
+	ath9k_hw_configpcipowersave(ah, false);
 
 	/*
 	 * The basic interface to setting the hardware in a good
@@ -1145,8 +1139,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
 					   AR_STOMP_LOW_WLAN_WGHT);
 		ath9k_hw_btcoex_enable(ah);
 
-		if (common->bus_ops->bt_coex_prep)
-			common->bus_ops->bt_coex_prep(common);
 		if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
 			ath9k_btcoex_timer_resume(sc);
 	}
@@ -1680,6 +1672,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 		struct ieee80211_channel *curchan = hw->conf.channel;
+		struct ath9k_channel old_chan;
 		int pos = curchan->hw_value;
 		int old_pos = -1;
 		unsigned long flags;
@@ -1696,14 +1689,24 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 			"Set channel: %d MHz type: %d\n",
 			curchan->center_freq, conf->channel_type);
 
-		ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
-					  curchan, conf->channel_type);
-
 		/* update survey stats for the old channel before switching */
 		spin_lock_irqsave(&common->cc_lock, flags);
 		ath_update_survey_stats(sc);
 		spin_unlock_irqrestore(&common->cc_lock, flags);
 
+		/*
+		 * Preserve the current channel values, before updating
+		 * the same channel
+		 */
+		if (old_pos == pos) {
+			memcpy(&old_chan, &sc->sc_ah->channels[pos],
+				sizeof(struct ath9k_channel));
+			ah->curchan = &old_chan;
+		}
+
+		ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
+					  curchan, conf->channel_type);
+
 		/*
 		 * If the operating channel changes, change the survey in-use flags
 		 * along with it.
@@ -2400,6 +2403,20 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
 	return sc->beacon.tx_last;
 }
 
+static int ath9k_get_stats(struct ieee80211_hw *hw,
+			   struct ieee80211_low_level_stats *stats)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
+
+	stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
+	stats->dot11RTSFailureCount = mib_stats->rts_bad;
+	stats->dot11FCSErrorCount = mib_stats->fcs_bad;
+	stats->dot11RTSSuccessCount = mib_stats->rts_good;
+	return 0;
+}
+
 struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
 	.start 		    = ath9k_start,
@@ -2424,5 +2441,6 @@ struct ieee80211_ops ath9k_ops = {
 	.set_coverage_class = ath9k_set_coverage_class,
 	.flush		    = ath9k_flush,
 	.tx_frames_pending  = ath9k_tx_frames_pending,
-	.tx_last_beacon = ath9k_tx_last_beacon,
+	.tx_last_beacon     = ath9k_tx_last_beacon,
+	.get_stats	    = ath9k_get_stats,
 };
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 5685cf11cfe35b322364081bdfe9f2fe0d3dd7af..891661a61513cdb65e0a4f5390a5d70f1abc3557 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -32,9 +32,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
 	{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
 	{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */
 	{ PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */
+	{ PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E  AR9580 */
 	{ 0 }
 };
 
+
 /* return bus cachesize in 4B word units */
 static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
 {
@@ -88,23 +90,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 	return true;
 }
 
-/*
- * Bluetooth coexistance requires disabling ASPM.
- */
-static void ath_pci_bt_coex_prep(struct ath_common *common)
-{
-	struct ath_softc *sc = (struct ath_softc *) common->priv;
-	struct pci_dev *pdev = to_pci_dev(sc->dev);
-	u8 aspm;
-
-	if (!pci_is_pcie(pdev))
-		return;
-
-	pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
-	aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1);
-	pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
-}
-
 static void ath_pci_extn_synch_enable(struct ath_common *common)
 {
 	struct ath_softc *sc = (struct ath_softc *) common->priv;
@@ -116,6 +101,7 @@ static void ath_pci_extn_synch_enable(struct ath_common *common)
 	pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
 }
 
+/* Need to be called after we discover btcoex capabilities */
 static void ath_pci_aspm_init(struct ath_common *common)
 {
 	struct ath_softc *sc = (struct ath_softc *) common->priv;
@@ -125,19 +111,38 @@ static void ath_pci_aspm_init(struct ath_common *common)
 	int pos;
 	u8 aspm;
 
-	if (!pci_is_pcie(pdev))
+	pos = pci_pcie_cap(pdev);
+	if (!pos)
 		return;
 
 	parent = pdev->bus->self;
-	if (WARN_ON(!parent))
+	if (!parent)
 		return;
 
+	if (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) {
+		/* Bluetooth coexistance requires disabling ASPM. */
+		pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm);
+		aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+		pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm);
+
+		/*
+		 * Both upstream and downstream PCIe components should
+		 * have the same ASPM settings.
+		 */
+		pos = pci_pcie_cap(parent);
+		pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm);
+		aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+		pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
+
+		return;
+	}
+
 	pos = pci_pcie_cap(parent);
 	pci_read_config_byte(parent, pos +  PCI_EXP_LNKCTL, &aspm);
 	if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
 		ah->aspm_enabled = true;
 		/* Initialize PCIe PM and SERDES registers. */
-		ath9k_hw_configpcipowersave(ah, 0, 0);
+		ath9k_hw_configpcipowersave(ah, false);
 	}
 }
 
@@ -145,7 +150,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
 	.ath_bus_type = ATH_PCI,
 	.read_cachesize = ath_pci_read_cachesize,
 	.eeprom_read = ath_pci_eeprom_read,
-	.bt_coex_prep = ath_pci_bt_coex_prep,
 	.extn_synch_en = ath_pci_extn_synch_enable,
 	.aspm_init = ath_pci_aspm_init,
 };
@@ -338,7 +342,7 @@ static int ath_pci_resume(struct device *device)
 	   * semi-random values after suspend/resume.
 	   */
 	ath9k_ps_wakeup(sc);
-	ath9k_init_crypto(sc);
+	ath9k_cmn_init_crypto(sc->sc_ah);
 	ath9k_ps_restore(sc);
 
 	sc->ps_idle = true;
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 9e3649a3d5ca310fa72b08d48aee15783a67334e..4f1301881137ee29f6a09b0823ed9a87912f4b6d 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -603,7 +603,8 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
 static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
 			         struct ath_rate_priv *ath_rc_priv,
 				 const struct ath_rate_table *rate_table,
-				 int *is_probing)
+				 int *is_probing,
+				 bool legacy)
 {
 	u32 best_thruput, this_thruput, now_msec;
 	u8 rate, next_rate, best_rate, maxindex, minindex;
@@ -624,6 +625,8 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
 		u8 per_thres;
 
 		rate = ath_rc_priv->valid_rate_index[index];
+		if (legacy && !(rate_table->info[rate].rate_flags & RC_LEGACY))
+			continue;
 		if (rate > ath_rc_priv->rate_max_phy)
 			continue;
 
@@ -767,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	struct ieee80211_tx_rate *rates = tx_info->control.rates;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	__le16 fc = hdr->frame_control;
-	u8 try_per_rate, i = 0, rix;
+	u8 try_per_rate, i = 0, rix, high_rix;
 	int is_probe = 0;
 
 	if (rate_control_send_low(sta, priv_sta, txrc))
@@ -786,7 +789,9 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	try_per_rate = 4;
 
 	rate_table = ath_rc_priv->rate_table;
-	rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
+	rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
+				     &is_probe, false);
+	high_rix = rix;
 
 	/*
 	 * If we're in HT mode and both us and our peer supports LDPC.
@@ -822,10 +827,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	}
 
 	/* Fill in the other rates for multirate retry */
-	for ( ; i < 4; i++) {
-		/* Use twice the number of tries for the last MRR segment. */
-		if (i + 1 == 4)
-			try_per_rate = 8;
+	for ( ; i < 3; i++) {
 
 		ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
 		/* All other rates in the series have RTS enabled */
@@ -833,6 +835,24 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 				       try_per_rate, rix, 1);
 	}
 
+	/* Use twice the number of tries for the last MRR segment. */
+	try_per_rate = 8;
+
+	/*
+	 * Use a legacy rate as last retry to ensure that the frame
+	 * is tried in both MCS and legacy rates.
+	 */
+	if ((rates[2].flags & IEEE80211_TX_RC_MCS) &&
+	    (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) ||
+	    (ath_rc_priv->per[high_rix] > 45)))
+		rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
+				&is_probe, true);
+	else
+		ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+
+	/* All other rates in the series have RTS enabled */
+	ath_rc_rate_set_series(rate_table, &rates[i], txrc,
+			       try_per_rate, rix, 1);
 	/*
 	 * NB:Change rate series to enable aggregation when operating
 	 * at lower MCS rates. When first rate in series is MCS2
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 74094022b654980b823e258033d7acce058b62b1..ad5f9bd2f0b9a5fd9cd55267a7cbb74ea2ecb8ca 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -761,7 +761,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
 	 * on.  All this is necessary because of our use of
 	 * a self-linked list to avoid rx overruns.
 	 */
-	ret = ath9k_hw_rxprocdesc(ah, ds, rs, 0);
+	ret = ath9k_hw_rxprocdesc(ah, ds, rs);
 	if (ret == -EINPROGRESS) {
 		struct ath_rx_status trs;
 		struct ath_buf *tbf;
@@ -787,7 +787,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
 		 */
 
 		tds = tbf->bf_desc;
-		ret = ath9k_hw_rxprocdesc(ah, tds, &trs, 0);
+		ret = ath9k_hw_rxprocdesc(ah, tds, &trs);
 		if (ret == -EINPROGRESS)
 			return NULL;
 	}
@@ -824,7 +824,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
 	is_mc = !!is_multicast_ether_addr(hdr->addr1);
 	is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID &&
 		test_bit(rx_stats->rs_keyix, common->tkip_keymap);
-	strip_mic = is_valid_tkip && !(rx_stats->rs_status &
+	strip_mic = is_valid_tkip && ieee80211_is_data(fc) &&
+		!(rx_stats->rs_status &
 		(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC));
 
 	if (!rx_stats->rs_datalen)
@@ -1978,5 +1979,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 
 	spin_unlock_bh(&sc->rx.rxbuflock);
 
+	if (!(ah->imask & ATH9K_INT_RXEOL)) {
+		ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+		ath9k_hw_set_interrupts(ah, ah->imask);
+	}
+
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index fa4c0bbce6b979eb6fc7ae8cb0107108ed2ffcb0..a3b8bbc6c0635fd1a2f9a756af4940fc5669eb42 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -793,6 +793,8 @@
 #define AR_SREV_REVISION_9485_10	0
 #define AR_SREV_REVISION_9485_11        1
 #define AR_SREV_VERSION_9340		0x300
+#define AR_SREV_VERSION_9580		0x1C0
+#define AR_SREV_REVISION_9580_10	4 /* AR9580 1.0 */
 
 #define AR_SREV_5416(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -893,6 +895,18 @@
     (AR_SREV_9285_12_OR_LATER(_ah) && \
      ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
 
+#define AR_SREV_9580(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
+	((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10))
+
+#define AR_SREV_9580_10(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
+	((_ah)->hw_version.macRev == AR_SREV_REVISION_9580_10))
+
+/* NOTE: When adding chips newer than Peacock, add chip check here */
+#define AR_SREV_9580_10_OR_LATER(_ah) \
+	(AR_SREV_9580(_ah))
+
 enum ath_usb_dev {
 	AR9280_USB = 1, /* AR7010 + AR9280, UB94 */
 	AR9287_USB = 2, /* AR7010 + AR9287, UB95 */
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index e1d1e903229b69c994ecc881d0632542b56d6ad5..5e2982938ffc3b9e5bc95b803367dfe6141b100e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -571,6 +571,25 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		ath_reset(sc, false);
 }
 
+static bool ath_lookup_legacy(struct ath_buf *bf)
+{
+	struct sk_buff *skb;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_tx_rate *rates;
+	int i;
+
+	skb = bf->bf_mpdu;
+	tx_info = IEEE80211_SKB_CB(skb);
+	rates = tx_info->control.rates;
+
+	for (i = 3; i >= 0; i--) {
+		if (!(rates[i].flags & IEEE80211_TX_RC_MCS))
+			return true;
+	}
+
+	return false;
+}
+
 static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
 			   struct ath_atx_tid *tid)
 {
@@ -644,8 +663,10 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
  * meet the minimum required mpdudensity.
  */
 static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
-				  struct ath_buf *bf, u16 frmlen)
+				  struct ath_buf *bf, u16 frmlen,
+				  bool first_subfrm)
 {
+#define FIRST_DESC_NDELIMS 60
 	struct sk_buff *skb = bf->bf_mpdu;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	u32 nsymbits, nsymbols;
@@ -667,6 +688,13 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 	    !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))
 		ndelim += ATH_AGGR_ENCRYPTDELIM;
 
+	/*
+	 * Add delimiter when using RTS/CTS with aggregation
+	 * and non enterprise AR9003 card
+	 */
+	if (first_subfrm)
+		ndelim = max(ndelim, FIRST_DESC_NDELIMS);
+
 	/*
 	 * Convert desired mpdu density from microeconds to bytes based
 	 * on highest rate in rate series (i.e. first rate) to determine
@@ -741,7 +769,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
 
 		if (nframes &&
-		    (aggr_limit < (al + bpad + al_delta + prev_al))) {
+		    ((aggr_limit < (al + bpad + al_delta + prev_al)) ||
+		     ath_lookup_legacy(bf))) {
 			status = ATH_AGGR_LIMITED;
 			break;
 		}
@@ -756,7 +785,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 			status = ATH_AGGR_LIMITED;
 			break;
 		}
-		nframes++;
 
 		/* add padding for previous frame to aggregation length */
 		al += bpad + al_delta;
@@ -765,9 +793,11 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		 * Get the delimiters needed to meet the MPDU
 		 * density for this node.
 		 */
-		ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
+		ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen,
+						!nframes);
 		bpad = PADBYTES(al_delta) + (ndelim << 2);
 
+		nframes++;
 		bf->bf_next = NULL;
 		ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
 
@@ -1574,9 +1604,9 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath9k_channel *curchan = ah->curchan;
-	if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
-			(curchan->channelFlags & CHANNEL_5GHZ) &&
-			(chainmask == 0x7) && (rate < 0x90))
+	if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) &&
+	    (curchan->channelFlags & CHANNEL_5GHZ) &&
+	    (chainmask == 0x7) && (rate < 0x90))
 		return 0x3;
 	else
 		return chainmask;
diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig
index 2d1b821b440d6ebda30969fd240c07fbee3ce12b..267d5dcf82dc61b5e992a524338965a29f979c56 100644
--- a/drivers/net/wireless/ath/carl9170/Kconfig
+++ b/drivers/net/wireless/ath/carl9170/Kconfig
@@ -39,3 +39,17 @@ config CARL9170_WPC
 	bool
 	depends on CARL9170 && (INPUT = y || INPUT = CARL9170)
 	default y
+
+config CARL9170_HWRNG
+        bool "Random number generator"
+        depends on CARL9170 && (HW_RANDOM = y || HW_RANDOM = CARL9170)
+        default n
+	help
+	  Provides a hardware random number generator to the kernel.
+
+	  SECURITY WARNING: It's relatively easy to eavesdrop all
+	  generated random numbers from the transport stream with
+	  usbmon [software] or special usb sniffer hardware.
+
+	  Say N, unless your setup[i.e.: embedded system] has no
+	  other rng source and you can afford to take the risk.
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index c5427a72a1e230fa168b0481894ac1256c959e99..6cfbb419e2f6d1efe8ddf7e2d551928efcd95f9d 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -43,6 +43,7 @@
 #include <linux/firmware.h>
 #include <linux/completion.h>
 #include <linux/spinlock.h>
+#include <linux/hw_random.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
 #include <linux/usb.h>
@@ -151,6 +152,7 @@ struct carl9170_sta_tid {
 #define CARL9170_TX_TIMEOUT		2500
 #define CARL9170_JANITOR_DELAY		128
 #define CARL9170_QUEUE_STUCK_TIMEOUT	5500
+#define CARL9170_STAT_WORK		30000
 
 #define CARL9170_NUM_TX_AGG_MAX		30
 
@@ -282,6 +284,7 @@ struct ar9170 {
 		bool rx_stream;
 		bool tx_stream;
 		bool rx_filter;
+		bool hw_counters;
 		unsigned int mem_blocks;
 		unsigned int mem_block_size;
 		unsigned int rx_size;
@@ -331,11 +334,21 @@ struct ar9170 {
 
 	/* PHY */
 	struct ieee80211_channel *channel;
+	unsigned int num_channels;
 	int noise[4];
 	unsigned int chan_fail;
 	unsigned int total_chan_fail;
 	u8 heavy_clip;
 	u8 ht_settings;
+	struct {
+		u64 active;	/* usec */
+		u64 cca;	/* usec */
+		u64 tx_time;	/* usec */
+		u64 rx_total;
+		u64 rx_overrun;
+	} tally;
+	struct delayed_work stat_work;
+	struct survey_info *survey;
 
 	/* power calibration data */
 	u8 power_5G_leg[4];
@@ -437,6 +450,17 @@ struct ar9170 {
 		unsigned int off_override;
 		bool state;
 	} ps;
+
+#ifdef CONFIG_CARL9170_HWRNG
+# define CARL9170_HWRNG_CACHE_SIZE	CARL9170_MAX_CMD_PAYLOAD_LEN
+	struct {
+		struct hwrng rng;
+		bool initialized;
+		char name[30 + 1];
+		u16 cache[CARL9170_HWRNG_CACHE_SIZE / sizeof(u16)];
+		unsigned int cache_idx;
+	} rng;
+#endif /* CONFIG_CARL9170_HWRNG */
 };
 
 enum carl9170_ps_off_override_reasons {
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
index cdfc94c371b41930e0fd50aca0119e877a6d0f10..195dc65381104aab0eb1d9657fecf53a3955c915 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.c
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -36,6 +36,7 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <asm/div64.h>
 #include "carl9170.h"
 #include "cmd.h"
 
@@ -165,6 +166,39 @@ int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
 	return __carl9170_exec_cmd(ar, cmd, true);
 }
 
+int carl9170_collect_tally(struct ar9170 *ar)
+{
+	struct carl9170_tally_rsp tally;
+	struct survey_info *info;
+	unsigned int tick;
+	int err;
+
+	err = carl9170_exec_cmd(ar, CARL9170_CMD_TALLY, 0, NULL,
+				sizeof(tally), (u8 *)&tally);
+	if (err)
+		return err;
+
+	tick = le32_to_cpu(tally.tick);
+	if (tick) {
+		ar->tally.active += le32_to_cpu(tally.active) / tick;
+		ar->tally.cca += le32_to_cpu(tally.cca) / tick;
+		ar->tally.tx_time += le32_to_cpu(tally.tx_time) / tick;
+		ar->tally.rx_total += le32_to_cpu(tally.rx_total);
+		ar->tally.rx_overrun += le32_to_cpu(tally.rx_overrun);
+
+		if (ar->channel) {
+			info = &ar->survey[ar->channel->hw_value];
+			info->channel_time = ar->tally.active;
+			info->channel_time_busy = ar->tally.cca;
+			info->channel_time_tx = ar->tally.tx_time;
+			do_div(info->channel_time, 1000);
+			do_div(info->channel_time_busy, 1000);
+			do_div(info->channel_time_tx, 1000);
+		}
+	}
+	return 0;
+}
+
 int carl9170_powersave(struct ar9170 *ar, const bool ps)
 {
 	struct carl9170_cmd *cmd;
diff --git a/drivers/net/wireless/ath/carl9170/cmd.h b/drivers/net/wireless/ath/carl9170/cmd.h
index d5f95bdc75c1cf1f1e8abafa09f3235b6faef7d4..885c42778b8b5817941c9c184904446cc91834fe 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.h
+++ b/drivers/net/wireless/ath/carl9170/cmd.h
@@ -50,6 +50,7 @@ int carl9170_echo_test(struct ar9170 *ar, u32 v);
 int carl9170_reboot(struct ar9170 *ar);
 int carl9170_mac_reset(struct ar9170 *ar);
 int carl9170_powersave(struct ar9170 *ar, const bool power_on);
+int carl9170_collect_tally(struct ar9170 *ar);
 int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
 		       const u32 mode, const u32 addr, const u32 len);
 
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 39ddea5794f703c45233600113ed94e3c3546a72..f4cae1cccbfff879f2e5859989f3e524be1b9f86 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -266,6 +266,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
 			FIF_PROMISC_IN_BSS;
 	}
 
+	if (SUPP(CARL9170FW_HW_COUNTERS))
+		ar->fw.hw_counters = true;
+
 	if (SUPP(CARL9170FW_WOL))
 		device_set_wakeup_enable(&ar->udev->dev, true);
 
diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h
index 0a6dec529b593ecb3b63d383893a927117b9d4d0..9443c802b25b8578f6afd2b2cb66243ab47f34f1 100644
--- a/drivers/net/wireless/ath/carl9170/fwcmd.h
+++ b/drivers/net/wireless/ath/carl9170/fwcmd.h
@@ -55,6 +55,7 @@ enum carl9170_cmd_oids {
 	CARL9170_CMD_READ_TSF		= 0x06,
 	CARL9170_CMD_RX_FILTER		= 0x07,
 	CARL9170_CMD_WOL		= 0x08,
+	CARL9170_CMD_TALLY		= 0x09,
 
 	/* CAM */
 	CARL9170_CMD_EKEY		= 0x10,
@@ -286,6 +287,15 @@ struct carl9170_tsf_rsp {
 } __packed;
 #define CARL9170_TSF_RSP_SIZE		8
 
+struct carl9170_tally_rsp {
+	__le32 active;
+	__le32 cca;
+	__le32 tx_time;
+	__le32 rx_total;
+	__le32 rx_overrun;
+	__le32 tick;
+} __packed;
+
 struct carl9170_rsp {
 	struct carl9170_cmd_head hdr;
 
@@ -300,6 +310,7 @@ struct carl9170_rsp {
 		struct carl9170_gpio		gpio;
 		struct carl9170_tsf_rsp		tsf;
 		struct carl9170_psm		psm;
+		struct carl9170_tally_rsp	tally;
 		u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
 	} __packed;
 } __packed __aligned(4);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 0122930b14c71f85ab0f9d779a87030373011ebb..782b8f3ae58f3ac408c43a6deea388a1cc962340 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -413,6 +413,9 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
 
 	carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STARTED);
 
+	ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
+		round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
+
 	ieee80211_wake_queues(ar->hw);
 	err = 0;
 
@@ -423,6 +426,7 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
 
 static void carl9170_cancel_worker(struct ar9170 *ar)
 {
+	cancel_delayed_work_sync(&ar->stat_work);
 	cancel_delayed_work_sync(&ar->tx_janitor);
 #ifdef CONFIG_CARL9170_LEDS
 	cancel_delayed_work_sync(&ar->led_work);
@@ -794,6 +798,43 @@ static void carl9170_ps_work(struct work_struct *work)
 	mutex_unlock(&ar->mutex);
 }
 
+static int carl9170_update_survey(struct ar9170 *ar, bool flush, bool noise)
+{
+	int err;
+
+	if (noise) {
+		err = carl9170_get_noisefloor(ar);
+		if (err)
+			return err;
+	}
+
+	if (ar->fw.hw_counters) {
+		err = carl9170_collect_tally(ar);
+		if (err)
+			return err;
+	}
+
+	if (flush)
+		memset(&ar->tally, 0, sizeof(ar->tally));
+
+	return 0;
+}
+
+static void carl9170_stat_work(struct work_struct *work)
+{
+	struct ar9170 *ar = container_of(work, struct ar9170, stat_work.work);
+	int err;
+
+	mutex_lock(&ar->mutex);
+	err = carl9170_update_survey(ar, false, true);
+	mutex_unlock(&ar->mutex);
+
+	if (err)
+		return;
+
+	ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
+		round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
+}
 
 static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
 {
@@ -828,11 +869,19 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
 		if (err)
 			goto out;
 
+		err = carl9170_update_survey(ar, true, false);
+		if (err)
+			goto out;
+
 		err = carl9170_set_channel(ar, hw->conf.channel,
 			hw->conf.channel_type, CARL9170_RFI_NONE);
 		if (err)
 			goto out;
 
+		err = carl9170_update_survey(ar, false, true);
+		if (err)
+			goto out;
+
 		err = carl9170_set_dyn_sifs_ack(ar);
 		if (err)
 			goto out;
@@ -1419,24 +1468,159 @@ static int carl9170_register_wps_button(struct ar9170 *ar)
 }
 #endif /* CONFIG_CARL9170_WPC */
 
-static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
-				struct survey_info *survey)
+#ifdef CONFIG_CARL9170_HWRNG
+static int carl9170_rng_get(struct ar9170 *ar)
 {
-	struct ar9170 *ar = hw->priv;
+
+#define RW	(CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32))
+#define RB	(CARL9170_MAX_CMD_PAYLOAD_LEN)
+
+	static const __le32 rng_load[RW] = {
+		[0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)};
+
+	u32 buf[RW];
+
+	unsigned int i, off = 0, transfer, count;
 	int err;
 
-	if (idx != 0)
-		return -ENOENT;
+	BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN);
+
+	if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized)
+		return -EAGAIN;
+
+	count = ARRAY_SIZE(ar->rng.cache);
+	while (count) {
+		err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
+					RB, (u8 *) rng_load,
+					RB, (u8 *) buf);
+		if (err)
+			return err;
+
+		transfer = min_t(unsigned int, count, RW);
+		for (i = 0; i < transfer; i++)
+			ar->rng.cache[off + i] = buf[i];
+
+		off += transfer;
+		count -= transfer;
+	}
+
+	ar->rng.cache_idx = 0;
+
+#undef RW
+#undef RB
+	return 0;
+}
+
+static int carl9170_rng_read(struct hwrng *rng, u32 *data)
+{
+	struct ar9170 *ar = (struct ar9170 *)rng->priv;
+	int ret = -EIO;
 
 	mutex_lock(&ar->mutex);
-	err = carl9170_get_noisefloor(ar);
+	if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) {
+		ret = carl9170_rng_get(ar);
+		if (ret) {
+			mutex_unlock(&ar->mutex);
+			return ret;
+		}
+	}
+
+	*data = ar->rng.cache[ar->rng.cache_idx++];
 	mutex_unlock(&ar->mutex);
-	if (err)
+
+	return sizeof(u16);
+}
+
+static void carl9170_unregister_hwrng(struct ar9170 *ar)
+{
+	if (ar->rng.initialized) {
+		hwrng_unregister(&ar->rng.rng);
+		ar->rng.initialized = false;
+	}
+}
+
+static int carl9170_register_hwrng(struct ar9170 *ar)
+{
+	int err;
+
+	snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name),
+		 "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy));
+	ar->rng.rng.name = ar->rng.name;
+	ar->rng.rng.data_read = carl9170_rng_read;
+	ar->rng.rng.priv = (unsigned long)ar;
+
+	if (WARN_ON(ar->rng.initialized))
+		return -EALREADY;
+
+	err = hwrng_register(&ar->rng.rng);
+	if (err) {
+		dev_err(&ar->udev->dev, "Failed to register the random "
+			"number generator (%d)\n", err);
 		return err;
+	}
+
+	ar->rng.initialized = true;
+
+	err = carl9170_rng_get(ar);
+	if (err) {
+		carl9170_unregister_hwrng(ar);
+		return err;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_CARL9170_HWRNG */
+
+static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
+				struct survey_info *survey)
+{
+	struct ar9170 *ar = hw->priv;
+	struct ieee80211_channel *chan;
+	struct ieee80211_supported_band *band;
+	int err, b, i;
+
+	chan = ar->channel;
+	if (!chan)
+		return -ENODEV;
+
+	if (idx == chan->hw_value) {
+		mutex_lock(&ar->mutex);
+		err = carl9170_update_survey(ar, false, true);
+		mutex_unlock(&ar->mutex);
+		if (err)
+			return err;
+	}
+
+	for (b = 0; b < IEEE80211_NUM_BANDS; b++) {
+		band = ar->hw->wiphy->bands[b];
+
+		if (!band)
+			continue;
+
+		for (i = 0; i < band->n_channels; i++) {
+			if (band->channels[i].hw_value == idx) {
+				chan = &band->channels[i];
+				goto found;
+			}
+		}
+	}
+	return -ENOENT;
+
+found:
+	memcpy(survey, &ar->survey[idx], sizeof(*survey));
 
-	survey->channel = ar->channel;
+	survey->channel = chan;
 	survey->filled = SURVEY_INFO_NOISE_DBM;
-	survey->noise = ar->noise[0];
+
+	if (ar->channel == chan)
+		survey->filled |= SURVEY_INFO_IN_USE;
+
+	if (ar->fw.hw_counters) {
+		survey->filled |= SURVEY_INFO_CHANNEL_TIME |
+				  SURVEY_INFO_CHANNEL_TIME_BUSY |
+				  SURVEY_INFO_CHANNEL_TIME_TX;
+	}
+
 	return 0;
 }
 
@@ -1569,6 +1753,7 @@ void *carl9170_alloc(size_t priv_size)
 	INIT_WORK(&ar->ping_work, carl9170_ping_work);
 	INIT_WORK(&ar->restart_work, carl9170_restart_work);
 	INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
+	INIT_DELAYED_WORK(&ar->stat_work, carl9170_stat_work);
 	INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
 	INIT_LIST_HEAD(&ar->tx_ampdu_list);
 	rcu_assign_pointer(ar->tx_ampdu_iter,
@@ -1652,6 +1837,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
 	struct ath_regulatory *regulatory = &ar->common.regulatory;
 	unsigned int rx_streams, tx_streams, tx_params = 0;
 	int bands = 0;
+	int chans = 0;
 
 	if (ar->eeprom.length == cpu_to_le16(0xffff))
 		return -ENODATA;
@@ -1675,14 +1861,24 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
 	if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) {
 		ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
 			&carl9170_band_2GHz;
+		chans += carl9170_band_2GHz.n_channels;
 		bands++;
 	}
 	if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) {
 		ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
 			&carl9170_band_5GHz;
+		chans += carl9170_band_5GHz.n_channels;
 		bands++;
 	}
 
+	if (!bands)
+		return -EINVAL;
+
+	ar->survey = kzalloc(sizeof(struct survey_info) * chans, GFP_KERNEL);
+	if (!ar->survey)
+		return -ENOMEM;
+	ar->num_channels = chans;
+
 	/*
 	 * I measured this, a bandswitch takes roughly
 	 * 135 ms and a frequency switch about 80.
@@ -1701,7 +1897,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
 	/* second part of wiphy init */
 	SET_IEEE80211_PERM_ADDR(ar->hw, ar->eeprom.mac_address);
 
-	return bands ? 0 : -EINVAL;
+	return 0;
 }
 
 static int carl9170_reg_notifier(struct wiphy *wiphy,
@@ -1785,6 +1981,12 @@ int carl9170_register(struct ar9170 *ar)
 		goto err_unreg;
 #endif /* CONFIG_CARL9170_WPC */
 
+#ifdef CONFIG_CARL9170_HWRNG
+	err = carl9170_register_hwrng(ar);
+	if (err)
+		goto err_unreg;
+#endif /* CONFIG_CARL9170_HWRNG */
+
 	dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n",
 		 wiphy_name(ar->hw->wiphy));
 
@@ -1817,6 +2019,10 @@ void carl9170_unregister(struct ar9170 *ar)
 	}
 #endif /* CONFIG_CARL9170_WPC */
 
+#ifdef CONFIG_CARL9170_HWRNG
+	carl9170_unregister_hwrng(ar);
+#endif /* CONFIG_CARL9170_HWRNG */
+
 	carl9170_cancel_worker(ar);
 	cancel_work_sync(&ar->restart_work);
 
@@ -1834,6 +2040,9 @@ void carl9170_free(struct ar9170 *ar)
 	kfree(ar->mem_bitmap);
 	ar->mem_bitmap = NULL;
 
+	kfree(ar->survey);
+	ar->survey = NULL;
+
 	mutex_destroy(&ar->mutex);
 
 	ieee80211_free_hw(ar->hw);
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index aa147a9120b6e4c7652cf49a9d4c791d2393bb2a..472efc7e34022ffbc9162afb9752069803833edd 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -578,11 +578,10 @@ static int carl9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
 	if (err)
 		return err;
 
-	/* XXX: remove magic! */
-	if (is_2ghz)
-		err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC, 0x5163);
-	else
-		err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC, 0x5143);
+	if (!ar->fw.hw_counters) {
+		err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC,
+					 is_2ghz ? 0x5163 : 0x5143);
+	}
 
 	return err;
 }
@@ -1574,6 +1573,9 @@ int carl9170_get_noisefloor(struct ar9170 *ar)
 			AR9170_PHY_EXT_CCA_MIN_PWR, phy_res[i + 2]), 8);
 	}
 
+	if (ar->channel)
+		ar->survey[ar->channel->hw_value].noise = ar->noise[0];
+
 	return 0;
 }
 
@@ -1766,10 +1768,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
 		ar->chan_fail = 0;
 	}
 
-	err = carl9170_get_noisefloor(ar);
-	if (err)
-		return err;
-
 	if (ar->heavy_clip) {
 		err = carl9170_write_reg(ar, AR9170_PHY_REG_HEAVY_CLIP_ENABLE,
 					 0x200 | ar->heavy_clip);
diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h
index 64703778cfeaac239ac91fe80e0b22cb94f67dab..e651db856344d8a25c1203f0bfae070a15d0fd55 100644
--- a/drivers/net/wireless/ath/carl9170/version.h
+++ b/drivers/net/wireless/ath/carl9170/version.h
@@ -1,7 +1,7 @@
 #ifndef __CARL9170_SHARED_VERSION_H
 #define __CARL9170_SHARED_VERSION_H
 #define CARL9170FW_VERSION_YEAR 11
-#define CARL9170FW_VERSION_MONTH 6
-#define CARL9170FW_VERSION_DAY 30
+#define CARL9170FW_VERSION_MONTH 8
+#define CARL9170FW_VERSION_DAY 15
 #define CARL9170FW_VERSION_GIT "1.9.4"
 #endif /* __CARL9170_SHARED_VERSION_H */
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index b81a2a1c26181cd1135d005903736f1f19e4d0a5..df2b7c0856ede670d197ec9d85bb60a6d6d70e33 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -169,13 +169,3 @@ config B43_DEBUG
 	  Say N, if you are a distributor or user building a release kernel
 	  for production use.
 	  Only say Y, if you are debugging a problem in the b43 driver sourcecode.
-
-config B43_FORCE_PIO
-	bool "Force usage of PIO instead of DMA"
-	depends on B43 && B43_DEBUG
-	---help---
-	  This will disable DMA and always enable PIO instead.
-
-	  Say N!
-	  This is only for debugging the PIO engine code. You do
-	  _NOT_ want to enable this.
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index c818b0bc88ec84fce7eb7db11d39220ff7900c08..8ff706289b5db6b8886c1559528ae23e575acde3 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -17,11 +17,6 @@
 #include "phy_common.h"
 
 
-/* The unique identifier of the firmware that's officially supported by
- * this driver version. */
-#define B43_SUPPORTED_FIRMWARE_ID	"FW13"
-
-
 #ifdef CONFIG_B43_DEBUG
 # define B43_DEBUG	1
 #else
@@ -594,6 +589,7 @@ struct b43_dma {
 	struct b43_dmaring *rx_ring;
 
 	u32 translation; /* Routing bits */
+	bool translation_in_low; /* Should translation bit go into low addr? */
 	bool parity; /* Check for parity */
 };
 
@@ -694,6 +690,12 @@ struct b43_firmware_file {
 	enum b43_firmware_file_type type;
 };
 
+enum b43_firmware_hdr_format {
+	B43_FW_HDR_598,
+	B43_FW_HDR_410,
+	B43_FW_HDR_351,
+};
+
 /* Pointers to the firmware data and meta information about it. */
 struct b43_firmware {
 	/* Microcode */
@@ -710,6 +712,9 @@ struct b43_firmware {
 	/* Firmware patchlevel */
 	u16 patch;
 
+	/* Format of header used by firmware */
+	enum b43_firmware_hdr_format hdr_format;
+
 	/* Set to true, if we are using an opensource firmware.
 	 * Use this to check for proprietary vs opensource. */
 	bool opensource;
@@ -875,7 +880,7 @@ struct b43_wl {
 	struct b43_leds leds;
 
 	/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
-	u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
+	u8 pio_scratchspace[118] __attribute__((__aligned__(8)));
 	u8 pio_tailspace[4] __attribute__((__aligned__(8)));
 };
 
@@ -965,12 +970,6 @@ static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
 	return dev->__using_pio_transfers;
 }
 
-#ifdef CONFIG_B43_FORCE_PIO
-# define B43_PIO_DEFAULT 1
-#else
-# define B43_PIO_DEFAULT 0
-#endif
-
 /* Message printing */
 void b43info(struct b43_wl *wl, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 481e534534eb3a437a732509c80bba6db73ff2e1..c5d890e74a1e426e80bc8379afa3b49a4617cb8c 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -47,6 +47,38 @@
  * into separate slots. */
 #define TX_SLOTS_PER_FRAME	2
 
+static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr,
+			   enum b43_addrtype addrtype)
+{
+	u32 uninitialized_var(addr);
+
+	switch (addrtype) {
+	case B43_DMA_ADDR_LOW:
+		addr = lower_32_bits(dmaaddr);
+		if (dma->translation_in_low) {
+			addr &= ~SSB_DMA_TRANSLATION_MASK;
+			addr |= dma->translation;
+		}
+		break;
+	case B43_DMA_ADDR_HIGH:
+		addr = upper_32_bits(dmaaddr);
+		if (!dma->translation_in_low) {
+			addr &= ~SSB_DMA_TRANSLATION_MASK;
+			addr |= dma->translation;
+		}
+		break;
+	case B43_DMA_ADDR_EXT:
+		if (dma->translation_in_low)
+			addr = lower_32_bits(dmaaddr);
+		else
+			addr = upper_32_bits(dmaaddr);
+		addr &= SSB_DMA_TRANSLATION_MASK;
+		addr >>= SSB_DMA_TRANSLATION_SHIFT;
+		break;
+	}
+
+	return addr;
+}
 
 /* 32bit DMA ops. */
 static
@@ -77,10 +109,9 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
 	slot = (int)(&(desc->dma32) - descbase);
 	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
 
-	addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
-	addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
-	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addr |= ring->dev->dma.translation;
+	addr = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+	addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
 	ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
 	if (slot == ring->nr_slots - 1)
 		ctl |= B43_DMA32_DCTL_DTABLEEND;
@@ -170,11 +201,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
 	slot = (int)(&(desc->dma64) - descbase);
 	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
 
-	addrlo = (u32) (dmaaddr & 0xFFFFFFFF);
-	addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
-	addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
-	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addrhi |= ring->dev->dma.translation;
+	addrlo = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+	addrhi = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_HIGH);
+	addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
 	if (slot == ring->nr_slots - 1)
 		ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
 	if (start)
@@ -658,41 +688,37 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 	int err = 0;
 	u32 value;
 	u32 addrext;
-	u32 trans = ring->dev->dma.translation;
 	bool parity = ring->dev->dma.parity;
+	u32 addrlo;
+	u32 addrhi;
 
 	if (ring->tx) {
 		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+			addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
 
-			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = B43_DMA64_TXENABLE;
 			value |= (addrext << B43_DMA64_TXADDREXT_SHIFT)
 			    & B43_DMA64_TXADDREXT_MASK;
 			if (!parity)
 				value |= B43_DMA64_TXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA64_TXCTL, value);
-			b43_dma_write(ring, B43_DMA64_TXRINGLO,
-				      (ringbase & 0xFFFFFFFF));
-			b43_dma_write(ring, B43_DMA64_TXRINGHI,
-				      ((ringbase >> 32) &
-				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA64_TXRINGLO, addrlo);
+			b43_dma_write(ring, B43_DMA64_TXRINGHI, addrhi);
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
 
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = B43_DMA32_TXENABLE;
 			value |= (addrext << B43_DMA32_TXADDREXT_SHIFT)
 			    & B43_DMA32_TXADDREXT_MASK;
 			if (!parity)
 				value |= B43_DMA32_TXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA32_TXCTL, value);
-			b43_dma_write(ring, B43_DMA32_TXRING,
-				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA32_TXRING, addrlo);
 		}
 	} else {
 		err = alloc_initial_descbuffers(ring);
@@ -700,9 +726,10 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			goto out;
 		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+			addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
 
-			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT);
 			value |= B43_DMA64_RXENABLE;
 			value |= (addrext << B43_DMA64_RXADDREXT_SHIFT)
@@ -710,19 +737,15 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			if (!parity)
 				value |= B43_DMA64_RXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA64_RXCTL, value);
-			b43_dma_write(ring, B43_DMA64_RXRINGLO,
-				      (ringbase & 0xFFFFFFFF));
-			b43_dma_write(ring, B43_DMA64_RXRINGHI,
-				      ((ringbase >> 32) &
-				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA64_RXRINGLO, addrlo);
+			b43_dma_write(ring, B43_DMA64_RXRINGHI, addrhi);
 			b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
 				      sizeof(struct b43_dmadesc64));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
 
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT);
 			value |= B43_DMA32_RXENABLE;
 			value |= (addrext << B43_DMA32_RXADDREXT_SHIFT)
@@ -730,9 +753,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			if (!parity)
 				value |= B43_DMA32_RXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA32_RXCTL, value);
-			b43_dma_write(ring, B43_DMA32_RXRING,
-				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA32_RXRING, addrlo);
 			b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
 				      sizeof(struct b43_dmadesc32));
 		}
@@ -872,8 +893,17 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 		ring->current_slot = -1;
 	} else {
 		if (ring->index == 0) {
-			ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
-			ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
+			switch (dev->fw.hdr_format) {
+			case B43_FW_HDR_598:
+				ring->rx_buffersize = B43_DMA0_RX_FW598_BUFSIZE;
+				ring->frameoffset = B43_DMA0_RX_FW598_FO;
+				break;
+			case B43_FW_HDR_410:
+			case B43_FW_HDR_351:
+				ring->rx_buffersize = B43_DMA0_RX_FW351_BUFSIZE;
+				ring->frameoffset = B43_DMA0_RX_FW351_FO;
+				break;
+			}
 		} else
 			B43_WARN_ON(1);
 	}
@@ -1066,6 +1096,25 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
 	return 0;
 }
 
+/* Some hardware with 64-bit DMA seems to be bugged and looks for translation
+ * bit in low address word instead of high one.
+ */
+static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
+					    enum b43_dmatype type)
+{
+	if (type != B43_DMA_64BIT)
+		return 1;
+
+#ifdef CONFIG_B43_SSB
+	if (dev->dev->bus_type == B43_BUS_SSB &&
+	    dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+	    !(dev->dev->sdev->bus->host_pci->is_pcie &&
+	      ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64))
+			return 1;
+#endif
+	return 0;
+}
+
 int b43_dma_init(struct b43_wldev *dev)
 {
 	struct b43_dma *dma = &dev->dma;
@@ -1091,6 +1140,7 @@ int b43_dma_init(struct b43_wldev *dev)
 		break;
 #endif
 	}
+	dma->translation_in_low = b43_dma_translation_in_low_word(dev, type);
 
 	dma->parity = true;
 #ifdef CONFIG_B43_BCMA
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index cdf87094efe8270a9b20c06c66a5b59e125c9f18..7e20b04fa51a60d6283344bf752199b6f3b09ade 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -162,12 +162,15 @@ struct b43_dmadesc_generic {
 
 /* Misc DMA constants */
 #define B43_DMA_RINGMEMSIZE		PAGE_SIZE
-#define B43_DMA0_RX_FRAMEOFFSET		30
+/* Offset of frame with actual data */
+#define B43_DMA0_RX_FW598_FO		38
+#define B43_DMA0_RX_FW351_FO		30
 
 /* DMA engine tuning knobs */
 #define B43_TXRING_SLOTS		256
 #define B43_RXRING_SLOTS		64
-#define B43_DMA0_RX_BUFFERSIZE		(B43_DMA0_RX_FRAMEOFFSET + IEEE80211_MAX_FRAME_LEN)
+#define B43_DMA0_RX_FW598_BUFSIZE	(B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN)
+#define B43_DMA0_RX_FW351_BUFSIZE	(B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN)
 
 /* Pointer poison */
 #define B43_DMA_PTR_POISON		((void *)ERR_PTR(-ENOMEM))
@@ -212,6 +215,12 @@ enum b43_dmatype {
 	B43_DMA_64BIT	= 64,
 };
 
+enum b43_addrtype {
+	B43_DMA_ADDR_LOW,
+	B43_DMA_ADDR_HIGH,
+	B43_DMA_ADDR_EXT,
+};
+
 struct b43_dmaring {
 	/* Lowlevel DMA ops. */
 	const struct b43_dma_ops *ops;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index d2661aaff50f91ac9d4e6a787b1fbb1a1e2ae601..d2b1d1fe202b867b7716e65e26c2675d962fcb10 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -66,7 +66,6 @@ MODULE_AUTHOR("Michael Buesch");
 MODULE_AUTHOR("Gábor Stefanik");
 MODULE_LICENSE("GPL");
 
-MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
 MODULE_FIRMWARE("b43/ucode11.fw");
 MODULE_FIRMWARE("b43/ucode13.fw");
 MODULE_FIRMWARE("b43/ucode14.fw");
@@ -108,7 +107,7 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
 module_param_named(verbose, b43_modparam_verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
 
-static int b43_modparam_pio = B43_PIO_DEFAULT;
+static int b43_modparam_pio = 0;
 module_param_named(pio, b43_modparam_pio, int, 0644);
 MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
 
@@ -320,6 +319,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev);
 static int b43_wireless_core_init(struct b43_wldev *dev);
 static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
 static int b43_wireless_core_start(struct b43_wldev *dev);
+static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_bss_conf *conf,
+				    u32 changed);
 
 static int b43_ratelimit(struct b43_wl *wl)
 {
@@ -2510,6 +2513,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 	}
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
+	if (dev->fw.rev >= 598)
+		dev->fw.hdr_format = B43_FW_HDR_598;
+	else if (dev->fw.rev >= 410)
+		dev->fw.hdr_format = B43_FW_HDR_410;
+	else
+		dev->fw.hdr_format = B43_FW_HDR_351;
 	dev->fw.opensource = (fwdate == 0xFFFF);
 
 	/* Default to use-all-queues. */
@@ -2557,7 +2566,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 			dev->fw.rev, dev->fw.patch);
 	wiphy->hw_version = dev->dev->core_id;
 
-	if (b43_is_old_txhdr_format(dev)) {
+	if (dev->fw.hdr_format == B43_FW_HDR_351) {
 		/* We're over the deadline, but we keep support for old fw
 		 * until it turns out to be in major conflict with something new. */
 		b43warn(dev->wl, "You are using an old firmware image. "
@@ -2943,6 +2952,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
 	case B43_PHYTYPE_G:
 	case B43_PHYTYPE_N:
 	case B43_PHYTYPE_LP:
+	case B43_PHYTYPE_HT:
 		b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -3778,14 +3788,24 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 	struct ieee80211_conf *conf = &hw->conf;
 	int antenna;
 	int err = 0;
+	bool reload_bss = false;
 
 	mutex_lock(&wl->mutex);
 
+	dev = wl->current_dev;
+
 	/* Switch the band (if necessary). This might change the active core. */
 	err = b43_switch_band(wl, conf->channel);
 	if (err)
 		goto out_unlock_mutex;
-	dev = wl->current_dev;
+
+	/* Need to reload all settings if the core changed */
+	if (dev != wl->current_dev) {
+		dev = wl->current_dev;
+		changed = ~0;
+		reload_bss = true;
+	}
+
 	phy = &dev->phy;
 
 	if (conf_is_ht(conf))
@@ -3846,6 +3866,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 out_unlock_mutex:
 	mutex_unlock(&wl->mutex);
 
+	if (wl->vif && reload_bss)
+		b43_op_bss_info_changed(hw, wl->vif, &wl->vif->bss_conf, ~0);
+
 	return err;
 }
 
@@ -3934,7 +3957,8 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
 	if (changed & BSS_CHANGED_BEACON_INT &&
 	    (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
 	     b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
-	     b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
+	     b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) &&
+	    conf->beacon_int)
 		b43_set_beacon_int(dev, conf->beacon_int);
 
 	if (changed & BSS_CHANGED_BASIC_RATES)
@@ -4629,8 +4653,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
 	if (b43_bus_host_is_pcmcia(dev->dev) ||
-	    b43_bus_host_is_sdio(dev->dev) ||
-	    dev->use_pio) {
+	    b43_bus_host_is_sdio(dev->dev)) {
+		dev->__using_pio_transfers = 1;
+		err = b43_pio_init(dev);
+	} else if (dev->use_pio) {
+		b43warn(dev->wl, "Forced PIO by use_pio module parameter. "
+			"This should not be needed and will result in lower "
+			"performance.\n");
 		dev->__using_pio_transfers = 1;
 		err = b43_pio_init(dev);
 	} else {
@@ -4702,6 +4731,9 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
  out_mutex_unlock:
 	mutex_unlock(&wl->mutex);
 
+	if (err == 0)
+		b43_op_bss_info_changed(hw, vif, &vif->bss_conf, ~0);
+
 	return err;
 }
 
@@ -4772,6 +4804,9 @@ static int b43_op_start(struct ieee80211_hw *hw)
  out_mutex_unlock:
 	mutex_unlock(&wl->mutex);
 
+	/* reload configuration */
+	b43_op_config(hw, ~0);
+
 	return err;
 }
 
@@ -4928,10 +4963,18 @@ static void b43_chip_reset(struct work_struct *work)
 	if (err)
 		wl->current_dev = NULL; /* Failed to init the dev. */
 	mutex_unlock(&wl->mutex);
-	if (err)
+
+	if (err) {
 		b43err(wl, "Controller restart FAILED\n");
-	else
-		b43info(wl, "Controller restarted\n");
+		return;
+	}
+
+	/* reload configuration */
+	b43_op_config(wl->hw, ~0);
+	if (wl->vif)
+		b43_op_bss_info_changed(wl->hw, wl->vif, &wl->vif->bss_conf, ~0);
+
+	b43info(wl, "Controller restarted\n");
 }
 
 static int b43_setup_bands(struct b43_wldev *dev,
@@ -5416,8 +5459,7 @@ static void b43_print_driverinfo(void)
 	feat_sdio = "S";
 #endif
 	printk(KERN_INFO "Broadcom 43xx driver loaded "
-	       "[ Features: %s%s%s%s%s, Firmware-ID: "
-	       B43_SUPPORTED_FIRMWARE_ID " ]\n",
+	       "[ Features: %s%s%s%s%s ]\n",
 	       feat_pci, feat_pcmcia, feat_nphy,
 	       feat_leds, feat_sdio);
 }
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 07f009ff5ee2bfdf58a87002a24b6702c24e2b85..3ea44bb036844ef4a5da47b91ffd80ec8a18ec31 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -448,6 +448,38 @@ bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type)
 		channel_type == NL80211_CHAN_HT40PLUS);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
+void b43_phy_force_clock(struct b43_wldev *dev, bool force)
+{
+	u32 tmp;
+
+	WARN_ON(dev->phy.type != B43_PHYTYPE_N &&
+		dev->phy.type != B43_PHYTYPE_HT);
+
+	switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+	case B43_BUS_BCMA:
+		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+		if (force)
+			tmp |= BCMA_IOCTL_FGC;
+		else
+			tmp &= ~BCMA_IOCTL_FGC;
+		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+		break;
+#endif
+#ifdef CONFIG_B43_SSB
+	case B43_BUS_SSB:
+		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+		if (force)
+			tmp |= SSB_TMSLOW_FGC;
+		else
+			tmp &= ~SSB_TMSLOW_FGC;
+		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+		break;
+#endif
+	}
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */
 struct b43_c32 b43_cordic(int theta)
 {
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index aa77ba612a92fac3e127c8a6f4a505e922438aba..9233b13fc16d8a205eb474a3870f59bc3b6b7e8c 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -444,6 +444,8 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
 
 bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type);
 
+void b43_phy_force_clock(struct b43_wldev *dev, bool force);
+
 struct b43_c32 b43_cordic(int theta);
 
 #endif /* LINUX_B43_PHY_COMMON_H_ */
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c
index 7c40919651a741d5eca93cf9d447275591a425e0..4d6345e8ee6bb7fc4aca143610ab23939da5e5e1 100644
--- a/drivers/net/wireless/b43/phy_ht.c
+++ b/drivers/net/wireless/b43/phy_ht.c
@@ -151,6 +151,92 @@ static void b43_radio_2059_init(struct b43_wldev *dev)
 	b43_radio_mask(dev, 0x11, ~0x0008);
 }
 
+/**************************************************
+ * Various PHY ops
+ **************************************************/
+
+static void b43_phy_ht_zero_extg(struct b43_wldev *dev)
+{
+	u8 i, j;
+	u16 base[] = { 0x40, 0x60, 0x80 };
+
+	for (i = 0; i < ARRAY_SIZE(base); i++) {
+		for (j = 0; j < 4; j++)
+			b43_phy_write(dev, B43_PHY_EXTG(base[i] + j), 0);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(base); i++)
+		b43_phy_write(dev, B43_PHY_EXTG(base[i] + 0xc), 0);
+}
+
+/* Some unknown AFE (Analog Frondned) op */
+static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
+{
+	u8 i;
+
+	const u16 ctl_regs[3][2] = {
+		{ B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 },
+		{ B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 },
+		{ B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6},
+	};
+
+	for (i = 0; i < 3; i++) {
+		/* TODO: verify masks&sets */
+		b43_phy_set(dev, ctl_regs[i][1], 0x4);
+		b43_phy_set(dev, ctl_regs[i][0], 0x4);
+		b43_phy_mask(dev, ctl_regs[i][1], ~0x1);
+		b43_phy_set(dev, ctl_regs[i][0], 0x1);
+		b43_httab_write(dev, B43_HTTAB16(8, 5 + (i * 0x10)), 0);
+		b43_phy_mask(dev, ctl_regs[i][0], ~0x4);
+	}
+}
+
+static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
+{
+	u8 i;
+
+	u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+	b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
+
+	b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
+	for (i = 0; i < 200; i++) {
+		if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
+			i = 0;
+			break;
+		}
+		msleep(1);
+	}
+	if (i)
+		b43err(dev->wl, "Forcing RF sequence timeout\n");
+
+	b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
+{
+	clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES);
+	clip_st[1] = b43_phy_read(dev, B43_PHY_HT_C2_CLIP1THRES);
+	clip_st[2] = b43_phy_read(dev, B43_PHY_HT_C3_CLIP1THRES);
+}
+
+static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
+{
+	unsigned int i;
+	u16 val;
+
+	val = 0x1E1F;
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+		val -= 0x202;
+	}
+	val = 0x3E3F;
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
+		val -= 0x202;
+	}
+	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
 /**************************************************
  * Channel switching ops.
  **************************************************/
@@ -255,8 +341,125 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev)
 
 static int b43_phy_ht_op_init(struct b43_wldev *dev)
 {
+	u16 tmp;
+	u16 clip_state[3];
+
 	b43_phy_ht_tables_init(dev);
 
+	b43_phy_mask(dev, 0x0be, ~0x2);
+	b43_phy_set(dev, 0x23f, 0x7ff);
+	b43_phy_set(dev, 0x240, 0x7ff);
+	b43_phy_set(dev, 0x241, 0x7ff);
+
+	b43_phy_ht_zero_extg(dev);
+
+	b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3);
+
+	b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0);
+	b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0);
+	b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0);
+
+	b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20);
+	b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20);
+	b43_phy_write(dev, 0x20d, 0xb8);
+	b43_phy_write(dev, B43_PHY_EXTG(0x14f), 0xc8);
+	b43_phy_write(dev, 0x70, 0x50);
+	b43_phy_write(dev, 0x1ff, 0x30);
+
+	if (0) /* TODO: condition */
+		; /* TODO: PHY op on reg 0x217 */
+
+	b43_phy_read(dev, 0xb0); /* TODO: what for? */
+	b43_phy_set(dev, 0xb0, 0x1);
+
+	b43_phy_set(dev, 0xb1, 0x91);
+	b43_phy_write(dev, 0x32f, 0x0003);
+	b43_phy_write(dev, 0x077, 0x0010);
+	b43_phy_write(dev, 0x0b4, 0x0258);
+	b43_phy_mask(dev, 0x17e, ~0x4000);
+
+	b43_phy_write(dev, 0x0b9, 0x0072);
+
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x14e), 2, 0x010f, 0x010f);
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x15e), 2, 0x010f, 0x010f);
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x16e), 2, 0x010f, 0x010f);
+
+	b43_phy_ht_afe_unk1(dev);
+
+	b43_httab_write_few(dev, B43_HTTAB16(7, 0x130), 9, 0x777, 0x111, 0x111,
+			    0x777, 0x111, 0x111, 0x777, 0x111, 0x111);
+
+	b43_httab_write(dev, B43_HTTAB16(7, 0x120), 0x0777);
+	b43_httab_write(dev, B43_HTTAB16(7, 0x124), 0x0777);
+
+	b43_httab_write(dev, B43_HTTAB16(8, 0x00), 0x02);
+	b43_httab_write(dev, B43_HTTAB16(8, 0x10), 0x02);
+	b43_httab_write(dev, B43_HTTAB16(8, 0x20), 0x02);
+
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x08), 4,
+			    0x8e, 0x96, 0x96, 0x96);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x18), 4,
+			    0x8f, 0x9f, 0x9f, 0x9f);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x28), 4,
+			    0x8f, 0x9f, 0x9f, 0x9f);
+
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x0c), 4, 0x2, 0x2, 0x2, 0x2);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x1c), 4, 0x2, 0x2, 0x2, 0x2);
+	b43_httab_write_few(dev, B43_HTTAB16(8, 0x2c), 4, 0x2, 0x2, 0x2, 0x2);
+
+	b43_phy_maskset(dev, 0x0280, 0xff00, 0x3e);
+	b43_phy_maskset(dev, 0x0283, 0xff00, 0x3e);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x0141), 0xff00, 0x46);
+	b43_phy_maskset(dev, 0x0283, 0xff00, 0x40);
+
+	b43_httab_write_few(dev, B43_HTTAB16(00, 0x8), 4,
+			    0x09, 0x0e, 0x13, 0x18);
+	b43_httab_write_few(dev, B43_HTTAB16(01, 0x8), 4,
+			    0x09, 0x0e, 0x13, 0x18);
+	/* TODO: Did wl mean 2 instead of 40? */
+	b43_httab_write_few(dev, B43_HTTAB16(40, 0x8), 4,
+			    0x09, 0x0e, 0x13, 0x18);
+
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x24), 0x3f, 0xd);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0x64), 0x3f, 0xd);
+	b43_phy_maskset(dev, B43_PHY_OFDM(0xa4), 0x3f, 0xd);
+
+	b43_phy_set(dev, B43_PHY_EXTG(0x060), 0x1);
+	b43_phy_set(dev, B43_PHY_EXTG(0x064), 0x1);
+	b43_phy_set(dev, B43_PHY_EXTG(0x080), 0x1);
+	b43_phy_set(dev, B43_PHY_EXTG(0x084), 0x1);
+
+	/* Copy some tables entries */
+	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x144));
+	b43_httab_write(dev, B43_HTTAB16(7, 0x14a), tmp);
+	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x154));
+	b43_httab_write(dev, B43_HTTAB16(7, 0x15a), tmp);
+	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x164));
+	b43_httab_write(dev, B43_HTTAB16(7, 0x16a), tmp);
+
+	/* Reset CCA */
+	b43_phy_force_clock(dev, true);
+	tmp = b43_phy_read(dev, B43_PHY_HT_BBCFG);
+	b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp | B43_PHY_HT_BBCFG_RSTCCA);
+	b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp & ~B43_PHY_HT_BBCFG_RSTCCA);
+	b43_phy_force_clock(dev, false);
+
+	b43_mac_phy_clock_set(dev, true);
+
+	b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX);
+	b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
+
+	/* TODO: PHY op on reg 0xb0 */
+
+	/* TODO: Should we restore it? Or store it in global PHY info? */
+	b43_phy_ht_read_clip_detection(dev, clip_state);
+
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+		b43_phy_ht_bphy_init(dev);
+
+	b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0),
+			B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late);
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h
index 7ad7affc8df08b8bc9e2caa7a03f5cb4e4e8e431..6544c4293b34ddc0f3980041d7f29ce547fb5212 100644
--- a/drivers/net/wireless/b43/phy_ht.h
+++ b/drivers/net/wireless/b43/phy_ht.h
@@ -4,7 +4,11 @@
 #include "phy_common.h"
 
 
+#define B43_PHY_HT_BBCFG			0x001 /* BB config */
+#define  B43_PHY_HT_BBCFG_RSTCCA		0x4000 /* Reset CCA */
+#define  B43_PHY_HT_BBCFG_RSTRX			0x8000 /* Reset RX */
 #define B43_PHY_HT_BANDCTL			0x009 /* Band control */
+#define  B43_PHY_HT_BANDCTL_5GHZ		0x0001 /* Use the 5GHz band */
 #define B43_PHY_HT_TABLE_ADDR			0x072 /* Table address */
 #define B43_PHY_HT_TABLE_DATALO			0x073 /* Table data low */
 #define B43_PHY_HT_TABLE_DATAHI			0x074 /* Table data high */
@@ -15,6 +19,21 @@
 #define B43_PHY_HT_BW5				0x1D2
 #define B43_PHY_HT_BW6				0x1D3
 
+#define B43_PHY_HT_C1_CLIP1THRES		B43_PHY_OFDM(0x00E)
+#define B43_PHY_HT_C2_CLIP1THRES		B43_PHY_OFDM(0x04E)
+#define B43_PHY_HT_C3_CLIP1THRES		B43_PHY_OFDM(0x08E)
+
+#define B43_PHY_HT_RF_SEQ_MODE			B43_PHY_EXTG(0x000)
+#define B43_PHY_HT_RF_SEQ_TRIG			B43_PHY_EXTG(0x003)
+#define  B43_PHY_HT_RF_SEQ_TRIG_RX2TX		0x0001 /* RX2TX */
+#define  B43_PHY_HT_RF_SEQ_TRIG_TX2RX		0x0002 /* TX2RX */
+#define  B43_PHY_HT_RF_SEQ_TRIG_UPGH		0x0004 /* Update gain H */
+#define  B43_PHY_HT_RF_SEQ_TRIG_UPGL		0x0008 /* Update gain L */
+#define  B43_PHY_HT_RF_SEQ_TRIG_UPGU		0x0010 /* Update gain U */
+#define  B43_PHY_HT_RF_SEQ_TRIG_RST2RX		0x0020 /* Reset to RX */
+#define B43_PHY_HT_RF_SEQ_STATUS		B43_PHY_EXTG(0x004)
+/* Values for the status are the same as for the trigger */
+
 #define B43_PHY_HT_RF_CTL1			B43_PHY_EXTG(0x010)
 
 #define B43_PHY_HT_AFE_CTL1			B43_PHY_EXTG(0x110)
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
index 9f7dbbd5ced6eca964c3c61bbfefdb8b0838cdf3..4b2cd6d24ce9573696057f36fbb6a09af23b8c54 100644
--- a/drivers/net/wireless/b43/phy_lcn.c
+++ b/drivers/net/wireless/b43/phy_lcn.c
@@ -27,26 +27,233 @@
 #include "tables_phy_lcn.h"
 #include "main.h"
 
+/**************************************************
+ * Radio 2064.
+ **************************************************/
+
+static void b43_radio_2064_init(struct b43_wldev *dev)
+{
+	b43_radio_write(dev, 0x09c, 0x0020);
+	b43_radio_write(dev, 0x105, 0x0008);
+	b43_radio_write(dev, 0x032, 0x0062);
+	b43_radio_write(dev, 0x033, 0x0019);
+	b43_radio_write(dev, 0x090, 0x0010);
+	b43_radio_write(dev, 0x010, 0x0000);
+	b43_radio_write(dev, 0x060, 0x007f);
+	b43_radio_write(dev, 0x061, 0x0072);
+	b43_radio_write(dev, 0x062, 0x007f);
+	b43_radio_write(dev, 0x01d, 0x0002);
+	b43_radio_write(dev, 0x01e, 0x0006);
+
+	b43_phy_write(dev, 0x4ea, 0x4688);
+	b43_phy_maskset(dev, 0x4eb, ~0x7, 0x2);
+	b43_phy_mask(dev, 0x4eb, ~0x01c0);
+	b43_phy_maskset(dev, 0x4eb, 0xff00, 0x19);
+
+	b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x55), 0);
+
+	b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
+	b43_radio_set(dev, 0x004, 0x40);
+	b43_radio_set(dev, 0x120, 0x10);
+	b43_radio_set(dev, 0x078, 0x80);
+	b43_radio_set(dev, 0x129, 0x2);
+	b43_radio_set(dev, 0x057, 0x1);
+	b43_radio_set(dev, 0x05b, 0x2);
+
+	/* TODO: wait for some bit to be set */
+	b43_radio_read(dev, 0x05c);
+
+	b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
+	b43_radio_mask(dev, 0x057, (u16) ~0xff01);
+
+	b43_phy_write(dev, 0x933, 0x2d6b);
+	b43_phy_write(dev, 0x934, 0x2d6b);
+	b43_phy_write(dev, 0x935, 0x2d6b);
+	b43_phy_write(dev, 0x936, 0x2d6b);
+	b43_phy_write(dev, 0x937, 0x016b);
+
+	b43_radio_mask(dev, 0x057, (u16) ~0xff02);
+	b43_radio_write(dev, 0x0c2, 0x006f);
+}
+
+/**************************************************
+ * Various PHY ops
+ **************************************************/
+
+static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev)
+{
+	u16 afe_ctl2 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL2);
+	u16 afe_ctl1 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL1);
+
+	b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 | 0x1);
+	b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 | 0x1);
+
+	b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 & ~0x1);
+	b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 & ~0x1);
+
+	b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2);
+	b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1);
+}
+
+static void b43_phy_lcn_clean_0x18_table(struct b43_wldev *dev)
+{
+	u8 i;
+
+	for (i = 0; i < 0x80; i++)
+		b43_lcntab_write(dev, B43_LCNTAB32(0x18, i), 0x80000);
+}
+
+static void b43_phy_lcn_clear_0x07_table(struct b43_wldev *dev)
+{
+	u8 i;
+
+	b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x340);
+	for (i = 0; i < 30; i++) {
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
+	}
+
+	b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x80);
+	for (i = 0; i < 64; i++) {
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
+	}
+}
+
+/**************************************************
+ * Basic PHY ops.
+ **************************************************/
+
+static int b43_phy_lcn_op_allocate(struct b43_wldev *dev)
+{
+	struct b43_phy_lcn *phy_lcn;
+
+	phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL);
+	if (!phy_lcn)
+		return -ENOMEM;
+	dev->phy.lcn = phy_lcn;
+
+	return 0;
+}
+
+static void b43_phy_lcn_op_free(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_lcn *phy_lcn = phy->lcn;
+
+	kfree(phy_lcn);
+	phy->lcn = NULL;
+}
+
+static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_lcn *phy_lcn = phy->lcn;
+
+	memset(phy_lcn, 0, sizeof(*phy_lcn));
+}
+
+static int b43_phy_lcn_op_init(struct b43_wldev *dev)
+{
+	b43_phy_set(dev, 0x44a, 0x80);
+	b43_phy_mask(dev, 0x44a, 0x7f);
+	b43_phy_set(dev, 0x6d1, 0x80);
+	b43_phy_write(dev, 0x6d0, 0x7);
+
+	b43_phy_lcn_afe_set_unset(dev);
+
+	b43_phy_write(dev, 0x60a, 0xa0);
+	b43_phy_write(dev, 0x46a, 0x19);
+	b43_phy_maskset(dev, 0x663, 0xFF00, 0x64);
+
+	b43_phy_lcn_tables_init(dev);
+	/* TODO: various tables ops here */
+	b43_phy_lcn_clean_0x18_table(dev);
+
+	/* TODO: some ops here */
+
+	b43_phy_lcn_clear_0x07_table(dev);
+
+	if (dev->phy.radio_ver == 0x2064)
+		b43_radio_2064_init(dev);
+	else
+		B43_WARN_ON(1);
+
+	return 0;
+}
+
+static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev,
+					bool blocked)
+{
+	if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
+		b43err(dev->wl, "MAC not suspended\n");
+
+	if (blocked) {
+		b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00);
+		b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00);
+
+		b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00);
+		b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2);
+		b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808);
+
+		b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8);
+		b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8);
+	} else {
+		b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00);
+		b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808);
+		b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8);
+	}
+}
+
+static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
+{
+	if (on) {
+		b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7);
+	} else {
+		b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7);
+		b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7);
+	}
+}
+
+static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
+{
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+		return 1;
+	return 36;
+}
+
+static enum b43_txpwr_result
+b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
+{
+	return B43_TXPWR_RES_DONE;
+}
+
+static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
+{
+}
+
 /**************************************************
  * PHY ops struct.
  **************************************************/
 
 const struct b43_phy_operations b43_phyops_lcn = {
-	/*
 	.allocate		= b43_phy_lcn_op_allocate,
 	.free			= b43_phy_lcn_op_free,
 	.prepare_structs	= b43_phy_lcn_op_prepare_structs,
 	.init			= b43_phy_lcn_op_init,
+	/*
 	.phy_read		= b43_phy_lcn_op_read,
 	.phy_write		= b43_phy_lcn_op_write,
 	.phy_maskset		= b43_phy_lcn_op_maskset,
 	.radio_read		= b43_phy_lcn_op_radio_read,
 	.radio_write		= b43_phy_lcn_op_radio_write,
+	*/
 	.software_rfkill	= b43_phy_lcn_op_software_rfkill,
 	.switch_analog		= b43_phy_lcn_op_switch_analog,
+	/*
 	.switch_channel		= b43_phy_lcn_op_switch_channel,
+	*/
 	.get_default_chan	= b43_phy_lcn_op_get_default_chan,
 	.recalc_txpower		= b43_phy_lcn_op_recalc_txpower,
 	.adjust_txpower		= b43_phy_lcn_op_adjust_txpower,
-	*/
 };
diff --git a/drivers/net/wireless/b43/phy_lcn.h b/drivers/net/wireless/b43/phy_lcn.h
index c046c2a6cab4aee16c4dfee664b2a9412e4273f3..25f06e8d453186e73aaa1d7939c6a3c4eb549b1c 100644
--- a/drivers/net/wireless/b43/phy_lcn.h
+++ b/drivers/net/wireless/b43/phy_lcn.h
@@ -4,6 +4,20 @@
 #include "phy_common.h"
 
 
+#define B43_PHY_LCN_AFE_CTL1			B43_PHY_OFDM(0x03B)
+#define B43_PHY_LCN_AFE_CTL2			B43_PHY_OFDM(0x03C)
+#define B43_PHY_LCN_RF_CTL1			B43_PHY_OFDM(0x04C)
+#define B43_PHY_LCN_RF_CTL2			B43_PHY_OFDM(0x04D)
+#define B43_PHY_LCN_TABLE_ADDR			B43_PHY_OFDM(0x055) /* Table address */
+#define B43_PHY_LCN_TABLE_DATALO		B43_PHY_OFDM(0x056) /* Table data low */
+#define B43_PHY_LCN_TABLE_DATAHI		B43_PHY_OFDM(0x057) /* Table data high */
+#define B43_PHY_LCN_RF_CTL3			B43_PHY_OFDM(0x0B0)
+#define B43_PHY_LCN_RF_CTL4			B43_PHY_OFDM(0x0B1)
+#define B43_PHY_LCN_RF_CTL5			B43_PHY_OFDM(0x0B7)
+#define B43_PHY_LCN_RF_CTL6			B43_PHY_OFDM(0x0F9)
+#define B43_PHY_LCN_RF_CTL7			B43_PHY_OFDM(0x0FA)
+
+
 struct b43_phy_lcn {
 };
 
@@ -11,4 +25,4 @@ struct b43_phy_lcn {
 struct b43_phy_operations;
 extern const struct b43_phy_operations b43_phyops_lcn;
 
-#endif /* B43_PHY_LCN_H_ */
\ No newline at end of file
+#endif /* B43_PHY_LCN_H_ */
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 3b46360da99b5790dac9020ceaa055dad8131f2b..2eadadf5f4fc375ced006719086846a624182a04 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -600,49 +600,17 @@ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
 	}
 }
 
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
-static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
-{
-	u32 tmp;
-
-	if (dev->phy.type != B43_PHYTYPE_N)
-		return;
-
-	switch (dev->dev->bus_type) {
-#ifdef CONFIG_B43_BCMA
-	case B43_BUS_BCMA:
-		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
-		if (force)
-			tmp |= BCMA_IOCTL_FGC;
-		else
-			tmp &= ~BCMA_IOCTL_FGC;
-		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
-		break;
-#endif
-#ifdef CONFIG_B43_SSB
-	case B43_BUS_SSB:
-		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
-		if (force)
-			tmp |= SSB_TMSLOW_FGC;
-		else
-			tmp &= ~SSB_TMSLOW_FGC;
-		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
-		break;
-#endif
-	}
-}
-
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
 static void b43_nphy_reset_cca(struct b43_wldev *dev)
 {
 	u16 bbcfg;
 
-	b43_nphy_bmac_clock_fgc(dev, 1);
+	b43_phy_force_clock(dev, 1);
 	bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
 	b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA);
 	udelay(1);
 	b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
-	b43_nphy_bmac_clock_fgc(dev, 0);
+	b43_phy_force_clock(dev, 0);
 	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
 }
 
@@ -3715,11 +3683,11 @@ int b43_phy_initn(struct b43_wldev *dev)
 	b43_nphy_workarounds(dev);
 
 	/* Reset CCA, in init code it differs a little from standard way */
-	b43_nphy_bmac_clock_fgc(dev, 1);
+	b43_phy_force_clock(dev, 1);
 	tmp = b43_phy_read(dev, B43_NPHY_BBCFG);
 	b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA);
 	b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
-	b43_nphy_bmac_clock_fgc(dev, 0);
+	b43_phy_force_clock(dev, 0);
 
 	b43_mac_phy_clock_set(dev, true);
 
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 6e4228c3ed1bde3b6e143bd06add80399ff334fe..fcff923b3c18b25d44ae4e266747825b8b571ebf 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -611,7 +611,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
 	struct b43_wldev *dev = q->dev;
 	struct b43_wl *wl = dev->wl;
 	u16 len;
-	u32 macstat;
+	u32 macstat = 0;
 	unsigned int i, padding;
 	struct sk_buff *skb;
 	const char *err_msg = NULL;
@@ -676,7 +676,15 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
 		goto rx_error;
 	}
 
-	macstat = le32_to_cpu(rxhdr->mac_status);
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		macstat = le32_to_cpu(rxhdr->format_598.mac_status);
+		break;
+	case B43_FW_HDR_410:
+	case B43_FW_HDR_351:
+		macstat = le32_to_cpu(rxhdr->format_351.mac_status);
+		break;
+	}
 	if (macstat & B43_RX_MAC_FCSERR) {
 		if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
 			/* Drop frames with failed FCS. */
diff --git a/drivers/net/wireless/b43/tables_phy_ht.c b/drivers/net/wireless/b43/tables_phy_ht.c
index 603938657b159d77f4dc91c8a70abe65de14a610..677d217b5fb32f1bef2ba9120c44a68a9f956932 100644
--- a/drivers/net/wireless/b43/tables_phy_ht.c
+++ b/drivers/net/wireless/b43/tables_phy_ht.c
@@ -574,6 +574,42 @@ static const u32 b43_httab_0x24[] = {
 	0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c,
 };
 
+/* Some late-init table */
+const u32 b43_httab_0x1a_0xc0_late[] = {
+	0x10f90040, 0x10e10040, 0x10e1003c, 0x10c9003d,
+	0x10b9003c, 0x10a9003d, 0x10a1003c, 0x1099003b,
+	0x1091003b, 0x1089003a, 0x1081003a, 0x10790039,
+	0x10710039, 0x1069003a, 0x1061003b, 0x1059003d,
+	0x1051003f, 0x10490042, 0x1049003e, 0x1049003b,
+	0x1041003e, 0x1041003b, 0x1039003e, 0x1039003b,
+	0x10390038, 0x10390035, 0x1031003a, 0x10310036,
+	0x10310033, 0x1029003a, 0x10290037, 0x10290034,
+	0x10290031, 0x10210039, 0x10210036, 0x10210033,
+	0x10210030, 0x1019003c, 0x10190039, 0x10190036,
+	0x10190033, 0x10190030, 0x1019002d, 0x1019002b,
+	0x10190028, 0x1011003a, 0x10110036, 0x10110033,
+	0x10110030, 0x1011002e, 0x1011002b, 0x10110029,
+	0x10110027, 0x10110024, 0x10110022, 0x10110020,
+	0x1011001f, 0x1011001d, 0x1009003a, 0x10090037,
+	0x10090034, 0x10090031, 0x1009002e, 0x1009002c,
+	0x10090029, 0x10090027, 0x10090025, 0x10090023,
+	0x10090021, 0x1009001f, 0x1009001d, 0x1009001b,
+	0x1009001a, 0x10090018, 0x10090017, 0x10090016,
+	0x10090015, 0x10090013, 0x10090012, 0x10090011,
+	0x10090010, 0x1009000f, 0x1009000f, 0x1009000e,
+	0x1009000d, 0x1009000c, 0x1009000c, 0x1009000b,
+	0x1009000a, 0x1009000a, 0x10090009, 0x10090009,
+	0x10090008, 0x10090008, 0x10090007, 0x10090007,
+	0x10090007, 0x10090006, 0x10090006, 0x10090005,
+	0x10090005, 0x10090005, 0x10090005, 0x10090004,
+	0x10090004, 0x10090004, 0x10090004, 0x10090003,
+	0x10090003, 0x10090003, 0x10090003, 0x10090003,
+	0x10090003, 0x10090002, 0x10090002, 0x10090002,
+	0x10090002, 0x10090002, 0x10090002, 0x10090002,
+	0x10090002, 0x10090002, 0x10090001, 0x10090001,
+	0x10090001, 0x10090001, 0x10090001, 0x10090001,
+};
+
 /**************************************************
  * R/W ops.
  **************************************************/
@@ -674,6 +710,51 @@ void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value)
 	return;
 }
 
+void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...)
+{
+	va_list args;
+	u32 type, value;
+	unsigned int i;
+
+	type = offset & B43_HTTAB_TYPEMASK;
+	offset &= 0xFFFF;
+
+	va_start(args, num);
+	switch (type) {
+	case B43_HTTAB_8BIT:
+		b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+		for (i = 0; i < num; i++) {
+			value = va_arg(args, int);
+			B43_WARN_ON(value & ~0xFF);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value);
+		}
+		break;
+	case B43_HTTAB_16BIT:
+		b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+		for (i = 0; i < num; i++) {
+			value = va_arg(args, int);
+			B43_WARN_ON(value & ~0xFFFF);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value);
+		}
+		break;
+	case B43_HTTAB_32BIT:
+		b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+		for (i = 0; i < num; i++) {
+			value = va_arg(args, int);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI,
+				      value >> 16);
+			b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO,
+				      value & 0xFFFF);
+		}
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	va_end(args);
+
+	return;
+}
+
 void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
 			  unsigned int nr_elements, const void *_data)
 {
@@ -723,6 +804,9 @@ void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
 	} while (0)
 void b43_phy_ht_tables_init(struct b43_wldev *dev)
 {
+	BUILD_BUG_ON(ARRAY_SIZE(b43_httab_0x1a_0xc0_late) !=
+			B43_HTTAB_1A_C0_LATE_SIZE);
+
 	httab_upload(dev, B43_HTTAB16(0x12, 0), b43_httab_0x12);
 	httab_upload(dev, B43_HTTAB16(0x27, 0), b43_httab_0x27);
 	httab_upload(dev, B43_HTTAB16(0x26, 0), b43_httab_0x26);
diff --git a/drivers/net/wireless/b43/tables_phy_ht.h b/drivers/net/wireless/b43/tables_phy_ht.h
index ea3be382c8945b70e010925c94ad446c59a1a70a..1b5ef2bc770c2b19e50e908c0fbc8992ec8e8964 100644
--- a/drivers/net/wireless/b43/tables_phy_ht.h
+++ b/drivers/net/wireless/b43/tables_phy_ht.h
@@ -14,9 +14,13 @@ u32 b43_httab_read(struct b43_wldev *dev, u32 offset);
 void b43_httab_read_bulk(struct b43_wldev *dev, u32 offset,
 			 unsigned int nr_elements, void *_data);
 void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value);
+void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...);
 void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
 			  unsigned int nr_elements, const void *_data);
 
 void b43_phy_ht_tables_init(struct b43_wldev *dev);
 
+#define B43_HTTAB_1A_C0_LATE_SIZE		128
+extern const u32 b43_httab_0x1a_0xc0_late[];
+
 #endif /* B43_TABLES_PHY_HT_H_ */
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.c b/drivers/net/wireless/b43/tables_phy_lcn.c
index 40c1d0915dd32977a7944f1db0fe67bcba0313b8..0a5842808a78229dd3670cba9aa861544dd2687a 100644
--- a/drivers/net/wireless/b43/tables_phy_lcn.c
+++ b/drivers/net/wireless/b43/tables_phy_lcn.c
@@ -25,10 +25,442 @@
 #include "phy_common.h"
 #include "phy_lcn.h"
 
+static const u16 b43_lcntab_0x02[] = {
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+	0x014d, 0x014d, 0x014d, 0x014d,
+};
+
+static const u16 b43_lcntab_0x01[] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u32 b43_lcntab_0x0b[] = {
+	0x000141f8, 0x000021f8, 0x000021fb, 0x000041fb,
+	0x0001fedb, 0x0000217b, 0x00002133, 0x000040eb,
+	0x0001fea3, 0x0000024b,
+};
+
+static const u32 b43_lcntab_0x0c[] = {
+	0x00100001, 0x00200010, 0x00300001, 0x00400010,
+	0x00500022, 0x00600122, 0x00700222, 0x00800322,
+	0x00900422, 0x00a00522, 0x00b00622, 0x00c00722,
+	0x00d00822, 0x00f00922, 0x00100a22, 0x00200b22,
+	0x00300c22, 0x00400d22, 0x00500e22, 0x00600f22,
+};
+
+static const u32 b43_lcntab_0x0d[] = {
+	0x00000000, 0x00000000, 0x10000000, 0x00000000,
+	0x20000000, 0x00000000, 0x30000000, 0x00000000,
+	0x40000000, 0x00000000, 0x50000000, 0x00000000,
+	0x60000000, 0x00000000, 0x70000000, 0x00000000,
+	0x80000000, 0x00000000, 0x90000000, 0x00000008,
+	0xa0000000, 0x00000008, 0xb0000000, 0x00000008,
+	0xc0000000, 0x00000008, 0xd0000000, 0x00000008,
+	0xe0000000, 0x00000008, 0xf0000000, 0x00000008,
+	0x00000000, 0x00000009, 0x10000000, 0x00000009,
+	0x20000000, 0x00000019, 0x30000000, 0x00000019,
+	0x40000000, 0x00000019, 0x50000000, 0x00000019,
+	0x60000000, 0x00000019, 0x70000000, 0x00000019,
+	0x80000000, 0x00000019, 0x90000000, 0x00000019,
+	0xa0000000, 0x00000019, 0xb0000000, 0x00000019,
+	0xc0000000, 0x00000019, 0xd0000000, 0x00000019,
+	0xe0000000, 0x00000019, 0xf0000000, 0x00000019,
+	0x00000000, 0x0000001a, 0x10000000, 0x0000001a,
+	0x20000000, 0x0000001a, 0x30000000, 0x0000001a,
+	0x40000000, 0x0000001a, 0x50000000, 0x00000002,
+	0x60000000, 0x00000002, 0x70000000, 0x00000002,
+	0x80000000, 0x00000002, 0x90000000, 0x00000002,
+	0xa0000000, 0x00000002, 0xb0000000, 0x00000002,
+	0xc0000000, 0x0000000a, 0xd0000000, 0x0000000a,
+	0xe0000000, 0x0000000a, 0xf0000000, 0x0000000a,
+	0x00000000, 0x0000000b, 0x10000000, 0x0000000b,
+	0x20000000, 0x0000000b, 0x30000000, 0x0000000b,
+	0x40000000, 0x0000000b, 0x50000000, 0x0000001b,
+	0x60000000, 0x0000001b, 0x70000000, 0x0000001b,
+	0x80000000, 0x0000001b, 0x90000000, 0x0000001b,
+	0xa0000000, 0x0000001b, 0xb0000000, 0x0000001b,
+	0xc0000000, 0x0000001b, 0xd0000000, 0x0000001b,
+	0xe0000000, 0x0000001b, 0xf0000000, 0x0000001b,
+	0x00000000, 0x0000001c, 0x10000000, 0x0000001c,
+	0x20000000, 0x0000001c, 0x30000000, 0x0000001c,
+	0x40000000, 0x0000001c, 0x50000000, 0x0000001c,
+	0x60000000, 0x0000001c, 0x70000000, 0x0000001c,
+	0x80000000, 0x0000001c, 0x90000000, 0x0000001c,
+};
+
+static const u16 b43_lcntab_0x0e[] = {
+	0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406,
+	0x0407, 0x0408, 0x0409, 0x040a, 0x058b, 0x058c,
+	0x058d, 0x058e, 0x058f, 0x0090, 0x0091, 0x0092,
+	0x0193, 0x0194, 0x0195, 0x0196, 0x0197, 0x0198,
+	0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e,
+	0x019f, 0x01a0, 0x01a1, 0x01a2, 0x01a3, 0x01a4,
+	0x01a5, 0x0000,
+};
+
+static const u16 b43_lcntab_0x0f[] = {
+	0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+	0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+	0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+	0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+	0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+	0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+	0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+	0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+	0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+	0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+	0x000a, 0x0009, 0x0006, 0x0005,
+};
+
+static const u16 b43_lcntab_0x10[] = {
+	0x005f, 0x0036, 0x0029, 0x001f, 0x005f, 0x0036,
+	0x0029, 0x001f, 0x005f, 0x0036, 0x0029, 0x001f,
+	0x005f, 0x0036, 0x0029, 0x001f,
+};
+
+static const u16 b43_lcntab_0x11[] = {
+	0x0009, 0x000f, 0x0014, 0x0018, 0x00fe, 0x0007,
+	0x000b, 0x000f, 0x00fb, 0x00fe, 0x0001, 0x0005,
+	0x0008, 0x000b, 0x000e, 0x0011, 0x0014, 0x0017,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f,
+	0x0012, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003,
+	0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015,
+	0x0018, 0x001b, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0003, 0x00eb, 0x0000, 0x0000,
+};
+
+static const u32 b43_lcntab_0x12[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000004, 0x00000000, 0x00000004, 0x00000008,
+	0x00000001, 0x00000005, 0x00000009, 0x0000000d,
+	0x0000004d, 0x0000008d, 0x0000000d, 0x0000004d,
+	0x0000008d, 0x000000cd, 0x0000004f, 0x0000008f,
+	0x000000cf, 0x000000d3, 0x00000113, 0x00000513,
+	0x00000913, 0x00000953, 0x00000d53, 0x00001153,
+	0x00001193, 0x00005193, 0x00009193, 0x0000d193,
+	0x00011193, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000004,
+	0x00000000, 0x00000004, 0x00000008, 0x00000001,
+	0x00000005, 0x00000009, 0x0000000d, 0x0000004d,
+	0x0000008d, 0x0000000d, 0x0000004d, 0x0000008d,
+	0x000000cd, 0x0000004f, 0x0000008f, 0x000000cf,
+	0x000000d3, 0x00000113, 0x00000513, 0x00000913,
+	0x00000953, 0x00000d53, 0x00001153, 0x00005153,
+	0x00009153, 0x0000d153, 0x00011153, 0x00015153,
+	0x00019153, 0x0001d153, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u16 b43_lcntab_0x14[] = {
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0002, 0x0003, 0x0001, 0x0003, 0x0002, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0003,
+	0x0001, 0x0003, 0x0002, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0001,
+};
+
+static const u16 b43_lcntab_0x17[] = {
+	0x001a, 0x0034, 0x004e, 0x0068, 0x009c, 0x00d0,
+	0x00ea, 0x0104, 0x0034, 0x0068, 0x009c, 0x00d0,
+	0x0138, 0x01a0, 0x01d4, 0x0208, 0x004e, 0x009c,
+	0x00ea, 0x0138, 0x01d4, 0x0270, 0x02be, 0x030c,
+	0x0068, 0x00d0, 0x0138, 0x01a0, 0x0270, 0x0340,
+	0x03a8, 0x0410, 0x0018, 0x009c, 0x00d0, 0x0104,
+	0x00ea, 0x0138, 0x0186, 0x00d0, 0x0104, 0x0104,
+	0x0138, 0x016c, 0x016c, 0x01a0, 0x0138, 0x0186,
+	0x0186, 0x01d4, 0x0222, 0x0222, 0x0270, 0x0104,
+	0x0138, 0x016c, 0x0138, 0x016c, 0x01a0, 0x01d4,
+	0x01a0, 0x01d4, 0x0208, 0x0208, 0x023c, 0x0186,
+	0x01d4, 0x0222, 0x01d4, 0x0222, 0x0270, 0x02be,
+	0x0270, 0x02be, 0x030c, 0x030c, 0x035a, 0x0036,
+	0x006c, 0x00a2, 0x00d8, 0x0144, 0x01b0, 0x01e6,
+	0x021c, 0x006c, 0x00d8, 0x0144, 0x01b0, 0x0288,
+	0x0360, 0x03cc, 0x0438, 0x00a2, 0x0144, 0x01e6,
+	0x0288, 0x03cc, 0x0510, 0x05b2, 0x0654, 0x00d8,
+	0x01b0, 0x0288, 0x0360, 0x0510, 0x06c0, 0x0798,
+	0x0870, 0x0018, 0x0144, 0x01b0, 0x021c, 0x01e6,
+	0x0288, 0x032a, 0x01b0, 0x021c, 0x021c, 0x0288,
+	0x02f4, 0x02f4, 0x0360, 0x0288, 0x032a, 0x032a,
+	0x03cc, 0x046e, 0x046e, 0x0510, 0x021c, 0x0288,
+	0x02f4, 0x0288, 0x02f4, 0x0360, 0x03cc, 0x0360,
+	0x03cc, 0x0438, 0x0438, 0x04a4, 0x032a, 0x03cc,
+	0x046e, 0x03cc, 0x046e, 0x0510, 0x05b2, 0x0510,
+	0x05b2, 0x0654, 0x0654, 0x06f6,
+};
+
+static const u16 b43_lcntab_0x00[] = {
+	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00,
+	0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005,
+	0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
+	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003,
+	0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007,
+	0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u32 b43_lcntab_0x18[] = {
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+	0x00080000, 0x00080000, 0x00080000, 0x00080000,
+};
+
+/**************************************************
+ * R/W ops.
+ **************************************************/
+
+u32 b43_lcntab_read(struct b43_wldev *dev, u32 offset)
+{
+	u32 type, value;
+
+	type = offset & B43_LCNTAB_TYPEMASK;
+	offset &= ~B43_LCNTAB_TYPEMASK;
+	B43_WARN_ON(offset > 0xFFFF);
+
+	switch (type) {
+	case B43_LCNTAB_8BIT:
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+		value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO) & 0xFF;
+		break;
+	case B43_LCNTAB_16BIT:
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+		value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO);
+		break;
+	case B43_LCNTAB_32BIT:
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+		value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATAHI);
+		value <<= 16;
+		value |= b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO);
+		break;
+	default:
+		B43_WARN_ON(1);
+		value = 0;
+	}
+
+	return value;
+}
+
+void b43_lcntab_read_bulk(struct b43_wldev *dev, u32 offset,
+			  unsigned int nr_elements, void *_data)
+{
+	u32 type;
+	u8 *data = _data;
+	unsigned int i;
+
+	type = offset & B43_LCNTAB_TYPEMASK;
+	offset &= ~B43_LCNTAB_TYPEMASK;
+	B43_WARN_ON(offset > 0xFFFF);
+
+	b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+
+	for (i = 0; i < nr_elements; i++) {
+		switch (type) {
+		case B43_LCNTAB_8BIT:
+			*data = b43_phy_read(dev,
+					     B43_PHY_LCN_TABLE_DATALO) & 0xFF;
+			data++;
+			break;
+		case B43_LCNTAB_16BIT:
+			*((u16 *)data) = b43_phy_read(dev,
+						      B43_PHY_LCN_TABLE_DATALO);
+			data += 2;
+			break;
+		case B43_LCNTAB_32BIT:
+			*((u32 *)data) = b43_phy_read(dev,
+						      B43_PHY_LCN_TABLE_DATAHI);
+			*((u32 *)data) <<= 16;
+			*((u32 *)data) |= b43_phy_read(dev,
+						B43_PHY_LCN_TABLE_DATALO);
+			data += 4;
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
+	}
+}
+
+void b43_lcntab_write(struct b43_wldev *dev, u32 offset, u32 value)
+{
+	u32 type;
+
+	type = offset & B43_LCNTAB_TYPEMASK;
+	offset &= 0xFFFF;
+
+	switch (type) {
+	case B43_LCNTAB_8BIT:
+		B43_WARN_ON(value & ~0xFF);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+		break;
+	case B43_LCNTAB_16BIT:
+		B43_WARN_ON(value & ~0xFFFF);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+		break;
+	case B43_LCNTAB_32BIT:
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, value >> 16);
+		b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value & 0xFFFF);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	return;
+}
+
+void b43_lcntab_write_bulk(struct b43_wldev *dev, u32 offset,
+			   unsigned int nr_elements, const void *_data)
+{
+	u32 type, value;
+	const u8 *data = _data;
+	unsigned int i;
+
+	type = offset & B43_LCNTAB_TYPEMASK;
+	offset &= ~B43_LCNTAB_TYPEMASK;
+	B43_WARN_ON(offset > 0xFFFF);
+
+	b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+
+	for (i = 0; i < nr_elements; i++) {
+		switch (type) {
+		case B43_LCNTAB_8BIT:
+			value = *data;
+			data++;
+			B43_WARN_ON(value & ~0xFF);
+			b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+			break;
+		case B43_LCNTAB_16BIT:
+			value = *((u16 *)data);
+			data += 2;
+			B43_WARN_ON(value & ~0xFFFF);
+			b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+			break;
+		case B43_LCNTAB_32BIT:
+			value = *((u32 *)data);
+			data += 4;
+			b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI,
+				      value >> 16);
+			b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO,
+				      value & 0xFFFF);
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
+	}
+}
+
 /**************************************************
  * Tables ops.
  **************************************************/
 
+#define lcntab_upload(dev, offset, data) do { \
+		b43_lcntab_write_bulk(dev, offset, ARRAY_SIZE(data), data); \
+	} while (0)
 void b43_phy_lcn_tables_init(struct b43_wldev *dev)
 {
+	lcntab_upload(dev, B43_LCNTAB16(0x02, 0), b43_lcntab_0x02);
+	lcntab_upload(dev, B43_LCNTAB16(0x01, 0), b43_lcntab_0x01);
+	lcntab_upload(dev, B43_LCNTAB32(0x0b, 0), b43_lcntab_0x0b);
+	lcntab_upload(dev, B43_LCNTAB32(0x0c, 0), b43_lcntab_0x0c);
+	lcntab_upload(dev, B43_LCNTAB32(0x0d, 0), b43_lcntab_0x0d);
+	lcntab_upload(dev, B43_LCNTAB16(0x0e, 0), b43_lcntab_0x0e);
+	lcntab_upload(dev, B43_LCNTAB16(0x0f, 0), b43_lcntab_0x0f);
+	lcntab_upload(dev, B43_LCNTAB16(0x10, 0), b43_lcntab_0x10);
+	lcntab_upload(dev, B43_LCNTAB16(0x11, 0), b43_lcntab_0x11);
+	lcntab_upload(dev, B43_LCNTAB32(0x12, 0), b43_lcntab_0x12);
+	lcntab_upload(dev, B43_LCNTAB16(0x14, 0), b43_lcntab_0x14);
+	lcntab_upload(dev, B43_LCNTAB16(0x17, 0), b43_lcntab_0x17);
+	lcntab_upload(dev, B43_LCNTAB16(0x00, 0), b43_lcntab_0x00);
+	lcntab_upload(dev, B43_LCNTAB32(0x18, 0), b43_lcntab_0x18);
 }
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.h b/drivers/net/wireless/b43/tables_phy_lcn.h
index 5e31b15b81ecf48e01a00f4990b8aa531efe8d3a..b6471e89c36f1a3fce2e05b3b54953148948b297 100644
--- a/drivers/net/wireless/b43/tables_phy_lcn.h
+++ b/drivers/net/wireless/b43/tables_phy_lcn.h
@@ -1,6 +1,22 @@
 #ifndef B43_TABLES_PHY_LCN_H_
 #define B43_TABLES_PHY_LCN_H_
 
+/* The LCN-PHY tables. */
+#define B43_LCNTAB_TYPEMASK		0xF0000000
+#define B43_LCNTAB_8BIT			0x10000000
+#define B43_LCNTAB_16BIT		0x20000000
+#define B43_LCNTAB_32BIT		0x30000000
+#define B43_LCNTAB8(table, offset)	(((table) << 10) | (offset) | B43_LCNTAB_8BIT)
+#define B43_LCNTAB16(table, offset)	(((table) << 10) | (offset) | B43_LCNTAB_16BIT)
+#define B43_LCNTAB32(table, offset)	(((table) << 10) | (offset) | B43_LCNTAB_32BIT)
+
+u32 b43_lcntab_read(struct b43_wldev *dev, u32 offset);
+void b43_lcntab_read_bulk(struct b43_wldev *dev, u32 offset,
+			  unsigned int nr_elements, void *_data);
+void b43_lcntab_write(struct b43_wldev *dev, u32 offset, u32 value);
+void b43_lcntab_write_bulk(struct b43_wldev *dev, u32 offset,
+			   unsigned int nr_elements, const void *_data);
+
 void b43_phy_lcn_tables_init(struct b43_wldev *dev);
 
 #endif /* B43_TABLES_PHY_LCN_H_ */
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index b74f25ec1ab4a89b4c1380b9ca9213b396a0ca49..b8de62c22479409a3d57904d41e8871d1ff4a716 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -337,12 +337,19 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 			memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 		}
 	}
-	if (b43_is_old_txhdr_format(dev)) {
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_598.plcp),
 				      plcp_fragment_len, rate);
-	} else {
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
+		break;
+	case B43_FW_HDR_351:
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_351.plcp),
+				      plcp_fragment_len, rate);
+		break;
+	case B43_FW_HDR_410:
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_410.plcp),
 				      plcp_fragment_len, rate);
+		break;
 	}
 	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
 			      plcp_fragment_len, rate_fb);
@@ -415,10 +422,10 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
 	    (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
 		unsigned int len;
-		struct ieee80211_hdr *hdr;
+		struct ieee80211_hdr *uninitialized_var(hdr);
 		int rts_rate, rts_rate_fb;
 		int rts_rate_ofdm, rts_rate_fb_ofdm;
-		struct b43_plcp_hdr6 *plcp;
+		struct b43_plcp_hdr6 *uninitialized_var(plcp);
 		struct ieee80211_rate *rts_cts_rate;
 
 		rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
@@ -429,14 +436,21 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
 		if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
-			struct ieee80211_cts *cts;
+			struct ieee80211_cts *uninitialized_var(cts);
 
-			if (b43_is_old_txhdr_format(dev)) {
+			switch (dev->fw.hdr_format) {
+			case B43_FW_HDR_598:
 				cts = (struct ieee80211_cts *)
-					(txhdr->old_format.rts_frame);
-			} else {
+					(txhdr->format_598.rts_frame);
+				break;
+			case B43_FW_HDR_351:
 				cts = (struct ieee80211_cts *)
-					(txhdr->new_format.rts_frame);
+					(txhdr->format_351.rts_frame);
+				break;
+			case B43_FW_HDR_410:
+				cts = (struct ieee80211_cts *)
+					(txhdr->format_410.rts_frame);
+				break;
 			}
 			ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
 						fragment_data, fragment_len,
@@ -444,14 +458,21 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 			mac_ctl |= B43_TXH_MAC_SENDCTS;
 			len = sizeof(struct ieee80211_cts);
 		} else {
-			struct ieee80211_rts *rts;
+			struct ieee80211_rts *uninitialized_var(rts);
 
-			if (b43_is_old_txhdr_format(dev)) {
+			switch (dev->fw.hdr_format) {
+			case B43_FW_HDR_598:
 				rts = (struct ieee80211_rts *)
-					(txhdr->old_format.rts_frame);
-			} else {
+					(txhdr->format_598.rts_frame);
+				break;
+			case B43_FW_HDR_351:
+				rts = (struct ieee80211_rts *)
+					(txhdr->format_351.rts_frame);
+				break;
+			case B43_FW_HDR_410:
 				rts = (struct ieee80211_rts *)
-					(txhdr->new_format.rts_frame);
+					(txhdr->format_410.rts_frame);
+				break;
 			}
 			ieee80211_rts_get(dev->wl->hw, info->control.vif,
 					  fragment_data, fragment_len,
@@ -462,22 +483,36 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 		len += FCS_LEN;
 
 		/* Generate the PLCP headers for the RTS/CTS frame */
-		if (b43_is_old_txhdr_format(dev))
-			plcp = &txhdr->old_format.rts_plcp;
-		else
-			plcp = &txhdr->new_format.rts_plcp;
+		switch (dev->fw.hdr_format) {
+		case B43_FW_HDR_598:
+			plcp = &txhdr->format_598.rts_plcp;
+			break;
+		case B43_FW_HDR_351:
+			plcp = &txhdr->format_351.rts_plcp;
+			break;
+		case B43_FW_HDR_410:
+			plcp = &txhdr->format_410.rts_plcp;
+			break;
+		}
 		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
 				      len, rts_rate);
 		plcp = &txhdr->rts_plcp_fb;
 		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
 				      len, rts_rate_fb);
 
-		if (b43_is_old_txhdr_format(dev)) {
+		switch (dev->fw.hdr_format) {
+		case B43_FW_HDR_598:
 			hdr = (struct ieee80211_hdr *)
-				(&txhdr->old_format.rts_frame);
-		} else {
+				(&txhdr->format_598.rts_frame);
+			break;
+		case B43_FW_HDR_351:
+			hdr = (struct ieee80211_hdr *)
+				(&txhdr->format_351.rts_frame);
+			break;
+		case B43_FW_HDR_410:
 			hdr = (struct ieee80211_hdr *)
-				(&txhdr->new_format.rts_frame);
+				(&txhdr->format_410.rts_frame);
+			break;
 		}
 		txhdr->rts_dur_fb = hdr->duration_id;
 
@@ -505,10 +540,17 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 	}
 
 	/* Magic cookie */
-	if (b43_is_old_txhdr_format(dev))
-		txhdr->old_format.cookie = cpu_to_le16(cookie);
-	else
-		txhdr->new_format.cookie = cpu_to_le16(cookie);
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		txhdr->format_598.cookie = cpu_to_le16(cookie);
+		break;
+	case B43_FW_HDR_351:
+		txhdr->format_351.cookie = cpu_to_le16(cookie);
+		break;
+	case B43_FW_HDR_410:
+		txhdr->format_410.cookie = cpu_to_le16(cookie);
+		break;
+	}
 
 	if (phy->type == B43_PHYTYPE_N) {
 		txhdr->phy_ctl1 =
@@ -611,8 +653,9 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	struct ieee80211_hdr *wlhdr;
 	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
 	__le16 fctl;
-	u16 phystat0, phystat3, chanstat, mactime;
-	u32 macstat;
+	u16 phystat0, phystat3;
+	u16 uninitialized_var(chanstat), uninitialized_var(mactime);
+	u32 uninitialized_var(macstat);
 	u16 chanid;
 	u16 phytype;
 	int padding;
@@ -622,9 +665,19 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	/* Get metadata about the frame from the header. */
 	phystat0 = le16_to_cpu(rxhdr->phy_status0);
 	phystat3 = le16_to_cpu(rxhdr->phy_status3);
-	macstat = le32_to_cpu(rxhdr->mac_status);
-	mactime = le16_to_cpu(rxhdr->mac_time);
-	chanstat = le16_to_cpu(rxhdr->channel);
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		macstat = le32_to_cpu(rxhdr->format_598.mac_status);
+		mactime = le16_to_cpu(rxhdr->format_598.mac_time);
+		chanstat = le16_to_cpu(rxhdr->format_598.channel);
+		break;
+	case B43_FW_HDR_410:
+	case B43_FW_HDR_351:
+		macstat = le32_to_cpu(rxhdr->format_351.mac_status);
+		mactime = le16_to_cpu(rxhdr->format_351.mac_time);
+		chanstat = le16_to_cpu(rxhdr->format_351.channel);
+		break;
+	}
 	phytype = chanstat & B43_RX_CHAN_PHYTYPE;
 
 	if (unlikely(macstat & B43_RX_MAC_FCSERR)) {
@@ -744,6 +797,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 		break;
 	case B43_PHYTYPE_N:
 	case B43_PHYTYPE_LP:
+	case B43_PHYTYPE_HT:
 		/* chanid is the SHM channel cookie. Which is the plain
 		 * channel number in b43. */
 		if (chanstat & B43_RX_CHAN_5GHZ) {
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 42debb5cd6fad0b042c579079ae325f2ecbb0a50..f6e8bc436d5a20028818e155369600279db285af 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -46,7 +46,24 @@ struct b43_txhdr {
 	__le32 timeout;			/* Timeout */
 
 	union {
-		/* The new r410 format. */
+		/* Tested with 598.314, 644.1001 and 666.2 */
+		struct {
+			__le16 mimo_antenna;            /* MIMO antenna select */
+			__le16 preload_size;            /* Preload size */
+			PAD_BYTES(2);
+			__le16 cookie;                  /* TX frame cookie */
+			__le16 tx_status;               /* TX status */
+			__le16 max_n_mpdus;
+			__le16 max_a_bytes_mrt;
+			__le16 max_a_bytes_fbr;
+			__le16 min_m_bytes;
+			struct b43_plcp_hdr6 rts_plcp;  /* RTS PLCP header */
+			__u8 rts_frame[16];             /* The RTS frame (if used) */
+			PAD_BYTES(2);
+			struct b43_plcp_hdr6 plcp;      /* Main PLCP header */
+		} format_598 __packed;
+
+		/* Tested with 410.2160, 478.104 and 508.* */
 		struct {
 			__le16 mimo_antenna;		/* MIMO antenna select */
 			__le16 preload_size;		/* Preload size */
@@ -57,9 +74,9 @@ struct b43_txhdr {
 			__u8 rts_frame[16];		/* The RTS frame (if used) */
 			PAD_BYTES(2);
 			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
-		} new_format __packed;
+		} format_410 __packed;
 
-		/* The old r351 format. */
+		/* Tested with 351.126 */
 		struct {
 			PAD_BYTES(2);
 			__le16 cookie;			/* TX frame cookie */
@@ -68,7 +85,7 @@ struct b43_txhdr {
 			__u8 rts_frame[16];		/* The RTS frame (if used) */
 			PAD_BYTES(2);
 			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
-		} old_format __packed;
+		} format_351 __packed;
 
 	} __packed;
 } __packed;
@@ -166,19 +183,18 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
 #define  B43_TXH_PHY1_MODUL_QAM256	0x2000 /* QAM256 */
 
 
-/* r351 firmware compatibility stuff. */
-static inline
-bool b43_is_old_txhdr_format(struct b43_wldev *dev)
-{
-	return (dev->fw.rev <= 351);
-}
-
 static inline
 size_t b43_txhdr_size(struct b43_wldev *dev)
 {
-	if (b43_is_old_txhdr_format(dev))
+	switch (dev->fw.hdr_format) {
+	case B43_FW_HDR_598:
+		return 112 + sizeof(struct b43_plcp_hdr6);
+	case B43_FW_HDR_410:
+		return 104 + sizeof(struct b43_plcp_hdr6);
+	case B43_FW_HDR_351:
 		return 100 + sizeof(struct b43_plcp_hdr6);
-	return 104 + sizeof(struct b43_plcp_hdr6);
+	}
+	return 0;
 }
 
 
@@ -234,9 +250,23 @@ struct b43_rxhdr_fw4 {
 	} __packed;
 	__le16 phy_status2;	/* PHY RX Status 2 */
 	__le16 phy_status3;	/* PHY RX Status 3 */
-	__le32 mac_status;	/* MAC RX status */
-	__le16 mac_time;
-	__le16 channel;
+	union {
+		/* Tested with 598.314, 644.1001 and 666.2 */
+		struct {
+			__le16 phy_status4;	/* PHY RX Status 4 */
+			__le16 phy_status5;	/* PHY RX Status 5 */
+			__le32 mac_status;	/* MAC RX status */
+			__le16 mac_time;
+			__le16 channel;
+		} format_598 __packed;
+
+		/* Tested with 351.126, 410.2160, 478.104 and 508.* */
+		struct {
+			__le32 mac_status;	/* MAC RX status */
+			__le16 mac_time;
+			__le16 channel;
+		} format_351 __packed;
+	} __packed;
 } __packed;
 
 /* PHY RX Status 0 */
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index ad4e743e476586554a25d523c7055bb78eab3499..12b5182515816e76d60fc08dd6ed2d54e43ac91b 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -22,10 +22,6 @@
 #include "phy.h"
 
 
-/* The unique identifier of the firmware that's officially supported by this
- * driver version. */
-#define B43legacy_SUPPORTED_FIRMWARE_ID	"FW10"
-
 #define B43legacy_IRQWAIT_MAX_RETRIES	20
 
 /* MMIO offsets */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index aae8dfcb852e54f54917409949124f9f5befb885..468d1836548eb5ee188cb75051fb39c762c67899 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -60,7 +60,6 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID);
 MODULE_FIRMWARE("b43legacy/ucode2.fw");
 MODULE_FIRMWARE("b43legacy/ucode4.fw");
 
@@ -3947,8 +3946,7 @@ static void b43legacy_print_driverinfo(void)
 	feat_dma = "D";
 #endif
 	printk(KERN_INFO "Broadcom 43xx-legacy driver loaded "
-	       "[ Features: %s%s%s%s, Firmware-ID: "
-	       B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
+	       "[ Features: %s%s%s%s ]\n",
 	       feat_pci, feat_leds, feat_pio, feat_dma);
 }
 
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 1453eec82a99288256e55bf7b9a408c3c1648408..91f2ca90c70faa9e010e9ff51ea6d306e199ef40 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -238,28 +238,3 @@ hostsleep
 		echo "1" > hostsleep : enable host sleep.
 		echo "0" > hostsleep : disable host sleep
 
-========================
-IWCONFIG COMMANDS
-========================
-power period
-
-	This command is used to configure the station in deep sleep mode /
-	auto deep sleep mode.
-
-	The timer is implemented to monitor the activities (command, event,
-	etc.). When an activity is detected station will exit from deep
-	sleep mode automatically and restart the timer. At timer expiry
-	(no activity for defined time period) the deep sleep mode is entered
-	automatically.
-
-	Note: this command is for SDIO interface only.
-
-	Usage:
-	To enable deep sleep mode do:
-		iwconfig wlan0 power period 0
-	To enable auto deep sleep mode with idle time period 5 seconds do:
-		iwconfig wlan0 power period 5
-	To disable deep sleep/auto deep sleep mode do:
-		iwconfig wlan0 power period -1
-
-==============================================================================
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 814838916b8271cfa390c3e7458dd09ec300bf1f..b9ff0dc53e8df047e4d01f2c2704073f32d96891 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -190,8 +190,8 @@ static inline int lbs_iface_active(struct lbs_private *priv)
 	int r;
 
 	r = netif_running(priv->dev);
-	if (priv->mesh_dev);
-		r |= netif_running(priv->dev);
+	if (priv->mesh_dev)
+		r |= netif_running(priv->mesh_dev);
 
 	return r;
 }
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index b28241c6e737bbe824dc8b0ed558b8db23063269..37ca2f90ad63360486b8e2e7cd441e13931bed12 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1480,8 +1480,8 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
 		return -ENOMEM;
 	}
 	beacon_ie = kzalloc(ie_len, GFP_KERNEL);
-	if (!bss_desc) {
-		dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+	if (!beacon_ie) {
+		dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
 		return -ENOMEM;
 	}
 	memcpy(beacon_ie, ie_buf, ie_len);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index da36dbf8d87118e51b2c94946b2fddfea043baca..771280a47ea7c66da2f1d74fa2fb92e4c4a9fe46 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -4097,9 +4097,6 @@ static int mwl8k_set_key(struct ieee80211_hw *hw,
 
 		if (rc)
 			goto out;
-
-		mwl8k_vif->is_hw_crypto_enabled = false;
-
 	}
 out:
 	return rc;
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 54cc0bba66b958ed88003b2cf256b76145c81d6a..8b6f363b3f7db581d47fdac99d4da01658187120 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -145,6 +145,7 @@ static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
 
 static int p54_generate_band(struct ieee80211_hw *dev,
 			     struct p54_channel_list *list,
+			     unsigned int *chan_num,
 			     enum ieee80211_band band)
 {
 	struct p54_common *priv = dev->priv;
@@ -190,7 +191,14 @@ static int p54_generate_band(struct ieee80211_hw *dev,
 
 		tmp->channels[j].band = chan->band;
 		tmp->channels[j].center_freq = chan->freq;
+		priv->survey[*chan_num].channel = &tmp->channels[j];
+		priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
+			SURVEY_INFO_CHANNEL_TIME |
+			SURVEY_INFO_CHANNEL_TIME_BUSY |
+			SURVEY_INFO_CHANNEL_TIME_TX;
+		tmp->channels[j].hw_value = (*chan_num);
 		j++;
+		(*chan_num)++;
 	}
 
 	if (j == 0) {
@@ -263,7 +271,7 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_channel_list *list;
-	unsigned int i, j, max_channel_num;
+	unsigned int i, j, k, max_channel_num;
 	int ret = 0;
 	u16 freq;
 
@@ -283,6 +291,13 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
 		ret = -ENOMEM;
 		goto free;
 	}
+	priv->chan_num = max_channel_num;
+	priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num,
+			       GFP_KERNEL);
+	if (!priv->survey) {
+		ret = -ENOMEM;
+		goto free;
+	}
 
 	list->max_entries = max_channel_num;
 	list->channels = kzalloc(sizeof(struct p54_channel_entry) *
@@ -321,8 +336,9 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
 	sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
 	     p54_compare_channels, NULL);
 
+	k = 0;
 	for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
-		if (p54_generate_band(dev, list, i) == 0)
+		if (p54_generate_band(dev, list, &k, i) == 0)
 			j++;
 	}
 	if (j == 0) {
@@ -335,6 +351,10 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
 		kfree(list->channels);
 		kfree(list);
 	}
+	if (ret) {
+		kfree(priv->survey);
+		priv->survey = NULL;
+	}
 
 	return ret;
 }
@@ -853,10 +873,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 	kfree(priv->output_limit);
 	kfree(priv->curve_data);
 	kfree(priv->rssi_db);
+	kfree(priv->survey);
 	priv->iq_autocal = NULL;
 	priv->output_limit = NULL;
 	priv->curve_data = NULL;
 	priv->rssi_db = NULL;
+	priv->survey = NULL;
 
 	wiphy_err(dev->wiphy, "eeprom parse failed!\n");
 	return err;
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index b6a061cbbdec1651f4fec04ecceac4539dd75ba7..53a3408931be3b94394e71de3ba8ac7051c969a6 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -385,6 +385,7 @@ int p54_setup_mac(struct p54_common *priv)
 		setup->v2.osc_start_delay = cpu_to_le16(65535);
 	}
 	p54_tx(priv, skb);
+	priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE;
 	return 0;
 }
 
@@ -626,6 +627,7 @@ int p54_set_ps(struct p54_common *priv)
 	psm->exclude[0] = WLAN_EID_TIM;
 
 	p54_tx(priv, skb);
+	priv->phy_ps = mode != P54_PSM_CAM;
 	return 0;
 }
 
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index a5a6d9e647bbe31fcf6909e504b570543c584115..726a9343f514cb9517f3836617b4354ec30d31fa 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -204,13 +204,11 @@ static void p54_stop(struct ieee80211_hw *dev)
 	struct p54_common *priv = dev->priv;
 	int i;
 
-	mutex_lock(&priv->conf_mutex);
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	priv->softled_state = 0;
-	p54_set_leds(priv);
-
 	cancel_delayed_work_sync(&priv->work);
-
+	mutex_lock(&priv->conf_mutex);
+	p54_set_leds(priv);
 	priv->stop(dev);
 	skb_queue_purge(&priv->tx_pending);
 	skb_queue_purge(&priv->tx_queue);
@@ -278,6 +276,42 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
 	mutex_unlock(&priv->conf_mutex);
 }
 
+static int p54_wait_for_stats(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	int ret;
+
+	priv->update_stats = true;
+	ret = p54_fetch_statistics(priv);
+	if (ret)
+		return ret;
+
+	ret = wait_for_completion_interruptible_timeout(&priv->stat_comp, HZ);
+	if (ret == 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static void p54_reset_stats(struct p54_common *priv)
+{
+	struct ieee80211_channel *chan = priv->curchan;
+
+	if (chan) {
+		struct survey_info *info = &priv->survey[chan->hw_value];
+
+		/* only reset channel statistics, don't touch .filled, etc. */
+		info->channel_time = 0;
+		info->channel_time_busy = 0;
+		info->channel_time_tx = 0;
+	}
+
+	priv->update_stats = true;
+	priv->survey_raw.active = 0;
+	priv->survey_raw.cca = 0;
+	priv->survey_raw.tx = 0;
+}
+
 static int p54_config(struct ieee80211_hw *dev, u32 changed)
 {
 	int ret = 0;
@@ -288,19 +322,36 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
 	if (changed & IEEE80211_CONF_CHANGE_POWER)
 		priv->output_power = conf->power_level << 2;
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		struct ieee80211_channel *oldchan;
+		WARN_ON(p54_wait_for_stats(dev));
+		oldchan = priv->curchan;
+		priv->curchan = NULL;
 		ret = p54_scan(priv, P54_SCAN_EXIT, 0);
-		if (ret)
+		if (ret) {
+			priv->curchan = oldchan;
 			goto out;
+		}
+		/*
+		 * TODO: Use the LM_SCAN_TRAP to determine the current
+		 * operating channel.
+		 */
+		priv->curchan = priv->hw->conf.channel;
+		p54_reset_stats(priv);
+		WARN_ON(p54_fetch_statistics(priv));
 	}
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
+		WARN_ON(p54_wait_for_stats(dev));
 		ret = p54_set_ps(priv);
 		if (ret)
 			goto out;
+		WARN_ON(p54_wait_for_stats(dev));
 	}
 	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+		WARN_ON(p54_wait_for_stats(dev));
 		ret = p54_setup_mac(priv);
 		if (ret)
 			goto out;
+		WARN_ON(p54_wait_for_stats(dev));
 	}
 
 out:
@@ -384,7 +435,9 @@ static void p54_work(struct work_struct *work)
 	 *      2. cancel stuck frames / reset the device if necessary.
 	 */
 
-	p54_fetch_statistics(priv);
+	mutex_lock(&priv->conf_mutex);
+	WARN_ON_ONCE(p54_fetch_statistics(priv));
+	mutex_unlock(&priv->conf_mutex);
 }
 
 static int p54_get_stats(struct ieee80211_hw *dev,
@@ -541,16 +594,47 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx,
 				struct survey_info *survey)
 {
 	struct p54_common *priv = dev->priv;
-	struct ieee80211_conf *conf = &dev->conf;
+	struct ieee80211_channel *chan;
+	int err, tries;
+	bool in_use = false;
 
-	if (idx != 0)
+	if (idx >= priv->chan_num)
 		return -ENOENT;
 
-	survey->channel = conf->channel;
-	survey->filled = SURVEY_INFO_NOISE_DBM;
-	survey->noise = clamp_t(s8, priv->noise, -128, 127);
+#define MAX_TRIES 1
+	for (tries = 0; tries < MAX_TRIES; tries++) {
+		chan = priv->curchan;
+		if (chan && chan->hw_value == idx) {
+			mutex_lock(&priv->conf_mutex);
+			err = p54_wait_for_stats(dev);
+			mutex_unlock(&priv->conf_mutex);
+			if (err)
+				return err;
+
+			in_use = true;
+		}
 
-	return 0;
+		memcpy(survey, &priv->survey[idx], sizeof(*survey));
+
+		if (in_use) {
+			/* test if the reported statistics are valid. */
+			if  (survey->channel_time != 0) {
+				survey->filled |= SURVEY_INFO_IN_USE;
+			} else {
+				/*
+				 * hw/fw has not accumulated enough sample sets.
+				 * Wait for 100ms, this ought to be enough to
+				 * to get at least one non-null set of channel
+				 * usage statistics.
+				 */
+				msleep(100);
+				continue;
+			}
+		}
+		return 0;
+	}
+	return -ETIMEDOUT;
+#undef MAX_TRIES
 }
 
 static unsigned int p54_flush_count(struct p54_common *priv)
@@ -686,11 +770,14 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 
 	mutex_init(&priv->conf_mutex);
 	mutex_init(&priv->eeprom_mutex);
+	init_completion(&priv->stat_comp);
 	init_completion(&priv->eeprom_comp);
 	init_completion(&priv->beacon_comp);
 	INIT_DELAYED_WORK(&priv->work, p54_work);
 
 	memset(&priv->mc_maclist[0], ~0, ETH_ALEN);
+	priv->curchan = NULL;
+	p54_reset_stats(priv);
 	return dev;
 }
 EXPORT_SYMBOL_GPL(p54_init_common);
@@ -730,11 +817,13 @@ void p54_free_common(struct ieee80211_hw *dev)
 	kfree(priv->curve_data);
 	kfree(priv->rssi_db);
 	kfree(priv->used_rxkeys);
+	kfree(priv->survey);
 	priv->iq_autocal = NULL;
 	priv->output_limit = NULL;
 	priv->curve_data = NULL;
 	priv->rssi_db = NULL;
 	priv->used_rxkeys = NULL;
+	priv->survey = NULL;
 	ieee80211_free_hw(dev);
 }
 EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 799d05e12595d0865c251ebe75383245253ea806..452fa3a64aa1297f033801802702f8056c619632 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -199,6 +199,22 @@ struct p54_common {
 	u8 tx_diversity_mask;
 	unsigned int output_power;
 	struct p54_rssi_db_entry *cur_rssi;
+	struct ieee80211_channel *curchan;
+	struct survey_info *survey;
+	unsigned int chan_num;
+	struct completion stat_comp;
+	bool update_stats;
+	struct {
+		unsigned int timestamp;
+		unsigned int cached_cca;
+		unsigned int cached_tx;
+		unsigned int cached_rssi;
+		u64 active;
+		u64 cca;
+		u64 tx;
+		u64 rssi;
+	} survey_raw;
+
 	int noise;
 	/* calibration, output power limit and rssi<->dBm conversation data */
 	struct pda_iq_autocal_entry *iq_autocal;
@@ -220,6 +236,8 @@ struct p54_common {
 	u32 basic_rate_mask;
 	u16 aid;
 	u8 coverage_class;
+	bool phy_idle;
+	bool phy_ps;
 	bool powersave_override;
 	__le32 beacon_req_id;
 	struct completion beacon_comp;
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 042842e704de17945d7f61b9c6069072ad5230fe..44a3bd4b0f43c5258d04db670f62b2ae4ec6a828 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -507,6 +507,8 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
 	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
 	struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
 	struct sk_buff *tmp;
+	struct ieee80211_channel *chan;
+	unsigned int i, rssi, tx, cca, dtime, dtotal, dcca, dtx, drssi, unit;
 	u32 tsf32;
 
 	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
@@ -523,8 +525,72 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
 
 	priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
 
+	/*
+	 * STSW450X LMAC API page 26 - 3.8 Statistics
+	 * "The exact measurement period can be derived from the
+	 * timestamp member".
+	 */
+	dtime = tsf32 - priv->survey_raw.timestamp;
+
+	/*
+	 * STSW450X LMAC API page 26 - 3.8.1 Noise histogram
+	 * The LMAC samples RSSI, CCA and transmit state at regular
+	 * periods (typically 8 times per 1k [as in 1024] usec).
+	 */
+	cca = le32_to_cpu(stats->sample_cca);
+	tx = le32_to_cpu(stats->sample_tx);
+	rssi = 0;
+	for (i = 0; i < ARRAY_SIZE(stats->sample_noise); i++)
+		rssi += le32_to_cpu(stats->sample_noise[i]);
+
+	dcca = cca - priv->survey_raw.cached_cca;
+	drssi = rssi - priv->survey_raw.cached_rssi;
+	dtx = tx - priv->survey_raw.cached_tx;
+	dtotal = dcca + drssi + dtx;
+
+	/*
+	 * update statistics when more than a second is over since the
+	 * last call, or when a update is badly needed.
+	 */
+	if (dtotal && (priv->update_stats || dtime >= USEC_PER_SEC) &&
+	    dtime >= dtotal) {
+		priv->survey_raw.timestamp = tsf32;
+		priv->update_stats = false;
+		unit = dtime / dtotal;
+
+		if (dcca) {
+			priv->survey_raw.cca += dcca * unit;
+			priv->survey_raw.cached_cca = cca;
+		}
+		if (dtx) {
+			priv->survey_raw.tx += dtx * unit;
+			priv->survey_raw.cached_tx = tx;
+		}
+		if (drssi) {
+			priv->survey_raw.rssi += drssi * unit;
+			priv->survey_raw.cached_rssi = rssi;
+		}
+
+		/* 1024 usec / 8 times = 128 usec / time */
+		if (!(priv->phy_ps || priv->phy_idle))
+			priv->survey_raw.active += dtotal * unit;
+		else
+			priv->survey_raw.active += (dcca + dtx) * unit;
+	}
+
+	chan = priv->curchan;
+	if (chan) {
+		struct survey_info *survey = &priv->survey[chan->hw_value];
+		survey->noise = clamp_t(s8, priv->noise, -128, 127);
+		survey->channel_time = priv->survey_raw.active / 1024;
+		survey->channel_time_tx = priv->survey_raw.tx / 1024;
+		survey->channel_time_busy = priv->survey_raw.cca / 1024 +
+			survey->channel_time_tx;
+	}
+
 	tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
 	dev_kfree_skb_any(tmp);
+	complete(&priv->stat_comp);
 }
 
 static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 0b598db38da99e09400f9e15d11a7f658d41ef66..098fc557a88d2a5f2d93639c15ed57bfd1038c58 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -664,6 +664,167 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw)
 	return hw_rate;
 }
 
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92_RATE1M-->DESC92_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92_RATE6M-->DESC92_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15
+ */
+int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
+			 bool isht, u8 desc_rate, bool first_ampdu)
+{
+	int rate_idx;
+
+	if (false == isht) {
+		if (IEEE80211_BAND_2GHZ == hw->conf.channel->band) {
+			switch (desc_rate) {
+			case DESC92_RATE1M:
+				rate_idx = 0;
+				break;
+			case DESC92_RATE2M:
+				rate_idx = 1;
+				break;
+			case DESC92_RATE5_5M:
+				rate_idx = 2;
+				break;
+			case DESC92_RATE11M:
+				rate_idx = 3;
+				break;
+			case DESC92_RATE6M:
+				rate_idx = 4;
+				break;
+			case DESC92_RATE9M:
+				rate_idx = 5;
+				break;
+			case DESC92_RATE12M:
+				rate_idx = 6;
+				break;
+			case DESC92_RATE18M:
+				rate_idx = 7;
+				break;
+			case DESC92_RATE24M:
+				rate_idx = 8;
+				break;
+			case DESC92_RATE36M:
+				rate_idx = 9;
+				break;
+			case DESC92_RATE48M:
+				rate_idx = 10;
+				break;
+			case DESC92_RATE54M:
+				rate_idx = 11;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		} else {
+			switch (desc_rate) {
+			case DESC92_RATE6M:
+				rate_idx = 0;
+				break;
+			case DESC92_RATE9M:
+				rate_idx = 1;
+				break;
+			case DESC92_RATE12M:
+				rate_idx = 2;
+				break;
+			case DESC92_RATE18M:
+				rate_idx = 3;
+				break;
+			case DESC92_RATE24M:
+				rate_idx = 4;
+				break;
+			case DESC92_RATE36M:
+				rate_idx = 5;
+				break;
+			case DESC92_RATE48M:
+				rate_idx = 6;
+				break;
+			case DESC92_RATE54M:
+				rate_idx = 7;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		}
+
+	} else {
+
+		switch (desc_rate) {
+		case DESC92_RATEMCS0:
+			rate_idx = 0;
+			break;
+		case DESC92_RATEMCS1:
+			rate_idx = 1;
+			break;
+		case DESC92_RATEMCS2:
+			rate_idx = 2;
+			break;
+		case DESC92_RATEMCS3:
+			rate_idx = 3;
+			break;
+		case DESC92_RATEMCS4:
+			rate_idx = 4;
+			break;
+		case DESC92_RATEMCS5:
+			rate_idx = 5;
+			break;
+		case DESC92_RATEMCS6:
+			rate_idx = 6;
+			break;
+		case DESC92_RATEMCS7:
+			rate_idx = 7;
+			break;
+		case DESC92_RATEMCS8:
+			rate_idx = 8;
+			break;
+		case DESC92_RATEMCS9:
+			rate_idx = 9;
+			break;
+		case DESC92_RATEMCS10:
+			rate_idx = 10;
+			break;
+		case DESC92_RATEMCS11:
+			rate_idx = 11;
+			break;
+		case DESC92_RATEMCS12:
+			rate_idx = 12;
+			break;
+		case DESC92_RATEMCS13:
+			rate_idx = 13;
+			break;
+		case DESC92_RATEMCS14:
+			rate_idx = 14;
+			break;
+		case DESC92_RATEMCS15:
+			rate_idx = 15;
+			break;
+		default:
+			rate_idx = 0;
+			break;
+		}
+	}
+	return rate_idx;
+}
+EXPORT_SYMBOL(rtlwifi_rate_mapping);
+
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
 		      struct ieee80211_tx_info *info,
 		      struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index a91f3eee59c88ff2de80337ab3891cf9d35d0322..4ae905983d0d5299670787b9001b07f4754d5dd4 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -140,4 +140,6 @@ u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie);
 void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
 u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid);
 extern struct attribute_group rtl_attribute_group;
+int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
+			 bool isht, u8 desc_rate, bool first_ampdu);
 #endif
diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c
index 5fa73852cb661b73274bd8e86e718a5ff92c80ba..b2f897acb23857836aee851f83b154e9e5a0e548 100644
--- a/drivers/net/wireless/rtlwifi/debug.c
+++ b/drivers/net/wireless/rtlwifi/debug.c
@@ -28,12 +28,16 @@
 
 #include "wifi.h"
 
+static unsigned int debug = DBG_EMERG;
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "Set global debug level for rtlwifi (0,2-5)");
+
 void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 i;
 
-	rtlpriv->dbg.global_debuglevel = DBG_EMERG;
+	rtlpriv->dbg.global_debuglevel = debug;
 
 	rtlpriv->dbg.global_debugcomponents =
 	    COMP_ERR | COMP_FW | COMP_INIT | COMP_RECV | COMP_SEND |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
index 35ff7df41a1d66b3e2243dd8ec164321a5217666..11f43196e61db8e0b34a12ebbe5fbd86e5ac9c21 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -220,41 +220,6 @@ enum rtl_desc_qsel {
 	QSLT_CMD = 0x13,
 };
 
-enum rtl_desc92c_rate {
-	DESC92C_RATE1M = 0x00,
-	DESC92C_RATE2M = 0x01,
-	DESC92C_RATE5_5M = 0x02,
-	DESC92C_RATE11M = 0x03,
-
-	DESC92C_RATE6M = 0x04,
-	DESC92C_RATE9M = 0x05,
-	DESC92C_RATE12M = 0x06,
-	DESC92C_RATE18M = 0x07,
-	DESC92C_RATE24M = 0x08,
-	DESC92C_RATE36M = 0x09,
-	DESC92C_RATE48M = 0x0a,
-	DESC92C_RATE54M = 0x0b,
-
-	DESC92C_RATEMCS0 = 0x0c,
-	DESC92C_RATEMCS1 = 0x0d,
-	DESC92C_RATEMCS2 = 0x0e,
-	DESC92C_RATEMCS3 = 0x0f,
-	DESC92C_RATEMCS4 = 0x10,
-	DESC92C_RATEMCS5 = 0x11,
-	DESC92C_RATEMCS6 = 0x12,
-	DESC92C_RATEMCS7 = 0x13,
-	DESC92C_RATEMCS8 = 0x14,
-	DESC92C_RATEMCS9 = 0x15,
-	DESC92C_RATEMCS10 = 0x16,
-	DESC92C_RATEMCS11 = 0x17,
-	DESC92C_RATEMCS12 = 0x18,
-	DESC92C_RATEMCS13 = 0x19,
-	DESC92C_RATEMCS14 = 0x1a,
-	DESC92C_RATEMCS15 = 0x1b,
-	DESC92C_RATEMCS15_SG = 0x1c,
-	DESC92C_RATEMCS32 = 0x20,
-};
-
 struct phy_sts_cck_8192s_t {
 	u8 adc_pwdb_X[4];
 	u8 sq_rpt;
@@ -267,108 +232,4 @@ struct h2c_cmd_8192c {
 	u8 *p_cmdbuffer;
 };
 
-/* NOTE: reference to rtl8192c_rates struct */
-static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT,
-				       u8 desc_rate, bool first_ampdu)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	int rate_idx = 0;
-
-	if (first_ampdu) {
-		if (false == isHT) {
-			switch (desc_rate) {
-			case DESC92C_RATE1M:
-				rate_idx = 0;
-				break;
-			case DESC92C_RATE2M:
-				rate_idx = 1;
-				break;
-			case DESC92C_RATE5_5M:
-				rate_idx = 2;
-				break;
-			case DESC92C_RATE11M:
-				rate_idx = 3;
-				break;
-			case DESC92C_RATE6M:
-				rate_idx = 4;
-				break;
-			case DESC92C_RATE9M:
-				rate_idx = 5;
-				break;
-			case DESC92C_RATE12M:
-				rate_idx = 6;
-				break;
-			case DESC92C_RATE18M:
-				rate_idx = 7;
-				break;
-			case DESC92C_RATE24M:
-				rate_idx = 8;
-				break;
-			case DESC92C_RATE36M:
-				rate_idx = 9;
-				break;
-			case DESC92C_RATE48M:
-				rate_idx = 10;
-				break;
-			case DESC92C_RATE54M:
-				rate_idx = 11;
-				break;
-			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
-					 ("Rate %d is not support, set to "
-					"1M rate.\n", desc_rate));
-				rate_idx = 0;
-				break;
-			}
-		} else {
-			rate_idx = 11;
-		}
-		return rate_idx;
-	}
-	switch (desc_rate) {
-	case DESC92C_RATE1M:
-		rate_idx = 0;
-		break;
-	case DESC92C_RATE2M:
-		rate_idx = 1;
-		break;
-	case DESC92C_RATE5_5M:
-		rate_idx = 2;
-		break;
-	case DESC92C_RATE11M:
-		rate_idx = 3;
-		break;
-	case DESC92C_RATE6M:
-		rate_idx = 4;
-		break;
-	case DESC92C_RATE9M:
-		rate_idx = 5;
-		break;
-	case DESC92C_RATE12M:
-		rate_idx = 6;
-		break;
-	case DESC92C_RATE18M:
-		rate_idx = 7;
-		break;
-	case DESC92C_RATE24M:
-		rate_idx = 8;
-		break;
-	case DESC92C_RATE36M:
-		rate_idx = 9;
-		break;
-	case DESC92C_RATE48M:
-		rate_idx = 10;
-		break;
-	case DESC92C_RATE54M:
-		rate_idx = 11;
-		break;
-	/* TODO: How to mapping MCS rate? */
-	/*  NOTE: referenc to __ieee80211_rx */
-	default:
-		rate_idx = 11;
-		break;
-	}
-	return rate_idx;
-}
-
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index 373dc78af1dcaef05f5511de4e509a87f06add03..4c34c4c1ae56b96f0a1c248cafe20e13027f0030 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -318,21 +318,21 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
 	.maps[RTL_IMR_ROK] = IMR_ROK,
 	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
 
-	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
-	.maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
-	.maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
-	.maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
-	.maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
-	.maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
-	.maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
-	.maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
-	.maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
-	.maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
-	.maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
-	.maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
-
-	.maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
-	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+	.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+	.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+	.maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+	.maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+	.maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+	.maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+	.maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+	.maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+	.maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+	.maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+	.maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+	.maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+
+	.maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+	.maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
 };
 
 DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index 230bbe900d8d07eacf1975fe85da3956bb8ffb62..4fb5ae24dee07fc08819add09b6e7793298beff8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -48,104 +48,6 @@ static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
 	return skb->priority;
 }
 
-static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
-{
-	int rate_idx;
-
-	if (first_ampdu) {
-		if (false == isht) {
-			switch (desc_rate) {
-			case DESC92C_RATE1M:
-				rate_idx = 0;
-				break;
-			case DESC92C_RATE2M:
-				rate_idx = 1;
-				break;
-			case DESC92C_RATE5_5M:
-				rate_idx = 2;
-				break;
-			case DESC92C_RATE11M:
-				rate_idx = 3;
-				break;
-			case DESC92C_RATE6M:
-				rate_idx = 4;
-				break;
-			case DESC92C_RATE9M:
-				rate_idx = 5;
-				break;
-			case DESC92C_RATE12M:
-				rate_idx = 6;
-				break;
-			case DESC92C_RATE18M:
-				rate_idx = 7;
-				break;
-			case DESC92C_RATE24M:
-				rate_idx = 8;
-				break;
-			case DESC92C_RATE36M:
-				rate_idx = 9;
-				break;
-			case DESC92C_RATE48M:
-				rate_idx = 10;
-				break;
-			case DESC92C_RATE54M:
-				rate_idx = 11;
-				break;
-			default:
-				rate_idx = 0;
-				break;
-			}
-		} else {
-			rate_idx = 11;
-		}
-
-		return rate_idx;
-	}
-
-	switch (desc_rate) {
-	case DESC92C_RATE1M:
-		rate_idx = 0;
-		break;
-	case DESC92C_RATE2M:
-		rate_idx = 1;
-		break;
-	case DESC92C_RATE5_5M:
-		rate_idx = 2;
-		break;
-	case DESC92C_RATE11M:
-		rate_idx = 3;
-		break;
-	case DESC92C_RATE6M:
-		rate_idx = 4;
-		break;
-	case DESC92C_RATE9M:
-		rate_idx = 5;
-		break;
-	case DESC92C_RATE12M:
-		rate_idx = 6;
-		break;
-	case DESC92C_RATE18M:
-		rate_idx = 7;
-		break;
-	case DESC92C_RATE24M:
-		rate_idx = 8;
-		break;
-	case DESC92C_RATE36M:
-		rate_idx = 9;
-		break;
-	case DESC92C_RATE48M:
-		rate_idx = 10;
-		break;
-	case DESC92C_RATE54M:
-		rate_idx = 11;
-		break;
-	default:
-		rate_idx = 11;
-		break;
-	}
-	return rate_idx;
-}
-
 static u8 _rtl92c_query_rxpwrpercentage(char antpower)
 {
 	if ((antpower <= -100) || (antpower >= 20))
@@ -336,8 +238,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
 		pstats->rxpower = rx_pwr_all;
 		pstats->recvsignalpower = rx_pwr_all;
 
-		if (pdesc->rxht && pdesc->rxmcs >= DESC92C_RATEMCS8 &&
-		    pdesc->rxmcs <= DESC92C_RATEMCS15)
+		if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 &&
+		    pdesc->rxmcs <= DESC92_RATEMCS15)
 			max_spatial_stream = 2;
 		else
 			max_spatial_stream = 1;
@@ -670,12 +572,10 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
 	if (stats->decrypted)
 		rx_status->flag |= RX_FLAG_DECRYPTED;
 
-	rx_status->rate_idx = _rtl92ce_rate_mapping((bool)
-						    GET_RX_DESC_RXHT(pdesc),
-						    (u8)
-						    GET_RX_DESC_RXMCS(pdesc),
-						    (bool)
-						    GET_RX_DESC_PAGGR(pdesc));
+	rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+				(bool)GET_RX_DESC_RXHT(pdesc),
+				(u8)GET_RX_DESC_RXMCS(pdesc),
+				(bool)GET_RX_DESC_PAGGR(pdesc));
 
 	rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
 	if (phystatus) {
@@ -768,7 +668,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 		SET_TX_DESC_RTS_BW(pdesc, 0);
 		SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc);
 		SET_TX_DESC_RTS_SHORT(pdesc,
-				      ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+				      ((tcb_desc->rts_rate <= DESC92_RATE54M) ?
 				       (tcb_desc->rts_use_shortpreamble ? 1 : 0)
 				       : (tcb_desc->rts_use_shortgi ? 1 : 0)));
 
@@ -886,7 +786,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
 	if (firstseg)
 		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
 
-	SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+	SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
 
 	SET_TX_DESC_SEQ(pdesc, 0);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
index 0f117713750126acd76f00353ba2e44fba2691f5..81ae64234f80a102a317b78cb3e3a79a263d49a7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -538,10 +538,10 @@ do {							\
 } while (0);
 
 #define RX_HAL_IS_CCK_RATE(_pdesc)\
-	(_pdesc->rxmcs == DESC92C_RATE1M ||		\
-	 _pdesc->rxmcs == DESC92C_RATE2M ||		\
-	 _pdesc->rxmcs == DESC92C_RATE5_5M ||		\
-	 _pdesc->rxmcs == DESC92C_RATE11M)
+	(_pdesc->rxmcs == DESC92_RATE1M ||		\
+	 _pdesc->rxmcs == DESC92_RATE2M ||		\
+	 _pdesc->rxmcs == DESC92_RATE5_5M ||		\
+	 _pdesc->rxmcs == DESC92_RATE11M)
 
 struct rx_fwinfo_92c {
 	u8 gain_trsw[4];
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index 194fc693c1fa8a9077b85bd39d7746d0116c42c2..060a06f4a885ef2d2bba48cee48d3c1e8f24a8df 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -892,8 +892,8 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw,
 		pstats->rxpower = rx_pwr_all;
 		pstats->recvsignalpower = rx_pwr_all;
 		if (GET_RX_DESC_RX_MCS(pdesc) &&
-		    GET_RX_DESC_RX_MCS(pdesc) >= DESC92C_RATEMCS8 &&
-		    GET_RX_DESC_RX_MCS(pdesc) <= DESC92C_RATEMCS15)
+		    GET_RX_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 &&
+		    GET_RX_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15)
 			max_spatial_stream = 2;
 		else
 			max_spatial_stream = 1;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
index 298fdb724aa58ea9414b7ee1c5dc3420dbc06092..35529f701fc04b1f469cd911ccfd1aa4f5b8cb61 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
@@ -88,10 +88,10 @@ void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter);
 u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw);
 
 #define RX_HAL_IS_CCK_RATE(_pdesc)\
-	(GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE1M ||\
-	 GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE2M ||\
-	 GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE5_5M ||\
-	 GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE11M)
+	(GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE1M ||\
+	 GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE2M ||\
+	 GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\
+	 GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE11M)
 
 struct rx_fwinfo_92c {
 	u8 gain_trsw[4];
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 17a8e9628512e448598ca403b2f4445dcee62d1e..1e851aae58db913ebd49cc34878b24ab7d45937d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -104,7 +104,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
 			tx_agc[RF90_PATH_A] = 0x10101010;
 			tx_agc[RF90_PATH_B] = 0x10101010;
 		} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
-			   TXHIGHPWRLEVEL_LEVEL2) {
+			   TXHIGHPWRLEVEL_LEVEL1) {
 			tx_agc[RF90_PATH_A] = 0x00000000;
 			tx_agc[RF90_PATH_B] = 0x00000000;
 		} else{
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index ef63c0df006ad313de8781656b2bca4a15942ee7..424b8a0323e21c602b117b3a12b24fc217e55503 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -241,20 +241,20 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = {
 	.maps[RTL_IMR_ROK] = IMR_ROK,
 	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
 
-	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
-	.maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
-	.maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
-	.maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
-	.maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
-	.maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
-	.maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
-	.maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
-	.maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
-	.maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
-	.maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
-	.maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
-	.maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
-	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+	.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+	.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+	.maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+	.maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+	.maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+	.maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+	.maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+	.maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+	.maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+	.maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+	.maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+	.maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+	.maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+	.maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
 };
 
 #define USB_VENDER_ID_REALTEK		0x0bda
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 906e7aa55bc39f40eb0c3743c91a821084d5a934..c4161148e0d87ab20136e57ce2dfadd993a8fd16 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -337,10 +337,10 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
 	rx_status->flag |= RX_FLAG_MACTIME_MPDU;
 	if (stats->decrypted)
 		rx_status->flag |= RX_FLAG_DECRYPTED;
-	rx_status->rate_idx = _rtl92c_rate_mapping(hw,
-						(bool)GET_RX_DESC_RX_HT(pdesc),
-						(u8)GET_RX_DESC_RX_MCS(pdesc),
-						(bool)GET_RX_DESC_PAGGR(pdesc));
+	rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+					(bool)GET_RX_DESC_RX_HT(pdesc),
+					(u8)GET_RX_DESC_RX_MCS(pdesc),
+					(bool)GET_RX_DESC_PAGGR(pdesc));
 	rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
 	if (phystatus) {
 		p_drvinfo = (struct rx_fwinfo_92c *)(pdesc + RTL_RX_DESC_SIZE);
@@ -406,11 +406,10 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
 	if (GET_RX_DESC_RX_HT(rxdesc))
 		rx_status->flag |= RX_FLAG_HT;
 	/* Data rate */
-	rx_status->rate_idx = _rtl92c_rate_mapping(hw,
-						(bool)GET_RX_DESC_RX_HT(rxdesc),
-						(u8)GET_RX_DESC_RX_MCS(rxdesc),
-						(bool)GET_RX_DESC_PAGGR(rxdesc)
-						);
+	rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+					(bool)GET_RX_DESC_RX_HT(rxdesc),
+					(u8)GET_RX_DESC_RX_MCS(rxdesc),
+					(bool)GET_RX_DESC_PAGGR(rxdesc));
 	/*  There is a phy status after this rx descriptor. */
 	if (GET_RX_DESC_PHY_STATUS(rxdesc)) {
 		p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE);
@@ -545,7 +544,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
 	SET_TX_DESC_RTS_BW(txdesc, 0);
 	SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc);
 	SET_TX_DESC_RTS_SHORT(txdesc,
-			      ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+			      ((tcb_desc->rts_rate <= DESC92_RATE54M) ?
 			       (tcb_desc->rts_use_shortpreamble ? 1 : 0)
 			       : (tcb_desc->rts_use_shortgi ? 1 : 0)));
 	if (mac->bw_40) {
@@ -643,7 +642,7 @@ void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc,
 	}
 	SET_TX_DESC_USE_RATE(pDesc, 1); /* use data rate which is set by Sw */
 	SET_TX_DESC_OWN(pDesc, 1);
-	SET_TX_DESC_TX_RATE(pDesc, DESC92C_RATE1M);
+	SET_TX_DESC_TX_RATE(pDesc, DESC92_RATE1M);
 	_rtl_tx_desc_checksum(pDesc);
 }
 
@@ -659,7 +658,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw,
 	memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE);
 	if (firstseg)
 		SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE);
-	SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+	SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
 	SET_TX_DESC_SEQ(pdesc, 0);
 	SET_TX_DESC_LINIP(pdesc, 0);
 	SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/def.h b/drivers/net/wireless/rtlwifi/rtl8192de/def.h
index f0f5f9bfbb7b6914fdccb3b32b2d9a7432779d39..aff7e19714ff86e526f74f3b908a7dad5948f377 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/def.h
@@ -193,41 +193,6 @@ enum rtl_desc_qsel {
 	QSLT_CMD = 0x13,
 };
 
-enum rtl_desc92d_rate {
-	DESC92D_RATE1M = 0x00,
-	DESC92D_RATE2M = 0x01,
-	DESC92D_RATE5_5M = 0x02,
-	DESC92D_RATE11M = 0x03,
-
-	DESC92D_RATE6M = 0x04,
-	DESC92D_RATE9M = 0x05,
-	DESC92D_RATE12M = 0x06,
-	DESC92D_RATE18M = 0x07,
-	DESC92D_RATE24M = 0x08,
-	DESC92D_RATE36M = 0x09,
-	DESC92D_RATE48M = 0x0a,
-	DESC92D_RATE54M = 0x0b,
-
-	DESC92D_RATEMCS0 = 0x0c,
-	DESC92D_RATEMCS1 = 0x0d,
-	DESC92D_RATEMCS2 = 0x0e,
-	DESC92D_RATEMCS3 = 0x0f,
-	DESC92D_RATEMCS4 = 0x10,
-	DESC92D_RATEMCS5 = 0x11,
-	DESC92D_RATEMCS6 = 0x12,
-	DESC92D_RATEMCS7 = 0x13,
-	DESC92D_RATEMCS8 = 0x14,
-	DESC92D_RATEMCS9 = 0x15,
-	DESC92D_RATEMCS10 = 0x16,
-	DESC92D_RATEMCS11 = 0x17,
-	DESC92D_RATEMCS12 = 0x18,
-	DESC92D_RATEMCS13 = 0x19,
-	DESC92D_RATEMCS14 = 0x1a,
-	DESC92D_RATEMCS15 = 0x1b,
-	DESC92D_RATEMCS15_SG = 0x1c,
-	DESC92D_RATEMCS32 = 0x20,
-};
-
 enum channel_plan {
 	CHPL_FCC	= 0,
 	CHPL_IC		= 1,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
index 351765df517d4bf513426981ca6f90cf9084c99d..f6419b7ed2f47908cd4dadaca7d35eeb236f2a5d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
@@ -340,21 +340,21 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = {
 	.maps[RTL_IMR_ROK] = IMR_ROK,
 	.maps[RTL_IBSS_INT_MASKS] = (IMR_BcnInt | IMR_TBDOK | IMR_TBDER),
 
-	.maps[RTL_RC_CCK_RATE1M] = DESC92D_RATE1M,
-	.maps[RTL_RC_CCK_RATE2M] = DESC92D_RATE2M,
-	.maps[RTL_RC_CCK_RATE5_5M] = DESC92D_RATE5_5M,
-	.maps[RTL_RC_CCK_RATE11M] = DESC92D_RATE11M,
-	.maps[RTL_RC_OFDM_RATE6M] = DESC92D_RATE6M,
-	.maps[RTL_RC_OFDM_RATE9M] = DESC92D_RATE9M,
-	.maps[RTL_RC_OFDM_RATE12M] = DESC92D_RATE12M,
-	.maps[RTL_RC_OFDM_RATE18M] = DESC92D_RATE18M,
-	.maps[RTL_RC_OFDM_RATE24M] = DESC92D_RATE24M,
-	.maps[RTL_RC_OFDM_RATE36M] = DESC92D_RATE36M,
-	.maps[RTL_RC_OFDM_RATE48M] = DESC92D_RATE48M,
-	.maps[RTL_RC_OFDM_RATE54M] = DESC92D_RATE54M,
-
-	.maps[RTL_RC_HT_RATEMCS7] = DESC92D_RATEMCS7,
-	.maps[RTL_RC_HT_RATEMCS15] = DESC92D_RATEMCS15,
+	.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+	.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+	.maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+	.maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+	.maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+	.maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+	.maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+	.maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+	.maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+	.maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+	.maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+	.maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+
+	.maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+	.maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
 };
 
 static struct pci_device_id rtl92de_pci_ids[] __devinitdata = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index dc86fcb0b3a3fb90895629405e7e9d89454c1038..3637c0c3352513b2dab6a6c964feb61b0f2085ad 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -48,99 +48,6 @@ static u8 _rtl92de_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
 	return skb->priority;
 }
 
-static int _rtl92de_rate_mapping(bool isht, u8 desc_rate)
-{
-	int rate_idx;
-
-	if (false == isht) {
-		switch (desc_rate) {
-		case DESC92D_RATE1M:
-			rate_idx = 0;
-			break;
-		case DESC92D_RATE2M:
-			rate_idx = 1;
-			break;
-		case DESC92D_RATE5_5M:
-			rate_idx = 2;
-			break;
-		case DESC92D_RATE11M:
-			rate_idx = 3;
-			break;
-		case DESC92D_RATE6M:
-			rate_idx = 4;
-			break;
-		case DESC92D_RATE9M:
-			rate_idx = 5;
-			break;
-		case DESC92D_RATE12M:
-			rate_idx = 6;
-			break;
-		case DESC92D_RATE18M:
-			rate_idx = 7;
-			break;
-		case DESC92D_RATE24M:
-			rate_idx = 8;
-			break;
-		case DESC92D_RATE36M:
-			rate_idx = 9;
-			break;
-		case DESC92D_RATE48M:
-			rate_idx = 10;
-			break;
-		case DESC92D_RATE54M:
-			rate_idx = 11;
-			break;
-		default:
-			rate_idx = 0;
-			break;
-		}
-		return rate_idx;
-	} else {
-		switch (desc_rate) {
-		case DESC92D_RATE1M:
-			rate_idx = 0;
-			break;
-		case DESC92D_RATE2M:
-			rate_idx = 1;
-			break;
-		case DESC92D_RATE5_5M:
-			rate_idx = 2;
-			break;
-		case DESC92D_RATE11M:
-			rate_idx = 3;
-			break;
-		case DESC92D_RATE6M:
-			rate_idx = 4;
-			break;
-		case DESC92D_RATE9M:
-			rate_idx = 5;
-			break;
-		case DESC92D_RATE12M:
-			rate_idx = 6;
-			break;
-		case DESC92D_RATE18M:
-			rate_idx = 7;
-			break;
-		case DESC92D_RATE24M:
-			rate_idx = 8;
-			break;
-		case DESC92D_RATE36M:
-			rate_idx = 9;
-			break;
-		case DESC92D_RATE48M:
-			rate_idx = 10;
-			break;
-		case DESC92D_RATE54M:
-			rate_idx = 11;
-			break;
-		default:
-			rate_idx = 11;
-			break;
-		}
-		return rate_idx;
-	}
-}
-
 static u8 _rtl92d_query_rxpwrpercentage(char antpower)
 {
 	if ((antpower <= -100) || (antpower >= 20))
@@ -328,8 +235,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,
 		pstats->rx_pwdb_all = pwdb_all;
 		pstats->rxpower = rx_pwr_all;
 		pstats->recvsignalpower = rx_pwr_all;
-		if (pdesc->rxht && pdesc->rxmcs >= DESC92D_RATEMCS8 &&
-		    pdesc->rxmcs <= DESC92D_RATEMCS15)
+		if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 &&
+		    pdesc->rxmcs <= DESC92_RATEMCS15)
 			max_spatial_stream = 2;
 		else
 			max_spatial_stream = 1;
@@ -609,10 +516,10 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw,	struct rtl_stats *stats,
 	rx_status->flag |= RX_FLAG_MACTIME_MPDU;
 	if (stats->decrypted)
 		rx_status->flag |= RX_FLAG_DECRYPTED;
-	rx_status->rate_idx = _rtl92de_rate_mapping((bool)
-						    GET_RX_DESC_RXHT(pdesc),
-						    (u8)
-						    GET_RX_DESC_RXMCS(pdesc));
+	rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+					(bool)GET_RX_DESC_RXHT(pdesc),
+					(u8)GET_RX_DESC_RXMCS(pdesc),
+					(bool)GET_RX_DESC_PAGGR(pdesc));
 	rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
 	if (phystatus) {
 		p_drvinfo = (struct rx_fwinfo_92d *)(skb->data +
@@ -705,14 +612,14 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
 		}
 		/* 5G have no CCK rate */
 		if (rtlhal->current_bandtype == BAND_ON_5G)
-			if (ptcb_desc->hw_rate < DESC92D_RATE6M)
-				ptcb_desc->hw_rate = DESC92D_RATE6M;
+			if (ptcb_desc->hw_rate < DESC92_RATE6M)
+				ptcb_desc->hw_rate = DESC92_RATE6M;
 		SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
 		if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble)
 			SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
 
 		if (rtlhal->macphymode == DUALMAC_DUALPHY &&
-			ptcb_desc->hw_rate == DESC92D_RATEMCS7)
+			ptcb_desc->hw_rate == DESC92_RATEMCS7)
 			SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
 
 		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
@@ -728,13 +635,13 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
 		SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
 		/* 5G have no CCK rate */
 		if (rtlhal->current_bandtype == BAND_ON_5G)
-			if (ptcb_desc->rts_rate < DESC92D_RATE6M)
-				ptcb_desc->rts_rate = DESC92D_RATE6M;
+			if (ptcb_desc->rts_rate < DESC92_RATE6M)
+				ptcb_desc->rts_rate = DESC92_RATE6M;
 		SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
 		SET_TX_DESC_RTS_BW(pdesc, 0);
 		SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
 		SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
-			DESC92D_RATE54M) ?
+			DESC92_RATE54M) ?
 			(ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
 			(ptcb_desc->rts_use_shortgi ? 1 : 0)));
 		if (bw_40) {
@@ -844,9 +751,9 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
 	 * The braces are needed no matter what checkpatch says
 	 */
 	if (rtlhal->current_bandtype == BAND_ON_5G) {
-		SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE6M);
+		SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE6M);
 	} else {
-		SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE1M);
+		SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
 	}
 	SET_TX_DESC_SEQ(pdesc, 0);
 	SET_TX_DESC_LINIP(pdesc, 0);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
index 992d6766e667c9b174445e069717ebf0c4bfe40c..6c2236868c9aea260fd4099d007eeec48edf1731 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
@@ -538,10 +538,10 @@ do {							\
 } while (0);
 
 #define RX_HAL_IS_CCK_RATE(_pdesc)\
-	(_pdesc->rxmcs == DESC92D_RATE1M ||		\
-	 _pdesc->rxmcs == DESC92D_RATE2M ||		\
-	 _pdesc->rxmcs == DESC92D_RATE5_5M ||		\
-	 _pdesc->rxmcs == DESC92D_RATE11M)
+	(_pdesc->rxmcs == DESC92_RATE1M ||		\
+	 _pdesc->rxmcs == DESC92_RATE2M ||		\
+	 _pdesc->rxmcs == DESC92_RATE5_5M ||		\
+	 _pdesc->rxmcs == DESC92_RATE11M)
 
 /* For 92D early mode */
 #define SET_EARLYMODE_PKTNUM(__paddr, __value)		\
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
index 69828f2b3fab1291f85afa17060cf21f8852faa5..68204ea175ddf594898cf1a8f60cd327025caa40 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
@@ -33,37 +33,6 @@
 #define RX_CMD_QUEUE				1
 #define RX_MAX_QUEUE				2
 
-#define DESC92S_RATE1M				0x00
-#define DESC92S_RATE2M				0x01
-#define DESC92S_RATE5_5M			0x02
-#define DESC92S_RATE11M				0x03
-#define DESC92S_RATE6M				0x04
-#define DESC92S_RATE9M				0x05
-#define DESC92S_RATE12M				0x06
-#define DESC92S_RATE18M				0x07
-#define DESC92S_RATE24M				0x08
-#define DESC92S_RATE36M				0x09
-#define DESC92S_RATE48M				0x0a
-#define DESC92S_RATE54M				0x0b
-#define DESC92S_RATEMCS0			0x0c
-#define DESC92S_RATEMCS1			0x0d
-#define DESC92S_RATEMCS2			0x0e
-#define DESC92S_RATEMCS3			0x0f
-#define DESC92S_RATEMCS4			0x10
-#define DESC92S_RATEMCS5			0x11
-#define DESC92S_RATEMCS6			0x12
-#define DESC92S_RATEMCS7			0x13
-#define DESC92S_RATEMCS8			0x14
-#define DESC92S_RATEMCS9			0x15
-#define DESC92S_RATEMCS10			0x16
-#define DESC92S_RATEMCS11			0x17
-#define DESC92S_RATEMCS12			0x18
-#define DESC92S_RATEMCS13			0x19
-#define DESC92S_RATEMCS14			0x1a
-#define DESC92S_RATEMCS15			0x1b
-#define DESC92S_RATEMCS15_SG			0x1c
-#define DESC92S_RATEMCS32			0x20
-
 #define SHORT_SLOT_TIME				9
 #define NON_SHORT_SLOT_TIME			20
 
@@ -491,10 +460,10 @@ do {								\
 	SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val)
 
 #define RX_HAL_IS_CCK_RATE(_pdesc)\
-	(GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M ||	\
-	 GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M ||	\
-	 GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\
-	 GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M)
+	(GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M ||	\
+	 GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M ||	\
+	 GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\
+	 GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE11M)
 
 enum rf_optype {
 	RF_OP_BY_SW_3WIRE = 0,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index 3876078a63def399a9e188d60502b7e36ac2648a..0055a1c845a2f8c213e8c8c4f945836e737cf5ad 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -348,21 +348,21 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = {
 	.maps[RTL_IMR_ROK] = IMR_ROK,
 	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
 
-	.maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M,
-	.maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M,
-	.maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M,
-	.maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M,
-	.maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M,
-	.maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M,
-	.maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M,
-	.maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M,
-	.maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M,
-	.maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M,
-	.maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M,
-	.maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M,
-
-	.maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7,
-	.maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15,
+	.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+	.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+	.maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+	.maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+	.maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+	.maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+	.maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+	.maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+	.maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+	.maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+	.maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+	.maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+
+	.maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+	.maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
 };
 
 static struct pci_device_id rtl92se_pci_ids[] __devinitdata = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index cffe30851f79fee127474f90c5c0fa3a662caa99..d9aeae7f8bdbed1e4ec68f7ab8138a2969c22802 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -51,104 +51,6 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb,	u8 skb_queue)
 	return skb->priority;
 }
 
-static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
-{
-	int rate_idx = 0;
-
-	if (first_ampdu) {
-		if (false == isht) {
-			switch (desc_rate) {
-			case DESC92S_RATE1M:
-				rate_idx = 0;
-				break;
-			case DESC92S_RATE2M:
-				rate_idx = 1;
-				break;
-			case DESC92S_RATE5_5M:
-				rate_idx = 2;
-				break;
-			case DESC92S_RATE11M:
-				rate_idx = 3;
-				break;
-			case DESC92S_RATE6M:
-				rate_idx = 4;
-				break;
-			case DESC92S_RATE9M:
-				rate_idx = 5;
-				break;
-			case DESC92S_RATE12M:
-				rate_idx = 6;
-				break;
-			case DESC92S_RATE18M:
-				rate_idx = 7;
-				break;
-			case DESC92S_RATE24M:
-				rate_idx = 8;
-				break;
-			case DESC92S_RATE36M:
-				rate_idx = 9;
-				break;
-			case DESC92S_RATE48M:
-				rate_idx = 10;
-				break;
-			case DESC92S_RATE54M:
-				rate_idx = 11;
-				break;
-			default:
-				rate_idx = 0;
-				break;
-			}
-		} else {
-			rate_idx = 11;
-		}
-
-		return rate_idx;
-	}
-
-	switch (desc_rate) {
-	case DESC92S_RATE1M:
-		rate_idx = 0;
-		break;
-	case DESC92S_RATE2M:
-		rate_idx = 1;
-		break;
-	case DESC92S_RATE5_5M:
-		rate_idx = 2;
-		break;
-	case DESC92S_RATE11M:
-		rate_idx = 3;
-		break;
-	case DESC92S_RATE6M:
-		rate_idx = 4;
-		break;
-	case DESC92S_RATE9M:
-		rate_idx = 5;
-		break;
-	case DESC92S_RATE12M:
-		rate_idx = 6;
-		break;
-	case DESC92S_RATE18M:
-		rate_idx = 7;
-		break;
-	case DESC92S_RATE24M:
-		rate_idx = 8;
-		break;
-	case DESC92S_RATE36M:
-		rate_idx = 9;
-		break;
-	case DESC92S_RATE48M:
-		rate_idx = 10;
-		break;
-	case DESC92S_RATE54M:
-		rate_idx = 11;
-		break;
-	default:
-		rate_idx = 11;
-		break;
-	}
-	return rate_idx;
-}
-
 static u8 _rtl92s_query_rxpwrpercentage(char antpower)
 {
 	if ((antpower <= -100) || (antpower >= 20))
@@ -345,8 +247,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
 		pstats->recvsignalpower = rx_pwr_all;
 
 		if (GET_RX_STATUS_DESC_RX_HT(pdesc) &&
-			GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 &&
-		    GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15)
+			GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 &&
+		    GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15)
 			max_spatial_stream = 2;
 		else
 			max_spatial_stream = 1;
@@ -654,10 +556,10 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
 	if (stats->decrypted)
 		rx_status->flag |= RX_FLAG_DECRYPTED;
 
-	rx_status->rate_idx = _rtl92se_rate_mapping((bool)
-			GET_RX_STATUS_DESC_RX_HT(pdesc),
-			(u8)GET_RX_STATUS_DESC_RX_MCS(pdesc),
-			(bool)GET_RX_STATUS_DESC_PAGGR(pdesc));
+	rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+				(bool)GET_RX_STATUS_DESC_RX_HT(pdesc),
+				(u8)GET_RX_STATUS_DESC_RX_MCS(pdesc),
+				(bool)GET_RX_STATUS_DESC_PAGGR(pdesc));
 
 
 	rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc);
@@ -723,14 +625,14 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
 		SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid);
 
 		SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >=
-				 DESC92S_RATEMCS0) ? 1 : 0));
+				 DESC92_RATEMCS0) ? 1 : 0));
 
 		if (rtlhal->version == VERSION_8192S_ACUT) {
-			if (ptcb_desc->hw_rate == DESC92S_RATE1M ||
-				ptcb_desc->hw_rate  == DESC92S_RATE2M ||
-				ptcb_desc->hw_rate == DESC92S_RATE5_5M ||
-				ptcb_desc->hw_rate == DESC92S_RATE11M) {
-				ptcb_desc->hw_rate = DESC92S_RATE12M;
+			if (ptcb_desc->hw_rate == DESC92_RATE1M ||
+				ptcb_desc->hw_rate  == DESC92_RATE2M ||
+				ptcb_desc->hw_rate == DESC92_RATE5_5M ||
+				ptcb_desc->hw_rate == DESC92_RATE11M) {
+				ptcb_desc->hw_rate = DESC92_RATE12M;
 			}
 		}
 
@@ -759,7 +661,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
 		SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0);
 		SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc);
 		SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
-		       DESC92S_RATE54M) ?
+		       DESC92_RATE54M) ?
 		       (ptcb_desc->rts_use_shortpreamble ? 1 : 0)
 		       : (ptcb_desc->rts_use_shortgi ? 1 : 0)));
 
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index d3c3ffd38984dbf6ed515e102606b240fe5837b9..8a9091968f316f449a5c7380e9ea7a738db3c76f 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -386,6 +386,41 @@ enum rtl_hal_state {
 	_HAL_STATE_START = 1,
 };
 
+enum rtl_desc92_rate {
+	DESC92_RATE1M = 0x00,
+	DESC92_RATE2M = 0x01,
+	DESC92_RATE5_5M = 0x02,
+	DESC92_RATE11M = 0x03,
+
+	DESC92_RATE6M = 0x04,
+	DESC92_RATE9M = 0x05,
+	DESC92_RATE12M = 0x06,
+	DESC92_RATE18M = 0x07,
+	DESC92_RATE24M = 0x08,
+	DESC92_RATE36M = 0x09,
+	DESC92_RATE48M = 0x0a,
+	DESC92_RATE54M = 0x0b,
+
+	DESC92_RATEMCS0 = 0x0c,
+	DESC92_RATEMCS1 = 0x0d,
+	DESC92_RATEMCS2 = 0x0e,
+	DESC92_RATEMCS3 = 0x0f,
+	DESC92_RATEMCS4 = 0x10,
+	DESC92_RATEMCS5 = 0x11,
+	DESC92_RATEMCS6 = 0x12,
+	DESC92_RATEMCS7 = 0x13,
+	DESC92_RATEMCS8 = 0x14,
+	DESC92_RATEMCS9 = 0x15,
+	DESC92_RATEMCS10 = 0x16,
+	DESC92_RATEMCS11 = 0x17,
+	DESC92_RATEMCS12 = 0x18,
+	DESC92_RATEMCS13 = 0x19,
+	DESC92_RATEMCS14 = 0x1a,
+	DESC92_RATEMCS15 = 0x1b,
+	DESC92_RATEMCS15_SG = 0x1c,
+	DESC92_RATEMCS32 = 0x20,
+};
+
 enum rtl_var_map {
 	/*reg map */
 	SYS_ISO_CTRL = 0,
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index c77e0543e5021be8d1b8696f5572d537bb654882..f81a93e5b59dfa865e413454a82ab01539c6457f 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1246,7 +1246,6 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
 {
 	int payload_len = skb->len;
 	struct pn533_frame *out_frame;
-	struct sk_buff *discarded;
 	u8 tg;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
@@ -1260,18 +1259,6 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
 		return -ENOSYS;
 	}
 
-	/* Reserving header space */
-	if (skb_cow_head(skb, PN533_CMD_DATAEXCH_HEAD_LEN)) {
-		nfc_dev_err(&dev->interface->dev, "Error to add header data");
-		return -ENOMEM;
-	}
-
-	/* Reserving tail space, see pn533_tx_frame_finish */
-	if (skb_cow_data(skb, PN533_FRAME_TAIL_SIZE, &discarded) < 0) {
-		nfc_dev_err(&dev->interface->dev, "Error to add tail data");
-		return -ENOMEM;
-	}
-
 	skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
 	out_frame = (struct pn533_frame *) skb->data;
 
@@ -1536,7 +1523,9 @@ static int pn533_probe(struct usb_interface *interface,
 			| NFC_PROTO_ISO14443_MASK
 			| NFC_PROTO_NFC_DEP_MASK;
 
-	dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols);
+	dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
+					   PN533_CMD_DATAEXCH_HEAD_LEN,
+					   PN533_FRAME_TAIL_SIZE);
 	if (!dev->nfc_dev)
 		goto kill_tasklet;
 
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 29c7d4f9d1ae1b7b9a073b6bf223e949b3d3be24..d0cbdb0cf9d53a12099fdafd2cc5f14d291a36d2 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -1260,16 +1260,34 @@ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
 }
 EXPORT_SYMBOL(ssb_device_disable);
 
+/* Some chipsets need routing known for PCIe and 64-bit DMA */
+static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
+{
+	u16 chip_id = dev->bus->chip_id;
+
+	if (dev->id.coreid == SSB_DEV_80211) {
+		return (chip_id == 0x4322 || chip_id == 43221 ||
+			chip_id == 43231 || chip_id == 43222);
+	}
+
+	return 0;
+}
+
 u32 ssb_dma_translation(struct ssb_device *dev)
 {
 	switch (dev->bus->bustype) {
 	case SSB_BUSTYPE_SSB:
 		return 0;
 	case SSB_BUSTYPE_PCI:
-		if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
+		if (pci_is_pcie(dev->bus->host_pci) &&
+		    ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 			return SSB_PCIE_DMA_H32;
-		else
-			return SSB_PCI_DMA;
+		} else {
+			if (ssb_dma_translation_special_bit(dev))
+				return SSB_PCIE_DMA_H32;
+			else
+				return SSB_PCI_DMA;
+		}
 	default:
 		__ssb_dma_not_implemented(dev);
 	}
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 6083725dd22e45e612681e7c4541b06467a81b41..a7ae33d06f246006f56a39b2a84adc40a0114c59 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -283,6 +283,22 @@
 #define BCMA_CC_PPL_PCHI_OFF		5
 #define BCMA_CC_PPL_PCHI_MASK		0x0000003f
 
+/* BCM4331 ChipControl numbers. */
+#define BCMA_CHIPCTL_4331_BT_COEXIST		BIT(0)	/* 0 disable */
+#define BCMA_CHIPCTL_4331_SECI			BIT(1)	/* 0 SECI is disabled (JATG functional) */
+#define BCMA_CHIPCTL_4331_EXT_LNA		BIT(2)	/* 0 disable */
+#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15	BIT(3)	/* sprom/gpio13-15 mux */
+#define BCMA_CHIPCTL_4331_EXTPA_EN		BIT(4)	/* 0 ext pa disable, 1 ext pa enabled */
+#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS	BIT(5)	/* set drive out GPIO_CLK on sprom_cs pin */
+#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS	BIT(6)	/* use sprom_cs pin as PCIE mdio interface */
+#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5	BIT(7)	/* aband extpa will be at gpio2/5 and sprom_dout */
+#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN	BIT(8)	/* override core control on pipe_AuxClkEnable */
+#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN	BIT(9)	/* override core control on pipe_AuxPowerDown */
+#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN		BIT(10)	/* pcie_auxclkenable */
+#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN	BIT(11)	/* pcie_pipe_pllpowerdown */
+#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4	BIT(16)	/* enable bt_shd0 at gpio4 */
+#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5	BIT(17)	/* enable bt_shd1 at gpio5 */
+
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
  */
@@ -342,6 +358,8 @@ extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
 extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+
 extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 					  u32 ticks);
 
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 54c878960872e47053751b57edd8187295b6fa1f..37f95f2e10f9606164b441fd0e4622bd01879183 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -629,9 +629,14 @@ struct ieee80211_rann_ie {
 	u8 rann_ttl;
 	u8 rann_addr[6];
 	u32 rann_seq;
+	u32 rann_interval;
 	u32 rann_metric;
 } __attribute__ ((packed));
 
+enum ieee80211_rann_flags {
+	RANN_FLAG_IS_GATE = 1 << 0,
+};
+
 #define WLAN_SA_QUERY_TR_ID_LEN 2
 
 struct ieee80211_mgmt {
@@ -736,19 +741,10 @@ struct ieee80211_mgmt {
 					__le16 params;
 					__le16 reason_code;
 				} __attribute__((packed)) delba;
-				struct{
+				struct {
 					u8 action_code;
-					/* capab_info for open and confirm,
-					 * reason for close
-					 */
-					__le16 aux;
-					/* Followed in plink_confirm by status
-					 * code, AID and supported rates,
-					 * and directly by supported rates in
-					 * plink_open and plink_close
-					 */
 					u8 variable[0];
-				} __attribute__((packed)) plink_action;
+				} __attribute__((packed)) self_prot;
 				struct{
 					u8 action_code;
 					u8 variable[0];
@@ -816,9 +812,11 @@ struct ieee80211_bar {
 } __attribute__((packed));
 
 /* 802.11 BAR control masks */
-#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL     0x0000
-#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA  0x0004
-
+#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL	0x0000
+#define IEEE80211_BAR_CTRL_MULTI_TID		0x0002
+#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA	0x0004
+#define IEEE80211_BAR_CTRL_TID_INFO_MASK	0xf000
+#define IEEE80211_BAR_CTRL_TID_INFO_SHIFT	12
 
 #define IEEE80211_HT_MCS_MASK_LEN		10
 
@@ -1194,11 +1192,6 @@ enum ieee80211_eid {
 	WLAN_EID_MESH_ID = 114,
 	WLAN_EID_LINK_METRIC_REPORT = 115,
 	WLAN_EID_CONGESTION_NOTIFICATION = 116,
-	/* Note that the Peer Link IE has been replaced with the similar
-	 * Peer Management IE.  We will keep the former definition until mesh
-	 * code is changed to comply with latest 802.11s drafts.
-	 */
-	WLAN_EID_PEER_LINK = 55,  /* no longer in 802.11s drafts */
 	WLAN_EID_PEER_MGMT = 117,
 	WLAN_EID_CHAN_SWITCH_PARAM = 118,
 	WLAN_EID_MESH_AWAKE_WINDOW = 119,
@@ -1281,9 +1274,6 @@ enum ieee80211_category {
 	WLAN_CATEGORY_MULTIHOP_ACTION = 14,
 	WLAN_CATEGORY_SELF_PROTECTED = 15,
 	WLAN_CATEGORY_WMM = 17,
-	/* TODO: remove MESH_PATH_SEL after mesh is updated
-	 * to current 802.11s draft  */
-	WLAN_CATEGORY_MESH_PATH_SEL = 32,
 	WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
 	WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
 };
@@ -1309,6 +1299,31 @@ enum ieee80211_ht_actioncode {
 	WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7,
 };
 
+/* Self Protected Action codes */
+enum ieee80211_self_protected_actioncode {
+	WLAN_SP_RESERVED = 0,
+	WLAN_SP_MESH_PEERING_OPEN = 1,
+	WLAN_SP_MESH_PEERING_CONFIRM = 2,
+	WLAN_SP_MESH_PEERING_CLOSE = 3,
+	WLAN_SP_MGK_INFORM = 4,
+	WLAN_SP_MGK_ACK = 5,
+};
+
+/* Mesh action codes */
+enum ieee80211_mesh_actioncode {
+	WLAN_MESH_ACTION_LINK_METRIC_REPORT,
+	WLAN_MESH_ACTION_HWMP_PATH_SELECTION,
+	WLAN_MESH_ACTION_GATE_ANNOUNCEMENT,
+	WLAN_MESH_ACTION_CONGESTION_CONTROL_NOTIFICATION,
+	WLAN_MESH_ACTION_MCCA_SETUP_REQUEST,
+	WLAN_MESH_ACTION_MCCA_SETUP_REPLY,
+	WLAN_MESH_ACTION_MCCA_ADVERTISEMENT_REQUEST,
+	WLAN_MESH_ACTION_MCCA_ADVERTISEMENT,
+	WLAN_MESH_ACTION_MCCA_TEARDOWN,
+	WLAN_MESH_ACTION_TBTT_ADJUSTMENT_REQUEST,
+	WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE,
+};
+
 /* Security key length */
 enum ieee80211_key_len {
 	WLAN_KEY_LEN_WEP40 = 5,
diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index 330a4c5db5887d177371c5510c308cc4581a58ef..c525e0b5876b9286d110a5f4dc14de7e4b93f010 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -123,4 +123,6 @@ struct sockaddr_nfc {
 #define NFC_SOCKPROTO_RAW	0
 #define NFC_SOCKPROTO_MAX	1
 
+#define NFC_HEADER_SIZE 1
+
 #endif /*__LINUX_NFC_H */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 89dec16b4697c3d26430560f780cc8c56894f770..0343504082a81847de1184d911d9f3b2b2d189b1 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1042,6 +1042,9 @@ enum nl80211_commands {
  *	(Re)Association Response frames when the driver (or firmware) replies to
  *	(Re)Association Request frames.
  *
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ *	of the station, see &enum nl80211_sta_wme_attr.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1252,6 +1255,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_IE_PROBE_RESP,
 	NL80211_ATTR_IE_ASSOC_RESP,
 
+	NL80211_ATTR_STA_WME,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1861,6 +1866,13 @@ enum nl80211_mntr_flags {
  * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
  * source mesh point for path selection elements.
  *
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS.  This is done via Root
+ * Announcement frames.
+ *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -1882,6 +1894,8 @@ enum nl80211_meshconf_params {
 	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
 	NL80211_MESHCONF_HWMP_ROOTMODE,
 	NL80211_MESHCONF_ELEMENT_TTL,
+	NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+	NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
 
 	/* keep last */
 	__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2473,4 +2487,22 @@ enum nl80211_hidden_ssid {
 	NL80211_HIDDEN_SSID_ZERO_CONTENTS
 };
 
+/**
+ * enum nl80211_sta_wme_attr - station WME attributes
+ * @__NL80211_STA_WME_INVALID: invalid number for nested attribute
+ * @NL80211_STA_WME_QUEUES: bitmap of uapsd queues.
+ * @NL80211_STA_WME_MAX_SP: max service period.
+ * @__NL80211_STA_WME_AFTER_LAST: internal
+ * @NL80211_STA_WME_MAX: highest station WME attribute
+ */
+enum nl80211_sta_wme_attr {
+	__NL80211_STA_WME_INVALID,
+	NL80211_STA_WME_UAPSD_QUEUES,
+	NL80211_STA_WME_MAX_SP,
+
+	/* keep last */
+	__NL80211_STA_WME_AFTER_LAST,
+	NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d86a15d87e585b833bcc7ea43357fbe0e91be168..88112ca59c8eeb299bc4b9e3a05d931dcaef769a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -452,6 +452,8 @@ struct station_parameters {
 	u8 plink_action;
 	u8 plink_state;
 	struct ieee80211_ht_cap *ht_capa;
+	u8 uapsd_queues;
+	u8 max_sp;
 };
 
 /**
@@ -755,6 +757,12 @@ struct mesh_config {
 	u16 dot11MeshHWMPpreqMinInterval;
 	u16 dot11MeshHWMPnetDiameterTraversalTime;
 	u8  dot11MeshHWMPRootMode;
+	u16 dot11MeshHWMPRannInterval;
+	/* This is missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol
+	 * set to true only means that the station will announce others it's a
+	 * mesh gate, but not necessarily using the gate announcement protocol.
+	 * Still keeping the same nomenclature to be in sync with the spec. */
+	bool  dot11MeshGateAnnouncementProtocol;
 };
 
 /**
@@ -2291,7 +2299,7 @@ struct ieee802_11_elems {
 	struct ieee80211_ht_info *ht_info_elem;
 	struct ieee80211_meshconf_ie *mesh_config;
 	u8 *mesh_id;
-	u8 *peer_link;
+	u8 *peering;
 	u8 *preq;
 	u8 *prep;
 	u8 *perr;
@@ -2318,7 +2326,7 @@ struct ieee802_11_elems {
 	u8 wmm_info_len;
 	u8 wmm_param_len;
 	u8 mesh_id_len;
-	u8 peer_link_len;
+	u8 peering_len;
 	u8 preq_len;
 	u8 prep_len;
 	u8 perr_len;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 2f01d84ca52f2d690eae5f6fd432a92e7b747288..2e752df575109dc1526d22d1dbe40aa5a3ed5f77 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -954,6 +954,8 @@ struct ieee80211_sta {
 	u16 aid;
 	struct ieee80211_sta_ht_cap ht_cap;
 	bool wme;
+	u8 uapsd_queues;
+	u8 max_sp;
 
 	/* must be last */
 	u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
diff --git a/include/net/nfc.h b/include/net/nfc.h
index cc0130312f7084ff3356a1e09bec598f2d9cdb22..87b51fe15b707c14ad1c662af04726b07fff45e1 100644
--- a/include/net/nfc.h
+++ b/include/net/nfc.h
@@ -82,6 +82,9 @@ struct nfc_dev {
 	struct nfc_genl_data genl_data;
 	u32 supported_protocols;
 
+	int tx_headroom;
+	int tx_tailroom;
+
 	struct nfc_ops *ops;
 };
 #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
@@ -89,7 +92,9 @@ struct nfc_dev {
 extern struct class nfc_class;
 
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
-					u32 supported_protocols);
+					u32 supported_protocols,
+					int tx_headroom,
+					int tx_tailroom);
 
 /**
  * nfc_free_device - free nfc device
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index 356d6e3dc20a581f9d1a529675ac69ab73559c5f..eb7d3c2d427480d8c9bb77723386681cdc6c1b35 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -3,11 +3,19 @@
 /*
  * regulatory support structures
  *
- * Copyright 2008-2009	Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008-2009	Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * 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.
  */
 
 
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index f5fdfcbf552a100d45e703455ed07145789e36bc..d1886b59bec4d451116eb3e5f4cecde5ff2cc4bf 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -199,6 +199,19 @@ config MAC80211_VERBOSE_MPL_DEBUG
 
 	  Do not select this option.
 
+config MAC80211_VERBOSE_MPATH_DEBUG
+	bool "Verbose mesh path debugging"
+	depends on MAC80211_DEBUG_MENU
+	depends on MAC80211_MESH
+	---help---
+	  Selecting this option causes mac80211 to print out very
+	  verbose mesh path selection debugging messages (when mac80211
+	  is taking part in a mesh network).
+	  It should not be selected on production systems as those
+	  messages are remotely triggerable.
+
+	  Do not select this option.
+
 config MAC80211_VERBOSE_MHWMP_DEBUG
 	bool "Verbose mesh HWMP routing debugging"
 	depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index b7075f33dc06c2eb997469fdf955408d8fce709d..018108d1a2fd5079d16a04edb030520aca0d7d8b 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -128,7 +128,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
 	memcpy(bar->ta, sdata->vif.addr, ETH_ALEN);
 	bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
 	bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
-	bar_control |= (u16)(tid << 12);
+	bar_control |= (u16)(tid << IEEE80211_BAR_CTRL_TID_INFO_SHIFT);
 	bar->control = cpu_to_le16(bar_control);
 	bar->start_seq_num = cpu_to_le16(ssn);
 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a589addf6ce1db3a3b2880f496f1318888e2ff56..4baa03b1c251b0691d45d4622b28d595d08dd076 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -697,6 +697,9 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 	}
 	spin_unlock_irqrestore(&sta->flaglock, flags);
 
+	sta->sta.uapsd_queues = params->uapsd_queues;
+	sta->sta.max_sp = params->max_sp;
+
 	/*
 	 * cfg80211 validates this (1-2007) and allows setting the AID
 	 * only when creating a new station entry
@@ -1137,6 +1140,22 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
 		conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
 		ieee80211_mesh_root_setup(ifmsh);
 	}
+	if (_chg_mesh_attr(NL80211_MESHCONF_GATE_ANNOUNCEMENTS, mask)) {
+		/* our current gate announcement implementation rides on root
+		 * announcements, so require this ifmsh to also be a root node
+		 * */
+		if (nconf->dot11MeshGateAnnouncementProtocol &&
+		    !conf->dot11MeshHWMPRootMode) {
+			conf->dot11MeshHWMPRootMode = 1;
+			ieee80211_mesh_root_setup(ifmsh);
+		}
+		conf->dot11MeshGateAnnouncementProtocol =
+			nconf->dot11MeshGateAnnouncementProtocol;
+	}
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
+		conf->dot11MeshHWMPRannInterval =
+			nconf->dot11MeshHWMPRannInterval;
+	}
 	return 0;
 }
 
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9ea7c0d0103f8d9f15fc5b7d04109316ee675ea2..6e8eab7919e2e2a95db3ee761419b066d5c7655a 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -372,6 +372,10 @@ IEEE80211_IF_FILE(min_discovery_timeout,
 		u.mesh.mshcfg.min_discovery_timeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
 		u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
+		u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
+		u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
 #endif
 
 
@@ -485,7 +489,9 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
 	MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
 	MESHPARAMS_ADD(path_refresh_time);
 	MESHPARAMS_ADD(min_discovery_timeout);
-
+	MESHPARAMS_ADD(dot11MeshHWMPRootMode);
+	MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
+	MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
 #undef MESHPARAMS_ADD
 }
 #endif
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ea7419050846b42ea6bf8ef44ac6803281ec9346..c204cee1189c4a858ca64c633ff0e8a26fcec453 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -514,6 +514,7 @@ struct ieee80211_if_mesh {
 	struct mesh_config mshcfg;
 	u32 mesh_seqnum;
 	bool accepting_plinks;
+	int num_gates;
 	const u8 *ie;
 	u8 ie_len;
 	enum {
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 29e9980c8e60c6b704c99ec213308d64c6864a8b..28ab510e621a58a040d9f14a5c9384f09296ebb5 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -13,10 +13,6 @@
 #include "ieee80211_i.h"
 #include "mesh.h"
 
-#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
-#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
-#define IEEE80211_MESH_RANN_INTERVAL	     (1 * HZ)
-
 #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
 #define MESHCONF_CAPAB_FORWARDING    0x08
 
@@ -27,6 +23,17 @@
 int mesh_allocated;
 static struct kmem_cache *rm_cache;
 
+#ifdef CONFIG_MAC80211_MESH
+bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
+{
+	return (mgmt->u.action.u.mesh_action.action_code ==
+			WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
+}
+#else
+bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
+{ return false; }
+#endif
+
 void ieee80211s_init(void)
 {
 	mesh_pathtbl_init();
@@ -204,36 +211,185 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
 	return 0;
 }
 
-void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+int
+mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	u8 *pos, neighbors;
+	u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
+
+	if (skb_tailroom(skb) < 2 + meshconf_len)
+		return -ENOMEM;
+
+	pos = skb_put(skb, 2 + meshconf_len);
+	*pos++ = WLAN_EID_MESH_CONFIG;
+	*pos++ = meshconf_len;
+
+	/* Active path selection protocol ID */
+	*pos++ = ifmsh->mesh_pp_id;
+	/* Active path selection metric ID   */
+	*pos++ = ifmsh->mesh_pm_id;
+	/* Congestion control mode identifier */
+	*pos++ = ifmsh->mesh_cc_id;
+	/* Synchronization protocol identifier */
+	*pos++ = ifmsh->mesh_sp_id;
+	/* Authentication Protocol identifier */
+	*pos++ = ifmsh->mesh_auth_id;
+	/* Mesh Formation Info - number of neighbors */
+	neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
+	/* Number of neighbor mesh STAs or 15 whichever is smaller */
+	neighbors = (neighbors > 15) ? 15 : neighbors;
+	*pos++ = neighbors << 1;
+	/* Mesh capability */
+	ifmsh->accepting_plinks = mesh_plink_availables(sdata);
+	*pos = MESHCONF_CAPAB_FORWARDING;
+	*pos++ |= ifmsh->accepting_plinks ?
+	    MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
+	*pos++ = 0x00;
+
+	return 0;
+}
+
+int
+mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	u8 *pos;
+
+	if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
+		return -ENOMEM;
+
+	pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
+	*pos++ = WLAN_EID_MESH_ID;
+	*pos++ = ifmsh->mesh_id_len;
+	if (ifmsh->mesh_id_len)
+		memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
+
+	return 0;
+}
+
+int
+mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	u8 offset, len;
+	const u8 *data;
+
+	if (!ifmsh->ie || !ifmsh->ie_len)
+		return 0;
+
+	/* fast-forward to vendor IEs */
+	offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
+
+	if (offset) {
+		len = ifmsh->ie_len - offset;
+		data = ifmsh->ie + offset;
+		if (skb_tailroom(skb) < len)
+			return -ENOMEM;
+		memcpy(skb_put(skb, len), data, len);
+	}
+
+	return 0;
+}
+
+int
+mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	u8 len = 0;
+	const u8 *data;
+
+	if (!ifmsh->ie || !ifmsh->ie_len)
+		return 0;
+
+	/* find RSN IE */
+	data = ifmsh->ie;
+	while (data < ifmsh->ie + ifmsh->ie_len) {
+		if (*data == WLAN_EID_RSN) {
+			len = data[1] + 2;
+			break;
+		}
+		data++;
+	}
+
+	if (len) {
+		if (skb_tailroom(skb) < len)
+			return -ENOMEM;
+		memcpy(skb_put(skb, len), data, len);
+	}
+
+	return 0;
+}
+
+int
+mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
-	u8 *pos;
-	int len, i, rate;
-	u8 neighbors;
+	int rate;
+	u8 i, rates, *pos;
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-	len = sband->n_bitrates;
-	if (len > 8)
-		len = 8;
-	pos = skb_put(skb, len + 2);
+	rates = sband->n_bitrates;
+	if (rates > 8)
+		rates = 8;
+
+	if (skb_tailroom(skb) < rates + 2)
+		return -ENOMEM;
+
+	pos = skb_put(skb, rates + 2);
 	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos++ = len;
-	for (i = 0; i < len; i++) {
+	*pos++ = rates;
+	for (i = 0; i < rates; i++) {
 		rate = sband->bitrates[i].bitrate;
 		*pos++ = (u8) (rate / 5);
 	}
 
-	if (sband->n_bitrates > len) {
-		pos = skb_put(skb, sband->n_bitrates - len + 2);
+	return 0;
+}
+
+int
+mesh_add_ext_srates_ie(struct sk_buff *skb,
+		       struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_supported_band *sband;
+	int rate;
+	u8 i, exrates, *pos;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	exrates = sband->n_bitrates;
+	if (exrates > 8)
+		exrates -= 8;
+	else
+		exrates = 0;
+
+	if (skb_tailroom(skb) < exrates + 2)
+		return -ENOMEM;
+
+	if (exrates) {
+		pos = skb_put(skb, exrates + 2);
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
-		*pos++ = sband->n_bitrates - len;
-		for (i = len; i < sband->n_bitrates; i++) {
+		*pos++ = exrates;
+		for (i = 8; i < sband->n_bitrates; i++) {
 			rate = sband->bitrates[i].bitrate;
 			*pos++ = (u8) (rate / 5);
 		}
 	}
+	return 0;
+}
 
+int mesh_add_ds_params_ie(struct sk_buff *skb,
+			  struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_supported_band *sband;
+	u8 *pos;
+
+	if (skb_tailroom(skb) < 3)
+		return -ENOMEM;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 	if (sband->band == IEEE80211_BAND_2GHZ) {
 		pos = skb_put(skb, 2 + 1);
 		*pos++ = WLAN_EID_DS_PARAMS;
@@ -241,53 +397,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
 		*pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
 	}
 
-	pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len);
-	*pos++ = WLAN_EID_MESH_ID;
-	*pos++ = sdata->u.mesh.mesh_id_len;
-	if (sdata->u.mesh.mesh_id_len)
-		memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
-
-	pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie));
-	*pos++ = WLAN_EID_MESH_CONFIG;
-	*pos++ = sizeof(struct ieee80211_meshconf_ie);
-
-	/* Active path selection protocol ID */
-	*pos++ = sdata->u.mesh.mesh_pp_id;
-
-	/* Active path selection metric ID   */
-	*pos++ = sdata->u.mesh.mesh_pm_id;
-
-	/* Congestion control mode identifier */
-	*pos++ = sdata->u.mesh.mesh_cc_id;
-
-	/* Synchronization protocol identifier */
-	*pos++ = sdata->u.mesh.mesh_sp_id;
-
-	/* Authentication Protocol identifier */
-	*pos++ = sdata->u.mesh.mesh_auth_id;
-
-	/* Mesh Formation Info - number of neighbors */
-	neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
-	/* Number of neighbor mesh STAs or 15 whichever is smaller */
-	neighbors = (neighbors > 15) ? 15 : neighbors;
-	*pos++ = neighbors << 1;
-
-	/* Mesh capability */
-	sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
-	*pos = MESHCONF_CAPAB_FORWARDING;
-	*pos++ |= sdata->u.mesh.accepting_plinks ?
-	    MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
-	*pos++ = 0x00;
-
-	if (sdata->u.mesh.ie) {
-		int len = sdata->u.mesh.ie_len;
-		const u8 *data = sdata->u.mesh.ie;
-		if (skb_tailroom(skb) > len)
-			memcpy(skb_put(skb, len), data, len);
-	}
+	return 0;
 }
 
-
 static void ieee80211_mesh_path_timer(unsigned long data)
 {
 	struct ieee80211_sub_if_data *sdata =
@@ -425,7 +537,8 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
 
 	mesh_path_tx_root_frame(sdata);
 	mod_timer(&ifmsh->mesh_path_root_timer,
-		  round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL));
+		  round_jiffies(TU_TO_EXP_TIME(
+				  ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
 }
 
 #ifdef CONFIG_PM
@@ -433,7 +546,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-	/* use atomic bitops in case both timers fire at the same time */
+	/* use atomic bitops in case all timers fire at the same time */
 
 	if (del_timer_sync(&ifmsh->housekeeping_timer))
 		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -557,11 +670,18 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
 					  struct ieee80211_rx_status *rx_status)
 {
 	switch (mgmt->u.action.category) {
-	case WLAN_CATEGORY_MESH_ACTION:
-		mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+	case WLAN_CATEGORY_SELF_PROTECTED:
+		switch (mgmt->u.action.u.self_prot.action_code) {
+		case WLAN_SP_MESH_PEERING_OPEN:
+		case WLAN_SP_MESH_PEERING_CLOSE:
+		case WLAN_SP_MESH_PEERING_CONFIRM:
+			mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+			break;
+		}
 		break;
-	case WLAN_CATEGORY_MESH_PATH_SEL:
-		mesh_rx_path_sel_frame(sdata, mgmt, len);
+	case WLAN_CATEGORY_MESH_ACTION:
+		if (mesh_action_is_path_sel(mgmt))
+			mesh_rx_path_sel_frame(sdata, mgmt, len);
 		break;
 	}
 }
@@ -633,6 +753,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
 	ifmsh->accepting_plinks = true;
 	ifmsh->preq_id = 0;
 	ifmsh->sn = 0;
+	ifmsh->num_gates = 0;
 	atomic_set(&ifmsh->mpaths, 0);
 	mesh_rmc_init(sdata);
 	ifmsh->last_preq = jiffies;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 249e733362e7b9bf4d48714800ba7da48273832d..20272072171f8c0bf2548fd4d80ede98fa59db5a 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -81,6 +81,7 @@ enum mesh_deferred_task_flags {
  * @discovery_retries: number of discovery retries
  * @flags: mesh path flags, as specified on &enum mesh_path_flags
  * @state_lock: mesh path state lock
+ * @is_gate: the destination station of this path is a mesh gate
  *
  *
  * The combination of dst and sdata is unique in the mesh path table. Since the
@@ -104,6 +105,7 @@ struct mesh_path {
 	u8 discovery_retries;
 	enum mesh_path_flags flags;
 	spinlock_t state_lock;
+	bool is_gate;
 };
 
 /**
@@ -120,6 +122,9 @@ struct mesh_path {
  *	buckets
  * @mean_chain_len: maximum average length for the hash buckets' list, if it is
  *	reached, the table will grow
+ * @known_gates: list of known mesh gates and their mpaths by the station. The
+ * gate's mpath may or may not be resolved and active.
+ *
  * rcu_head: RCU head to free the table
  */
 struct mesh_table {
@@ -133,6 +138,8 @@ struct mesh_table {
 	int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
 	int size_order;
 	int mean_chain_len;
+	struct hlist_head *known_gates;
+	spinlock_t gates_lock;
 
 	struct rcu_head rcu_head;
 };
@@ -166,6 +173,8 @@ struct mesh_rmc {
 	u32 idx_mask;
 };
 
+#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
+#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
 
 #define MESH_DEFAULT_BEACON_INTERVAL		1000 	/* in 1024 us units */
 
@@ -177,14 +186,6 @@ struct mesh_rmc {
 /* Maximum number of paths per interface */
 #define MESH_MAX_MPATHS		1024
 
-/* Pending ANA approval */
-#define MESH_PATH_SEL_ACTION	0
-
-/* PERR reason codes */
-#define PEER_RCODE_UNSPECIFIED  11
-#define PERR_RCODE_NO_ROUTE     12
-#define PERR_RCODE_DEST_UNREACH 13
-
 /* Public interfaces */
 /* Various */
 int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
@@ -199,6 +200,20 @@ bool mesh_matches_local(struct ieee802_11_elems *ie,
 void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
 void mesh_mgmt_ies_add(struct sk_buff *skb,
 		struct ieee80211_sub_if_data *sdata);
+int mesh_add_meshconf_ie(struct sk_buff *skb,
+			 struct ieee80211_sub_if_data *sdata);
+int mesh_add_meshid_ie(struct sk_buff *skb,
+		       struct ieee80211_sub_if_data *sdata);
+int mesh_add_rsn_ie(struct sk_buff *skb,
+		    struct ieee80211_sub_if_data *sdata);
+int mesh_add_vendor_ies(struct sk_buff *skb,
+			struct ieee80211_sub_if_data *sdata);
+int mesh_add_srates_ie(struct sk_buff *skb,
+		       struct ieee80211_sub_if_data *sdata);
+int mesh_add_ext_srates_ie(struct sk_buff *skb,
+			   struct ieee80211_sub_if_data *sdata);
+int mesh_add_ds_params_ie(struct sk_buff *skb,
+			  struct ieee80211_sub_if_data *sdata);
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
@@ -227,6 +242,10 @@ void mesh_path_flush(struct ieee80211_sub_if_data *sdata);
 void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
 		struct ieee80211_mgmt *mgmt, size_t len);
 int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
+
+int mesh_path_add_gate(struct mesh_path *mpath);
+int mesh_path_send_to_gates(struct mesh_path *mpath);
+int mesh_gate_num(struct ieee80211_sub_if_data *sdata);
 /* Mesh plinks */
 void mesh_neighbour_update(u8 *hw_addr, u32 rates,
 		struct ieee80211_sub_if_data *sdata,
@@ -262,6 +281,7 @@ void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
 void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
 void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
 
+bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
 extern int mesh_paths_generation;
 
 #ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 3d8e55ae6ab6fea5fa7b41605a1be66b1d97ae6d..fd4f76a3e139ef3fb88211e058a58b044792a369 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -11,7 +11,8 @@
 #include "mesh.h"
 
 #ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
-#define mhwmp_dbg(fmt, args...)   printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args)
+#define mhwmp_dbg(fmt, args...) \
+	printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
 #else
 #define mhwmp_dbg(fmt, args...)   do { (void)(0); } while (0)
 #endif
@@ -68,12 +69,12 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
 #define PREP_IE_FLAGS(x)	PREQ_IE_FLAGS(x)
 #define PREP_IE_HOPCOUNT(x)	PREQ_IE_HOPCOUNT(x)
 #define PREP_IE_TTL(x)		PREQ_IE_TTL(x)
-#define PREP_IE_ORIG_ADDR(x)	(x + 3)
-#define PREP_IE_ORIG_SN(x)	u32_field_get(x, 9, 0)
+#define PREP_IE_ORIG_ADDR(x)	(AE_F_SET(x) ? x + 27 : x + 21)
+#define PREP_IE_ORIG_SN(x)	u32_field_get(x, 27, AE_F_SET(x))
 #define PREP_IE_LIFETIME(x)	u32_field_get(x, 13, AE_F_SET(x))
 #define PREP_IE_METRIC(x)	u32_field_get(x, 17, AE_F_SET(x))
-#define PREP_IE_TARGET_ADDR(x)	(AE_F_SET(x) ? x + 27 : x + 21)
-#define PREP_IE_TARGET_SN(x)	u32_field_get(x, 27, AE_F_SET(x))
+#define PREP_IE_TARGET_ADDR(x)	(x + 3)
+#define PREP_IE_TARGET_SN(x)	u32_field_get(x, 9, 0)
 
 #define PERR_IE_TTL(x)		(*(x))
 #define PERR_IE_TARGET_FLAGS(x)	(*(x + 2))
@@ -132,24 +133,25 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
 	/* BSSID == SA */
 	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
-	mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
-	mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
+	mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
+	mgmt->u.action.u.mesh_action.action_code =
+					WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
 
 	switch (action) {
 	case MPATH_PREQ:
-		mhwmp_dbg("sending PREQ to %pM\n", target);
+		mhwmp_dbg("sending PREQ to %pM", target);
 		ie_len = 37;
 		pos = skb_put(skb, 2 + ie_len);
 		*pos++ = WLAN_EID_PREQ;
 		break;
 	case MPATH_PREP:
-		mhwmp_dbg("sending PREP to %pM\n", target);
+		mhwmp_dbg("sending PREP to %pM", target);
 		ie_len = 31;
 		pos = skb_put(skb, 2 + ie_len);
 		*pos++ = WLAN_EID_PREP;
 		break;
 	case MPATH_RANN:
-		mhwmp_dbg("sending RANN from %pM\n", orig_addr);
+		mhwmp_dbg("sending RANN from %pM", orig_addr);
 		ie_len = sizeof(struct ieee80211_rann_ie);
 		pos = skb_put(skb, 2 + ie_len);
 		*pos++ = WLAN_EID_RANN;
@@ -163,29 +165,37 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
 	*pos++ = flags;
 	*pos++ = hop_count;
 	*pos++ = ttl;
-	if (action == MPATH_PREQ) {
-		memcpy(pos, &preq_id, 4);
+	if (action == MPATH_PREP) {
+		memcpy(pos, target, ETH_ALEN);
+		pos += ETH_ALEN;
+		memcpy(pos, &target_sn, 4);
 		pos += 4;
-	}
-	memcpy(pos, orig_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	memcpy(pos, &orig_sn, 4);
-	pos += 4;
-	if (action != MPATH_RANN) {
-		memcpy(pos, &lifetime, 4);
+	} else {
+		if (action == MPATH_PREQ) {
+			memcpy(pos, &preq_id, 4);
+			pos += 4;
+		}
+		memcpy(pos, orig_addr, ETH_ALEN);
+		pos += ETH_ALEN;
+		memcpy(pos, &orig_sn, 4);
 		pos += 4;
 	}
+	memcpy(pos, &lifetime, 4);	/* interval for RANN */
+	pos += 4;
 	memcpy(pos, &metric, 4);
 	pos += 4;
 	if (action == MPATH_PREQ) {
-		/* destination count */
-		*pos++ = 1;
+		*pos++ = 1; /* destination count */
 		*pos++ = target_flags;
-	}
-	if (action != MPATH_RANN) {
 		memcpy(pos, target, ETH_ALEN);
 		pos += ETH_ALEN;
 		memcpy(pos, &target_sn, 4);
+		pos += 4;
+	} else if (action == MPATH_PREP) {
+		memcpy(pos, orig_addr, ETH_ALEN);
+		pos += ETH_ALEN;
+		memcpy(pos, &orig_sn, 4);
+		pos += 4;
 	}
 
 	ieee80211_tx_skb(sdata, skb);
@@ -224,9 +234,11 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
 
 	memcpy(mgmt->da, ra, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
-	/* BSSID is left zeroed, wildcard value */
-	mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
-	mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
+	/* BSSID == SA */
+	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
+	mgmt->u.action.u.mesh_action.action_code =
+					WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
 	ie_len = 15;
 	pos = skb_put(skb, 2 + ie_len);
 	*pos++ = WLAN_EID_PERR;
@@ -483,10 +495,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 	orig_sn = PREQ_IE_ORIG_SN(preq_elem);
 	target_flags = PREQ_IE_TARGET_F(preq_elem);
 
-	mhwmp_dbg("received PREQ from %pM\n", orig_addr);
+	mhwmp_dbg("received PREQ from %pM", orig_addr);
 
 	if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
-		mhwmp_dbg("PREQ is for us\n");
+		mhwmp_dbg("PREQ is for us");
 		forward = false;
 		reply = true;
 		metric = 0;
@@ -522,7 +534,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 		lifetime = PREQ_IE_LIFETIME(preq_elem);
 		ttl = ifmsh->mshcfg.element_ttl;
 		if (ttl != 0) {
-			mhwmp_dbg("replying to the PREQ\n");
+			mhwmp_dbg("replying to the PREQ");
 			mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr,
 				cpu_to_le32(target_sn), 0, orig_addr,
 				cpu_to_le32(orig_sn), mgmt->sa, 0, ttl,
@@ -542,7 +554,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 			ifmsh->mshstats.dropped_frames_ttl++;
 			return;
 		}
-		mhwmp_dbg("forwarding the PREQ from %pM\n", orig_addr);
+		mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
 		--ttl;
 		flags = PREQ_IE_FLAGS(preq_elem);
 		preq_id = PREQ_IE_PREQ_ID(preq_elem);
@@ -577,7 +589,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
 	u8 next_hop[ETH_ALEN];
 	u32 target_sn, orig_sn, lifetime;
 
-	mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem));
+	mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
 
 	/* Note that we divert from the draft nomenclature and denominate
 	 * destination to what the draft refers to as origininator. So in this
@@ -683,6 +695,8 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 	u8 ttl, flags, hopcount;
 	u8 *orig_addr;
 	u32 orig_sn, metric;
+	u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+	bool root_is_gate;
 
 	ttl = rann->rann_ttl;
 	if (ttl <= 1) {
@@ -691,12 +705,19 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 	}
 	ttl--;
 	flags = rann->rann_flags;
+	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
 	orig_addr = rann->rann_addr;
 	orig_sn = rann->rann_seq;
 	hopcount = rann->rann_hopcount;
 	hopcount++;
 	metric = rann->rann_metric;
-	mhwmp_dbg("received RANN from %pM\n", orig_addr);
+
+	/*  Ignore our own RANNs */
+	if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
+		return;
+
+	mhwmp_dbg("received RANN from %pM (is_gate=%d)", orig_addr,
+			root_is_gate);
 
 	rcu_read_lock();
 	mpath = mesh_path_lookup(orig_addr, sdata);
@@ -708,18 +729,28 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 			sdata->u.mesh.mshstats.dropped_frames_no_route++;
 			return;
 		}
-		mesh_queue_preq(mpath,
-				PREQ_Q_F_START | PREQ_Q_F_REFRESH);
 	}
+
+	if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
+	     time_after(jiffies, mpath->exp_time - 1*HZ)) &&
+	     !(mpath->flags & MESH_PATH_FIXED)) {
+		mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name,
+							       orig_addr);
+		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+	}
+
 	if (mpath->sn < orig_sn) {
 		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
 				       cpu_to_le32(orig_sn),
 				       0, NULL, 0, broadcast_addr,
-				       hopcount, ttl, 0,
+				       hopcount, ttl, cpu_to_le32(interval),
 				       cpu_to_le32(metric + mpath->metric),
 				       0, sdata);
 		mpath->sn = orig_sn;
 	}
+	if (root_is_gate)
+		mesh_path_add_gate(mpath);
+
 	rcu_read_unlock();
 }
 
@@ -787,7 +818,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 
 	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
 	if (!preq_node) {
-		mhwmp_dbg("could not allocate PREQ node\n");
+		mhwmp_dbg("could not allocate PREQ node");
 		return;
 	}
 
@@ -796,7 +827,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
 		kfree(preq_node);
 		if (printk_ratelimit())
-			mhwmp_dbg("PREQ node queue full\n");
+			mhwmp_dbg("PREQ node queue full");
 		return;
 	}
 
@@ -981,35 +1012,46 @@ void mesh_path_timer(unsigned long data)
 {
 	struct mesh_path *mpath = (void *) data;
 	struct ieee80211_sub_if_data *sdata = mpath->sdata;
+	int ret;
 
 	if (sdata->local->quiescing)
 		return;
 
 	spin_lock_bh(&mpath->state_lock);
 	if (mpath->flags & MESH_PATH_RESOLVED ||
-			(!(mpath->flags & MESH_PATH_RESOLVING)))
+			(!(mpath->flags & MESH_PATH_RESOLVING))) {
 		mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
-	else if (mpath->discovery_retries < max_preq_retries(sdata)) {
+		spin_unlock_bh(&mpath->state_lock);
+	} else if (mpath->discovery_retries < max_preq_retries(sdata)) {
 		++mpath->discovery_retries;
 		mpath->discovery_timeout *= 2;
+		spin_unlock_bh(&mpath->state_lock);
 		mesh_queue_preq(mpath, 0);
 	} else {
 		mpath->flags = 0;
 		mpath->exp_time = jiffies;
-		mesh_path_flush_pending(mpath);
+		spin_unlock_bh(&mpath->state_lock);
+		if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
+			ret = mesh_path_send_to_gates(mpath);
+			if (ret)
+				mhwmp_dbg("no gate was reachable");
+		} else
+			mesh_path_flush_pending(mpath);
 	}
-
-	spin_unlock_bh(&mpath->state_lock);
 }
 
 void
 mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+	u8 flags;
 
-	mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
+	flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
+			? RANN_FLAG_IS_GATE : 0;
+	mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
 			       cpu_to_le32(++ifmsh->sn),
 			       0, NULL, 0, broadcast_addr,
 			       0, sdata->u.mesh.mshcfg.element_ttl,
-			       0, 0, 0, sdata);
+			       cpu_to_le32(interval), 0, 0, sdata);
 }
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index dc7ae8d31aaf2d0ae3ed0b466115a4a5d7568537..7fde32159fdcd1bc077bb9a071575b3920626a9c 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -17,6 +17,12 @@
 #include "ieee80211_i.h"
 #include "mesh.h"
 
+#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
+#define mpath_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args)
+#else
+#define mpath_dbg(fmt, args...)	do { (void)(0); } while (0)
+#endif
+
 /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
 #define INIT_PATHS_SIZE_ORDER	2
 
@@ -60,6 +66,8 @@ static inline struct mesh_table *resize_dereference_mpp_paths(void)
 		lockdep_is_held(&pathtbl_resize_lock));
 }
 
+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath);
+
 /*
  * CAREFUL -- "tbl" must not be an expression,
  * in particular not an rcu_dereference(), since
@@ -103,6 +111,7 @@ static struct mesh_table *mesh_table_alloc(int size_order)
 			sizeof(newtbl->hash_rnd));
 	for (i = 0; i <= newtbl->hash_mask; i++)
 		spin_lock_init(&newtbl->hashwlock[i]);
+	spin_lock_init(&newtbl->gates_lock);
 
 	return newtbl;
 }
@@ -118,6 +127,7 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
 {
 	struct hlist_head *mesh_hash;
 	struct hlist_node *p, *q;
+	struct mpath_node *gate;
 	int i;
 
 	mesh_hash = tbl->hash_buckets;
@@ -129,6 +139,17 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
 		}
 		spin_unlock_bh(&tbl->hashwlock[i]);
 	}
+	if (free_leafs) {
+		spin_lock_bh(&tbl->gates_lock);
+		hlist_for_each_entry_safe(gate, p, q,
+					 tbl->known_gates, list) {
+			hlist_del(&gate->list);
+			kfree(gate);
+		}
+		kfree(tbl->known_gates);
+		spin_unlock_bh(&tbl->gates_lock);
+	}
+
 	__mesh_table_free(tbl);
 }
 
@@ -146,6 +167,7 @@ static int mesh_table_grow(struct mesh_table *oldtbl,
 	newtbl->free_node = oldtbl->free_node;
 	newtbl->mean_chain_len = oldtbl->mean_chain_len;
 	newtbl->copy_node = oldtbl->copy_node;
+	newtbl->known_gates = oldtbl->known_gates;
 	atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
 
 	oldhash = oldtbl->hash_buckets;
@@ -205,6 +227,111 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
 	spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
 }
 
+static void prepare_for_gate(struct sk_buff *skb, char *dst_addr,
+			     struct mesh_path *gate_mpath)
+{
+	struct ieee80211_hdr *hdr;
+	struct ieee80211s_hdr *mshdr;
+	int mesh_hdrlen, hdrlen;
+	char *next_hop;
+
+	hdr = (struct ieee80211_hdr *) skb->data;
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+
+	if (!(mshdr->flags & MESH_FLAGS_AE)) {
+		/* size of the fixed part of the mesh header */
+		mesh_hdrlen = 6;
+
+		/* make room for the two extended addresses */
+		skb_push(skb, 2 * ETH_ALEN);
+		memmove(skb->data, hdr, hdrlen + mesh_hdrlen);
+
+		hdr = (struct ieee80211_hdr *) skb->data;
+
+		/* we preserve the previous mesh header and only add
+		 * the new addreses */
+		mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+		mshdr->flags = MESH_FLAGS_AE_A5_A6;
+		memcpy(mshdr->eaddr1, hdr->addr3, ETH_ALEN);
+		memcpy(mshdr->eaddr2, hdr->addr4, ETH_ALEN);
+	}
+
+	/* update next hop */
+	hdr = (struct ieee80211_hdr *) skb->data;
+	rcu_read_lock();
+	next_hop = rcu_dereference(gate_mpath->next_hop)->sta.addr;
+	memcpy(hdr->addr1, next_hop, ETH_ALEN);
+	rcu_read_unlock();
+	memcpy(hdr->addr3, dst_addr, ETH_ALEN);
+}
+
+/**
+ *
+ * mesh_path_move_to_queue - Move or copy frames from one mpath queue to another
+ *
+ * This function is used to transfer or copy frames from an unresolved mpath to
+ * a gate mpath.  The function also adds the Address Extension field and
+ * updates the next hop.
+ *
+ * If a frame already has an Address Extension field, only the next hop and
+ * destination addresses are updated.
+ *
+ * The gate mpath must be an active mpath with a valid mpath->next_hop.
+ *
+ * @mpath: An active mpath the frames will be sent to (i.e. the gate)
+ * @from_mpath: The failed mpath
+ * @copy: When true, copy all the frames to the new mpath queue.  When false,
+ * move them.
+ */
+static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
+				    struct mesh_path *from_mpath,
+				    bool copy)
+{
+	struct sk_buff *skb, *cp_skb = NULL;
+	struct sk_buff_head gateq, failq;
+	unsigned long flags;
+	int num_skbs;
+
+	BUG_ON(gate_mpath == from_mpath);
+	BUG_ON(!gate_mpath->next_hop);
+
+	__skb_queue_head_init(&gateq);
+	__skb_queue_head_init(&failq);
+
+	spin_lock_irqsave(&from_mpath->frame_queue.lock, flags);
+	skb_queue_splice_init(&from_mpath->frame_queue, &failq);
+	spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
+
+	num_skbs = skb_queue_len(&failq);
+
+	while (num_skbs--) {
+		skb = __skb_dequeue(&failq);
+		if (copy)
+			cp_skb = skb_copy(skb, GFP_ATOMIC);
+
+		prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
+		__skb_queue_tail(&gateq, skb);
+
+		if (copy && cp_skb)
+			__skb_queue_tail(&failq, cp_skb);
+	}
+
+	spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags);
+	skb_queue_splice(&gateq, &gate_mpath->frame_queue);
+	mpath_dbg("Mpath queue for gate %pM has %d frames\n",
+			gate_mpath->dst,
+			skb_queue_len(&gate_mpath->frame_queue));
+	spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags);
+
+	if (!copy)
+		return;
+
+	spin_lock_irqsave(&from_mpath->frame_queue.lock, flags);
+	skb_queue_splice(&failq, &from_mpath->frame_queue);
+	spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
+}
+
 
 /**
  * mesh_path_lookup - look up a path in the mesh path table
@@ -304,6 +431,109 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
 	return NULL;
 }
 
+static void mesh_gate_node_reclaim(struct rcu_head *rp)
+{
+	struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+	kfree(node);
+}
+
+/**
+ * mesh_gate_add - mark mpath as path to a mesh gate and add to known_gates
+ * @mesh_tbl: table which contains known_gates list
+ * @mpath: mpath to known mesh gate
+ *
+ * Returns: 0 on success
+ *
+ */
+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath)
+{
+	struct mpath_node *gate, *new_gate;
+	struct hlist_node *n;
+	int err;
+
+	rcu_read_lock();
+	tbl = rcu_dereference(tbl);
+
+	hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list)
+		if (gate->mpath == mpath) {
+			err = -EEXIST;
+			goto err_rcu;
+		}
+
+	new_gate = kzalloc(sizeof(struct mpath_node), GFP_ATOMIC);
+	if (!new_gate) {
+		err = -ENOMEM;
+		goto err_rcu;
+	}
+
+	mpath->is_gate = true;
+	mpath->sdata->u.mesh.num_gates++;
+	new_gate->mpath = mpath;
+	spin_lock_bh(&tbl->gates_lock);
+	hlist_add_head_rcu(&new_gate->list, tbl->known_gates);
+	spin_unlock_bh(&tbl->gates_lock);
+	rcu_read_unlock();
+	mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates\n",
+		  mpath->sdata->name, mpath->dst,
+		  mpath->sdata->u.mesh.num_gates);
+	return 0;
+err_rcu:
+	rcu_read_unlock();
+	return err;
+}
+
+/**
+ * mesh_gate_del - remove a mesh gate from the list of known gates
+ * @tbl: table which holds our list of known gates
+ * @mpath: gate mpath
+ *
+ * Returns: 0 on success
+ *
+ * Locking: must be called inside rcu_read_lock() section
+ */
+static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
+{
+	struct mpath_node *gate;
+	struct hlist_node *p, *q;
+
+	tbl = rcu_dereference(tbl);
+
+	hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list)
+		if (gate->mpath == mpath) {
+			spin_lock_bh(&tbl->gates_lock);
+			hlist_del_rcu(&gate->list);
+			call_rcu(&gate->rcu, mesh_gate_node_reclaim);
+			spin_unlock_bh(&tbl->gates_lock);
+			mpath->sdata->u.mesh.num_gates--;
+			mpath->is_gate = false;
+			mpath_dbg("Mesh path (%s): Deleted gate: %pM. "
+				  "%d known gates\n", mpath->sdata->name,
+				  mpath->dst, mpath->sdata->u.mesh.num_gates);
+			break;
+		}
+
+	return 0;
+}
+
+/**
+ *
+ * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
+ * @mpath: gate path to add to table
+ */
+int mesh_path_add_gate(struct mesh_path *mpath)
+{
+	return mesh_gate_add(mesh_paths, mpath);
+}
+
+/**
+ * mesh_gate_num - number of gates known to this interface
+ * @sdata: subif data
+ */
+int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
+{
+	return sdata->u.mesh.num_gates;
+}
+
 /**
  * mesh_path_add - allocate and add a new path to the mesh path table
  * @addr: destination address of the path (ETH_ALEN length)
@@ -481,6 +711,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 	new_mpath->flags = 0;
 	skb_queue_head_init(&new_mpath->frame_queue);
 	new_node->mpath = new_mpath;
+	init_timer(&new_mpath->timer);
 	new_mpath->exp_time = jiffies;
 	spin_lock_init(&new_mpath->state_lock);
 
@@ -539,6 +770,7 @@ void mesh_plink_broken(struct sta_info *sta)
 	struct hlist_node *p;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	int i;
+	__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
 
 	rcu_read_lock();
 	tbl = rcu_dereference(mesh_paths);
@@ -553,8 +785,7 @@ void mesh_plink_broken(struct sta_info *sta)
 			spin_unlock_bh(&mpath->state_lock);
 			mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
 					mpath->dst, cpu_to_le32(mpath->sn),
-					cpu_to_le16(PERR_RCODE_DEST_UNREACH),
-					bcast, sdata);
+					reason, bcast, sdata);
 		} else
 		spin_unlock_bh(&mpath->state_lock);
 	}
@@ -647,12 +878,14 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
 		mpath = node->mpath;
 		if (mpath->sdata == sdata &&
 		    memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
-			spin_lock(&mpath->state_lock);
+			spin_lock_bh(&mpath->state_lock);
+			if (mpath->is_gate)
+				mesh_gate_del(tbl, mpath);
 			mpath->flags |= MESH_PATH_RESOLVING;
 			hlist_del_rcu(&node->list);
 			call_rcu(&node->rcu, mesh_path_node_reclaim);
 			atomic_dec(&tbl->entries);
-			spin_unlock(&mpath->state_lock);
+			spin_unlock_bh(&mpath->state_lock);
 			goto enddel;
 		}
 	}
@@ -680,6 +913,58 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
 				&mpath->frame_queue);
 }
 
+/**
+ * mesh_path_send_to_gates - sends pending frames to all known mesh gates
+ *
+ * @mpath: mesh path whose queue will be emptied
+ *
+ * If there is only one gate, the frames are transferred from the failed mpath
+ * queue to that gate's queue.  If there are more than one gates, the frames
+ * are copied from each gate to the next.  After frames are copied, the
+ * mpath queues are emptied onto the transmission queue.
+ */
+int mesh_path_send_to_gates(struct mesh_path *mpath)
+{
+	struct ieee80211_sub_if_data *sdata = mpath->sdata;
+	struct hlist_node *n;
+	struct mesh_table *tbl;
+	struct mesh_path *from_mpath = mpath;
+	struct mpath_node *gate = NULL;
+	bool copy = false;
+	struct hlist_head *known_gates;
+
+	rcu_read_lock();
+	tbl = rcu_dereference(mesh_paths);
+	known_gates = tbl->known_gates;
+	rcu_read_unlock();
+
+	if (!known_gates)
+		return -EHOSTUNREACH;
+
+	hlist_for_each_entry_rcu(gate, n, known_gates, list) {
+		if (gate->mpath->sdata != sdata)
+			continue;
+
+		if (gate->mpath->flags & MESH_PATH_ACTIVE) {
+			mpath_dbg("Forwarding to %pM\n", gate->mpath->dst);
+			mesh_path_move_to_queue(gate->mpath, from_mpath, copy);
+			from_mpath = gate->mpath;
+			copy = true;
+		} else {
+			mpath_dbg("Not forwarding %p\n", gate->mpath);
+			mpath_dbg("flags %x\n", gate->mpath->flags);
+		}
+	}
+
+	hlist_for_each_entry_rcu(gate, n, known_gates, list)
+		if (gate->mpath->sdata == sdata) {
+			mpath_dbg("Sending to %pM\n", gate->mpath->dst);
+			mesh_path_tx_pending(gate->mpath);
+		}
+
+	return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
+}
+
 /**
  * mesh_path_discard_frame - discard a frame whose path could not be resolved
  *
@@ -699,6 +984,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct mesh_path *mpath;
 	u32 sn = 0;
+	__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
 
 	if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
 		u8 *ra, *da;
@@ -709,8 +995,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
 		if (mpath)
 			sn = ++mpath->sn;
 		mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data,
-				   cpu_to_le32(sn),
-				   cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
+				   cpu_to_le32(sn), reason, ra, sdata);
 	}
 
 	kfree_skb(skb);
@@ -728,8 +1013,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath)
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
-			(mpath->flags & MESH_PATH_ACTIVE))
+	while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
 		mesh_path_discard_frame(skb, mpath->sdata);
 }
 
@@ -797,6 +1081,9 @@ int mesh_pathtbl_init(void)
 	tbl_path->free_node = &mesh_path_node_free;
 	tbl_path->copy_node = &mesh_path_node_copy;
 	tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
+	tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+	INIT_HLIST_HEAD(tbl_path->known_gates);
+
 
 	tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
 	if (!tbl_mpp) {
@@ -806,6 +1093,8 @@ int mesh_pathtbl_init(void)
 	tbl_mpp->free_node = &mesh_path_node_free;
 	tbl_mpp->copy_node = &mesh_path_node_copy;
 	tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
+	tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+	INIT_HLIST_HEAD(tbl_mpp->known_gates);
 
 	/* Need no locking since this is during init */
 	RCU_INIT_POINTER(mesh_paths, tbl_path);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index f4adc0917888d61f6ea033063af41b4c41f60f40..1a00d0f701c36f64c3c6b99589044ae9b945a346 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -19,35 +19,18 @@
 #define mpl_dbg(fmt, args...)	do { (void)(0); } while (0)
 #endif
 
-#define PLINK_GET_LLID(p) (p + 4)
-#define PLINK_GET_PLID(p) (p + 6)
+#define PLINK_GET_LLID(p) (p + 2)
+#define PLINK_GET_PLID(p) (p + 4)
 
 #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
 				jiffies + HZ * t / 1000))
 
-/* Peer link cancel reasons, all subject to ANA approval */
-#define MESH_LINK_CANCELLED			2
-#define MESH_MAX_NEIGHBORS			3
-#define MESH_CAPABILITY_POLICY_VIOLATION	4
-#define MESH_CLOSE_RCVD				5
-#define MESH_MAX_RETRIES			6
-#define MESH_CONFIRM_TIMEOUT			7
-#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS	8
-#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE	9
-#define MESH_SECURITY_FAILED_VERIFICATION	10
-
 #define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
 #define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
 #define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
 #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
 #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
 
-enum plink_frame_type {
-	PLINK_OPEN = 1,
-	PLINK_CONFIRM,
-	PLINK_CLOSE
-};
-
 enum plink_event {
 	PLINK_UNDEFINED,
 	OPN_ACPT,
@@ -157,16 +140,16 @@ void mesh_plink_deactivate(struct sta_info *sta)
 }
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
-		enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
-		__le16 reason) {
+		enum ieee80211_self_protected_actioncode action,
+		u8 *da, __le16 llid, __le16 plid, __le16 reason) {
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
 			sdata->u.mesh.ie_len);
 	struct ieee80211_mgmt *mgmt;
 	bool include_plid = false;
-	static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
+	int ie_len = 4;
+	u16 peering_proto = 0;
 	u8 *pos;
-	int ie_len;
 
 	if (!skb)
 		return -1;
@@ -175,63 +158,75 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 	 * common action part (1)
 	 */
 	mgmt = (struct ieee80211_mgmt *)
-		skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
-	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
+		skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot));
+	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 					  IEEE80211_STYPE_ACTION);
 	memcpy(mgmt->da, da, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
 	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
-	mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
-	mgmt->u.action.u.plink_action.action_code = action;
-
-	if (action == PLINK_CLOSE)
-		mgmt->u.action.u.plink_action.aux = reason;
-	else {
-		mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
-		if (action == PLINK_CONFIRM) {
-			pos = skb_put(skb, 4);
-			/* two-byte status code followed by two-byte AID */
-			memset(pos, 0, 2);
+	mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
+	mgmt->u.action.u.self_prot.action_code = action;
+
+	if (action != WLAN_SP_MESH_PEERING_CLOSE) {
+		/* capability info */
+		pos = skb_put(skb, 2);
+		memset(pos, 0, 2);
+		if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
+			/* AID */
+			pos = skb_put(skb, 2);
 			memcpy(pos + 2, &plid, 2);
 		}
-		mesh_mgmt_ies_add(skb, sdata);
+		if (mesh_add_srates_ie(skb, sdata) ||
+		    mesh_add_ext_srates_ie(skb, sdata) ||
+		    mesh_add_rsn_ie(skb, sdata) ||
+		    mesh_add_meshid_ie(skb, sdata) ||
+		    mesh_add_meshconf_ie(skb, sdata))
+			return -1;
+	} else {	/* WLAN_SP_MESH_PEERING_CLOSE */
+		if (mesh_add_meshid_ie(skb, sdata))
+			return -1;
 	}
 
-	/* Add Peer Link Management element */
+	/* Add Mesh Peering Management element */
 	switch (action) {
-	case PLINK_OPEN:
-		ie_len = 6;
+	case WLAN_SP_MESH_PEERING_OPEN:
 		break;
-	case PLINK_CONFIRM:
-		ie_len = 8;
+	case WLAN_SP_MESH_PEERING_CONFIRM:
+		ie_len += 2;
 		include_plid = true;
 		break;
-	case PLINK_CLOSE:
-	default:
-		if (!plid)
-			ie_len = 8;
-		else {
-			ie_len = 10;
+	case WLAN_SP_MESH_PEERING_CLOSE:
+		if (plid) {
+			ie_len += 2;
 			include_plid = true;
 		}
+		ie_len += 2;	/* reason code */
 		break;
+	default:
+		return -EINVAL;
 	}
 
+	if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
+		return -ENOMEM;
+
 	pos = skb_put(skb, 2 + ie_len);
-	*pos++ = WLAN_EID_PEER_LINK;
+	*pos++ = WLAN_EID_PEER_MGMT;
 	*pos++ = ie_len;
-	memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto));
-	pos += 4;
+	memcpy(pos, &peering_proto, 2);
+	pos += 2;
 	memcpy(pos, &llid, 2);
+	pos += 2;
 	if (include_plid) {
-		pos += 2;
 		memcpy(pos, &plid, 2);
-	}
-	if (action == PLINK_CLOSE) {
 		pos += 2;
+	}
+	if (action == WLAN_SP_MESH_PEERING_CLOSE) {
 		memcpy(pos, &reason, 2);
+		pos += 2;
 	}
+	if (mesh_add_vendor_ies(skb, sdata))
+		return -1;
 
 	ieee80211_tx_skb(sdata, skb);
 	return 0;
@@ -322,21 +317,21 @@ static void mesh_plink_timer(unsigned long data)
 			++sta->plink_retries;
 			mod_plink_timer(sta, sta->plink_timeout);
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
-					    0, 0);
+			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
+					    sta->sta.addr, llid, 0, 0);
 			break;
 		}
-		reason = cpu_to_le16(MESH_MAX_RETRIES);
+		reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
 		/* fall through on else */
 	case NL80211_PLINK_CNF_RCVD:
 		/* confirm timer */
 		if (!reason)
-			reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
+			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
 		sta->plink_state = NL80211_PLINK_HOLDING;
 		mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
 		spin_unlock_bh(&sta->lock);
-		mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid,
-				    reason);
+		mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+				    sta->sta.addr, llid, plid, reason);
 		break;
 	case NL80211_PLINK_HOLDING:
 		/* holding timer */
@@ -396,7 +391,7 @@ int mesh_plink_open(struct sta_info *sta)
 	mpl_dbg("Mesh plink: starting establishment with %pM\n",
 		sta->sta.addr);
 
-	return mesh_plink_frame_tx(sdata, PLINK_OPEN,
+	return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
 				   sta->sta.addr, llid, 0, 0);
 }
 
@@ -422,7 +417,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 	struct ieee802_11_elems elems;
 	struct sta_info *sta;
 	enum plink_event event;
-	enum plink_frame_type ftype;
+	enum ieee80211_self_protected_actioncode ftype;
 	size_t baselen;
 	bool deactivated, matches_local = true;
 	u8 ie_len;
@@ -449,14 +444,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 		return;
 	}
 
-	baseaddr = mgmt->u.action.u.plink_action.variable;
-	baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
-	if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
+	baseaddr = mgmt->u.action.u.self_prot.variable;
+	baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
+	if (mgmt->u.action.u.self_prot.action_code ==
+						WLAN_SP_MESH_PEERING_CONFIRM) {
 		baseaddr += 4;
 		baselen += 4;
 	}
 	ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
-	if (!elems.peer_link) {
+	if (!elems.peering) {
 		mpl_dbg("Mesh plink: missing necessary peer link ie\n");
 		return;
 	}
@@ -466,31 +462,34 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 		return;
 	}
 
-	ftype = mgmt->u.action.u.plink_action.action_code;
-	ie_len = elems.peer_link_len;
-	if ((ftype == PLINK_OPEN && ie_len != 6) ||
-	    (ftype == PLINK_CONFIRM && ie_len != 8) ||
-	    (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) {
+	ftype = mgmt->u.action.u.self_prot.action_code;
+	ie_len = elems.peering_len;
+	if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
+	    (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
+	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
+							&& ie_len != 8)) {
 		mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
 		    ftype, ie_len);
 		return;
 	}
 
-	if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
+	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
+				(!elems.mesh_id || !elems.mesh_config)) {
 		mpl_dbg("Mesh plink: missing necessary ie\n");
 		return;
 	}
 	/* Note the lines below are correct, the llid in the frame is the plid
 	 * from the point of view of this host.
 	 */
-	memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
-	if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10))
-		memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
+	memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
+	if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
+	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
+		memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
 
 	rcu_read_lock();
 
 	sta = sta_info_get(sdata, mgmt->sa);
-	if (!sta && ftype != PLINK_OPEN) {
+	if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
 		mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
 		rcu_read_unlock();
 		return;
@@ -509,30 +508,30 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
 	/* Now we will figure out the appropriate event... */
 	event = PLINK_UNDEFINED;
-	if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) {
+	if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
+	    (!mesh_matches_local(&elems, sdata))) {
 		matches_local = false;
 		switch (ftype) {
-		case PLINK_OPEN:
+		case WLAN_SP_MESH_PEERING_OPEN:
 			event = OPN_RJCT;
 			break;
-		case PLINK_CONFIRM:
+		case WLAN_SP_MESH_PEERING_CONFIRM:
 			event = CNF_RJCT;
 			break;
-		case PLINK_CLOSE:
-			/* avoid warning */
+		default:
 			break;
 		}
 	}
 
 	if (!sta && !matches_local) {
 		rcu_read_unlock();
-		reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+		reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
 		llid = 0;
-		mesh_plink_frame_tx(sdata, PLINK_CLOSE, mgmt->sa, llid,
-				    plid, reason);
+		mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+				    mgmt->sa, llid, plid, reason);
 		return;
 	} else if (!sta) {
-		/* ftype == PLINK_OPEN */
+		/* ftype == WLAN_SP_MESH_PEERING_OPEN */
 		u32 rates;
 
 		rcu_read_unlock();
@@ -557,21 +556,21 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 	} else if (matches_local) {
 		spin_lock_bh(&sta->lock);
 		switch (ftype) {
-		case PLINK_OPEN:
+		case WLAN_SP_MESH_PEERING_OPEN:
 			if (!mesh_plink_free_count(sdata) ||
 			    (sta->plid && sta->plid != plid))
 				event = OPN_IGNR;
 			else
 				event = OPN_ACPT;
 			break;
-		case PLINK_CONFIRM:
+		case WLAN_SP_MESH_PEERING_CONFIRM:
 			if (!mesh_plink_free_count(sdata) ||
 			    (sta->llid != llid || sta->plid != plid))
 				event = CNF_IGNR;
 			else
 				event = CNF_ACPT;
 			break;
-		case PLINK_CLOSE:
+		case WLAN_SP_MESH_PEERING_CLOSE:
 			if (sta->plink_state == NL80211_PLINK_ESTAB)
 				/* Do not check for llid or plid. This does not
 				 * follow the standard but since multiple plinks
@@ -620,10 +619,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 			sta->llid = llid;
 			mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
-					    0, 0);
-			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr,
-					    llid, plid, 0);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_OPEN,
+					    sta->sta.addr, llid, 0, 0);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_CONFIRM,
+					    sta->sta.addr, llid, plid, 0);
 			break;
 		default:
 			spin_unlock_bh(&sta->lock);
@@ -635,10 +636,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 		switch (event) {
 		case OPN_RJCT:
 		case CNF_RJCT:
-			reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
 		case CLS_ACPT:
 			if (!reason)
-				reason = cpu_to_le16(MESH_CLOSE_RCVD);
+				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
 			sta->reason = reason;
 			sta->plink_state = NL80211_PLINK_HOLDING;
 			if (!mod_plink_timer(sta,
@@ -647,8 +648,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
-					    plid, reason);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_CLOSE,
+					    sta->sta.addr, llid, plid, reason);
 			break;
 		case OPN_ACPT:
 			/* retry timer is left untouched */
@@ -656,8 +658,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 			sta->plid = plid;
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
-					    plid, 0);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_CONFIRM,
+					    sta->sta.addr, llid, plid, 0);
 			break;
 		case CNF_ACPT:
 			sta->plink_state = NL80211_PLINK_CNF_RCVD;
@@ -677,10 +680,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 		switch (event) {
 		case OPN_RJCT:
 		case CNF_RJCT:
-			reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
 		case CLS_ACPT:
 			if (!reason)
-				reason = cpu_to_le16(MESH_CLOSE_RCVD);
+				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
 			sta->reason = reason;
 			sta->plink_state = NL80211_PLINK_HOLDING;
 			if (!mod_plink_timer(sta,
@@ -689,14 +692,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
-					    plid, reason);
+			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+					    sta->sta.addr, llid, plid, reason);
 			break;
 		case OPN_ACPT:
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
-					    plid, 0);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_CONFIRM,
+					    sta->sta.addr, llid, plid, 0);
 			break;
 		case CNF_ACPT:
 			del_timer(&sta->plink_timer);
@@ -717,10 +721,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 		switch (event) {
 		case OPN_RJCT:
 		case CNF_RJCT:
-			reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+			reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
 		case CLS_ACPT:
 			if (!reason)
-				reason = cpu_to_le16(MESH_CLOSE_RCVD);
+				reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
 			sta->reason = reason;
 			sta->plink_state = NL80211_PLINK_HOLDING;
 			if (!mod_plink_timer(sta,
@@ -729,8 +733,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
-					    plid, reason);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_CLOSE,
+					    sta->sta.addr, llid, plid, reason);
 			break;
 		case OPN_ACPT:
 			del_timer(&sta->plink_timer);
@@ -740,8 +745,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 			ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 			mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
 				sta->sta.addr);
-			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
-					    plid, 0);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_CONFIRM,
+					    sta->sta.addr, llid, plid, 0);
 			break;
 		default:
 			spin_unlock_bh(&sta->lock);
@@ -752,7 +758,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 	case NL80211_PLINK_ESTAB:
 		switch (event) {
 		case CLS_ACPT:
-			reason = cpu_to_le16(MESH_CLOSE_RCVD);
+			reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
 			sta->reason = reason;
 			deactivated = __mesh_plink_deactivate(sta);
 			sta->plink_state = NL80211_PLINK_HOLDING;
@@ -761,14 +767,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 			spin_unlock_bh(&sta->lock);
 			if (deactivated)
 				ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
-			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
-					    plid, reason);
+			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+					    sta->sta.addr, llid, plid, reason);
 			break;
 		case OPN_ACPT:
 			llid = sta->llid;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
-					    plid, 0);
+			mesh_plink_frame_tx(sdata,
+					    WLAN_SP_MESH_PEERING_CONFIRM,
+					    sta->sta.addr, llid, plid, 0);
 			break;
 		default:
 			spin_unlock_bh(&sta->lock);
@@ -790,8 +797,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 			llid = sta->llid;
 			reason = sta->reason;
 			spin_unlock_bh(&sta->lock);
-			mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr,
-					    llid, plid, reason);
+			mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+					    sta->sta.addr, llid, plid, reason);
 			break;
 		default:
 			spin_unlock_bh(&sta->lock);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d6470c7fd6ce34cd226632a30fac0e0be6c7f71f..60a6f273cd3060293a3b601e76a8dfaa355e865a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1482,10 +1482,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
 
 	ifmgd->aid = aid;
 
-	sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
-	if (!sta) {
-		printk(KERN_DEBUG "%s: failed to alloc STA entry for"
-		       " the AP\n", sdata->name);
+	mutex_lock(&sdata->local->sta_mtx);
+	/*
+	 * station info was already allocated and inserted before
+	 * the association and should be available to us
+	 */
+	sta = sta_info_get_rx(sdata, cbss->bssid);
+	if (WARN_ON(!sta)) {
+		mutex_unlock(&sdata->local->sta_mtx);
 		return false;
 	}
 
@@ -1556,7 +1560,8 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
 	if (elems.wmm_param)
 		set_sta_flags(sta, WLAN_STA_WME);
 
-	err = sta_info_insert(sta);
+	/* sta_info_reinsert will also unlock the mutex lock */
+	err = sta_info_reinsert(sta);
 	sta = NULL;
 	if (err) {
 		printk(KERN_DEBUG "%s: failed to insert STA entry for"
@@ -2429,6 +2434,32 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 	return 0;
 }
 
+/* create and insert a dummy station entry */
+static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata,
+				u8 *bssid) {
+	struct sta_info *sta;
+	int err;
+
+	sta = sta_info_alloc(sdata, bssid, GFP_KERNEL);
+	if (!sta) {
+		printk(KERN_DEBUG "%s: failed to alloc STA entry for"
+			   " the AP\n", sdata->name);
+		return -ENOMEM;
+	}
+
+	sta->dummy = true;
+
+	err = sta_info_insert(sta);
+	sta = NULL;
+	if (err) {
+		printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for"
+		       " the AP (error %d)\n", sdata->name, err);
+		return err;
+	}
+
+	return 0;
+}
+
 static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
 						  struct sk_buff *skb)
 {
@@ -2436,9 +2467,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
 	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_rx_status *rx_status;
 	struct ieee802_11_elems elems;
+	struct cfg80211_bss *cbss = wk->assoc.bss;
 	u16 status;
 
 	if (!skb) {
+		sta_info_destroy_addr(wk->sdata, cbss->bssid);
 		cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta);
 		goto destroy;
 	}
@@ -2468,12 +2501,16 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
 		if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {
 			mutex_unlock(&wk->sdata->u.mgd.mtx);
 			/* oops -- internal error -- send timeout for now */
+			sta_info_destroy_addr(wk->sdata, cbss->bssid);
 			cfg80211_send_assoc_timeout(wk->sdata->dev,
 						    wk->filter_ta);
 			return WORK_DONE_DESTROY;
 		}
 
 		mutex_unlock(&wk->sdata->u.mgd.mtx);
+	} else {
+		/* assoc failed - destroy the dummy station entry */
+		sta_info_destroy_addr(wk->sdata, cbss->bssid);
 	}
 
 	cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
@@ -2492,7 +2529,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_bss *bss = (void *)req->bss->priv;
 	struct ieee80211_work *wk;
 	const u8 *ssid;
-	int i;
+	int i, err;
 
 	mutex_lock(&ifmgd->mtx);
 	if (ifmgd->associated) {
@@ -2517,6 +2554,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	if (!wk)
 		return -ENOMEM;
 
+	/*
+	 * create a dummy station info entry in order
+	 * to start accepting incoming EAPOL packets from the station
+	 */
+	err = ieee80211_pre_assoc(sdata, req->bss->bssid);
+	if (err) {
+		kfree(wk);
+		return err;
+	}
+
 	ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
 	ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fe2c2a7177930b2f7df8c42d81eac9987956c761..f45fd2fedc2415b6f5f68a58b2c00439dc4a71e6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -850,8 +850,21 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
 		      ieee80211_is_pspoll(hdr->frame_control)) &&
 		     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 		     rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
-		     (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC))))
+		     (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
+		if (rx->sta && rx->sta->dummy &&
+		    ieee80211_is_data_present(hdr->frame_control)) {
+			u16 ethertype;
+			u8 *payload;
+
+			payload = rx->skb->data +
+				ieee80211_hdrlen(hdr->frame_control);
+			ethertype = (payload[6] << 8) | payload[7];
+			if (cpu_to_be16(ethertype) ==
+			    rx->sdata->control_port_protocol)
+				return RX_CONTINUE;
+		}
 		return RX_DROP_MONITOR;
+	}
 
 	return RX_CONTINUE;
 }
@@ -2220,12 +2233,29 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 			goto handled;
 		}
 		break;
+	case WLAN_CATEGORY_SELF_PROTECTED:
+		switch (mgmt->u.action.u.self_prot.action_code) {
+		case WLAN_SP_MESH_PEERING_OPEN:
+		case WLAN_SP_MESH_PEERING_CLOSE:
+		case WLAN_SP_MESH_PEERING_CONFIRM:
+			if (!ieee80211_vif_is_mesh(&sdata->vif))
+				goto invalid;
+			if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+				/* userspace handles this frame */
+				break;
+			goto queue;
+		case WLAN_SP_MGK_INFORM:
+		case WLAN_SP_MGK_ACK:
+			if (!ieee80211_vif_is_mesh(&sdata->vif))
+				goto invalid;
+			break;
+		}
+		break;
 	case WLAN_CATEGORY_MESH_ACTION:
 		if (!ieee80211_vif_is_mesh(&sdata->vif))
 			break;
-		goto queue;
-	case WLAN_CATEGORY_MESH_PATH_SEL:
-		if (!mesh_path_sel_is_hwmp(sdata))
+		if (mesh_action_is_path_sel(mgmt) &&
+		  (!mesh_path_sel_is_hwmp(sdata)))
 			break;
 		goto queue;
 	}
@@ -2686,7 +2716,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
 		} else if (!ieee80211_bssid_match(bssid,
 					sdata->vif.addr)) {
 			if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
-			    !ieee80211_is_beacon(hdr->frame_control))
+			    !ieee80211_is_beacon(hdr->frame_control) &&
+			    !(ieee80211_is_action(hdr->frame_control) &&
+			      sdata->vif.p2p))
 				return 0;
 			status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
 		}
@@ -2791,7 +2823,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 	if (ieee80211_is_data(fc)) {
 		prev_sta = NULL;
 
-		for_each_sta_info(local, hdr->addr2, sta, tmp) {
+		for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
 			if (!prev_sta) {
 				prev_sta = sta;
 				continue;
@@ -2835,7 +2867,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 			continue;
 		}
 
-		rx.sta = sta_info_get_bss(prev, hdr->addr2);
+		rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
 		rx.sdata = prev;
 		ieee80211_prepare_and_rx_handle(&rx, skb, false);
 
@@ -2843,7 +2875,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 	}
 
 	if (prev) {
-		rx.sta = sta_info_get_bss(prev, hdr->addr2);
+		rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
 		rx.sdata = prev;
 
 		if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 0bdbf3b8f28b466648f2c5c38b2204f0fc042580..6bc17fb80ee90403e2a91829be237db472971c8a 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -96,6 +96,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 
+	sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
+				    lockdep_is_held(&local->sta_lock) ||
+				    lockdep_is_held(&local->sta_mtx));
+	while (sta) {
+		if (sta->sdata == sdata && !sta->dummy &&
+		    memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+			break;
+		sta = rcu_dereference_check(sta->hnext,
+					    lockdep_is_held(&local->sta_lock) ||
+					    lockdep_is_held(&local->sta_mtx));
+	}
+	return sta;
+}
+
+/* get a station info entry even if it is a dummy station*/
+struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
+			      const u8 *addr)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+
 	sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
 				    lockdep_is_held(&local->sta_lock) ||
 				    lockdep_is_held(&local->sta_mtx));
@@ -120,6 +141,32 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 
+	sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
+				    lockdep_is_held(&local->sta_lock) ||
+				    lockdep_is_held(&local->sta_mtx));
+	while (sta) {
+		if ((sta->sdata == sdata ||
+		     (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
+		    !sta->dummy &&
+		    memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+			break;
+		sta = rcu_dereference_check(sta->hnext,
+					    lockdep_is_held(&local->sta_lock) ||
+					    lockdep_is_held(&local->sta_mtx));
+	}
+	return sta;
+}
+
+/*
+ * Get sta info either from the specified interface
+ * or from one of its vlans (including dummy stations)
+ */
+struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
+				  const u8 *addr)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+
 	sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
 				    lockdep_is_held(&local->sta_lock) ||
 				    lockdep_is_held(&local->sta_mtx));
@@ -280,7 +327,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 	return sta;
 }
 
-static int sta_info_finish_insert(struct sta_info *sta, bool async)
+static int sta_info_finish_insert(struct sta_info *sta,
+				bool async, bool dummy_reinsert)
 {
 	struct ieee80211_local *local = sta->local;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -290,51 +338,58 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
 
 	lockdep_assert_held(&local->sta_mtx);
 
-	/* notify driver */
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-		sdata = container_of(sdata->bss,
-				     struct ieee80211_sub_if_data,
-				     u.ap);
-	err = drv_sta_add(local, sdata, &sta->sta);
-	if (err) {
-		if (!async)
-			return err;
-		printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)"
-				  " - keeping it anyway.\n",
-		       sdata->name, sta->sta.addr, err);
-	} else {
-		sta->uploaded = true;
+	if (!sta->dummy || dummy_reinsert) {
+		/* notify driver */
+		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+			sdata = container_of(sdata->bss,
+					     struct ieee80211_sub_if_data,
+					     u.ap);
+		err = drv_sta_add(local, sdata, &sta->sta);
+		if (err) {
+			if (!async)
+				return err;
+			printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
+					  "driver (%d) - keeping it anyway.\n",
+			       sdata->name, sta->sta.addr, err);
+		} else {
+			sta->uploaded = true;
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (async)
-			wiphy_debug(local->hw.wiphy,
-				    "Finished adding IBSS STA %pM\n",
-				    sta->sta.addr);
+			if (async)
+				wiphy_debug(local->hw.wiphy,
+					    "Finished adding IBSS STA %pM\n",
+					    sta->sta.addr);
 #endif
+		}
+
+		sdata = sta->sdata;
 	}
 
-	sdata = sta->sdata;
+	if (!dummy_reinsert) {
+		if (!async) {
+			local->num_sta++;
+			local->sta_generation++;
+			smp_mb();
 
-	if (!async) {
-		local->num_sta++;
-		local->sta_generation++;
-		smp_mb();
+			/* make the station visible */
+			spin_lock_irqsave(&local->sta_lock, flags);
+			sta_info_hash_add(local, sta);
+			spin_unlock_irqrestore(&local->sta_lock, flags);
+		}
 
-		/* make the station visible */
-		spin_lock_irqsave(&local->sta_lock, flags);
-		sta_info_hash_add(local, sta);
-		spin_unlock_irqrestore(&local->sta_lock, flags);
+		list_add(&sta->list, &local->sta_list);
+	} else {
+		sta->dummy = false;
 	}
 
-	list_add(&sta->list, &local->sta_list);
-
-	ieee80211_sta_debugfs_add(sta);
-	rate_control_add_sta_debugfs(sta);
-
-	memset(&sinfo, 0, sizeof(sinfo));
-	sinfo.filled = 0;
-	sinfo.generation = local->sta_generation;
-	cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+	if (!sta->dummy) {
+		ieee80211_sta_debugfs_add(sta);
+		rate_control_add_sta_debugfs(sta);
 
+		memset(&sinfo, 0, sizeof(sinfo));
+		sinfo.filled = 0;
+		sinfo.generation = local->sta_generation;
+		cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+	}
 
 	return 0;
 }
@@ -351,7 +406,7 @@ static void sta_info_finish_pending(struct ieee80211_local *local)
 		list_del(&sta->list);
 		spin_unlock_irqrestore(&local->sta_lock, flags);
 
-		sta_info_finish_insert(sta, true);
+		sta_info_finish_insert(sta, true, false);
 
 		spin_lock_irqsave(&local->sta_lock, flags);
 	}
@@ -368,106 +423,117 @@ static void sta_info_finish_work(struct work_struct *work)
 	mutex_unlock(&local->sta_mtx);
 }
 
-int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
+static int sta_info_insert_check(struct sta_info *sta)
 {
-	struct ieee80211_local *local = sta->local;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
-	unsigned long flags;
-	int err = 0;
 
 	/*
 	 * Can't be a WARN_ON because it can be triggered through a race:
 	 * something inserts a STA (on one CPU) without holding the RTNL
 	 * and another CPU turns off the net device.
 	 */
-	if (unlikely(!ieee80211_sdata_running(sdata))) {
-		err = -ENETDOWN;
-		rcu_read_lock();
-		goto out_free;
-	}
+	if (unlikely(!ieee80211_sdata_running(sdata)))
+		return -ENETDOWN;
 
 	if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
-		    is_multicast_ether_addr(sta->sta.addr))) {
-		err = -EINVAL;
+		    is_multicast_ether_addr(sta->sta.addr)))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU)
+{
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	/* check if STA exists already */
+	if (sta_info_get_bss_rx(sdata, sta->sta.addr)) {
+		spin_unlock_irqrestore(&local->sta_lock, flags);
 		rcu_read_lock();
-		goto out_free;
+		return -EEXIST;
 	}
 
-	/*
-	 * In ad-hoc mode, we sometimes need to insert stations
-	 * from tasklet context from the RX path. To avoid races,
-	 * always do so in that case -- see the comment below.
-	 */
-	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-		spin_lock_irqsave(&local->sta_lock, flags);
-		/* check if STA exists already */
-		if (sta_info_get_bss(sdata, sta->sta.addr)) {
-			spin_unlock_irqrestore(&local->sta_lock, flags);
-			rcu_read_lock();
-			err = -EEXIST;
-			goto out_free;
-		}
-
-		local->num_sta++;
-		local->sta_generation++;
-		smp_mb();
-		sta_info_hash_add(local, sta);
+	local->num_sta++;
+	local->sta_generation++;
+	smp_mb();
+	sta_info_hash_add(local, sta);
 
-		list_add_tail(&sta->list, &local->sta_pending_list);
+	list_add_tail(&sta->list, &local->sta_pending_list);
 
-		rcu_read_lock();
-		spin_unlock_irqrestore(&local->sta_lock, flags);
+	rcu_read_lock();
+	spin_unlock_irqrestore(&local->sta_lock, flags);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
-			    sta->sta.addr);
+	wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
+			sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
-		ieee80211_queue_work(&local->hw, &local->sta_finish_work);
+	ieee80211_queue_work(&local->hw, &local->sta_finish_work);
 
-		return 0;
-	}
+	return 0;
+}
+
+/*
+ * should be called with sta_mtx locked
+ * this function replaces the mutex lock
+ * with a RCU lock
+ */
+static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
+{
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	unsigned long flags;
+	struct sta_info *exist_sta;
+	bool dummy_reinsert = false;
+	int err = 0;
+
+	lockdep_assert_held(&local->sta_mtx);
 
 	/*
 	 * On first glance, this will look racy, because the code
-	 * below this point, which inserts a station with sleeping,
+	 * in this function, which inserts a station with sleeping,
 	 * unlocks the sta_lock between checking existence in the
 	 * hash table and inserting into it.
 	 *
 	 * However, it is not racy against itself because it keeps
-	 * the mutex locked. It still seems to race against the
-	 * above code that atomically inserts the station... That,
-	 * however, is not true because the above code can only
-	 * be invoked for IBSS interfaces, and the below code will
-	 * not be -- and the two do not race against each other as
-	 * the hash table also keys off the interface.
+	 * the mutex locked.
 	 */
 
-	might_sleep();
-
-	mutex_lock(&local->sta_mtx);
-
 	spin_lock_irqsave(&local->sta_lock, flags);
-	/* check if STA exists already */
-	if (sta_info_get_bss(sdata, sta->sta.addr)) {
-		spin_unlock_irqrestore(&local->sta_lock, flags);
-		mutex_unlock(&local->sta_mtx);
-		rcu_read_lock();
-		err = -EEXIST;
-		goto out_free;
+	/*
+	 * check if STA exists already.
+	 * only accept a scenario of a second call to sta_info_insert_non_ibss
+	 * with a dummy station entry that was inserted earlier
+	 * in that case - assume that the dummy station flag should
+	 * be removed.
+	 */
+	exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr);
+	if (exist_sta) {
+		if (exist_sta == sta && sta->dummy) {
+			dummy_reinsert = true;
+		} else {
+			spin_unlock_irqrestore(&local->sta_lock, flags);
+			mutex_unlock(&local->sta_mtx);
+			rcu_read_lock();
+			return -EEXIST;
+		}
 	}
 
 	spin_unlock_irqrestore(&local->sta_lock, flags);
 
-	err = sta_info_finish_insert(sta, false);
+	err = sta_info_finish_insert(sta, false, dummy_reinsert);
 	if (err) {
 		mutex_unlock(&local->sta_mtx);
 		rcu_read_lock();
-		goto out_free;
+		return err;
 	}
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
+	wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n",
+			sta->dummy ? "dummy " : "", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	/* move reference to rcu-protected */
@@ -477,6 +543,51 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
 	if (ieee80211_vif_is_mesh(&sdata->vif))
 		mesh_accept_plinks_update(sdata);
 
+	return 0;
+}
+
+int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
+{
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	int err = 0;
+
+	err = sta_info_insert_check(sta);
+	if (err) {
+		rcu_read_lock();
+		goto out_free;
+	}
+
+	/*
+	 * In ad-hoc mode, we sometimes need to insert stations
+	 * from tasklet context from the RX path. To avoid races,
+	 * always do so in that case -- see the comment below.
+	 */
+	if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		err = sta_info_insert_ibss(sta);
+		if (err)
+			goto out_free;
+
+		return 0;
+	}
+
+	/*
+	 * It might seem that the function called below is in race against
+	 * the function call above that atomically inserts the station... That,
+	 * however, is not true because the above code can only
+	 * be invoked for IBSS interfaces, and the below code will
+	 * not be -- and the two do not race against each other as
+	 * the hash table also keys off the interface.
+	 */
+
+	might_sleep();
+
+	mutex_lock(&local->sta_mtx);
+
+	err = sta_info_insert_non_ibss(sta);
+	if (err)
+		goto out_free;
+
 	return 0;
  out_free:
 	BUG_ON(!err);
@@ -493,6 +604,25 @@ int sta_info_insert(struct sta_info *sta)
 	return err;
 }
 
+/* Caller must hold sta->local->sta_mtx */
+int sta_info_reinsert(struct sta_info *sta)
+{
+	struct ieee80211_local *local = sta->local;
+	int err = 0;
+
+	err = sta_info_insert_check(sta);
+	if (err) {
+		mutex_unlock(&local->sta_mtx);
+		return err;
+	}
+
+	might_sleep();
+
+	err = sta_info_insert_non_ibss(sta);
+	rcu_read_unlock();
+	return err;
+}
+
 static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
 {
 	/*
@@ -733,7 +863,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr)
 	int ret;
 
 	mutex_lock(&sdata->local->sta_mtx);
-	sta = sta_info_get(sdata, addr);
+	sta = sta_info_get_rx(sdata, addr);
 	ret = __sta_info_destroy(sta);
 	mutex_unlock(&sdata->local->sta_mtx);
 
@@ -747,7 +877,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
 	int ret;
 
 	mutex_lock(&sdata->local->sta_mtx);
-	sta = sta_info_get_bss(sdata, addr);
+	sta = sta_info_get_bss_rx(sdata, addr);
 	ret = __sta_info_destroy(sta);
 	mutex_unlock(&sdata->local->sta_mtx);
 
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 28beb78e601edc4f0e3f4d8e596f8dad1428c755..e9eb565506da06ac3f5d8b5bd4a166f9483d6a79 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -238,10 +238,12 @@ struct sta_ampdu_mlme {
  * @plink_timer: peer link watch timer
  * @plink_timer_was_running: used by suspend/resume to restore timers
  * @debugfs: debug filesystem info
- * @sta: station information we share with the driver
  * @dead: set to true when sta is unlinked
  * @uploaded: set to true when sta is uploaded to the driver
  * @lost_packets: number of consecutive lost packets
+ * @dummy: indicate a dummy station created for receiving
+ *	EAP frames before association
+ * @sta: station information we share with the driver
  */
 struct sta_info {
 	/* General information, mostly static */
@@ -336,6 +338,9 @@ struct sta_info {
 
 	unsigned int lost_packets;
 
+	/* should be right in front of sta to be in the same cache line */
+	bool dummy;
+
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
@@ -436,9 +441,15 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
 struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
 			      const u8 *addr);
 
+struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
+			      const u8 *addr);
+
 struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
 				  const u8 *addr);
 
+struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
+				  const u8 *addr);
+
 static inline
 void for_each_sta_info_type_check(struct ieee80211_local *local,
 				  const u8 *addr,
@@ -448,6 +459,22 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
 }
 
 #define for_each_sta_info(local, _addr, _sta, nxt) 			\
+	for (	/* initialise loop */					\
+		_sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
+		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL;	\
+		/* typecheck */						\
+		for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
+		/* continue condition */				\
+		_sta;							\
+		/* advance loop */					\
+		_sta = nxt,						\
+		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL	\
+	     )								\
+	/* run code only if address matches and it's not a dummy sta */	\
+	if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 &&		\
+		!_sta->dummy)
+
+#define for_each_sta_info_rx(local, _addr, _sta, nxt)			\
 	for (	/* initialise loop */					\
 		_sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
 		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL;	\
@@ -484,6 +511,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 int sta_info_insert(struct sta_info *sta);
 int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
 int sta_info_insert_atomic(struct sta_info *sta);
+int sta_info_reinsert(struct sta_info *sta);
 
 int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
 			  const u8 *addr);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index a89cca3491b4c71a2aa17bed5a099b906b6c7d17..e51bd2a1a0735de0adfff2566c5f1d6b584ef6de 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -187,6 +187,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 	int rates_idx = -1;
 	bool send_to_cooked;
 	bool acked;
+	struct ieee80211_bar *bar;
+	u16 tid;
 
 	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
 		if (info->status.rates[i].idx < 0) {
@@ -243,6 +245,22 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 					   tid, ssn);
 		}
 
+		if (!acked && ieee80211_is_back_req(fc)) {
+			/*
+			 * BAR failed, let's tear down the BA session as a
+			 * last resort as some STAs (Intel 5100 on Windows)
+			 * can get stuck when the BA window isn't flushed
+			 * correctly.
+			 */
+			bar = (struct ieee80211_bar *) skb->data;
+			if (!(bar->control & IEEE80211_BAR_CTRL_MULTI_TID)) {
+				tid = (bar->control &
+				       IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+				      IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
+				ieee80211_stop_tx_ba_session(&sta->sta, tid);
+			}
+		}
+
 		if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
 			ieee80211_handle_filtered_frame(local, sta, skb);
 			rcu_read_unlock();
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 69fd494f32f9f3bdd476bb71351d31d08a701243..01072639666fb77bccceda47aad242c6ec241405 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2295,13 +2295,23 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
 		mgmt->u.beacon.beacon_int =
 			cpu_to_le16(sdata->vif.bss_conf.beacon_int);
-		mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
+		mgmt->u.beacon.capab_info |= cpu_to_le16(
+			sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
 
 		pos = skb_put(skb, 2);
 		*pos++ = WLAN_EID_SSID;
 		*pos++ = 0x0;
 
-		mesh_mgmt_ies_add(skb, sdata);
+		if (mesh_add_srates_ie(skb, sdata) ||
+		    mesh_add_ds_params_ie(skb, sdata) ||
+		    mesh_add_ext_srates_ie(skb, sdata) ||
+		    mesh_add_rsn_ie(skb, sdata) ||
+		    mesh_add_meshid_ie(skb, sdata) ||
+		    mesh_add_meshconf_ie(skb, sdata) ||
+		    mesh_add_vendor_ies(skb, sdata)) {
+			pr_err("o11s: couldn't add ies!\n");
+			goto out;
+		}
 	} else {
 		WARN_ON(1);
 		goto out;
diff --git a/net/nfc/core.c b/net/nfc/core.c
index b6fd4e1f20570683946c4b75925540fd1ba4be39..284e2f6a14ff490f287354bdd60058b87123d475 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -322,7 +322,9 @@ struct nfc_dev *nfc_get_device(unsigned idx)
  * @supported_protocols: NFC protocols supported by the device
  */
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
-					u32 supported_protocols)
+					u32 supported_protocols,
+					int tx_headroom,
+					int tx_tailroom)
 {
 	static atomic_t dev_no = ATOMIC_INIT(0);
 	struct nfc_dev *dev;
@@ -345,6 +347,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 
 	dev->ops = ops;
 	dev->supported_protocols = supported_protocols;
+	dev->tx_headroom = tx_headroom;
+	dev->tx_tailroom = tx_tailroom;
 
 	spin_lock_init(&dev->targets_lock);
 	nfc_genl_data_init(&dev->genl_data);
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index 52de84a55115719a4596c26b30f2cb1543fabaa6..9fd652a51424bc88fb0a3a9bad7fc8e120418c4f 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -123,11 +123,7 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
 
 static int rawsock_add_header(struct sk_buff *skb)
 {
-
-	if (skb_cow_head(skb, 1))
-		return -ENOMEM;
-
-	*skb_push(skb, 1) = 0;
+	*skb_push(skb, NFC_HEADER_SIZE) = 0;
 
 	return 0;
 }
@@ -197,6 +193,7 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
 					struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
+	struct nfc_dev *dev = nfc_rawsock(sk)->dev;
 	struct sk_buff *skb;
 	int rc;
 
@@ -208,11 +205,13 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
 	if (sock->state != SS_CONNECTED)
 		return -ENOTCONN;
 
-	skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT,
-									&rc);
+	skb = sock_alloc_send_skb(sk, len + dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE,
+					msg->msg_flags & MSG_DONTWAIT, &rc);
 	if (!skb)
 		return rc;
 
+	skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
+
 	rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
 	if (rc < 0) {
 		kfree_skb(skb);
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 5c116083eeca7f99c28b9f8e9835a5d32e0e24db..4423e64c7d983e3d8b294dcb6d2ebc3d4d5b6e88 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -12,6 +12,7 @@
 #define MESH_HOLD_T 		100
 
 #define MESH_PATH_TIMEOUT	5000
+#define MESH_RANN_INTERVAL      5000
 
 /*
  * Minimum interval between two consecutive PREQs originated by the same
@@ -49,6 +50,8 @@ const struct mesh_config default_mesh_config = {
 	.dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
 	.path_refresh_time = MESH_PATH_REFRESH_TIME,
 	.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
+	.dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
+	.dot11MeshGateAnnouncementProtocol = false,
 };
 
 const struct mesh_setup default_mesh_setup = {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2aa6a2189842982b199272438951583f97ee23bd..bddb5595c6598bf62d21bf1520fffa578d1eaf68 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2545,6 +2545,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
+static struct nla_policy
+nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
+	[NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
+	[NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
+};
+
 static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -2590,6 +2596,27 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 	if (parse_station_flags(info, &params))
 		return -EINVAL;
 
+	/* parse WME attributes if sta is WME capable */
+	if ((params.sta_flags_set & NL80211_STA_FLAG_WME) &&
+	    info->attrs[NL80211_ATTR_STA_WME]) {
+		struct nlattr *tb[NL80211_STA_WME_MAX + 1];
+		struct nlattr *nla;
+
+		nla = info->attrs[NL80211_ATTR_STA_WME];
+		err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
+				       nl80211_sta_wme_policy);
+		if (err)
+			return err;
+
+		if (tb[NL80211_STA_WME_UAPSD_QUEUES])
+			params.uapsd_queues =
+			     nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]);
+
+		if (tb[NL80211_STA_WME_MAX_SP])
+			params.max_sp =
+			     nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
+	}
+
 	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
 	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
 	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
@@ -3035,6 +3062,10 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
 			cur_params.dot11MeshHWMPnetDiameterTraversalTime);
 	NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
 			cur_params.dot11MeshHWMPRootMode);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+			cur_params.dot11MeshHWMPRannInterval);
+	NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+			cur_params.dot11MeshGateAnnouncementProtocol);
 	nla_nest_end(msg, pinfoattr);
 	genlmsg_end(msg, hdr);
 	return genlmsg_reply(msg, info);
@@ -3062,6 +3093,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
 	[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
 	[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
 	[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
+	[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
 };
 
 static const struct nla_policy
@@ -3140,6 +3174,14 @@ do {\
 			dot11MeshHWMPRootMode, mask,
 			NL80211_MESHCONF_HWMP_ROOTMODE,
 			nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+			dot11MeshHWMPRannInterval, mask,
+			NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+			nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+			dot11MeshGateAnnouncementProtocol, mask,
+			NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+			nla_get_u8);
 	if (mask_out)
 		*mask_out = mask;
 
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 844ddb0aa6533fe3c6071af43b9a43f73e23f461..eef82f79554dba1fdce02daddcee9178635716e3 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1158,9 +1158,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
 			if (elen >= sizeof(struct ieee80211_meshconf_ie))
 				elems->mesh_config = (void *)pos;
 			break;
-		case WLAN_EID_PEER_LINK:
-			elems->peer_link = pos;
-			elems->peer_link_len = elen;
+		case WLAN_EID_PEER_MGMT:
+			elems->peering = pos;
+			elems->peering_len = elen;
 			break;
 		case WLAN_EID_PREQ:
 			elems->preq = pos;