diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 84206898f77d89daa5821a9afeece34b275f3f67..3510de2cf6224c6ec11b091cfb3f50dd1fccf6b9 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -158,6 +158,11 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
 	txlat = AR5K_REG_MS(usec_reg, AR5K_USEC_TX_LATENCY_5211);
 	rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211);
 
+	/*
+	 * Set default Tx frame to Tx data start delay
+	 */
+	txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT;
+
 	/*
 	 * 5210 initvals don't include usec settings
 	 * so we need to use magic values here for
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 5193ed58a17b781516bd0a6773762b68fdb5f3f8..61956392f2da44c3b8dd86b0f84c5a6e6675c5ed 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -21,11 +21,15 @@
 #include <linux/ath9k_platform.h>
 #include "ath9k.h"
 
-const struct platform_device_id ath9k_platform_id_table[] = {
+static const struct platform_device_id ath9k_platform_id_table[] = {
 	{
 		.name = "ath9k",
 		.driver_data = AR5416_AR9100_DEVID,
 	},
+	{
+		.name = "ar934x_wmac",
+		.driver_data = AR9300_DEVID_AR9340,
+	},
 	{},
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 2e31c775351fb3c4e2fba12960a92954a211b4ea..5a1f4f511bc152df2e033380e666c45a0bb9cc5b 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -899,12 +899,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 	 * check here default level should not modify INI setting.
 	 */
 	if (use_new_ani(ah)) {
-		const struct ani_ofdm_level_entry *entry_ofdm;
-		const struct ani_cck_level_entry *entry_cck;
-
-		entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL];
-		entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL];
-
 		ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
 		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
 	} else {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 4a4cd88429c069076945e3d0c13807c8d83b2729..f276cb922b4d5d96bf16703bd67b75ac40aecb55 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -18,13 +18,13 @@
 #include "hw-ops.h"
 #include "ar9003_phy.h"
 
-#define MPASS	3
 #define MAX_MEASUREMENT	8
-#define MAX_DIFFERENCE	10
+#define MAX_MAG_DELTA	11
+#define MAX_PHS_DELTA	10
 
 struct coeff {
-	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
-	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
+	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
+	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
 	int iqc_coeff[2];
 };
 
@@ -185,17 +185,19 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
 
 	/* Accumulate IQ cal measures for active chains */
 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ah->totalPowerMeasI[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-		ah->totalPowerMeasQ[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-		ah->totalIqCorrMeas[i] +=
-			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-		ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
-			"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
-			ah->cal_samples, i, ah->totalPowerMeasI[i],
-			ah->totalPowerMeasQ[i],
-			ah->totalIqCorrMeas[i]);
+		if (ah->txchainmask & BIT(i)) {
+			ah->totalPowerMeasI[i] +=
+				REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+			ah->totalPowerMeasQ[i] +=
+				REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+			ah->totalIqCorrMeas[i] +=
+				(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+			ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+				"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+				ah->cal_samples, i, ah->totalPowerMeasI[i],
+				ah->totalPowerMeasQ[i],
+				ah->totalIqCorrMeas[i]);
+		}
 	}
 }
 
@@ -608,36 +610,48 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
 	return true;
 }
 
-static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
+static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
+				     int max_delta)
 {
-	int diff[MPASS];
-
-	diff[0] = abs(mp_coeff[0] - mp_coeff[1]);
-	diff[1] = abs(mp_coeff[1] - mp_coeff[2]);
-	diff[2] = abs(mp_coeff[2] - mp_coeff[0]);
-
-	if (diff[0] > MAX_DIFFERENCE &&
-	    diff[1] > MAX_DIFFERENCE &&
-	    diff[2] > MAX_DIFFERENCE)
-		return false;
+	int mp_max = -64, max_idx = 0;
+	int mp_min = 63, min_idx = 0;
+	int mp_avg = 0, i, outlier_idx = 0;
+
+	/* find min/max mismatch across all calibrated gains */
+	for (i = 0; i < nmeasurement; i++) {
+		mp_avg += mp_coeff[i];
+		if (mp_coeff[i] > mp_max) {
+			mp_max = mp_coeff[i];
+			max_idx = i;
+		} else if (mp_coeff[i] < mp_min) {
+			mp_min = mp_coeff[i];
+			min_idx = i;
+		}
+	}
 
-	if (diff[0] <= diff[1] && diff[0] <= diff[2])
-		*mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2;
-	else if (diff[1] <= diff[2])
-		*mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2;
-	else
-		*mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2;
+	/* find average (exclude max abs value) */
+	for (i = 0; i < nmeasurement; i++) {
+		if ((abs(mp_coeff[i]) < abs(mp_max)) ||
+		    (abs(mp_coeff[i]) < abs(mp_min)))
+			mp_avg += mp_coeff[i];
+	}
+	mp_avg /= (nmeasurement - 1);
 
-	return true;
+	/* detect outlier */
+	if (abs(mp_max - mp_min) > max_delta) {
+		if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
+			outlier_idx = max_idx;
+		else
+			outlier_idx = min_idx;
+	}
+	mp_coeff[outlier_idx] = mp_avg;
 }
 
 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
 						 u8 num_chains,
 						 struct coeff *coeff)
 {
-	struct ath_common *common = ath9k_hw_common(ah);
 	int i, im, nmeasurement;
-	int magnitude, phase;
 	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
 
 	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
@@ -657,37 +671,28 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
 
 	/* Load the average of 2 passes */
 	for (i = 0; i < num_chains; i++) {
-		if (AR_SREV_9485(ah))
-			nmeasurement = REG_READ_FIELD(ah,
-					AR_PHY_TX_IQCAL_STATUS_B0_9485,
-					AR_PHY_CALIBRATED_GAINS_0);
-		else
-			nmeasurement = REG_READ_FIELD(ah,
-					AR_PHY_TX_IQCAL_STATUS_B0,
-					AR_PHY_CALIBRATED_GAINS_0);
+		nmeasurement = REG_READ_FIELD(ah,
+				AR_PHY_TX_IQCAL_STATUS_B0,
+				AR_PHY_CALIBRATED_GAINS_0);
 
 		if (nmeasurement > MAX_MEASUREMENT)
 			nmeasurement = MAX_MEASUREMENT;
 
-		for (im = 0; im < nmeasurement; im++) {
-			/*
-			 * Determine which 2 passes are closest and compute avg
-			 * magnitude
-			 */
-			if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im],
-								    &magnitude))
-				goto disable_txiqcal;
+		/* detect outlier only if nmeasurement > 1 */
+		if (nmeasurement > 1) {
+			/* Detect magnitude outlier */
+			ar9003_hw_detect_outlier(coeff->mag_coeff[i],
+					nmeasurement, MAX_MAG_DELTA);
 
-			/*
-			 * Determine which 2 passes are closest and compute avg
-			 * phase
-			 */
-			if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im],
-								    &phase))
-				goto disable_txiqcal;
+			/* Detect phase outlier */
+			ar9003_hw_detect_outlier(coeff->phs_coeff[i],
+					nmeasurement, MAX_PHS_DELTA);
+		}
+
+		for (im = 0; im < nmeasurement; im++) {
 
-			coeff->iqc_coeff[0] = (magnitude & 0x7f) |
-					      ((phase & 0x7f) << 7);
+			coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
+				((coeff->phs_coeff[i][im] & 0x7f) << 7);
 
 			if ((im % 2) == 0)
 				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
@@ -707,141 +712,37 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
 
 	return;
 
-disable_txiqcal:
-	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
-		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0);
-	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
-		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0);
-
-	ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n");
 }
 
-static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
+static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
-		AR_PHY_TX_IQCAL_STATUS_B0,
-		AR_PHY_TX_IQCAL_STATUS_B1,
-		AR_PHY_TX_IQCAL_STATUS_B2,
-	};
-	static const u32 chan_info_tab[] = {
-		AR_PHY_CHAN_INFO_TAB_0,
-		AR_PHY_CHAN_INFO_TAB_1,
-		AR_PHY_CHAN_INFO_TAB_2,
-	};
-	struct coeff coeff;
-	s32 iq_res[6];
-	s32 i, j, ip, im, nmeasurement;
-	u8 nchains = get_streams(common->tx_chainmask);
-
-	for (ip = 0; ip < MPASS; ip++) {
-		REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
-			      AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
-			      DELPT);
-		REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
-			      AR_PHY_TX_IQCAL_START_DO_CAL,
-			      AR_PHY_TX_IQCAL_START_DO_CAL);
-
-		if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
-				   AR_PHY_TX_IQCAL_START_DO_CAL,
-				   0, AH_WAIT_TIMEOUT)) {
-			ath_dbg(common, ATH_DBG_CALIBRATE,
-				"Tx IQ Cal not complete.\n");
-			goto TX_IQ_CAL_FAILED;
-		}
-
-		nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0,
-					      AR_PHY_CALIBRATED_GAINS_0);
-			if (nmeasurement > MAX_MEASUREMENT)
-				nmeasurement = MAX_MEASUREMENT;
-
-		for (i = 0; i < nchains; i++) {
-			ath_dbg(common, ATH_DBG_CALIBRATE,
-				"Doing Tx IQ Cal for chain %d.\n", i);
-			for (im = 0; im < nmeasurement; im++) {
-				if (REG_READ(ah, txiqcal_status[i]) &
-					     AR_PHY_TX_IQCAL_STATUS_FAILED) {
-					ath_dbg(common, ATH_DBG_CALIBRATE,
-						"Tx IQ Cal failed for chain %d.\n", i);
-					goto TX_IQ_CAL_FAILED;
-				}
-
-				for (j = 0; j < 3; j++) {
-					u8 idx = 2 * j,
-					   offset = 4 * (3 * im + j);
-
-					REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
-						      AR_PHY_CHAN_INFO_TAB_S2_READ,
-						      0);
-
-					/* 32 bits */
-					iq_res[idx] = REG_READ(ah,
-							chan_info_tab[i] +
-							offset);
-
-					REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
-						      AR_PHY_CHAN_INFO_TAB_S2_READ,
-						      1);
-
-					/* 16 bits */
-					iq_res[idx+1] = 0xffff & REG_READ(ah,
-								chan_info_tab[i] +
-								offset);
-
-					ath_dbg(common, ATH_DBG_CALIBRATE,
-						"IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
-						idx, iq_res[idx], idx+1, iq_res[idx+1]);
-				}
-
-				if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
-							    coeff.iqc_coeff)) {
-					ath_dbg(common, ATH_DBG_CALIBRATE,
-						"Failed in calculation of IQ correction.\n");
-					goto TX_IQ_CAL_FAILED;
-				}
-				coeff.mag_coeff[i][im][ip] =
-						coeff.iqc_coeff[0] & 0x7f;
-				coeff.phs_coeff[i][im][ip] =
-						(coeff.iqc_coeff[0] >> 7) & 0x7f;
-
-				if (coeff.mag_coeff[i][im][ip] > 63)
-					coeff.mag_coeff[i][im][ip] -= 128;
-				if (coeff.phs_coeff[i][im][ip] > 63)
-					coeff.phs_coeff[i][im][ip] -= 128;
-
-			}
-		}
-	}
-
-	ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff);
-
-	return;
-
-TX_IQ_CAL_FAILED:
-	ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
-}
-
-static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
-{
 	u8 tx_gain_forced;
 
-	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485,
-		      AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);
 	tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
 					AR_PHY_TXGAIN_FORCE);
 	if (tx_gain_forced)
 		REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
 			      AR_PHY_TXGAIN_FORCE, 0);
 
-	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485,
-		      AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1);
+	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
+		      AR_PHY_TX_IQCAL_START_DO_CAL, 1);
+
+	if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
+			AR_PHY_TX_IQCAL_START_DO_CAL, 0,
+			AH_WAIT_TIMEOUT)) {
+		ath_dbg(common, ATH_DBG_CALIBRATE,
+			"Tx IQ Cal is not completed.\n");
+		return false;
+	}
+	return true;
 }
 
 static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
-		AR_PHY_TX_IQCAL_STATUS_B0_9485,
+		AR_PHY_TX_IQCAL_STATUS_B0,
 		AR_PHY_TX_IQCAL_STATUS_B1,
 		AR_PHY_TX_IQCAL_STATUS_B2,
 	};
@@ -853,7 +754,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
 	struct coeff coeff;
 	s32 iq_res[6];
 	u8 num_chains = 0;
-	int i, ip, im, j;
+	int i, im, j;
 	int nmeasurement;
 
 	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
@@ -861,71 +762,69 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
 			num_chains++;
 	}
 
-	for (ip = 0; ip < MPASS; ip++) {
-		for (i = 0; i < num_chains; i++) {
-			nmeasurement = REG_READ_FIELD(ah,
-					AR_PHY_TX_IQCAL_STATUS_B0_9485,
-					AR_PHY_CALIBRATED_GAINS_0);
-			if (nmeasurement > MAX_MEASUREMENT)
-				nmeasurement = MAX_MEASUREMENT;
+	for (i = 0; i < num_chains; i++) {
+		nmeasurement = REG_READ_FIELD(ah,
+				AR_PHY_TX_IQCAL_STATUS_B0,
+				AR_PHY_CALIBRATED_GAINS_0);
+		if (nmeasurement > MAX_MEASUREMENT)
+			nmeasurement = MAX_MEASUREMENT;
 
-			for (im = 0; im < nmeasurement; im++) {
-				ath_dbg(common, ATH_DBG_CALIBRATE,
-					"Doing Tx IQ Cal for chain %d.\n", i);
+		for (im = 0; im < nmeasurement; im++) {
+			ath_dbg(common, ATH_DBG_CALIBRATE,
+				"Doing Tx IQ Cal for chain %d.\n", i);
 
-				if (REG_READ(ah, txiqcal_status[i]) &
-				    AR_PHY_TX_IQCAL_STATUS_FAILED) {
-					ath_dbg(common, ATH_DBG_CALIBRATE,
+			if (REG_READ(ah, txiqcal_status[i]) &
+					AR_PHY_TX_IQCAL_STATUS_FAILED) {
+				ath_dbg(common, ATH_DBG_CALIBRATE,
 					"Tx IQ Cal failed for chain %d.\n", i);
-					goto tx_iqcal_fail;
-				}
+				goto tx_iqcal_fail;
+			}
 
-				for (j = 0; j < 3; j++) {
-					u32 idx = 2 * j, offset = 4 * (3 * im + j);
+			for (j = 0; j < 3; j++) {
+				u32 idx = 2 * j, offset = 4 * (3 * im + j);
 
-					REG_RMW_FIELD(ah,
+				REG_RMW_FIELD(ah,
 						AR_PHY_CHAN_INFO_MEMORY,
 						AR_PHY_CHAN_INFO_TAB_S2_READ,
 						0);
 
-					/* 32 bits */
-					iq_res[idx] = REG_READ(ah,
-							chan_info_tab[i] +
-							offset);
+				/* 32 bits */
+				iq_res[idx] = REG_READ(ah,
+						chan_info_tab[i] +
+						offset);
 
-					REG_RMW_FIELD(ah,
+				REG_RMW_FIELD(ah,
 						AR_PHY_CHAN_INFO_MEMORY,
 						AR_PHY_CHAN_INFO_TAB_S2_READ,
 						1);
 
-					/* 16 bits */
-					iq_res[idx + 1] = 0xffff & REG_READ(ah,
-							  chan_info_tab[i] + offset);
+				/* 16 bits */
+				iq_res[idx + 1] = 0xffff & REG_READ(ah,
+						chan_info_tab[i] + offset);
 
-					ath_dbg(common, ATH_DBG_CALIBRATE,
-						"IQ RES[%d]=0x%x"
-						"IQ_RES[%d]=0x%x\n",
-						idx, iq_res[idx], idx + 1,
-						iq_res[idx + 1]);
-				}
+				ath_dbg(common, ATH_DBG_CALIBRATE,
+					"IQ RES[%d]=0x%x"
+					"IQ_RES[%d]=0x%x\n",
+					idx, iq_res[idx], idx + 1,
+					iq_res[idx + 1]);
+			}
 
-				if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
-							    coeff.iqc_coeff)) {
-					ath_dbg(common, ATH_DBG_CALIBRATE,
-					 "Failed in calculation of IQ correction.\n");
-					goto tx_iqcal_fail;
-				}
+			if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+						coeff.iqc_coeff)) {
+				ath_dbg(common, ATH_DBG_CALIBRATE,
+					"Failed in calculation of \
+					IQ correction.\n");
+				goto tx_iqcal_fail;
+			}
 
-				coeff.mag_coeff[i][im][ip] =
-						coeff.iqc_coeff[0] & 0x7f;
-				coeff.phs_coeff[i][im][ip] =
-						(coeff.iqc_coeff[0] >> 7) & 0x7f;
+			coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
+			coeff.phs_coeff[i][im] =
+				(coeff.iqc_coeff[0] >> 7) & 0x7f;
 
-				if (coeff.mag_coeff[i][im][ip] > 63)
-					coeff.mag_coeff[i][im][ip] -= 128;
-				if (coeff.phs_coeff[i][im][ip] > 63)
-					coeff.phs_coeff[i][im][ip] -= 128;
-			}
+			if (coeff.mag_coeff[i][im] > 63)
+				coeff.mag_coeff[i][im] -= 128;
+			if (coeff.phs_coeff[i][im] > 63)
+				coeff.phs_coeff[i][im] -= 128;
 		}
 	}
 	ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff);
@@ -940,31 +839,37 @@ 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);
 
-	if (AR_SREV_9485(ah))
-		ar9003_hw_set_chain_masks(ah, 0x1, 0x1);
-	else if (val & AR_ENT_OTP_CHAIN2_DISABLE)
+	/* 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
-		/*
-		 * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain
-		 * mode before running AGC/TxIQ cals
-		 */
-		ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
+		ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask,
+					  pCap->tx_chainmask);
 
 	/* Do Tx IQ Calibration */
-	if (AR_SREV_9485(ah))
-		ar9003_hw_tx_iq_cal_run(ah);
-	else
-		ar9003_hw_tx_iq_cal(ah);
+	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+		      DELPT);
 
-	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
-	udelay(5);
-	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+	/*
+	 * For AR9485 or later chips, TxIQ cal runs as part of
+	 * AGC calibration
+	 */
+	if (AR_SREV_9485_OR_LATER(ah))
+		txiqcal_done = true;
+	else {
+		txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
+		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+		udelay(5);
+		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+	}
 
 	/* Calibrate the AGC */
 	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
@@ -979,7 +884,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 		return false;
 	}
 
-	if (AR_SREV_9485(ah))
+	if (txiqcal_done)
 		ar9003_hw_tx_iq_cal_post_proc(ah);
 
 	/* Revert chainmasks to their original values before NF cal */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 6eadf975ae4884cc0c3bfb09dcaf0b09b9e407c4..fb892e5d141af5d7f19cce2aada7f8936986a44c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3217,7 +3217,6 @@ static int ar9300_compress_decision(struct ath_hw *ah,
 				    u8 *word, int length, int mdata_size)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
-	u8 *dptr;
 	const struct ar9300_eeprom *eep = NULL;
 
 	switch (code) {
@@ -3235,7 +3234,6 @@ static int ar9300_compress_decision(struct ath_hw *ah,
 		break;
 	case _CompressBlock:
 		if (reference == 0) {
-			dptr = mptr;
 		} else {
 			eep = ar9003_eeprom_struct_find_by_id(reference);
 			if (eep == NULL) {
@@ -3448,9 +3446,13 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
 		REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
 	else {
 		REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
-		REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB,
-			      bias >> 2);
-		REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1);
+		if (!AR_SREV_9340(ah)) {
+			REG_RMW_FIELD(ah, AR_CH0_THERM,
+				      AR_CH0_THERM_XPABIASLVL_MSB,
+				      bias >> 2);
+			REG_RMW_FIELD(ah, AR_CH0_THERM,
+				      AR_CH0_THERM_XPASHORT2GND, 1);
+		}
 	}
 }
 
@@ -3497,23 +3499,28 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
 
 static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
 {
+	int chain;
+	static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = {
+			AR_PHY_SWITCH_CHAIN_0,
+			AR_PHY_SWITCH_CHAIN_1,
+			AR_PHY_SWITCH_CHAIN_2,
+	};
+
 	u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
+
 	REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value);
 
 	value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
 	REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
 
-	value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz);
-	REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value);
-
-	if (!AR_SREV_9485(ah)) {
-		value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz);
-		REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL,
-			      value);
-
-		value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz);
-		REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL,
-			      value);
+	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+		if ((ah->rxchainmask & BIT(chain)) ||
+		    (ah->txchainmask & BIT(chain))) {
+			value = ar9003_hw_ant_ctrl_chain_get(ah, chain,
+							     is2ghz);
+			REG_RMW_FIELD(ah, switch_chain_reg[chain],
+				      AR_SWITCH_TABLE_ALL, value);
+		}
 	}
 
 	if (AR_SREV_9485(ah)) {
@@ -3634,13 +3641,16 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan)
 
 	/* Test value. if 0 then attenuation is unused. Don't load anything. */
 	for (i = 0; i < 3; i++) {
-		value = ar9003_hw_atten_chain_get(ah, i, chan);
-		REG_RMW_FIELD(ah, ext_atten_reg[i],
-			      AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
-
-		value = ar9003_hw_atten_chain_get_margin(ah, i, chan);
-		REG_RMW_FIELD(ah, ext_atten_reg[i],
-			      AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value);
+		if (ah->txchainmask & BIT(i)) {
+			value = ar9003_hw_atten_chain_get(ah, i, chan);
+			REG_RMW_FIELD(ah, ext_atten_reg[i],
+				      AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
+
+			value = ar9003_hw_atten_chain_get_margin(ah, i, chan);
+			REG_RMW_FIELD(ah, ext_atten_reg[i],
+				      AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
+				      value);
+		}
 	}
 }
 
@@ -3749,8 +3759,9 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
 	ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
 	ar9003_hw_drive_strength_apply(ah);
 	ar9003_hw_atten_apply(ah, chan);
-	ar9003_hw_internal_regulator_apply(ah);
-	if (AR_SREV_9485(ah))
+	if (!AR_SREV_9340(ah))
+		ar9003_hw_internal_regulator_apply(ah);
+	if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
 		ar9003_hw_apply_tuning_caps(ah);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index aebaad97b190fe6ec774364df01922561dd12198..a55eddbb258923aaf85a35966fb35a3974fa15f0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -18,6 +18,7 @@
 #include "ar9003_mac.h"
 #include "ar9003_2p2_initvals.h"
 #include "ar9485_initvals.h"
+#include "ar9340_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
 
@@ -28,7 +29,63 @@
  */
 static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
 {
-	if (AR_SREV_9485_11(ah)) {
+	if (AR_SREV_9340(ah)) {
+		/* mac */
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+				ar9340_1p0_mac_core,
+				ARRAY_SIZE(ar9340_1p0_mac_core), 2);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+				ar9340_1p0_mac_postamble,
+				ARRAY_SIZE(ar9340_1p0_mac_postamble), 5);
+
+		/* bb */
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+				ar9340_1p0_baseband_core,
+				ARRAY_SIZE(ar9340_1p0_baseband_core), 2);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+				ar9340_1p0_baseband_postamble,
+				ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5);
+
+		/* radio */
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+				ar9340_1p0_radio_core,
+				ARRAY_SIZE(ar9340_1p0_radio_core), 2);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+				ar9340_1p0_radio_postamble,
+				ARRAY_SIZE(ar9340_1p0_radio_postamble), 5);
+
+		/* soc */
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+				ar9340_1p0_soc_preamble,
+				ARRAY_SIZE(ar9340_1p0_soc_preamble), 2);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+				ar9340_1p0_soc_postamble,
+				ARRAY_SIZE(ar9340_1p0_soc_postamble), 5);
+
+		/* rx/tx gain */
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
+				ar9340Common_wo_xlna_rx_gain_table_1p0,
+				ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
+				5);
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9340Modes_high_ob_db_tx_gain_table_1p0,
+				ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0),
+				5);
+
+		INIT_INI_ARRAY(&ah->iniModesAdditional,
+				ar9340Modes_fast_clock_1p0,
+				ARRAY_SIZE(ar9340Modes_fast_clock_1p0),
+				3);
+
+		INIT_INI_ARRAY(&ah->iniModesAdditional_40M,
+				ar9340_1p0_radio_core_40M,
+				ARRAY_SIZE(ar9340_1p0_radio_core_40M),
+				2);
+	} else if (AR_SREV_9485_11(ah)) {
 		/* mac */
 		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
 		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@@ -163,7 +220,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 	switch (ar9003_hw_get_tx_gain_idx(ah)) {
 	case 0:
 	default:
-		if (AR_SREV_9485_11(ah))
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9485_modes_lowest_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
@@ -175,7 +237,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 				       5);
 		break;
 	case 1:
-		if (AR_SREV_9485_11(ah))
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9485Modes_high_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
@@ -187,7 +254,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 				       5);
 		break;
 	case 2:
-		if (AR_SREV_9485_11(ah))
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9485Modes_low_ob_db_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
@@ -199,7 +271,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 				       5);
 		break;
 	case 3:
-		if (AR_SREV_9485_11(ah))
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
 			INIT_INI_ARRAY(&ah->iniModesTxGain,
 				       ar9485Modes_high_power_tx_gain_1_1,
 				       ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
@@ -218,7 +295,12 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
 	switch (ar9003_hw_get_rx_gain_idx(ah)) {
 	case 0:
 	default:
-		if (AR_SREV_9485_11(ah))
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9340Common_rx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Common_rx_gain_table_1p0),
+				       2);
+		else if (AR_SREV_9485_11(ah))
 			INIT_INI_ARRAY(&ah->iniModesRxGain,
 				       ar9485Common_wo_xlna_rx_gain_1_1,
 				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
@@ -230,7 +312,12 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
 				       2);
 		break;
 	case 1:
-		if (AR_SREV_9485_11(ah))
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9340Common_wo_xlna_rx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
+				       2);
+		else if (AR_SREV_9485_11(ah))
 			INIT_INI_ARRAY(&ah->iniModesRxGain,
 				       ar9485Common_wo_xlna_rx_gain_1_1,
 				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 1bc33f51e4663c877fca5208d4c9fcee83df8481..c83be2dd5718d16057f0ec84a7b92e2aa23ea656 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -86,14 +86,31 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
 			channelSel = (freq * 4) / 120;
 			chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
 			channelSel = (channelSel << 17) | chan_frac;
+		} else if (AR_SREV_9340(ah)) {
+			if (ah->is_clk_25mhz) {
+				u32 chan_frac;
+
+				channelSel = (freq * 2) / 75;
+				chan_frac = (((freq * 2) % 75) * 0x20000) / 75;
+				channelSel = (channelSel << 17) | chan_frac;
+			} else
+				channelSel = CHANSEL_2G(freq) >> 1;
 		} else
 			channelSel = CHANSEL_2G(freq);
 		/* Set to 2G mode */
 		bMode = 1;
 	} else {
-		channelSel = CHANSEL_5G(freq);
-		/* Doubler is ON, so, divide channelSel by 2. */
-		channelSel >>= 1;
+		if (AR_SREV_9340(ah) && ah->is_clk_25mhz) {
+			u32 chan_frac;
+
+			channelSel = (freq * 2) / 75;
+			chan_frac = ((freq % 75) * 0x20000) / 75;
+			channelSel = (channelSel << 17) | chan_frac;
+		} else {
+			channelSel = CHANSEL_5G(freq);
+			/* Doubler is ON, so, divide channelSel by 2. */
+			channelSel >>= 1;
+		}
 		/* Set to 5G mode */
 		bMode = 0;
 	}
@@ -151,7 +168,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
 	 * is out-of-band and can be ignored.
 	 */
 
-	if (AR_SREV_9485(ah)) {
+	if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) {
 		spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah,
 							 IS_CHAN_2GHZ(chan));
 		if (spur_fbin_ptr[0] == 0) /* No spur */
@@ -176,7 +193,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
 
 	for (i = 0; i < max_spur_cnts; i++) {
 		negative = 0;
-		if (AR_SREV_9485(ah))
+		if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
 			cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
 					IS_CHAN_2GHZ(chan)) - synth_freq;
 		else
@@ -599,29 +616,25 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
 	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	unsigned int regWrites = 0, i;
 	struct ieee80211_channel *channel = chan->chan;
-	u32 modesIndex, freqIndex;
+	u32 modesIndex;
 
 	switch (chan->chanmode) {
 	case CHANNEL_A:
 	case CHANNEL_A_HT20:
 		modesIndex = 1;
-		freqIndex = 1;
 		break;
 	case CHANNEL_A_HT40PLUS:
 	case CHANNEL_A_HT40MINUS:
 		modesIndex = 2;
-		freqIndex = 1;
 		break;
 	case CHANNEL_G:
 	case CHANNEL_G_HT20:
 	case CHANNEL_B:
 		modesIndex = 4;
-		freqIndex = 2;
 		break;
 	case CHANNEL_G_HT40PLUS:
 	case CHANNEL_G_HT40MINUS:
 		modesIndex = 3;
-		freqIndex = 2;
 		break;
 
 	default:
@@ -646,6 +659,9 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
 		REG_WRITE_ARRAY(&ah->iniModesAdditional,
 				modesIndex, regWrites);
 
+	if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
+		REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
+
 	ar9003_hw_override_ini(ah);
 	ar9003_hw_set_channel_regs(ah, chan);
 	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 8bdda2cf9dd75e7ba7fbef00b43579333f553273..2a0d5cbb7e76b8aadd5074581962d23fe0a475f1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -548,15 +548,12 @@
 
 #define AR_PHY_TXGAIN_TABLE      (AR_SM_BASE + 0x300)
 
-#define AR_PHY_TX_IQCAL_START_9485		(AR_SM_BASE + 0x3c4)
-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485	0x80000000
-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S	31
-#define AR_PHY_TX_IQCAL_CONTROL_1_9485		(AR_SM_BASE + 0x3c8)
-#define AR_PHY_TX_IQCAL_STATUS_B0_9485		(AR_SM_BASE + 0x3f0)
-
-#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + 0x448)
-#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + 0x440)
-#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + 0x48c)
+#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + AR_SREV_9485(ah) ? \
+						 0x3c8 : 0x448)
+#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + AR_SREV_9485(ah) ? \
+						 0x3c4 : 0x440)
+#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + AR_SREV_9485(ah) ? \
+						 0x3f0 : 0x48c)
 #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i)    (AR_SM_BASE + \
 					     (AR_SREV_9485(ah) ? \
 					      0x3d0 : 0x450) + ((_i) << 2))
@@ -588,7 +585,7 @@
 #define AR_PHY_65NM_CH0_BIAS2       0x160c4
 #define AR_PHY_65NM_CH0_BIAS4       0x160cc
 #define AR_PHY_65NM_CH0_RXTX4       0x1610c
-#define AR_PHY_65NM_CH0_THERM       (AR_SREV_9485(ah) ? 0x1628c : 0x16290)
+#define AR_PHY_65NM_CH0_THERM       (AR_SREV_9300(ah) ? 0x16290 : 0x1628c)
 
 #define AR_PHY_65NM_CH0_THERM_LOCAL   0x80000000
 #define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
@@ -758,10 +755,10 @@
 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT   0x01000000
 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
 #define AR_PHY_CHANNEL_STATUS_RX_CLEAR      0x00000004
-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT             0x01fc0000
-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S                   18
-#define AR_PHY_TX_IQCAL_START_DO_CAL        0x00000001
-#define AR_PHY_TX_IQCAL_START_DO_CAL_S      0
+#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT             0x01fc0000
+#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S                   18
+#define AR_PHY_TX_IQCAL_START_DO_CAL	    0x00000001
+#define AR_PHY_TX_IQCAL_START_DO_CAL_S	    0
 
 #define AR_PHY_TX_IQCAL_STATUS_FAILED    0x00000001
 #define AR_PHY_CALIBRATED_GAINS_0	 0x3e
diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..815a8af1beefd6684f09c29924a586e3f471dcb1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
@@ -0,0 +1,1525 @@
+/*
+ * Copyright (c) 2011 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_9340_H
+#define INITVALS_9340_H
+
+static const u32 ar9340_1p0_radio_postamble[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800},
+	{0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+	{0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
+	{0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+	{0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
+};
+
+static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = {
+	/*   Addr     5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{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, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27020223, 0x27020223, 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, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x770a308c, 0x770a308c, 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, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27820223, 0x27820223, 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, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_fast_clock_1p0[][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, 0x03721821, 0x03721821},
+	{0x0000a230, 0x0000000b, 0x00000016},
+	{0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9340_1p0_radio_core[][2] = {
+	/*  Addr     allmodes  */
+	{0x00016000, 0x36db6db6},
+	{0x00016004, 0x6db6db40},
+	{0x00016008, 0x73f00000},
+	{0x0001600c, 0x00000000},
+	{0x00016040, 0x7f80fff8},
+	{0x00016044, 0x03b6d2db},
+	{0x00016048, 0x24925266},
+	{0x0001604c, 0x000f0278},
+	{0x00016050, 0x6db6db6c},
+	{0x00016054, 0x6db60000},
+	{0x00016080, 0x00080000},
+	{0x00016084, 0x0e48048c},
+	{0x00016088, 0x14214514},
+	{0x0001608c, 0x119f081c},
+	{0x00016090, 0x24926490},
+	{0x00016094, 0x00000000},
+	{0x00016098, 0xd411eb84},
+	{0x0001609c, 0x03e47f32},
+	{0x000160a0, 0xc2108ffe},
+	{0x000160a4, 0x812fc370},
+	{0x000160a8, 0x423c8000},
+	{0x000160ac, 0xa4646800},
+	{0x000160b0, 0x00fe7f46},
+	{0x000160b4, 0x92480000},
+	{0x000160c0, 0x006db6db},
+	{0x000160c4, 0x6db6db60},
+	{0x000160c8, 0x6db6db6c},
+	{0x000160cc, 0x6de6db6c},
+	{0x000160d0, 0xb6da4924},
+	{0x00016100, 0x04cb0001},
+	{0x00016104, 0xfff80000},
+	{0x00016108, 0x00080010},
+	{0x0001610c, 0x00000000},
+	{0x00016140, 0x50804008},
+	{0x00016144, 0x01884080},
+	{0x00016148, 0x000080c0},
+	{0x00016280, 0x01000015},
+	{0x00016284, 0x05530000},
+	{0x00016288, 0x00318000},
+	{0x0001628c, 0x50000000},
+	{0x00016290, 0x4080294f},
+	{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},
+	{0x00016444, 0x03b6d2db},
+	{0x00016448, 0x24927266},
+	{0x0001644c, 0x000f0278},
+	{0x00016450, 0x6db6db6c},
+	{0x00016454, 0x6db60000},
+	{0x00016500, 0x04cb0001},
+	{0x00016504, 0xfff80000},
+	{0x00016508, 0x00080010},
+	{0x0001650c, 0x00000000},
+	{0x00016540, 0x50804008},
+	{0x00016544, 0x01884080},
+	{0x00016548, 0x000080c0},
+	{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},
+};
+
+static const u32 ar9340_1p0_radio_core_40M[][2] = {
+	{0x0001609c, 0x02566f3a},
+	{0x000160ac, 0xa4647c00},
+	{0x000160b0, 0x01885f5a},
+};
+
+static const u32 ar9340_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 ar9340_1p0_soc_postamble[][5] = {
+	/*   Addr     5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9340_1p0_baseband_postamble[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+	{0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e},
+	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+	{0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
+	{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+	{0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
+	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e},
+	{0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+	{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+	{0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0},
+	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+	{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, 0x00000220, 0x00000220, 0x00000110, 0x00000110},
+	{0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222},
+	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
+	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000},
+	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+	{0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9340_1p0_baseband_core[][2] = {
+	/*  Addr     allmodes  */
+	{0x00009800, 0xafe68e30},
+	{0x00009804, 0xfd14e000},
+	{0x00009808, 0x9c0a9f6b},
+	{0x0000980c, 0x04900000},
+	{0x00009814, 0xb280c00a},
+	{0x00009818, 0x00000000},
+	{0x0000981c, 0x00020028},
+	{0x00009834, 0x5f3ca3de},
+	{0x00009838, 0x0108ecff},
+	{0x0000983c, 0x14750600},
+	{0x00009880, 0x201fff00},
+	{0x00009884, 0x00001042},
+	{0x000098a4, 0x00200400},
+	{0x000098b0, 0x52440bbe},
+	{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},
+	{0x00009e3c, 0xcf946222},
+	{0x00009e40, 0x0d261820},
+	{0x00009e4c, 0x00001004},
+	{0x00009e50, 0x00ff03f1},
+	{0x00009e54, 0x00000000},
+	{0x00009fc0, 0x803e4788},
+	{0x00009fc4, 0x0001efb5},
+	{0x00009fcc, 0x40000014},
+	{0x00009fd0, 0x01193b93},
+	{0x0000a20c, 0x00000000},
+	{0x0000a220, 0x00000000},
+	{0x0000a224, 0x00000000},
+	{0x0000a228, 0x10002310},
+	{0x0000a22c, 0x01036a1e},
+	{0x0000a234, 0x10000fff},
+	{0x0000a23c, 0x00000000},
+	{0x0000a244, 0x0c000000},
+	{0x0000a2a0, 0x00000001},
+	{0x0000a2c0, 0x00000001},
+	{0x0000a2c8, 0x00000000},
+	{0x0000a2cc, 0x18c43433},
+	{0x0000a2d4, 0x00000000},
+	{0x0000a2dc, 0x00000000},
+	{0x0000a2e0, 0x00000000},
+	{0x0000a2e4, 0x00000000},
+	{0x0000a2e8, 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, 0x00000246},
+	{0x0000a3f8, 0x0cdbd380},
+	{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, 0x00000000},
+	{0x0000a440, 0x00000000},
+	{0x0000a444, 0x00000000},
+	{0x0000a448, 0x04000080},
+	{0x0000a44c, 0x00000001},
+	{0x0000a450, 0x00010000},
+	{0x0000a458, 0x00000000},
+	{0x0000a600, 0x00000000},
+	{0x0000a604, 0x00000000},
+	{0x0000a608, 0x00000000},
+	{0x0000a60c, 0x00000000},
+	{0x0000a610, 0x00000000},
+	{0x0000a614, 0x00000000},
+	{0x0000a618, 0x00000000},
+	{0x0000a61c, 0x00000000},
+	{0x0000a620, 0x00000000},
+	{0x0000a624, 0x00000000},
+	{0x0000a628, 0x00000000},
+	{0x0000a62c, 0x00000000},
+	{0x0000a630, 0x00000000},
+	{0x0000a634, 0x00000000},
+	{0x0000a638, 0x00000000},
+	{0x0000a63c, 0x00000000},
+	{0x0000a640, 0x00000000},
+	{0x0000a644, 0x3fad9d74},
+	{0x0000a648, 0x0048060a},
+	{0x0000a64c, 0x00000637},
+	{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},
+	{0x0000b2dc, 0x00000000},
+	{0x0000b2e0, 0x00000000},
+	{0x0000b2e4, 0x00000000},
+	{0x0000b2e8, 0x00000000},
+	{0x0000b2ec, 0x00000000},
+	{0x0000b2f0, 0x00000000},
+	{0x0000b2f4, 0x00000000},
+	{0x0000b2f8, 0x00000000},
+	{0x0000b408, 0x0e79e5c0},
+	{0x0000b40c, 0x00820820},
+	{0x0000b420, 0x00000000},
+};
+
+static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{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, 0x59025eb5, 0x59025eb5, 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},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = {
+	/*  Addr       5G_HT20    5G_HT40     2G_HT40     2G_HT20  */
+	{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, 0x59025eb5, 0x59025eb5, 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},
+	{0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+	{0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+};
+static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = {
+	/*  Addr      5G_HT20      5G_HT40     2G_HT40    2G_HT20  */
+	{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, 0x59025eb5, 0x59025eb5, 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},
+	{0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
+	{0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
+	{0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
+	{0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
+};
+
+
+static const u32 ar9340Common_rx_gain_table_1p0[][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, 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 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{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, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27020223, 0x27020223, 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, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x770a308c, 0x770a308c, 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, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27820223, 0x27820223, 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, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
+	/*  Addr       5G_HT20     5G_HT40     2G_HT40    2G_HT20  */
+	{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, 0x21020220, 0x21020220, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x27020223, 0x27020223, 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, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x770a308c, 0x770a308c, 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, 0x21820220, 0x21820220, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x27820223, 0x27820223, 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, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266},
+};
+
+static const u32 ar9340_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, 0x13881c20},
+	{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},
+	{0x00008170, 0x18486200},
+	{0x00008174, 0x33332210},
+	{0x00008178, 0x00000000},
+	{0x0000817c, 0x00020000},
+	{0x000081c0, 0x00000000},
+	{0x000081c4, 0x33332210},
+	{0x000081c8, 0x00000000},
+	{0x000081cc, 0x00000000},
+	{0x000081d4, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f424},
+	{0x00008248, 0x00000800},
+	{0x0000824c, 0x0001e848},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x40000000},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x9d400010},
+	{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 ar9340Common_wo_xlna_rx_gain_table_1p0[][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 ar9340_1p0_soc_preamble[][2] = {
+	/*    Addr        allmodes        */
+	{0x000040a4, 0x00a0c1c9},
+	{0x00007008, 0x00000000},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+};
+
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a6b538802251ae4108fd1ac4027bcf66c5b2da70..0312aa0918074c37f1c074ed5c201fbb4dd42d83 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -423,6 +423,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 #define ATH_PAPRD_TIMEOUT	100 /* msecs */
 
 void ath_hw_check(struct work_struct *work);
+void ath_hw_pll_work(struct work_struct *work);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 
@@ -453,6 +454,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
 
 #define ATH_LED_PIN_DEF 		1
 #define ATH_LED_PIN_9287		8
+#define ATH_LED_PIN_9300		10
 #define ATH_LED_PIN_9485		6
 
 #ifdef CONFIG_MAC80211_LEDS
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 24f565ba9988a4a0726aec7dbf0f2434479172b0..22cd241a098b31bdfe7dff1950bebf499df6773b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -781,12 +781,6 @@ void ath_set_beacon(struct ath_softc *sc)
 		break;
 	case NL80211_IFTYPE_STATION:
 		ath_beacon_config_sta(sc, cur_conf);
-		/*
-		 * Request a re-configuration of Beacon related timers
-		 * on the receipt of the first Beacon frame (i.e.,
-		 * after time sync with the AP).
-		 */
-		sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
 		break;
 	default:
 		ath_dbg(common, ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index d33bf204c995e743f1650e053a7030fbcc110721..23f15a7ca7f128a364ddc32d4ed5cee3fa66834d 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -51,6 +51,10 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
 		.bt_hold_rx_clear = true,
 	};
 	u32 i;
+	bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
+
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
 
 	btcoex_hw->bt_coex_mode =
 		(btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
@@ -59,7 +63,7 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
 		SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
 		SM(ath_bt_config.bt_mode, AR_BT_MODE) |
 		SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
-		SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
+		SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
 		SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
 		SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
 		SM(qnum, AR_BT_QCU_THRESH);
@@ -142,6 +146,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
 }
 EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
 
+
 static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
 {
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
@@ -152,9 +157,22 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
 	 * enable coex 3-wire
 	 */
 	REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode);
-	REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
 	REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
 
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, ah->bt_coex_wlan_weight[0]);
+		REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, ah->bt_coex_wlan_weight[1]);
+		REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, ah->bt_coex_bt_weight[0]);
+		REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, ah->bt_coex_bt_weight[1]);
+		REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, ah->bt_coex_bt_weight[2]);
+		REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, ah->bt_coex_bt_weight[3]);
+
+	} else
+		REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
+
+
+
 	if (AR_SREV_9271(ah)) {
 		val = REG_READ(ah, 0x50040);
 		val &= 0xFFFFFEFF;
@@ -202,10 +220,86 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah)
 
 	if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
 		REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
-		REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
 		REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+
+		if (AR_SREV_9300_20_OR_LATER(ah)) {
+			REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0);
+			REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0);
+			REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, 0);
+			REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, 0);
+			REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, 0);
+			REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, 0);
+		} else
+			REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+
 	}
 
 	ah->btcoex_hw.enabled = false;
 }
 EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
+
+static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
+			 enum ath_stomp_type stomp_type)
+{
+	ah->bt_coex_bt_weight[0] = AR9300_BT_WGHT;
+	ah->bt_coex_bt_weight[1] = AR9300_BT_WGHT;
+	ah->bt_coex_bt_weight[2] = AR9300_BT_WGHT;
+	ah->bt_coex_bt_weight[3] = AR9300_BT_WGHT;
+
+
+	switch (stomp_type) {
+	case ATH_BTCOEX_STOMP_ALL:
+		ah->bt_coex_wlan_weight[0] = AR9300_STOMP_ALL_WLAN_WGHT0;
+		ah->bt_coex_wlan_weight[1] = AR9300_STOMP_ALL_WLAN_WGHT1;
+		break;
+	case ATH_BTCOEX_STOMP_LOW:
+		ah->bt_coex_wlan_weight[0] = AR9300_STOMP_LOW_WLAN_WGHT0;
+		ah->bt_coex_wlan_weight[1] = AR9300_STOMP_LOW_WLAN_WGHT1;
+		break;
+	case ATH_BTCOEX_STOMP_NONE:
+		ah->bt_coex_wlan_weight[0] = AR9300_STOMP_NONE_WLAN_WGHT0;
+		ah->bt_coex_wlan_weight[1] = AR9300_STOMP_NONE_WLAN_WGHT1;
+		break;
+
+	default:
+		ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+				"Invalid Stomptype\n");
+		break;
+	}
+
+	ath9k_hw_btcoex_enable(ah);
+}
+
+/*
+ * Configures appropriate weight based on stomp type.
+ */
+void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
+			      enum ath_stomp_type stomp_type)
+{
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		ar9003_btcoex_bt_stomp(ah, stomp_type);
+		return;
+	}
+
+	switch (stomp_type) {
+	case ATH_BTCOEX_STOMP_ALL:
+		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+				AR_STOMP_ALL_WLAN_WGHT);
+		break;
+	case ATH_BTCOEX_STOMP_LOW:
+		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+				AR_STOMP_LOW_WLAN_WGHT);
+		break;
+	case ATH_BTCOEX_STOMP_NONE:
+		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+				AR_STOMP_NONE_WLAN_WGHT);
+		break;
+	default:
+		ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+				"Invalid Stomptype\n");
+		break;
+	}
+
+	ath9k_hw_btcoex_enable(ah);
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp);
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 588dfd464dd19938a59a3517729c1ed4330a6506..a9efca83d676dc08de3ca884004a886e5ec9824b 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -19,9 +19,13 @@
 
 #include "hw.h"
 
-#define ATH_WLANACTIVE_GPIO	5
-#define ATH_BTACTIVE_GPIO	6
-#define ATH_BTPRIORITY_GPIO	7
+#define ATH_WLANACTIVE_GPIO_9280     5
+#define ATH_BTACTIVE_GPIO_9280       6
+#define ATH_BTPRIORITY_GPIO_9285     7
+
+#define ATH_WLANACTIVE_GPIO_9300     5
+#define ATH_BTACTIVE_GPIO_9300       4
+#define ATH_BTPRIORITY_GPIO_9300     8
 
 #define ATH_BTCOEX_DEF_BT_PERIOD  45
 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55
@@ -32,6 +36,14 @@
 #define ATH_BT_CNT_THRESHOLD	       3
 #define ATH_BT_CNT_SCAN_THRESHOLD      15
 
+/* Defines the BT AR_BT_COEX_WGHT used */
+enum ath_stomp_type {
+	ATH_BTCOEX_NO_STOMP,
+	ATH_BTCOEX_STOMP_ALL,
+	ATH_BTCOEX_STOMP_LOW,
+	ATH_BTCOEX_STOMP_NONE
+};
+
 enum ath_btcoex_scheme {
 	ATH_BTCOEX_CFG_NONE,
 	ATH_BTCOEX_CFG_2WIRE,
@@ -57,5 +69,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
 				u32 wlan_weight);
 void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 void ath9k_hw_btcoex_disable(struct ath_hw *ah);
+void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
+			      enum ath_stomp_type stomp_type);
 
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 16ba8c67fbd5a62adba7d067952867ff3c0e4403..74535e6dfb82a024538caf059c6545f701ba3606 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -158,37 +158,6 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max)
 }
 EXPORT_SYMBOL(ath9k_cmn_count_streams);
 
-/*
- * Configures appropriate weight based on stomp type.
- */
-void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
-				  enum ath_stomp_type stomp_type)
-{
-	struct ath_hw *ah = common->ah;
-
-	switch (stomp_type) {
-	case ATH_BTCOEX_STOMP_ALL:
-		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-					   AR_STOMP_ALL_WLAN_WGHT);
-		break;
-	case ATH_BTCOEX_STOMP_LOW:
-		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-					   AR_STOMP_LOW_WLAN_WGHT);
-		break;
-	case ATH_BTCOEX_STOMP_NONE:
-		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-					   AR_STOMP_NONE_WLAN_WGHT);
-		break;
-	default:
-		ath_dbg(common, ATH_DBG_BTCOEX,
-			"Invalid Stomptype\n");
-		break;
-	}
-
-	ath9k_hw_btcoex_enable(ah);
-}
-EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp);
-
 void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
 			    u16 new_txpow, u16 *txpower)
 {
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index b2f7b5f89097422fb6a1ef696b5201d993a26544..5124f1420b3ae404cbcc80dfdf7732c3c0a06d91 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -50,14 +50,6 @@
 #define ATH_EP_RND(x, mul) 						\
 	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
 
-/* Defines the BT AR_BT_COEX_WGHT used */
-enum ath_stomp_type {
-	ATH_BTCOEX_NO_STOMP,
-	ATH_BTCOEX_STOMP_ALL,
-	ATH_BTCOEX_STOMP_LOW,
-	ATH_BTCOEX_STOMP_NONE
-};
-
 int ath9k_cmn_padpos(__le16 frame_control);
 int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
 void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 34f191ec8e8cab2b3a043dcf1640fb69984a35d7..bad1a87249b6011898027cce7300cea8358dbc49 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -326,6 +326,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
 		sc->debug.stats.istats.dtimsync++;
 	if (status & ATH9K_INT_DTIM)
 		sc->debug.stats.istats.dtim++;
+	if (status & ATH9K_INT_TSFOOR)
+		sc->debug.stats.istats.tsfoor++;
 }
 
 static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
@@ -379,9 +381,12 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
 		"%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync);
 	len += snprintf(buf + len, sizeof(buf) - len,
 		"%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "TSFOOR", sc->debug.stats.istats.tsfoor);
 	len += snprintf(buf + len, sizeof(buf) - len,
 		"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
 
+
 	if (len > sizeof(buf))
 		len = sizeof(buf);
 
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 1f9f8eada465d88331e46a334aeaa31c7da05e55..5488a324cc100b142ed1871a9ce493f18b893543 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -54,6 +54,9 @@ struct ath_buf;
  * @dtimsync: DTIM sync lossage
  * @dtim: RX Beacon with DTIM
  * @bb_watchdog: Baseband watchdog
+ * @tsfoor: TSF out of range, indicates that the corrected TSF received
+ * from a beacon differs from the PCU's internal TSF by more than a
+ * (programmable) threshold
  */
 struct ath_interrupt_stats {
 	u32 total;
@@ -78,6 +81,7 @@ struct ath_interrupt_stats {
 	u32 dtimsync;
 	u32 dtim;
 	u32 bb_watchdog;
+	u32 tsfoor;
 };
 
 /**
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 13579752a3006c9ccf883ed0cb55c19d818285c5..b87db4763098bad950f78824102d2626b598aa38 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -319,10 +319,9 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
 	u16 numXpdGain, xpdMask;
 	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
 	u32 reg32, regOffset, regChainOffset, regval;
-	int16_t modalIdx, diff = 0;
+	int16_t diff = 0;
 	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
 
-	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
 	xpdMask = pEepData->modalHeader.xpdGain;
 
 	if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 995949ddd63e4d707aa79c5b0c1734dc9731276e..c031854b569fe0a5c3c145724ec3373c802b68e2 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -231,6 +231,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
 				integer = swab32(pModal->antCtrlChain[i]);
 				pModal->antCtrlChain[i] = integer;
 			}
+			for (i = 0; i < 3; i++) {
+				word = swab16(pModal->xpaBiasLvlFreq[i]);
+				pModal->xpaBiasLvlFreq[i] = word;
+			}
 
 			for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
 				word = swab16(pModal->spurChans[i].spurChan);
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 44a0a886124d1738f6316eb671596bacb9d37088..0349b3a1cc58c8dcb29729f0237f9d4137e8de46 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -46,6 +46,8 @@ void ath_init_leds(struct ath_softc *sc)
 			sc->sc_ah->led_pin = ATH_LED_PIN_9287;
 		else if (AR_SREV_9485(sc->sc_ah))
 			sc->sc_ah->led_pin = ATH_LED_PIN_9485;
+		else if (AR_SREV_9300(sc->sc_ah))
+			sc->sc_ah->led_pin = ATH_LED_PIN_9300;
 		else
 			sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
 	}
@@ -138,10 +140,10 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
 
 static void ath9k_gen_timer_start(struct ath_hw *ah,
 				  struct ath_gen_timer *timer,
-				  u32 timer_next,
+				  u32 trig_timeout,
 				  u32 timer_period)
 {
-	ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
+	ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period);
 
 	if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
 		ath9k_hw_disable_interrupts(ah);
@@ -174,17 +176,17 @@ static void ath_btcoex_period_timer(unsigned long data)
 	struct ath_softc *sc = (struct ath_softc *) data;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_btcoex *btcoex = &sc->btcoex;
-	struct ath_common *common = ath9k_hw_common(ah);
 	u32 timer_period;
 	bool is_btscan;
 
+	ath9k_ps_wakeup(sc);
 	ath_detect_bt_priority(sc);
 
 	is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
 	spin_lock_bh(&btcoex->btcoex_lock);
 
-	ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+	ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
 			      btcoex->bt_stomp_type);
 
 	spin_unlock_bh(&btcoex->btcoex_lock);
@@ -195,11 +197,12 @@ static void ath_btcoex_period_timer(unsigned long data)
 
 		timer_period = is_btscan ? btcoex->btscan_no_stomp :
 					   btcoex->btcoex_no_stomp;
-		ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0,
+		ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
 				      timer_period * 10);
 		btcoex->hw_timer_enabled = true;
 	}
 
+	ath9k_ps_restore(sc);
 	mod_timer(&btcoex->period_timer, jiffies +
 				  msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
 }
@@ -219,14 +222,16 @@ static void ath_btcoex_no_stomp_timer(void *arg)
 	ath_dbg(common, ATH_DBG_BTCOEX,
 		"no stomp timer running\n");
 
+	ath9k_ps_wakeup(sc);
 	spin_lock_bh(&btcoex->btcoex_lock);
 
 	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
-		ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
+		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
 	 else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
-		ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
+		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
 
 	spin_unlock_bh(&btcoex->btcoex_lock);
+	ath9k_ps_restore(sc);
 }
 
 int ath_init_btcoex_timer(struct ath_softc *sc)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index f59df48a86e22de3b160df5187ef7f989e9b0ef2..2bdcdbc14b1ea899c687170522e6c3ced11475e2 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -17,6 +17,9 @@
 #ifndef HTC_USB_H
 #define HTC_USB_H
 
+#define MAJOR_VERSION_REQ 1
+#define MINOR_VERSION_REQ 2
+
 #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB))
 
 #define AR9271_FIRMWARE       0x501000
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 48a885575085286bd0aae8539071152ff3e72638..dfc7a982fc7eb265e263e524926603ba631574fc 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -66,8 +66,6 @@ enum htc_opmode {
 	HTC_M_WDS	= 2
 };
 
-#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr)
-
 #define ATH9K_HTC_AMPDU  1
 #define ATH9K_HTC_NORMAL 2
 #define ATH9K_HTC_BEACON 3
@@ -75,7 +73,6 @@ enum htc_opmode {
 
 #define ATH9K_HTC_TX_CTSONLY      0x1
 #define ATH9K_HTC_TX_RTSCTS       0x2
-#define ATH9K_HTC_TX_USE_MIN_RATE 0x100
 
 struct tx_frame_hdr {
 	u8 data_type;
@@ -106,15 +103,14 @@ struct tx_beacon_header {
 	u16 rev;
 } __packed;
 
+#define MAX_TX_AMPDU_SUBFRAMES_9271 17
+#define MAX_TX_AMPDU_SUBFRAMES_7010 22
+
 struct ath9k_htc_cap_target {
-	u32 flags;
-	u32 flags_ext;
-	u32 ampdu_limit;
+	__be32 ampdu_limit;
 	u8 ampdu_subframes;
+	u8 enable_coex;
 	u8 tx_chainmask;
-	u8 tx_chainmask_legacy;
-	u8 rtscts_ratecode;
-	u8 protmode;
 	u8 pad;
 } __packed;
 
@@ -175,6 +171,13 @@ struct ath9k_htc_target_rate {
 	struct ath9k_htc_rate rates;
 };
 
+struct ath9k_htc_target_rate_mask {
+	u8 vif_index;
+	u8 band;
+	__be32 mask;
+	u16 pad;
+} __packed;
+
 struct ath9k_htc_target_int_stats {
 	__be32 rx;
 	__be32 rxorn;
@@ -382,25 +385,6 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
 #define ATH_LED_PIN_9287            10
 #define ATH_LED_PIN_9271            15
 #define ATH_LED_PIN_7010            12
-#define ATH_LED_ON_DURATION_IDLE    350	/* in msecs */
-#define ATH_LED_OFF_DURATION_IDLE   250	/* in msecs */
-
-enum ath_led_type {
-	ATH_LED_RADIO,
-	ATH_LED_ASSOC,
-	ATH_LED_TX,
-	ATH_LED_RX
-};
-
-struct ath_led {
-	struct ath9k_htc_priv *priv;
-	struct led_classdev led_cdev;
-	enum ath_led_type led_type;
-	struct delayed_work brightness_work;
-	char name[32];
-	bool registered;
-	int brightness;
-};
 
 #define BSTUCK_THRESHOLD 10
 
@@ -434,14 +418,11 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
 
 #define OP_INVALID		   BIT(0)
 #define OP_SCANNING		   BIT(1)
-#define OP_LED_ASSOCIATED	   BIT(2)
-#define OP_LED_ON		   BIT(3)
-#define OP_ENABLE_BEACON	   BIT(4)
-#define OP_LED_DEINIT		   BIT(5)
-#define OP_BT_PRIORITY_DETECTED    BIT(6)
-#define OP_BT_SCAN                 BIT(7)
-#define OP_ANI_RUNNING             BIT(8)
-#define OP_TSF_RESET               BIT(9)
+#define OP_ENABLE_BEACON           BIT(2)
+#define OP_BT_PRIORITY_DETECTED    BIT(3)
+#define OP_BT_SCAN                 BIT(4)
+#define OP_ANI_RUNNING             BIT(5)
+#define OP_TSF_RESET               BIT(6)
 
 struct ath9k_htc_priv {
 	struct device *dev;
@@ -501,15 +482,13 @@ struct ath9k_htc_priv {
 	bool ps_enabled;
 	bool ps_idle;
 
-	struct ath_led radio_led;
-	struct ath_led assoc_led;
-	struct ath_led tx_led;
-	struct ath_led rx_led;
-	struct delayed_work ath9k_led_blink_work;
-	int led_on_duration;
-	int led_off_duration;
-	int led_on_cnt;
-	int led_off_cnt;
+#ifdef CONFIG_MAC80211_LEDS
+	enum led_brightness brightness;
+	bool led_registered;
+	char led_name[32];
+	struct led_classdev led_cdev;
+	struct work_struct led_work;
+#endif
 
 	int beaconq;
 	int cabq;
@@ -551,7 +530,8 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id,
 void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
 			enum htc_endpoint_id ep_id, bool txok);
 
-int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv);
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
+				u8 enable_coex);
 void ath9k_htc_station_work(struct work_struct *work);
 void ath9k_htc_aggr_work(struct work_struct *work);
 void ath9k_htc_ani_work(struct work_struct *work);
@@ -593,9 +573,24 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
 void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
 void ath9k_htc_radio_enable(struct ieee80211_hw *hw);
 void ath9k_htc_radio_disable(struct ieee80211_hw *hw);
-void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv);
+
+#ifdef CONFIG_MAC80211_LEDS
 void ath9k_init_leds(struct ath9k_htc_priv *priv);
 void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
+void ath9k_led_work(struct work_struct *work);
+#else
+static inline void ath9k_init_leds(struct ath9k_htc_priv *priv)
+{
+}
+
+static inline void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
+{
+}
+
+static inline void ath9k_led_work(struct work_struct *work)
+{
+}
+#endif
 
 int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
 			   u16 devid, char *product, u32 drv_info);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index a157107b3f3b894d39779f59205a1382770d3f91..0ded2c66d5ffdd13fe38607794cf65b291d90f32 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -74,7 +74,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 	__be32 htc_imask = 0;
 	u64 tsf;
 	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
-	int ret;
+	int ret __attribute__ ((unused));
 	u8 cmd_rsp;
 
 	memset(&bs, 0, sizeof(bs));
@@ -190,7 +190,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
 	enum ath9k_int imask = 0;
 	u32 nexttbtt, intval, tsftu;
 	__be32 htc_imask = 0;
-	int ret;
+	int ret __attribute__ ((unused));
 	u8 cmd_rsp;
 	u64 tsf;
 
@@ -246,7 +246,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
 	enum ath9k_int imask = 0;
 	u32 nexttbtt, intval, tsftu;
 	__be32 htc_imask = 0;
-	int ret;
+	int ret __attribute__ ((unused));
 	u8 cmd_rsp;
 	u64 tsf;
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index eca777497fe5806405b6307fcbaf7db2af19664a..aa48b3abbc48eba276714af3b91ae0a0e4b74c27 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -33,9 +33,15 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
 
 	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
 
+	ath9k_htc_ps_wakeup(priv);
+
 	WMI_CMD(WMI_INT_STATS_CMDID);
-	if (ret)
+	if (ret) {
+		ath9k_htc_ps_restore(priv);
 		return -EINVAL;
+	}
+
+	ath9k_htc_ps_restore(priv);
 
 	len += snprintf(buf + len, sizeof(buf) - len,
 			"%20s : %10u\n", "RX",
@@ -85,9 +91,15 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,
 
 	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
 
+	ath9k_htc_ps_wakeup(priv);
+
 	WMI_CMD(WMI_TX_STATS_CMDID);
-	if (ret)
+	if (ret) {
+		ath9k_htc_ps_restore(priv);
 		return -EINVAL;
+	}
+
+	ath9k_htc_ps_restore(priv);
 
 	len += snprintf(buf + len, sizeof(buf) - len,
 			"%20s : %10u\n", "Xretries",
@@ -149,9 +161,15 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,
 
 	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
 
+	ath9k_htc_ps_wakeup(priv);
+
 	WMI_CMD(WMI_RX_STATS_CMDID);
-	if (ret)
+	if (ret) {
+		ath9k_htc_ps_restore(priv);
 		return -EINVAL;
+	}
+
+	ath9k_htc_ps_restore(priv);
 
 	len += snprintf(buf + len, sizeof(buf) - len,
 			"%20s : %10u\n", "NoBuf",
@@ -474,6 +492,439 @@ static const struct file_operations fops_debug = {
 	.llseek = default_llseek,
 };
 
+static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct base_eep_header *pBase = NULL;
+	unsigned int len = 0, size = 1500;
+	ssize_t retval = 0;
+	char *buf;
+
+	/*
+	 * This can be done since all the 3 EEPROM families have the
+	 * same base header upto a certain point, and we are interested in
+	 * the data only upto that point.
+	 */
+
+	if (AR_SREV_9271(priv->ah))
+		pBase = (struct base_eep_header *)
+			&priv->ah->eeprom.map4k.baseEepHeader;
+	else if (priv->ah->hw_version.usbdev == AR9280_USB)
+		pBase = (struct base_eep_header *)
+			&priv->ah->eeprom.def.baseEepHeader;
+	else if (priv->ah->hw_version.usbdev == AR9287_USB)
+		pBase = (struct base_eep_header *)
+			&priv->ah->eeprom.map9287.baseEepHeader;
+
+	if (pBase == NULL) {
+		ath_err(common, "Unknown EEPROM type\n");
+		return 0;
+	}
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n", "Major Version",
+			pBase->version >> 12);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n", "Minor Version",
+			pBase->version & 0xFFF);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n", "Checksum",
+			pBase->checksum);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n", "Length",
+			pBase->length);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n", "RegDomain1",
+			pBase->regDmn[0]);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n", "RegDomain2",
+			pBase->regDmn[1]);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"TX Mask", pBase->txMask);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"RX Mask", pBase->rxMask);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Allow 5GHz",
+			!!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Allow 2GHz",
+			!!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Disable 2GHz HT20",
+			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20));
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Disable 2GHz HT40",
+			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40));
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Disable 5Ghz HT20",
+			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20));
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Disable 5Ghz HT40",
+			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40));
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Big Endian",
+			!!(pBase->eepMisc & 0x01));
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Cal Bin Major Ver",
+			(pBase->binBuildNumber >> 24) & 0xFF);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Cal Bin Minor Ver",
+			(pBase->binBuildNumber >> 16) & 0xFF);
+	len += snprintf(buf + len, size - len,
+			"%20s : %10d\n",
+			"Cal Bin Build",
+			(pBase->binBuildNumber >> 8) & 0xFF);
+
+	/*
+	 * UB91 specific data.
+	 */
+	if (AR_SREV_9271(priv->ah)) {
+		struct base_eep_header_4k *pBase4k =
+			&priv->ah->eeprom.map4k.baseEepHeader;
+
+		len += snprintf(buf + len, size - len,
+				"%20s : %10d\n",
+				"TX Gain type",
+				pBase4k->txGainType);
+	}
+
+	/*
+	 * UB95 specific data.
+	 */
+	if (priv->ah->hw_version.usbdev == AR9287_USB) {
+		struct base_eep_ar9287_header *pBase9287 =
+			&priv->ah->eeprom.map9287.baseEepHeader;
+
+		len += snprintf(buf + len, size - len,
+				"%20s : %10ddB\n",
+				"Power Table Offset",
+				pBase9287->pwrTableOffset);
+
+		len += snprintf(buf + len, size - len,
+				"%20s : %10d\n",
+				"OpenLoop Power Ctrl",
+				pBase9287->openLoopPwrCntl);
+	}
+
+	len += snprintf(buf + len, size - len,
+			"%20s : %02X:%02X:%02X:%02X:%02X:%02X\n",
+			"MacAddress",
+			pBase->macAddr[0], pBase->macAddr[1], pBase->macAddr[2],
+			pBase->macAddr[3], pBase->macAddr[4], pBase->macAddr[5]);
+	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_base_eeprom = {
+	.read = read_file_base_eeprom,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_4k_modal_eeprom(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+#define PR_EEP(_s, _val)						\
+	do {								\
+		len += snprintf(buf + len, size - len, "%20s : %10d\n",	\
+				_s, (_val));				\
+	} while (0)
+
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader;
+	unsigned int len = 0, size = 2048;
+	ssize_t retval = 0;
+	char *buf;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]);
+	PR_EEP("Ant. Common Control", pModal->antCtrlCommon);
+	PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]);
+	PR_EEP("Switch Settle", pModal->switchSettling);
+	PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]);
+	PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]);
+	PR_EEP("ADC Desired size", pModal->adcDesiredSize);
+	PR_EEP("PGA Desired size", pModal->pgaDesiredSize);
+	PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]);
+	PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff);
+	PR_EEP("txEndToRxOn", pModal->txEndToRxOn);
+	PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn);
+	PR_EEP("CCA Threshold)", pModal->thresh62);
+	PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]);
+	PR_EEP("xpdGain", pModal->xpdGain);
+	PR_EEP("External PD", pModal->xpd);
+	PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]);
+	PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]);
+	PR_EEP("pdGainOverlap", pModal->pdGainOverlap);
+	PR_EEP("O/D Bias Version", pModal->version);
+	PR_EEP("CCK OutputBias", pModal->ob_0);
+	PR_EEP("BPSK OutputBias", pModal->ob_1);
+	PR_EEP("QPSK OutputBias", pModal->ob_2);
+	PR_EEP("16QAM OutputBias", pModal->ob_3);
+	PR_EEP("64QAM OutputBias", pModal->ob_4);
+	PR_EEP("CCK Driver1_Bias", pModal->db1_0);
+	PR_EEP("BPSK Driver1_Bias", pModal->db1_1);
+	PR_EEP("QPSK Driver1_Bias", pModal->db1_2);
+	PR_EEP("16QAM Driver1_Bias", pModal->db1_3);
+	PR_EEP("64QAM Driver1_Bias", pModal->db1_4);
+	PR_EEP("CCK Driver2_Bias", pModal->db2_0);
+	PR_EEP("BPSK Driver2_Bias", pModal->db2_1);
+	PR_EEP("QPSK Driver2_Bias", pModal->db2_2);
+	PR_EEP("16QAM Driver2_Bias", pModal->db2_3);
+	PR_EEP("64QAM Driver2_Bias", pModal->db2_4);
+	PR_EEP("xPA Bias Level", pModal->xpaBiasLvl);
+	PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart);
+	PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn);
+	PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc);
+	PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]);
+	PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]);
+	PR_EEP("HT40 Switch Settle", pModal->swSettleHt40);
+	PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]);
+	PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]);
+	PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1);
+	PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2);
+	PR_EEP("TX Diversity", pModal->tx_diversity);
+
+	if (len > size)
+		len = size;
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+
+#undef PR_EEP
+}
+
+static ssize_t read_def_modal_eeprom(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+#define PR_EEP(_s, _val)						\
+	do {								\
+		if (pBase->opCapFlags & AR5416_OPFLAGS_11G) {		\
+			pModal = &priv->ah->eeprom.def.modalHeader[1];	\
+			len += snprintf(buf + len, size - len, "%20s : %8d%7s", \
+					_s, (_val), "|");		\
+		}							\
+		if (pBase->opCapFlags & AR5416_OPFLAGS_11A) {		\
+			pModal = &priv->ah->eeprom.def.modalHeader[0];	\
+			len += snprintf(buf + len, size - len, "%9d\n", \
+					(_val));			\
+		}							\
+	} while (0)
+
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader;
+	struct modal_eep_header *pModal = NULL;
+	unsigned int len = 0, size = 3500;
+	ssize_t retval = 0;
+	char *buf;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	len += snprintf(buf + len, size - len,
+			"%31s %15s\n", "2G", "5G");
+	len += snprintf(buf + len, size - len,
+			"%32s %16s\n", "====", "====\n");
+
+	PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]);
+	PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]);
+	PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]);
+	PR_EEP("Ant. Common Control", pModal->antCtrlCommon);
+	PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]);
+	PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]);
+	PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]);
+	PR_EEP("Switch Settle", pModal->switchSettling);
+	PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]);
+	PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]);
+	PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]);
+	PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]);
+	PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]);
+	PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]);
+	PR_EEP("ADC Desired size", pModal->adcDesiredSize);
+	PR_EEP("PGA Desired size", pModal->pgaDesiredSize);
+	PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]);
+	PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]);
+	PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]);
+	PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff);
+	PR_EEP("txEndToRxOn", pModal->txEndToRxOn);
+	PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn);
+	PR_EEP("CCA Threshold)", pModal->thresh62);
+	PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]);
+	PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]);
+	PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]);
+	PR_EEP("xpdGain", pModal->xpdGain);
+	PR_EEP("External PD", pModal->xpd);
+	PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]);
+	PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]);
+	PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]);
+	PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]);
+	PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]);
+	PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]);
+	PR_EEP("pdGainOverlap", pModal->pdGainOverlap);
+	PR_EEP("Chain0 OutputBias", pModal->ob);
+	PR_EEP("Chain0 DriverBias", pModal->db);
+	PR_EEP("xPA Bias Level", pModal->xpaBiasLvl);
+	PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain);
+	PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain);
+	PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart);
+	PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn);
+	PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc);
+	PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]);
+	PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]);
+	PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]);
+	PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]);
+	PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]);
+	PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]);
+	PR_EEP("HT40 Switch Settle", pModal->swSettleHt40);
+	PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]);
+	PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]);
+	PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]);
+	PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]);
+	PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]);
+	PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]);
+	PR_EEP("Chain1 OutputBias", pModal->ob_ch1);
+	PR_EEP("Chain1 DriverBias", pModal->db_ch1);
+	PR_EEP("LNA Control", pModal->lna_ctl);
+	PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]);
+	PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]);
+	PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]);
+
+	if (len > size)
+		len = size;
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+
+#undef PR_EEP
+}
+
+static ssize_t read_9287_modal_eeprom(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+#define PR_EEP(_s, _val)						\
+	do {								\
+		len += snprintf(buf + len, size - len, "%20s : %10d\n",	\
+				_s, (_val));				\
+	} while (0)
+
+	struct ath9k_htc_priv *priv = file->private_data;
+	struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader;
+	unsigned int len = 0, size = 3000;
+	ssize_t retval = 0;
+	char *buf;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]);
+	PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]);
+	PR_EEP("Ant. Common Control", pModal->antCtrlCommon);
+	PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]);
+	PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]);
+	PR_EEP("Switch Settle", pModal->switchSettling);
+	PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]);
+	PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]);
+	PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]);
+	PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]);
+	PR_EEP("ADC Desired size", pModal->adcDesiredSize);
+	PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff);
+	PR_EEP("txEndToRxOn", pModal->txEndToRxOn);
+	PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn);
+	PR_EEP("CCA Threshold)", pModal->thresh62);
+	PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]);
+	PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]);
+	PR_EEP("xpdGain", pModal->xpdGain);
+	PR_EEP("External PD", pModal->xpd);
+	PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]);
+	PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]);
+	PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]);
+	PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]);
+	PR_EEP("pdGainOverlap", pModal->pdGainOverlap);
+	PR_EEP("xPA Bias Level", pModal->xpaBiasLvl);
+	PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart);
+	PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn);
+	PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc);
+	PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]);
+	PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]);
+	PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]);
+	PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]);
+	PR_EEP("HT40 Switch Settle", pModal->swSettleHt40);
+	PR_EEP("AR92x7 Version", pModal->version);
+	PR_EEP("DriverBias1", pModal->db1);
+	PR_EEP("DriverBias2", pModal->db1);
+	PR_EEP("CCK OutputBias", pModal->ob_cck);
+	PR_EEP("PSK OutputBias", pModal->ob_psk);
+	PR_EEP("QAM OutputBias", pModal->ob_qam);
+	PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off);
+
+	if (len > size)
+		len = size;
+
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+
+#undef PR_EEP
+}
+
+static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath9k_htc_priv *priv = file->private_data;
+
+	if (AR_SREV_9271(priv->ah))
+		return read_4k_modal_eeprom(file, user_buf, count, ppos);
+	else if (priv->ah->hw_version.usbdev == AR9280_USB)
+		return read_def_modal_eeprom(file, user_buf, count, ppos);
+	else if (priv->ah->hw_version.usbdev == AR9287_USB)
+		return read_9287_modal_eeprom(file, user_buf, count, ppos);
+
+	return 0;
+}
+
+static const struct file_operations fops_modal_eeprom = {
+	.read = read_file_modal_eeprom,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath9k_htc_init_debug(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -485,21 +936,25 @@ int ath9k_htc_init_debug(struct ath_hw *ah)
 		return -ENOMEM;
 
 	debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy,
-				priv, &fops_tgt_int_stats);
+			    priv, &fops_tgt_int_stats);
 	debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy,
-				priv, &fops_tgt_tx_stats);
+			    priv, &fops_tgt_tx_stats);
 	debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy,
-				priv, &fops_tgt_rx_stats);
+			    priv, &fops_tgt_rx_stats);
 	debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,
-				priv, &fops_xmit);
+			    priv, &fops_xmit);
 	debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy,
-				priv, &fops_recv);
+			    priv, &fops_recv);
 	debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,
-				priv, &fops_slot);
+			    priv, &fops_slot);
 	debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,
-				priv, &fops_queue);
+			    priv, &fops_queue);
 	debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
-				priv, &fops_debug);
+			    priv, &fops_debug);
+	debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy,
+			    priv, &fops_base_eeprom);
+	debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy,
+			    priv, &fops_modal_eeprom);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index dc0b33d012104f5ee610217910c7a8cf4eca88b1..af57fe5aab98848f52bcd129184181a84c773033 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -65,17 +65,19 @@ static void ath_btcoex_period_work(struct work_struct *work)
 	u32 timer_period;
 	bool is_btscan;
 	int ret;
-	u8 cmd_rsp, aggr;
 
 	ath_detect_bt_priority(priv);
 
 	is_btscan = !!(priv->op_flags & OP_BT_SCAN);
 
-	aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
-
-	WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
+	ret = ath9k_htc_update_cap_target(priv,
+				  !!(priv->op_flags & OP_BT_PRIORITY_DETECTED));
+	if (ret) {
+		ath_err(common, "Unable to set BTCOEX parameters\n");
+		return;
+	}
 
-	ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+	ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
 			btcoex->bt_stomp_type);
 
 	timer_period = is_btscan ? btcoex->btscan_no_stomp :
@@ -103,9 +105,9 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work)
 		"time slice work for bt and wlan\n");
 
 	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
-		ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
+		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
 	else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
-		ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
+		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
 }
 
 void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
@@ -152,140 +154,41 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
 /* LED */
 /*******/
 
-static void ath9k_led_blink_work(struct work_struct *work)
+#ifdef CONFIG_MAC80211_LEDS
+void ath9k_led_work(struct work_struct *work)
 {
-	struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
-						   ath9k_led_blink_work.work);
+	struct ath9k_htc_priv *priv = container_of(work,
+						   struct ath9k_htc_priv,
+						   led_work);
 
-	if (!(priv->op_flags & OP_LED_ASSOCIATED))
-		return;
-
-	if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
-	    (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
-		ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
-	else
-		ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
-				  (priv->op_flags & OP_LED_ON) ? 1 : 0);
-
-	ieee80211_queue_delayed_work(priv->hw,
-				     &priv->ath9k_led_blink_work,
-				     (priv->op_flags & OP_LED_ON) ?
-				     msecs_to_jiffies(priv->led_off_duration) :
-				     msecs_to_jiffies(priv->led_on_duration));
-
-	priv->led_on_duration = priv->led_on_cnt ?
-		max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
-		ATH_LED_ON_DURATION_IDLE;
-	priv->led_off_duration = priv->led_off_cnt ?
-		max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
-		ATH_LED_OFF_DURATION_IDLE;
-	priv->led_on_cnt = priv->led_off_cnt = 0;
-
-	if (priv->op_flags & OP_LED_ON)
-		priv->op_flags &= ~OP_LED_ON;
-	else
-		priv->op_flags |= OP_LED_ON;
-}
-
-static void ath9k_led_brightness_work(struct work_struct *work)
-{
-	struct ath_led *led = container_of(work, struct ath_led,
-					   brightness_work.work);
-	struct ath9k_htc_priv *priv = led->priv;
-
-	switch (led->brightness) {
-	case LED_OFF:
-		if (led->led_type == ATH_LED_ASSOC ||
-		    led->led_type == ATH_LED_RADIO) {
-			ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
-					  (led->led_type == ATH_LED_RADIO));
-			priv->op_flags &= ~OP_LED_ASSOCIATED;
-			if (led->led_type == ATH_LED_RADIO)
-				priv->op_flags &= ~OP_LED_ON;
-		} else {
-			priv->led_off_cnt++;
-		}
-		break;
-	case LED_FULL:
-		if (led->led_type == ATH_LED_ASSOC) {
-			priv->op_flags |= OP_LED_ASSOCIATED;
-			ieee80211_queue_delayed_work(priv->hw,
-					     &priv->ath9k_led_blink_work, 0);
-		} else if (led->led_type == ATH_LED_RADIO) {
-			ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
-			priv->op_flags |= OP_LED_ON;
-		} else {
-			priv->led_on_cnt++;
-		}
-		break;
-	default:
-		break;
-	}
+	ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
+			  (priv->brightness == LED_OFF));
 }
 
 static void ath9k_led_brightness(struct led_classdev *led_cdev,
 				 enum led_brightness brightness)
 {
-	struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
-	struct ath9k_htc_priv *priv = led->priv;
+	struct ath9k_htc_priv *priv = container_of(led_cdev,
+						   struct ath9k_htc_priv,
+						   led_cdev);
 
-	led->brightness = brightness;
-	if (!(priv->op_flags & OP_LED_DEINIT))
-		ieee80211_queue_delayed_work(priv->hw,
-					     &led->brightness_work, 0);
-}
-
-void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
-{
-	cancel_delayed_work_sync(&priv->radio_led.brightness_work);
-	cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
-	cancel_delayed_work_sync(&priv->tx_led.brightness_work);
-	cancel_delayed_work_sync(&priv->rx_led.brightness_work);
-}
-
-static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
-			      char *trigger)
-{
-	int ret;
-
-	led->priv = priv;
-	led->led_cdev.name = led->name;
-	led->led_cdev.default_trigger = trigger;
-	led->led_cdev.brightness_set = ath9k_led_brightness;
-
-	ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
-	if (ret)
-		ath_err(ath9k_hw_common(priv->ah),
-			"Failed to register led:%s", led->name);
-	else
-		led->registered = 1;
-
-	INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
-
-	return ret;
-}
-
-static void ath9k_unregister_led(struct ath_led *led)
-{
-	if (led->registered) {
-		led_classdev_unregister(&led->led_cdev);
-		led->registered = 0;
-	}
+	/* Not locked, but it's just a tiny green light..*/
+	priv->brightness = brightness;
+	ieee80211_queue_work(priv->hw, &priv->led_work);
 }
 
 void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
 {
-	priv->op_flags |= OP_LED_DEINIT;
-	ath9k_unregister_led(&priv->assoc_led);
-	priv->op_flags &= ~OP_LED_ASSOCIATED;
-	ath9k_unregister_led(&priv->tx_led);
-	ath9k_unregister_led(&priv->rx_led);
-	ath9k_unregister_led(&priv->radio_led);
+	if (!priv->led_registered)
+		return;
+
+	ath9k_led_brightness(&priv->led_cdev, LED_OFF);
+	led_classdev_unregister(&priv->led_cdev);
+	cancel_work_sync(&priv->led_work);
 }
 
 void ath9k_init_leds(struct ath9k_htc_priv *priv)
 {
-	char *trigger;
 	int ret;
 
 	if (AR_SREV_9287(priv->ah))
@@ -303,48 +206,21 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
 	/* LED off, active low */
 	ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
 
-	INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
-
-	trigger = ieee80211_get_radio_led_name(priv->hw);
-	snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
-		"ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
-	ret = ath9k_register_led(priv, &priv->radio_led, trigger);
-	priv->radio_led.led_type = ATH_LED_RADIO;
-	if (ret)
-		goto fail;
-
-	trigger = ieee80211_get_assoc_led_name(priv->hw);
-	snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
-		"ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
-	ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
-	priv->assoc_led.led_type = ATH_LED_ASSOC;
-	if (ret)
-		goto fail;
-
-	trigger = ieee80211_get_tx_led_name(priv->hw);
-	snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
-		"ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
-	ret = ath9k_register_led(priv, &priv->tx_led, trigger);
-	priv->tx_led.led_type = ATH_LED_TX;
-	if (ret)
-		goto fail;
-
-	trigger = ieee80211_get_rx_led_name(priv->hw);
-	snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
-		"ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
-	ret = ath9k_register_led(priv, &priv->rx_led, trigger);
-	priv->rx_led.led_type = ATH_LED_RX;
-	if (ret)
-		goto fail;
-
-	priv->op_flags &= ~OP_LED_DEINIT;
+	snprintf(priv->led_name, sizeof(priv->led_name),
+		"ath9k_htc-%s", wiphy_name(priv->hw->wiphy));
+	priv->led_cdev.name = priv->led_name;
+	priv->led_cdev.brightness_set = ath9k_led_brightness;
 
-	return;
+	ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev);
+	if (ret < 0)
+		return;
 
-fail:
-	cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
-	ath9k_deinit_leds(priv);
+	INIT_WORK(&priv->led_work, ath9k_led_work);
+	priv->led_registered = true;
+
+	return;
 }
+#endif
 
 /*******************/
 /*	Rfkill	   */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 06e043bffaf45c72376e965257aa13002bf1d887..bfdc8a8871830b5ccb63aa848d69d8121d3745b0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -117,6 +117,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = {
 	RATE(540, 0x0c, 0),
 };
 
+#ifdef CONFIG_MAC80211_LEDS
+static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
+	{ .throughput = 0 * 1024, .blink_time = 334 },
+	{ .throughput = 1 * 1024, .blink_time = 260 },
+	{ .throughput = 5 * 1024, .blink_time = 220 },
+	{ .throughput = 10 * 1024, .blink_time = 190 },
+	{ .throughput = 20 * 1024, .blink_time = 170 },
+	{ .throughput = 50 * 1024, .blink_time = 150 },
+	{ .throughput = 70 * 1024, .blink_time = 130 },
+	{ .throughput = 100 * 1024, .blink_time = 110 },
+	{ .throughput = 200 * 1024, .blink_time = 80 },
+	{ .throughput = 300 * 1024, .blink_time = 50 },
+};
+#endif
+
 static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
 {
 	int time_left;
@@ -243,7 +258,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
 	 */
 
 	if (IS_AR7010_DEVICE(drv_info))
-		priv->htc->credits = 45;
+		priv->htc->credits = 48;
 	else
 		priv->htc->credits = 33;
 
@@ -753,6 +768,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
 	hw->queues = 4;
 	hw->channel_change_time = 5000;
 	hw->max_listen_interval = 10;
+
+	if (AR_SREV_9271(priv->ah))
+		hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_9271;
+	else
+		hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_7010;
+
 	hw->vif_data_size = sizeof(struct ath9k_htc_vif);
 	hw->sta_data_size = sizeof(struct ath9k_htc_sta);
 
@@ -802,6 +823,17 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
 		 priv->fw_version_major,
 		 priv->fw_version_minor);
 
+	/*
+	 * Check if the available FW matches the driver's
+	 * required version.
+	 */
+	if (priv->fw_version_major != MAJOR_VERSION_REQ ||
+	    priv->fw_version_minor != MINOR_VERSION_REQ) {
+		dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
+			MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -846,6 +878,13 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
 	if (error != 0)
 		goto err_rx;
 
+#ifdef CONFIG_MAC80211_LEDS
+	/* must be initialized before ieee80211_register_hw */
+	priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
+		IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink,
+		ARRAY_SIZE(ath9k_htc_tpt_blink));
+#endif
+
 	/* Register with mac80211 */
 	error = ieee80211_register_hw(hw);
 	if (error)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 4de38643cb5311429abe06716b8e993a7d654e72..5aa104fe7eebf26e44d60eee2efcfc21d5129ed0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -332,6 +332,11 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
 	memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
 	hvif.index = priv->mon_vif_idx;
 	WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+	if (ret) {
+		ath_err(common, "Unable to remove monitor interface at idx: %d\n",
+			priv->mon_vif_idx);
+	}
+
 	priv->nvifs--;
 	priv->vif_slot &= ~(1 << priv->mon_vif_idx);
 }
@@ -462,6 +467,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
 	struct ath9k_htc_sta *ista;
 	int ret, sta_idx;
 	u8 cmd_rsp;
+	u16 maxampdu;
 
 	if (priv->nstations >= ATH9K_HTC_MAX_STA)
 		return -ENOBUFS;
@@ -485,7 +491,15 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
 
 	tsta.sta_index = sta_idx;
 	tsta.vif_index = avp->index;
-	tsta.maxampdu = cpu_to_be16(0xffff);
+
+	if (!sta) {
+		tsta.maxampdu = cpu_to_be16(0xffff);
+	} else {
+		maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+				 sta->ht_cap.ampdu_factor);
+		tsta.maxampdu = cpu_to_be16(maxampdu);
+	}
+
 	if (sta && sta->ht_cap.ht_supported)
 		tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
 
@@ -558,7 +572,8 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
 	return 0;
 }
 
-int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
+				u8 enable_coex)
 {
 	struct ath9k_htc_cap_target tcap;
 	int ret;
@@ -566,13 +581,9 @@ int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
 
 	memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
 
-	/* FIXME: Values are hardcoded */
-	tcap.flags = 0x240c40;
-	tcap.flags_ext = 0x80601000;
-	tcap.ampdu_limit = 0xffff0000;
-	tcap.ampdu_subframes = 20;
-	tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask;
-	tcap.protmode = 1;
+	tcap.ampdu_limit = cpu_to_be32(0xffff);
+	tcap.ampdu_subframes = priv->hw->max_tx_aggregation_subframes;
+	tcap.enable_coex = enable_coex;
 	tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
 
 	WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
@@ -931,7 +942,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
 
 	ath9k_host_rx_init(priv);
 
-	ret = ath9k_htc_update_cap_target(priv);
+	ret = ath9k_htc_update_cap_target(priv, 0);
 	if (ret)
 		ath_dbg(common, ATH_DBG_CONFIG,
 			"Failed to update capability in target\n");
@@ -964,7 +975,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 	struct ath9k_htc_priv *priv = hw->priv;
 	struct ath_hw *ah = priv->ah;
 	struct ath_common *common = ath9k_hw_common(ah);
-	int ret = 0;
+	int ret __attribute__ ((unused));
 	u8 cmd_rsp;
 
 	mutex_lock(&priv->mutex);
@@ -992,9 +1003,11 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 	/* Cancel all the running timers/work .. */
 	cancel_work_sync(&priv->fatal_work);
 	cancel_work_sync(&priv->ps_work);
-	cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+
+#ifdef CONFIG_MAC80211_LEDS
+	cancel_work_sync(&priv->led_work);
+#endif
 	ath9k_htc_stop_ani(priv);
-	ath9k_led_stop_brightness(priv);
 
 	mutex_lock(&priv->mutex);
 
@@ -1135,6 +1148,10 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
 	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
 	hvif.index = avp->index;
 	WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+	if (ret) {
+		ath_err(common, "Unable to remove interface at idx: %d\n",
+			avp->index);
+	}
 	priv->nvifs--;
 	priv->vif_slot &= ~(1 << avp->index);
 
@@ -1567,6 +1584,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
 	int ret = 0;
 
 	mutex_lock(&priv->mutex);
+	ath9k_htc_ps_wakeup(priv);
 
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
@@ -1592,6 +1610,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
 		ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
 	}
 
+	ath9k_htc_ps_restore(priv);
 	mutex_unlock(&priv->mutex);
 
 	return ret;
@@ -1642,6 +1661,55 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
 	mutex_unlock(&priv->mutex);
 }
 
+/*
+ * Currently, this is used only for selecting the minimum rate
+ * for management frames, rate selection for data frames remain
+ * unaffected.
+ */
+static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
+				      const struct cfg80211_bitrate_mask *mask)
+{
+	struct ath9k_htc_priv *priv = hw->priv;
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct ath9k_htc_target_rate_mask tmask;
+	struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
+	int ret = 0;
+	u8 cmd_rsp;
+
+	memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask));
+
+	tmask.vif_index = avp->index;
+	tmask.band = IEEE80211_BAND_2GHZ;
+	tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy);
+
+	WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask);
+	if (ret) {
+		ath_err(common,
+			"Unable to set 2G rate mask for "
+			"interface at idx: %d\n", avp->index);
+		goto out;
+	}
+
+	tmask.band = IEEE80211_BAND_5GHZ;
+	tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy);
+
+	WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask);
+	if (ret) {
+		ath_err(common,
+			"Unable to set 5G rate mask for "
+			"interface at idx: %d\n", avp->index);
+		goto out;
+	}
+
+	ath_dbg(common, ATH_DBG_CONFIG,
+		"Set bitrate masks: 0x%x, 0x%x\n",
+		mask->control[IEEE80211_BAND_2GHZ].legacy,
+		mask->control[IEEE80211_BAND_5GHZ].legacy);
+out:
+	return ret;
+}
+
 struct ieee80211_ops ath9k_htc_ops = {
 	.tx                 = ath9k_htc_tx,
 	.start              = ath9k_htc_start,
@@ -1664,4 +1732,5 @@ struct ieee80211_ops ath9k_htc_ops = {
 	.set_rts_threshold  = ath9k_htc_set_rts_threshold,
 	.rfkill_poll        = ath9k_htc_rfkill_poll_state,
 	.set_coverage_class = ath9k_htc_set_coverage_class,
+	.set_bitrate_mask   = ath9k_htc_set_bitrate_mask,
 };
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 723a3a9c5cd91426262ee1770149a40a85981c64..a898dac22337e559cf46b7f53d2743f2a1341904 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -446,7 +446,6 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
 	struct ieee80211_tx_info *tx_info;
 	struct ieee80211_tx_rate *rate;
 	struct ieee80211_conf *cur_conf = &priv->hw->conf;
-	struct ieee80211_supported_band *sband;
 	bool txok;
 	int slot;
 
@@ -461,7 +460,6 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
 	tx_info = IEEE80211_SKB_CB(skb);
 	vif = tx_info->control.vif;
 	rate = &tx_info->status.rates[0];
-	sband = priv->hw->wiphy->bands[cur_conf->channel->band];
 
 	memset(&tx_info->status, 0, sizeof(tx_info->status));
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index cb9174ade53ee83445fa9656a3d094e68ddf2c70..91a5305db95a317eced836e417c9e601de8abdf8 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -83,21 +83,10 @@ struct htc_ep_callbacks {
 	void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id);
 };
 
-#define HTC_TX_QUEUE_SIZE 256
-
-struct htc_txq {
-	struct sk_buff *buf[HTC_TX_QUEUE_SIZE];
-	u32 txqdepth;
-	u16 txbuf_cnt;
-	u16 txq_head;
-	u16 txq_tail;
-};
-
 struct htc_endpoint {
 	u16 service_id;
 
 	struct htc_ep_callbacks ep_callbacks;
-	struct htc_txq htc_txq;
 	u32 max_txqdepth;
 	int max_msglen;
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 045abd5578407b2a2cf5645ebaaa232ea2cfaed1..58f3d4210338cfd91624db0b4b8849acb42f4816 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -247,6 +247,17 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
 {
 	u32 val;
 
+	switch (ah->hw_version.devid) {
+	case AR5416_AR9100_DEVID:
+		ah->hw_version.macVersion = AR_SREV_VERSION_9100;
+		break;
+	case AR9300_DEVID_AR9340:
+		ah->hw_version.macVersion = AR_SREV_VERSION_9340;
+		val = REG_READ(ah, AR_SREV);
+		ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+		return;
+	}
+
 	val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
 
 	if (val == 0xFF) {
@@ -462,7 +473,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
 		return ecode;
 	}
 
-	if (!AR_SREV_9100(ah)) {
+	if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) {
 		ath9k_hw_ani_setup(ah);
 		ath9k_hw_ani_init(ah);
 	}
@@ -484,9 +495,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	struct ath_common *common = ath9k_hw_common(ah);
 	int r = 0;
 
-	if (ah->hw_version.devid == AR5416_AR9100_DEVID)
-		ah->hw_version.macVersion = AR_SREV_VERSION_9100;
-
 	ath9k_hw_read_revisions(ah);
 
 	/*
@@ -544,6 +552,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	case AR_SREV_VERSION_9271:
 	case AR_SREV_VERSION_9300:
 	case AR_SREV_VERSION_9485:
+	case AR_SREV_VERSION_9340:
 		break;
 	default:
 		ath_err(common,
@@ -552,7 +561,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 		return -EOPNOTSUPP;
 	}
 
-	if (AR_SREV_9271(ah) || AR_SREV_9100(ah))
+	if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah))
 		ah->is_pciexpress = false;
 
 	ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
@@ -621,6 +630,7 @@ int ath9k_hw_init(struct ath_hw *ah)
 	case AR2427_DEVID_PCIE:
 	case AR9300_DEVID_PCIE:
 	case AR9300_DEVID_AR9485_PCIE:
+	case AR9300_DEVID_AR9340:
 		break;
 	default:
 		if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -663,7 +673,7 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
 	REGWRITE_BUFFER_FLUSH(ah);
 }
 
-unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
+u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
 {
 	REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
 	udelay(100);
@@ -676,7 +686,6 @@ unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
 
-#define DPLL3_PHASE_SHIFT_VAL 0x1
 static void ath9k_hw_init_pll(struct ath_hw *ah,
 			      struct ath9k_channel *chan)
 {
@@ -713,16 +722,48 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
 		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 			      AR_CH0_BB_DPLL2_PLL_PWD, 0x0);
 		udelay(1000);
+	} else if (AR_SREV_9340(ah)) {
+		u32 regval, pll2_divint, pll2_divfrac, refdiv;
 
-		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
-			      AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
+		REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
+		udelay(1000);
+
+		REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16);
+		udelay(100);
+
+		if (ah->is_clk_25mhz) {
+			pll2_divint = 0x54;
+			pll2_divfrac = 0x1eb85;
+			refdiv = 3;
+		} else {
+			pll2_divint = 88;
+			pll2_divfrac = 0;
+			refdiv = 5;
+		}
+
+		regval = REG_READ(ah, AR_PHY_PLL_MODE);
+		regval |= (0x1 << 16);
+		REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
+		udelay(100);
+
+		REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) |
+			  (pll2_divint << 18) | pll2_divfrac);
+		udelay(100);
+
+		regval = REG_READ(ah, AR_PHY_PLL_MODE);
+		regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) |
+			 (0x4 << 26) | (0x18 << 19);
+		REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
+		REG_WRITE(ah, AR_PHY_PLL_MODE,
+			  REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
+		udelay(1000);
 	}
 
 	pll = ath9k_hw_compute_pll_control(ah, chan);
 
 	REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
 
-	if (AR_SREV_9485(ah))
+	if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
 		udelay(1000);
 
 	/* Switch the core clock for ar9271 to 117Mhz */
@@ -734,17 +775,34 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
 	udelay(RTC_PLL_SETTLE_DELAY);
 
 	REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
+
+	if (AR_SREV_9340(ah)) {
+		if (ah->is_clk_25mhz) {
+			REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
+			REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
+			REG_WRITE(ah,  AR_SLP32_INC, 0x0001e7ae);
+		} else {
+			REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
+			REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
+			REG_WRITE(ah,  AR_SLP32_INC, 0x0001e800);
+		}
+		udelay(100);
+	}
 }
 
 static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
 					  enum nl80211_iftype opmode)
 {
+	u32 sync_default = AR_INTR_SYNC_DEFAULT;
 	u32 imr_reg = AR_IMR_TXERR |
 		AR_IMR_TXURN |
 		AR_IMR_RXERR |
 		AR_IMR_RXORN |
 		AR_IMR_BCNMISC;
 
+	if (AR_SREV_9340(ah))
+		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		imr_reg |= AR_IMR_RXOK_HP;
 		if (ah->config.rx_intr_mitigation)
@@ -775,7 +833,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
 
 	if (!AR_SREV_9100(ah)) {
 		REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
-		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
+		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
 		REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
 	}
 
@@ -1487,7 +1545,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 				REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
 		}
 #ifdef __BIG_ENDIAN
-                else
+		else if (AR_SREV_9340(ah))
+			REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
+		else
 			REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
 #endif
 	}
@@ -1793,7 +1853,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-	u16 capField = 0, eeval;
+	u16 eeval;
 	u8 ant_div_ctl1, tx_chainmask, rx_chainmask;
 
 	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
@@ -1804,8 +1864,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 		eeval |= AR9285_RDEXT_DEFAULT;
 	regulatory->current_rd_ext = eeval;
 
-	capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP);
-
 	if (ah->opmode != NL80211_IFTYPE_AP &&
 	    ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
 		if (regulatory->current_rd == 0x64 ||
@@ -1898,15 +1956,23 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 	else
 		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
-	if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) {
-		btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
-		btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
-
-		if (AR_SREV_9285(ah)) {
+	if (common->btcoex_enabled) {
+		if (AR_SREV_9300_20_OR_LATER(ah)) {
 			btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
-			btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO;
-		} else {
-			btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
+			btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
+			btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
+			btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
+		} else if (AR_SREV_9280_20_OR_LATER(ah)) {
+			btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
+			btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
+
+			if (AR_SREV_9285(ah)) {
+				btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+				btcoex_hw->btpriority_gpio =
+						ATH_BTPRIORITY_GPIO_9285;
+			} else {
+				btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
+			}
 		}
 	} else {
 		btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
@@ -2359,11 +2425,11 @@ EXPORT_SYMBOL(ath_gen_timer_alloc);
 
 void ath9k_hw_gen_timer_start(struct ath_hw *ah,
 			      struct ath_gen_timer *timer,
-			      u32 timer_next,
+			      u32 trig_timeout,
 			      u32 timer_period)
 {
 	struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
-	u32 tsf;
+	u32 tsf, timer_next;
 
 	BUG_ON(!timer_period);
 
@@ -2371,17 +2437,12 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
 
 	tsf = ath9k_hw_gettsf32(ah);
 
+	timer_next = tsf + trig_timeout;
+
 	ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER,
 		"current tsf %x period %x timer_next %x\n",
 		tsf, timer_period, timer_next);
 
-	/*
-	 * Pull timer_next forward if the current TSF already passed it
-	 * because of software latency
-	 */
-	if (timer_next < tsf)
-		timer_next = tsf + timer_period;
-
 	/*
 	 * Program generic timer registers
 	 */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 1018d6cbd5301bf1d5a779ef85ae960f1cb57699..34ed1bd0e85527c67e7388b269bc0500d6a23a94 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -43,6 +43,7 @@
 #define AR9287_DEVID_PCI	0x002d
 #define AR9287_DEVID_PCIE	0x002e
 #define AR9300_DEVID_PCIE	0x0030
+#define AR9300_DEVID_AR9340	0x0031
 #define AR9300_DEVID_AR9485_PCIE 0x0032
 
 #define AR5416_AR9100_DEVID	0x000b
@@ -55,6 +56,9 @@
 #define AT9285_COEX3WIRE_SA_SUBSYSID	0x30aa
 #define AT9285_COEX3WIRE_DA_SUBSYSID	0x30ab
 
+#define AR9300_NUM_BT_WEIGHTS   4
+#define AR9300_NUM_WLAN_WEIGHTS 4
+
 #define ATH_AMPDU_LIMIT_MAX        (64 * 1024 - 1)
 
 #define	ATH_DEFAULT_NOISE_FLOOR -95
@@ -121,7 +125,7 @@
 #define AR_GPIO_BIT(_gpio)          (1 << (_gpio))
 
 #define BASE_ACTIVATE_DELAY         100
-#define RTC_PLL_SETTLE_DELAY        100
+#define RTC_PLL_SETTLE_DELAY        (AR_SREV_9340(ah) ? 1000 : 100)
 #define COEF_SCALE_S                24
 #define HT40_CHANNEL_CENTER_SHIFT   10
 
@@ -771,6 +775,8 @@ struct ath_hw {
 
 	/* Bluetooth coexistance */
 	struct ath_btcoex_hw btcoex_hw;
+	u32 bt_coex_bt_weight[AR9300_NUM_BT_WEIGHTS];
+	u32 bt_coex_wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
 
 	u32 intr_txqs;
 	u8 txchainmask;
@@ -799,6 +805,7 @@ struct ath_hw {
 	struct ar5416IniArray iniPcieSerdes;
 	struct ar5416IniArray iniPcieSerdesLowPower;
 	struct ar5416IniArray iniModesAdditional;
+	struct ar5416IniArray iniModesAdditional_40M;
 	struct ar5416IniArray iniModesRxGain;
 	struct ar5416IniArray iniModesTxGain;
 	struct ar5416IniArray iniModes_9271_1_0_only;
@@ -845,6 +852,8 @@ struct ath_hw {
 
 	/* Enterprise mode cap */
 	u32 ent_mode;
+
+	bool is_clk_25mhz;
 };
 
 struct ath_bus_ops {
@@ -928,7 +937,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
 void ath9k_hw_reset_tsf(struct ath_hw *ah);
 void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
 void ath9k_hw_init_global_settings(struct ath_hw *ah);
-unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
+u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
 void ath9k_hw_set11nmac2040(struct ath_hw *ah);
 void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
 void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1ac8318d82a397a6fcf51371407ca50e98d4bb1d..b172d1509515e97881eb9a14945df7cb1830a207 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -574,6 +574,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
 		sc->sc_ah->gpio_mask = pdata->gpio_mask;
 		sc->sc_ah->gpio_val = pdata->gpio_val;
 		sc->sc_ah->led_pin = pdata->led_pin;
+		ah->is_clk_25mhz = pdata->is_clk_25mhz;
 	}
 
 	common = ath9k_hw_common(ah);
@@ -800,6 +801,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
 
 	INIT_WORK(&sc->hw_check_work, ath_hw_check);
 	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
 	sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
 
 	ath_init_leds(sc);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 1968c67e3fababaa1eb357f482acfc9d46309530..9cf7a7d0e118b2f52a77f9ec8e772719f4606f99 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -812,10 +812,14 @@ EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
 void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
+	u32 sync_default = AR_INTR_SYNC_DEFAULT;
 
 	if (!(ah->imask & ATH9K_INT_GLOBAL))
 		return;
 
+	if (AR_SREV_9340(ah))
+		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+
 	ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
 	REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
 	if (!AR_SREV_9100(ah)) {
@@ -824,10 +828,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 		REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
 
 
-		REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
-			  AR_INTR_SYNC_DEFAULT);
-		REG_WRITE(ah, AR_INTR_SYNC_MASK,
-			  AR_INTR_SYNC_DEFAULT);
+		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
+		REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);
 	}
 	ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
 		REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
@@ -883,6 +885,9 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 			mask |= AR_IMR_GENTMR;
 	}
 
+	if (ints & ATH9K_INT_GENTIMER)
+		mask |= AR_IMR_GENTMR;
+
 	if (ints & (ATH9K_INT_BMISC)) {
 		mask |= AR_IMR_BCNMISC;
 		if (ints & ATH9K_INT_TIM)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index a8d9009a76d5a183f4a20527c187779a859c4030..c3dbf2661a3ff826815ac41962020ba6b260898a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -624,6 +624,43 @@ out:
 	ath9k_ps_restore(sc);
 }
 
+static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
+{
+	static int count;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	if (pll_sqsum >= 0x40000) {
+		count++;
+		if (count == 3) {
+			/* Rx is hung for more than 500ms. Reset it */
+			ath_dbg(common, ATH_DBG_RESET,
+				"Possible RX hang, resetting");
+			ath_reset(sc, true);
+			count = 0;
+		}
+	} else
+		count = 0;
+}
+
+void ath_hw_pll_work(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    hw_pll_work.work);
+	u32 pll_sqsum;
+
+	if (AR_SREV_9485(sc->sc_ah)) {
+
+		ath9k_ps_wakeup(sc);
+		pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
+		ath9k_ps_restore(sc);
+
+		ath_hw_pll_rx_hang_check(sc, pll_sqsum);
+
+		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
+	}
+}
+
+
 void ath9k_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
@@ -1932,6 +1969,12 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 				"Bss Info ASSOC %d, bssid: %pM\n",
 				bss_conf->aid, common->curbssid);
 			ath_beacon_config(sc, vif);
+			/*
+			 * Request a re-configuration of Beacon related timers
+			 * on the receipt of the first Beacon frame (i.e.,
+			 * after time sync with the AP).
+			 */
+			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
 			/* Reset rssi stats */
 			sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
 			sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
@@ -2219,9 +2262,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
 	int timeout = 200; /* ms */
 	int i, j;
 
-	ath9k_ps_wakeup(sc);
 	mutex_lock(&sc->mutex);
-
 	cancel_delayed_work_sync(&sc->tx_complete_work);
 
 	if (drop)
@@ -2244,15 +2285,15 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
 		    goto out;
 	}
 
+	ath9k_ps_wakeup(sc);
 	if (!ath_drain_all_txq(sc, false))
 		ath_reset(sc, false);
-
+	ath9k_ps_restore(sc);
 	ieee80211_wake_queues(hw);
 
 out:
 	ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
 	mutex_unlock(&sc->mutex);
-	ath9k_ps_restore(sc);
 }
 
 static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index 8e5fe9d7f1749066c9aa3b481fba98fff7bd3705..9441bf8ca2fd6cf003331d04898e96551a184d6f 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -45,4 +45,7 @@
 #define	AR_PHY_TIMING11_SPUR_FREQ_SD		0x3FF00000
 #define	AR_PHY_TIMING11_SPUR_FREQ_SD_S		20
 
+#define AR_PHY_PLL_CONTROL 0x16180
+#define AR_PHY_PLL_MODE 0x16184
+
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 18094094b298fd9e055fa422feb331b4820ce938..4ccbf2ddb5535c27c0699418f723b9314c5e7191 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -854,14 +854,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	ath_rc_rate_set_rtscts(sc, rate_table, tx_info);
 }
 
-static bool ath_rc_update_per(struct ath_softc *sc,
+static void ath_rc_update_per(struct ath_softc *sc,
 			      const struct ath_rate_table *rate_table,
 			      struct ath_rate_priv *ath_rc_priv,
 				  struct ieee80211_tx_info *tx_info,
 			      int tx_rate, int xretries, int retries,
 			      u32 now_msec)
 {
-	bool state_change = false;
 	int count, n_bad_frames;
 	u8 last_per;
 	static const u32 nretry_to_per_lookup[10] = {
@@ -992,8 +991,6 @@ static bool ath_rc_update_per(struct ath_softc *sc,
 
 		}
 	}
-
-	return state_change;
 }
 
 static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
@@ -1017,7 +1014,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
 	u32 now_msec = jiffies_to_msecs(jiffies);
 	int rate;
 	u8 last_per;
-	bool state_change = false;
 	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
 	int size = ath_rc_priv->rate_table_size;
 
@@ -1027,9 +1023,9 @@ static void ath_rc_update_ht(struct ath_softc *sc,
 	last_per = ath_rc_priv->per[tx_rate];
 
 	/* Update PER first */
-	state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
-					 tx_info, tx_rate, xretries,
-					 retries, now_msec);
+	ath_rc_update_per(sc, rate_table, ath_rc_priv,
+			  tx_info, tx_rate, xretries,
+			  retries, now_msec);
 
 	/*
 	 * If this rate looks bad (high PER) then stop using it for
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index f69dcdf0e2e61116d6e76310858cd874fcc3424a..c5b7cbe59bfafe8aa1dea63256c5aa2dbe69aa5b 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1339,7 +1339,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
 	struct ath_hw_antcomb_conf div_ant_conf;
 	struct ath_ant_comb *antcomb = &sc->ant_comb;
 	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
-	int curr_main_set, curr_bias;
+	int curr_main_set;
 	int main_rssi = rs->rs_rssi_ctl0;
 	int alt_rssi = rs->rs_rssi_ctl1;
 	int rx_ant_conf,  main_ant_conf;
@@ -1393,7 +1393,6 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
 	ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
 	curr_alt_set = div_ant_conf.alt_lna_conf;
 	curr_main_set = div_ant_conf.main_lna_conf;
-	curr_bias = div_ant_conf.fast_div_bias;
 
 	antcomb->count++;
 
@@ -1743,7 +1742,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
 					      PS_WAIT_FOR_CAB |
 					      PS_WAIT_FOR_PSPOLL_DATA)) ||
-					unlikely(ath9k_check_auto_sleep(sc)))
+						ath9k_check_auto_sleep(sc))
 			ath_rx_ps(sc, skb);
 		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 6acbf0e2240b9182e98714e1795ac90d96f0d1bf..456f3ec20fef94235ccb724c66419b6a7012d260 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -693,7 +693,7 @@
 #define AR_RC_APB            0x00000002
 #define AR_RC_HOSTIF         0x00000100
 
-#define AR_WA                		0x4004
+#define AR_WA			(AR_SREV_9340(ah) ? 0x40c4 : 0x4004)
 #define AR_WA_BIT6			(1 << 6)
 #define AR_WA_BIT7			(1 << 7)
 #define AR_WA_BIT23			(1 << 23)
@@ -712,7 +712,7 @@
 #define AR_PM_STATE                 0x4008
 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000
 
-#define AR_HOST_TIMEOUT             0x4018
+#define AR_HOST_TIMEOUT             (AR_SREV_9340(ah) ? 0x4008 : 0x4018)
 #define AR_HOST_TIMEOUT_APB_CNTR    0x0000FFFF
 #define AR_HOST_TIMEOUT_APB_CNTR_S  0
 #define AR_HOST_TIMEOUT_LCL_CNTR    0xFFFF0000
@@ -742,7 +742,8 @@
 #define EEPROM_PROTECT_WP_1024_2047   0x8000
 
 #define AR_SREV \
-	((AR_SREV_9100(ah)) ? 0x0600 : 0x4020)
+	((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \
+					? 0x400c : 0x4020))
 
 #define AR_SREV_ID \
 	((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF)
@@ -790,6 +791,7 @@
 #define AR_SREV_VERSION_9485		0x240
 #define AR_SREV_REVISION_9485_10	0
 #define AR_SREV_REVISION_9485_11        1
+#define AR_SREV_VERSION_9340		0x300
 
 #define AR_SREV_5416(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -868,6 +870,11 @@
 #define AR_SREV_9485_11(_ah) \
 	(AR_SREV_9485(_ah) && \
 	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
+#define AR_SREV_9485_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
+
+#define AR_SREV_9340(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
 
 #define AR_SREV_9285E_20(_ah) \
     (AR_SREV_9285_12_OR_LATER(_ah) && \
@@ -910,11 +917,11 @@ enum ath_usb_dev {
 #define AR_INTR_SPURIOUS                      0xFFFFFFFF
 
 
-#define AR_INTR_SYNC_CAUSE_CLR                0x4028
+#define AR_INTR_SYNC_CAUSE                    (AR_SREV_9340(ah) ? 0x4010 : 0x4028)
+#define AR_INTR_SYNC_CAUSE_CLR                (AR_SREV_9340(ah) ? 0x4010 : 0x4028)
 
-#define AR_INTR_SYNC_CAUSE                    0x4028
 
-#define AR_INTR_SYNC_ENABLE                   0x402c
+#define AR_INTR_SYNC_ENABLE                   (AR_SREV_9340(ah) ? 0x4014 : 0x402c)
 #define AR_INTR_SYNC_ENABLE_GPIO              0xFFFC0000
 #define AR_INTR_SYNC_ENABLE_GPIO_S            18
 
@@ -954,24 +961,24 @@ enum {
 
 };
 
-#define AR_INTR_ASYNC_MASK                       0x4030
+#define AR_INTR_ASYNC_MASK                       (AR_SREV_9340(ah) ? 0x4018 : 0x4030)
 #define AR_INTR_ASYNC_MASK_GPIO                  0xFFFC0000
 #define AR_INTR_ASYNC_MASK_GPIO_S                18
 
-#define AR_INTR_SYNC_MASK                        0x4034
+#define AR_INTR_SYNC_MASK                        (AR_SREV_9340(ah) ? 0x401c : 0x4034)
 #define AR_INTR_SYNC_MASK_GPIO                   0xFFFC0000
 #define AR_INTR_SYNC_MASK_GPIO_S                 18
 
-#define AR_INTR_ASYNC_CAUSE_CLR                  0x4038
-#define AR_INTR_ASYNC_CAUSE                      0x4038
+#define AR_INTR_ASYNC_CAUSE_CLR                  (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
+#define AR_INTR_ASYNC_CAUSE                      (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
 
-#define AR_INTR_ASYNC_ENABLE                     0x403c
+#define AR_INTR_ASYNC_ENABLE                     (AR_SREV_9340(ah) ? 0x4024 : 0x403c)
 #define AR_INTR_ASYNC_ENABLE_GPIO                0xFFFC0000
 #define AR_INTR_ASYNC_ENABLE_GPIO_S              18
 
 #define AR_PCIE_SERDES                           0x4040
 #define AR_PCIE_SERDES2                          0x4044
-#define AR_PCIE_PM_CTRL                          0x4014
+#define AR_PCIE_PM_CTRL                          (AR_SREV_9340(ah) ? 0x4004 : 0x4014)
 #define AR_PCIE_PM_CTRL_ENA                      0x00080000
 
 #define AR_NUM_GPIO                              14
@@ -982,7 +989,7 @@ enum {
 #define AR9300_NUM_GPIO                          17
 #define AR7010_NUM_GPIO                          16
 
-#define AR_GPIO_IN_OUT                           0x4048
+#define AR_GPIO_IN_OUT                           (AR_SREV_9340(ah) ? 0x4028 : 0x4048)
 #define AR_GPIO_IN_VAL                           0x0FFFC000
 #define AR_GPIO_IN_VAL_S                         14
 #define AR928X_GPIO_IN_VAL                       0x000FFC00
@@ -996,11 +1003,12 @@ enum {
 #define AR7010_GPIO_IN_VAL                       0x0000FFFF
 #define AR7010_GPIO_IN_VAL_S                     0
 
-#define AR_GPIO_IN				 0x404c
+#define AR_GPIO_IN				 (AR_SREV_9340(ah) ? 0x402c : 0x404c)
 #define AR9300_GPIO_IN_VAL                       0x0001FFFF
 #define AR9300_GPIO_IN_VAL_S                     0
 
-#define AR_GPIO_OE_OUT                           (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
+#define AR_GPIO_OE_OUT                           (AR_SREV_9340(ah) ? 0x4030 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c))
 #define AR_GPIO_OE_OUT_DRV                       0x3
 #define AR_GPIO_OE_OUT_DRV_NO                    0x0
 #define AR_GPIO_OE_OUT_DRV_LOW                   0x1
@@ -1022,11 +1030,13 @@ enum {
 #define AR7010_GPIO_INT_MASK                     0x52024
 #define AR7010_GPIO_FUNCTION                     0x52028
 
-#define AR_GPIO_INTR_POL                         (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)
+#define AR_GPIO_INTR_POL                         (AR_SREV_9340(ah) ? 0x4038 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050))
 #define AR_GPIO_INTR_POL_VAL                     0x0001FFFF
 #define AR_GPIO_INTR_POL_VAL_S                   0
 
-#define AR_GPIO_INPUT_EN_VAL                     (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)
+#define AR_GPIO_INPUT_EN_VAL                     (AR_SREV_9340(ah) ? 0x403c : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054))
 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF     0x00000004
 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S       2
 #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF    0x00000008
@@ -1044,13 +1054,15 @@ enum {
 #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE        0x00010000
 #define AR_GPIO_JTAG_DISABLE                     0x00020000
 
-#define AR_GPIO_INPUT_MUX1                       (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)
+#define AR_GPIO_INPUT_MUX1                       (AR_SREV_9340(ah) ? 0x4040 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058))
 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE             0x000f0000
 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S           16
 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY           0x00000f00
 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S         8
 
-#define AR_GPIO_INPUT_MUX2                       (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)
+#define AR_GPIO_INPUT_MUX2                       (AR_SREV_9340(ah) ? 0x4044 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c))
 #define AR_GPIO_INPUT_MUX2_CLK25                 0x0000000f
 #define AR_GPIO_INPUT_MUX2_CLK25_S               0
 #define AR_GPIO_INPUT_MUX2_RFSILENT              0x000000f0
@@ -1058,13 +1070,18 @@ enum {
 #define AR_GPIO_INPUT_MUX2_RTC_RESET             0x00000f00
 #define AR_GPIO_INPUT_MUX2_RTC_RESET_S           8
 
-#define AR_GPIO_OUTPUT_MUX1                      (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)
-#define AR_GPIO_OUTPUT_MUX2                      (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)
-#define AR_GPIO_OUTPUT_MUX3                      (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)
+#define AR_GPIO_OUTPUT_MUX1                      (AR_SREV_9340(ah) ? 0x4048 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060))
+#define AR_GPIO_OUTPUT_MUX2                      (AR_SREV_9340(ah) ? 0x404c : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064))
+#define AR_GPIO_OUTPUT_MUX3                      (AR_SREV_9340(ah) ? 0x4050 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068))
 
-#define AR_INPUT_STATE                           (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)
+#define AR_INPUT_STATE                           (AR_SREV_9340(ah) ? 0x4054 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c))
 
-#define AR_EEPROM_STATUS_DATA                    (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)
+#define AR_EEPROM_STATUS_DATA                    (AR_SREV_9340(ah) ? 0x40c8 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c))
 #define AR_EEPROM_STATUS_DATA_VAL                0x0000ffff
 #define AR_EEPROM_STATUS_DATA_VAL_S              0
 #define AR_EEPROM_STATUS_DATA_BUSY               0x00010000
@@ -1072,17 +1089,19 @@ enum {
 #define AR_EEPROM_STATUS_DATA_PROT_ACCESS        0x00040000
 #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS      0x00080000
 
-#define AR_OBS                  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)
+#define AR_OBS                  (AR_SREV_9340(ah) ? 0x405c : \
+				 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080))
 
 #define AR_GPIO_PDPU                             (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088)
 
-#define AR_PCIE_MSI                              (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)
+#define AR_PCIE_MSI                             (AR_SREV_9340(ah) ? 0x40d8 : \
+						 (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094))
 #define AR_PCIE_MSI_ENABLE                       0x00000001
 
-#define AR_INTR_PRIO_SYNC_ENABLE  0x40c4
-#define AR_INTR_PRIO_ASYNC_MASK   0x40c8
-#define AR_INTR_PRIO_SYNC_MASK    0x40cc
-#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4
+#define AR_INTR_PRIO_SYNC_ENABLE  (AR_SREV_9340(ah) ? 0x4088 : 0x40c4)
+#define AR_INTR_PRIO_ASYNC_MASK   (AR_SREV_9340(ah) ? 0x408c : 0x40c8)
+#define AR_INTR_PRIO_SYNC_MASK    (AR_SREV_9340(ah) ? 0x4090 : 0x40cc)
+#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4)
 #define AR_ENT_OTP		  0x40d8
 #define AR_ENT_OTP_CHAIN2_DISABLE               0x00020000
 #define AR_ENT_OTP_MPSD		0x00800000
@@ -1163,6 +1182,7 @@ enum {
 #define AR_RTC_PLL_REFDIV_5     0x000000c0
 #define AR_RTC_PLL_CLKSEL       0x00000300
 #define AR_RTC_PLL_CLKSEL_S     8
+#define AR_RTC_PLL_BYPASS	0x00010000
 
 #define PLL3 0x16188
 #define PLL3_DO_MEAS_MASK 0x40000000
@@ -1209,7 +1229,8 @@ enum {
 
 /* RTC_DERIVED_* - only for AR9100 */
 
-#define AR_RTC_DERIVED_CLK           (AR_RTC_BASE + 0x0038)
+#define AR_RTC_DERIVED_CLK \
+	(AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038)
 #define AR_RTC_DERIVED_CLK_PERIOD    0x0000fffe
 #define AR_RTC_DERIVED_CLK_PERIOD_S  1
 
@@ -1688,6 +1709,22 @@ enum {
 #define AR_BTCOEX_WL_WGHT          0xffff0000
 #define AR_BTCOEX_WL_WGHT_S        16
 
+#define AR_BT_COEX_WL_WEIGHTS0     0x8174
+#define AR_BT_COEX_WL_WEIGHTS1     0x81c4
+
+#define AR_BT_COEX_BT_WEIGHTS0     0x83ac
+#define AR_BT_COEX_BT_WEIGHTS1     0x83b0
+#define AR_BT_COEX_BT_WEIGHTS2     0x83b4
+#define AR_BT_COEX_BT_WEIGHTS3     0x83b8
+
+#define AR9300_BT_WGHT                     0xcccc4444
+#define AR9300_STOMP_ALL_WLAN_WGHT0        0xfffffff0
+#define AR9300_STOMP_ALL_WLAN_WGHT1        0xfffffff0
+#define AR9300_STOMP_LOW_WLAN_WGHT0        0x88888880
+#define AR9300_STOMP_LOW_WLAN_WGHT1        0x88888880
+#define AR9300_STOMP_NONE_WLAN_WGHT0       0x00000000
+#define AR9300_STOMP_NONE_WLAN_WGHT1       0x00000000
+
 #define AR_BT_COEX_MODE2           0x817c
 #define AR_BT_BCN_MISS_THRESH      0x000000ff
 #define AR_BT_BCN_MISS_THRESH_S    0
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 8f095ad0a3db146f59b44f922fa7179a5737fe7f..f9b1eb4853c4a93a1f964e239a41349e5e7fa0cf 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -79,8 +79,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
 		return "WMI_TX_STATS_CMDID";
 	case WMI_RX_STATS_CMDID:
 		return "WMI_RX_STATS_CMDID";
-	case WMI_AGGR_LIMIT_CMD:
-		return "WMI_AGGR_LIMIT_CMD";
+	case WMI_BITRATE_MASK_CMDID:
+		return "WMI_BITRATE_MASK_CMDID";
 	}
 
 	return "Bogus";
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 02ecb9f06db02dd03d6f93801d4daee3a1082c8e..6095eeb6e025fdd08f971da826e0a5680b3a2f98 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -111,7 +111,7 @@ enum wmi_cmd_id {
 	WMI_INT_STATS_CMDID,
 	WMI_TX_STATS_CMDID,
 	WMI_RX_STATS_CMDID,
-	WMI_AGGR_LIMIT_CMD = 0x0026,
+	WMI_BITRATE_MASK_CMDID,
 };
 
 enum wmi_event_id {
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index e9e99f730ca8ee2827f2f8e27094149bd6024065..7b91b2aa6240e3160028b300e5534fe908e37e12 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2180,28 +2180,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 	}
 }
 
-static void ath_hw_pll_work(struct work_struct *work)
-{
-	struct ath_softc *sc = container_of(work, struct ath_softc,
-					    hw_pll_work.work);
-	static int count;
-
-	if (AR_SREV_9485(sc->sc_ah)) {
-		if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) {
-			count++;
-
-			if (count == 3) {
-				/* Rx is hung for more than 500ms. Reset it */
-				ath_reset(sc, true);
-				count = 0;
-			}
-		} else
-			count = 0;
-
-		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
-	}
-}
-
 static void ath_tx_complete_poll_work(struct work_struct *work)
 {
 	struct ath_softc *sc = container_of(work, struct ath_softc,
@@ -2396,7 +2374,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
 	}
 
 	INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
-	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
 
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 		error = ath_tx_edma_init(sc);
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 3d4ed5863732c6f2d6c4facb11aa042218d4e965..bb578690935e7f88327bcedf94231219d27cc973 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -448,6 +448,8 @@ struct carl9170_ba_stats {
 
 struct carl9170_sta_info {
 	bool ht_sta;
+	bool sleeping;
+	atomic_t pending_frames;
 	unsigned int ampdu_max_len;
 	struct carl9170_sta_tid *agg[CARL9170_NUM_TID];
 	struct carl9170_ba_stats stats[CARL9170_NUM_TID];
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 89fe60accf8550f7a7234d7c0542eec7e1670bb3..1638468be5a3cfe8e0d8586d72a3ec05f4c8e90f 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1193,6 +1193,8 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw,
 	struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
 	unsigned int i;
 
+	atomic_set(&sta_info->pending_frames, 0);
+
 	if (sta->ht_cap.ht_supported) {
 		if (sta->ht_cap.ampdu_density > 6) {
 			/*
@@ -1467,99 +1469,17 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw,
 				   enum sta_notify_cmd cmd,
 				   struct ieee80211_sta *sta)
 {
-	struct ar9170 *ar = hw->priv;
 	struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
-	struct sk_buff *skb, *tmp;
-	struct sk_buff_head free;
-	int i;
 
 	switch (cmd) {
 	case STA_NOTIFY_SLEEP:
-		/*
-		 * Since the peer is no longer listening, we have to return
-		 * as many SKBs as possible back to the mac80211 stack.
-		 * It will deal with the retry procedure, once the peer
-		 * has become available again.
-		 *
-		 * NB: Ideally, the driver should return the all frames in
-		 * the correct, ascending order. However, I think that this
-		 * functionality should be implemented in the stack and not
-		 * here...
-		 */
-
-		__skb_queue_head_init(&free);
-
-		if (sta->ht_cap.ht_supported) {
-			rcu_read_lock();
-			for (i = 0; i < CARL9170_NUM_TID; i++) {
-				struct carl9170_sta_tid *tid_info;
-
-				tid_info = rcu_dereference(sta_info->agg[i]);
-
-				if (!tid_info)
-					continue;
-
-				spin_lock_bh(&ar->tx_ampdu_list_lock);
-				if (tid_info->state >
-				    CARL9170_TID_STATE_SUSPEND)
-					tid_info->state =
-						CARL9170_TID_STATE_SUSPEND;
-				spin_unlock_bh(&ar->tx_ampdu_list_lock);
-
-				spin_lock_bh(&tid_info->lock);
-				while ((skb = __skb_dequeue(&tid_info->queue)))
-					__skb_queue_tail(&free, skb);
-				spin_unlock_bh(&tid_info->lock);
-			}
-			rcu_read_unlock();
-		}
-
-		for (i = 0; i < ar->hw->queues; i++) {
-			spin_lock_bh(&ar->tx_pending[i].lock);
-			skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) {
-				struct _carl9170_tx_superframe *super;
-				struct ieee80211_hdr *hdr;
-				struct ieee80211_tx_info *info;
-
-				super = (void *) skb->data;
-				hdr = (void *) super->frame_data;
-
-				if (compare_ether_addr(hdr->addr1, sta->addr))
-					continue;
-
-				__skb_unlink(skb, &ar->tx_pending[i]);
-
-				info = IEEE80211_SKB_CB(skb);
-				if (info->flags & IEEE80211_TX_CTL_AMPDU)
-					atomic_dec(&ar->tx_ampdu_upload);
-
-				carl9170_tx_status(ar, skb, false);
-			}
-			spin_unlock_bh(&ar->tx_pending[i].lock);
-		}
-
-		while ((skb = __skb_dequeue(&free)))
-			carl9170_tx_status(ar, skb, false);
-
+		sta_info->sleeping = true;
+		if (atomic_read(&sta_info->pending_frames))
+			ieee80211_sta_block_awake(hw, sta, true);
 		break;
 
 	case STA_NOTIFY_AWAKE:
-		if (!sta->ht_cap.ht_supported)
-			return;
-
-		rcu_read_lock();
-		for (i = 0; i < CARL9170_NUM_TID; i++) {
-			struct carl9170_sta_tid *tid_info;
-
-			tid_info = rcu_dereference(sta_info->agg[i]);
-
-			if (!tid_info)
-				continue;
-
-			if ((tid_info->state == CARL9170_TID_STATE_SUSPEND))
-				tid_info->state = CARL9170_TID_STATE_IDLE;
-		}
-		rcu_read_unlock();
+		sta_info->sleeping = false;
 		break;
 	}
 }
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index cb70ed7ec5ccff939c7c29b6cd340ecba07d0933..bf2eff9dd58247e0dba4b2647c02b056085c60a8 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -104,6 +104,56 @@ static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb)
 	spin_unlock_bh(&ar->tx_stats_lock);
 }
 
+/* needs rcu_read_lock */
+static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar,
+						   struct sk_buff *skb)
+{
+	struct _carl9170_tx_superframe *super = (void *) skb->data;
+	struct ieee80211_hdr *hdr = (void *) super->frame_data;
+	struct ieee80211_vif *vif;
+	unsigned int vif_id;
+
+	vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
+		 CARL9170_TX_SUPER_MISC_VIF_ID_S;
+
+	if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC))
+		return NULL;
+
+	vif = rcu_dereference(ar->vif_priv[vif_id].vif);
+	if (unlikely(!vif))
+		return NULL;
+
+	/*
+	 * Normally we should use wrappers like ieee80211_get_DA to get
+	 * the correct peer ieee80211_sta.
+	 *
+	 * But there is a problem with indirect traffic (broadcasts, or
+	 * data which is designated for other stations) in station mode.
+	 * The frame will be directed to the AP for distribution and not
+	 * to the actual destination.
+	 */
+
+	return ieee80211_find_sta(vif, hdr->addr1);
+}
+
+static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb)
+{
+	struct ieee80211_sta *sta;
+	struct carl9170_sta_info *sta_info;
+
+	rcu_read_lock();
+	sta = __carl9170_get_tx_sta(ar, skb);
+	if (unlikely(!sta))
+		goto out_rcu;
+
+	sta_info = (struct carl9170_sta_info *) sta->drv_priv;
+	if (atomic_dec_return(&sta_info->pending_frames) == 0)
+		ieee80211_sta_block_awake(ar->hw, sta, false);
+
+out_rcu:
+	rcu_read_unlock();
+}
+
 static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *txinfo;
@@ -135,6 +185,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb)
 	}
 
 	spin_unlock_bh(&ar->tx_stats_lock);
+
 	if (atomic_dec_and_test(&ar->tx_total_queued))
 		complete(&ar->tx_flush);
 }
@@ -329,13 +380,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
 {
 	struct _carl9170_tx_superframe *super = (void *) skb->data;
 	struct ieee80211_hdr *hdr = (void *) super->frame_data;
-	struct ieee80211_tx_info *tx_info;
 	struct carl9170_tx_info *ar_info;
-	struct carl9170_sta_info *sta_info;
 	struct ieee80211_sta *sta;
+	struct carl9170_sta_info *sta_info;
 	struct carl9170_sta_tid *tid_info;
-	struct ieee80211_vif *vif;
-	unsigned int vif_id;
 	u8 tid;
 
 	if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) ||
@@ -343,30 +391,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
 	   (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR))))
 		return;
 
-	tx_info = IEEE80211_SKB_CB(skb);
-	ar_info = (void *) tx_info->rate_driver_data;
-
-	vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
-		 CARL9170_TX_SUPER_MISC_VIF_ID_S;
-
-	if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC))
-		return;
+	ar_info = (void *) txinfo->rate_driver_data;
 
 	rcu_read_lock();
-	vif = rcu_dereference(ar->vif_priv[vif_id].vif);
-	if (unlikely(!vif))
-		goto out_rcu;
-
-	/*
-	 * Normally we should use wrappers like ieee80211_get_DA to get
-	 * the correct peer ieee80211_sta.
-	 *
-	 * But there is a problem with indirect traffic (broadcasts, or
-	 * data which is designated for other stations) in station mode.
-	 * The frame will be directed to the AP for distribution and not
-	 * to the actual destination.
-	 */
-	sta = ieee80211_find_sta(vif, hdr->addr1);
+	sta = __carl9170_get_tx_sta(ar, skb);
 	if (unlikely(!sta))
 		goto out_rcu;
 
@@ -427,6 +455,7 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
 	if (txinfo->flags & IEEE80211_TX_CTL_AMPDU)
 		carl9170_tx_status_process_ampdu(ar, skb, txinfo);
 
+	carl9170_tx_ps_unblock(ar, skb);
 	carl9170_tx_put_skb(skb);
 }
 
@@ -540,11 +569,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *txinfo;
 	struct carl9170_tx_info *arinfo;
-	struct _carl9170_tx_superframe *super;
 	struct ieee80211_sta *sta;
-	struct ieee80211_vif *vif;
-	struct ieee80211_hdr *hdr;
-	unsigned int vif_id;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) {
@@ -562,20 +587,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
 		    msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT)))
 			goto unlock;
 
-		super = (void *) skb->data;
-		hdr = (void *) super->frame_data;
-
-		vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
-			 CARL9170_TX_SUPER_MISC_VIF_ID_S;
-
-		if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC))
-			goto unlock;
-
-		vif = rcu_dereference(ar->vif_priv[vif_id].vif);
-		if (WARN_ON(!vif))
-			goto unlock;
-
-		sta = ieee80211_find_sta(vif, hdr->addr1);
+		sta = __carl9170_get_tx_sta(ar, skb);
 		if (WARN_ON(!sta))
 			goto unlock;
 
@@ -1199,15 +1211,6 @@ static struct sk_buff *carl9170_tx_pick_skb(struct ar9170 *ar,
 	arinfo = (void *) info->rate_driver_data;
 
 	arinfo->timeout = jiffies;
-
-	/*
-	 * increase ref count to "2".
-	 * Ref counting is the easiest way to solve the race between
-	 * the the urb's completion routine: carl9170_tx_callback and
-	 * wlan tx status functions: carl9170_tx_status/janitor.
-	 */
-	carl9170_tx_get_skb(skb);
-
 	return skb;
 
 err_unlock:
@@ -1228,6 +1231,36 @@ void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb)
 	__carl9170_tx_process_status(ar, super->s.cookie, q);
 }
 
+static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
+{
+	struct ieee80211_sta *sta;
+	struct carl9170_sta_info *sta_info;
+
+	rcu_read_lock();
+	sta = __carl9170_get_tx_sta(ar, skb);
+	if (!sta)
+		goto out_rcu;
+
+	sta_info = (void *) sta->drv_priv;
+	if (unlikely(sta_info->sleeping)) {
+		struct ieee80211_tx_info *tx_info;
+
+		rcu_read_unlock();
+
+		tx_info = IEEE80211_SKB_CB(skb);
+		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+			atomic_dec(&ar->tx_ampdu_upload);
+
+		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+		carl9170_tx_status(ar, skb, false);
+		return true;
+	}
+
+out_rcu:
+	rcu_read_unlock();
+	return false;
+}
+
 static void carl9170_tx(struct ar9170 *ar)
 {
 	struct sk_buff *skb;
@@ -1247,6 +1280,9 @@ static void carl9170_tx(struct ar9170 *ar)
 			if (unlikely(!skb))
 				break;
 
+			if (unlikely(carl9170_tx_ps_drop(ar, skb)))
+				continue;
+
 			atomic_inc(&ar->tx_total_pending);
 
 			q = __carl9170_get_queue(ar, i);
@@ -1256,6 +1292,16 @@ static void carl9170_tx(struct ar9170 *ar)
 			 */
 			skb_queue_tail(&ar->tx_status[q], skb);
 
+			/*
+			 * increase ref count to "2".
+			 * Ref counting is the easiest way to solve the
+			 * race between the urb's completion routine:
+			 *	carl9170_tx_callback
+			 * and wlan tx status functions:
+			 *	carl9170_tx_status/janitor.
+			 */
+			carl9170_tx_get_skb(skb);
+
 			carl9170_usb_tx(ar, skb);
 			schedule_garbagecollector = true;
 		}
@@ -1368,6 +1414,11 @@ void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	 * all ressouces which are associated with the frame.
 	 */
 
+	if (sta) {
+		struct carl9170_sta_info *stai = (void *) sta->drv_priv;
+		atomic_inc(&stai->pending_frames);
+	}
+
 	if (info->flags & IEEE80211_TX_CTL_AMPDU) {
 		run = carl9170_tx_ampdu_queue(ar, sta, skb);
 		if (run)
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 8a00f9a95dbbe9f339d8e37e2586522ae25a0a3d..6755063f955a5dea5e8cba38e7487178cef29658 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -2281,6 +2281,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
 		save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
 		save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
 		save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
+		save_regs_phy[8] = 0;
 	} else {
 		save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
 		save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
@@ -2289,6 +2290,8 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
 		save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
 		save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
 		save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
+		save_regs_phy[7] = 0;
+		save_regs_phy[8] = 0;
 	}
 
 	b43_nphy_rssi_select(dev, 5, type);
@@ -3845,8 +3848,8 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
 {
 	struct b43_phy *phy = &dev->phy;
 
-	const struct b43_nphy_channeltab_entry_rev2 *tabent_r2;
-	const struct b43_nphy_channeltab_entry_rev3 *tabent_r3;
+	const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL;
+	const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL;
 
 	u8 tmp;
 
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c
index 5a8a3cce27bcf0a75544fe623d6aab66b7f000cd..7e5e85a017b5c0f9da0435f84cf94965b72a6ee3 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c
@@ -955,9 +955,6 @@ int iwl4965_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 	if (priv->cfg->scan_rx_antennas[band])
 		rx_ant = priv->cfg->scan_rx_antennas[band];
 
-	if (priv->cfg->scan_tx_antennas[band])
-		scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
-
 	priv->scan_tx_ant[band] = iwl4965_toggle_tx_ant(priv,
 						priv->scan_tx_ant[band],
 						    scan_tx_antennas);
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c
index c1511b14b239c69884292e5e8e33296debbdebc4..d743373a9424508055feec442998f4675b03994b 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.c
+++ b/drivers/net/wireless/iwlegacy/iwl-core.c
@@ -211,10 +211,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv)
 		if (!iwl_legacy_is_channel_valid(ch))
 			continue;
 
-		if (iwl_legacy_is_channel_a_band(ch))
-			sband =  &priv->bands[IEEE80211_BAND_5GHZ];
-		else
-			sband =  &priv->bands[IEEE80211_BAND_2GHZ];
+		sband = &priv->bands[ch->band];
 
 		geo_ch = &sband->channels[sband->n_channels++];
 
@@ -2117,10 +2114,9 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
 	IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
 					channel->hw_value, changed);
 
-	if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
-			test_bit(STATUS_SCANNING, &priv->status))) {
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
 		scan_active = 1;
-		IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+		IWL_DEBUG_MAC80211(priv, "scan active\n");
 	}
 
 	if (changed & (IEEE80211_CONF_CHANGE_SMPS |
@@ -2433,11 +2429,13 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
 
 	IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
 
-	if (!iwl_legacy_is_alive(priv))
-		return;
-
 	mutex_lock(&priv->mutex);
 
+	if (!iwl_legacy_is_alive(priv)) {
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
 	if (changes & BSS_CHANGED_QOS) {
 		unsigned long flags;
 
@@ -2646,7 +2644,7 @@ unplugged:
 
 none:
 	/* re-enable interrupts here since we don't have anything to service. */
-	/* only Re-enable if diabled by irq */
+	/* only Re-enable if disabled by irq */
 	if (test_bit(STATUS_INT_ENABLED, &priv->status))
 		iwl_legacy_enable_interrupts(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h
index f03b463e4378e7a4c93d5d3a933ef69cc563bbe9..bc66c604106cb990e79b73a337395523c1d60973 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.h
+++ b/drivers/net/wireless/iwlegacy/iwl-core.h
@@ -287,7 +287,6 @@ struct iwl_cfg {
 	struct iwl_base_params *base_params;
 	/* params likely to change within a device family */
 	u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
-	u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
 	enum iwl_led_mode led_mode;
 };
 
diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h
index 9ee849d669f30532c8ddba597ef09d0827eb49b2..2d87dba2cfa3d137802d14f219b33d63f6f6fc77 100644
--- a/drivers/net/wireless/iwlegacy/iwl-dev.h
+++ b/drivers/net/wireless/iwlegacy/iwl-dev.h
@@ -134,7 +134,7 @@ struct iwl_queue {
 				* space more than this */
 	int high_mark;         /* high watermark, stop queue if free
 				* space less than this */
-} __packed;
+};
 
 /* One for each TFD */
 struct iwl_tx_info {
@@ -290,6 +290,7 @@ enum {
 	CMD_SIZE_HUGE = (1 << 0),
 	CMD_ASYNC = (1 << 1),
 	CMD_WANT_SKB = (1 << 2),
+	CMD_MAPPED = (1 << 3),
 };
 
 #define DEF_CMD_PAYLOAD_SIZE 320
@@ -1076,7 +1077,6 @@ struct iwl_priv {
 	spinlock_t hcmd_lock;	/* protect hcmd */
 	spinlock_t reg_lock;	/* protect hw register access */
 	struct mutex mutex;
-	struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
 
 	/* basic pci-network driver stuff */
 	struct pci_dev *pci_dev;
diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
index 9d721cbda5bb04560e62fca55a5a25d767369acf..62b4b09122cbac4489561a0a1428cc70d7a5b538 100644
--- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
@@ -145,6 +145,8 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	int cmd_idx;
 	int ret;
 
+	lockdep_assert_held(&priv->mutex);
+
 	BUG_ON(cmd->flags & CMD_ASYNC);
 
 	 /* A synchronous command can not have a callback set. */
@@ -152,7 +154,6 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
 	IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
 			iwl_legacy_get_cmd_string(cmd->id));
-	mutex_lock(&priv->sync_cmd_mutex);
 
 	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
 	IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
@@ -224,7 +225,6 @@ fail:
 		cmd->reply_page = 0;
 	}
 out:
-	mutex_unlock(&priv->sync_cmd_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(iwl_legacy_send_cmd_sync);
diff --git a/drivers/net/wireless/iwlegacy/iwl-helpers.h b/drivers/net/wireless/iwlegacy/iwl-helpers.h
index 02132e7558315364929c2e5de2230b6a797ae682..a6effdae63f98ffa645eef690eb12ee4aa4feec4 100644
--- a/drivers/net/wireless/iwlegacy/iwl-helpers.h
+++ b/drivers/net/wireless/iwlegacy/iwl-helpers.h
@@ -149,6 +149,12 @@ static inline void iwl_legacy_disable_interrupts(struct iwl_priv *priv)
 	IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
 }
 
+static inline void iwl_legacy_enable_rfkill_int(struct iwl_priv *priv)
+{
+	IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n");
+	iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+}
+
 static inline void iwl_legacy_enable_interrupts(struct iwl_priv *priv)
 {
 	IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c
index a227773cb384443ac4e41c0f4db81a98b6dbaea9..4fff995c6f3e2f4cbb97139d52625fa5ccce2321 100644
--- a/drivers/net/wireless/iwlegacy/iwl-tx.c
+++ b/drivers/net/wireless/iwlegacy/iwl-tx.c
@@ -146,33 +146,32 @@ void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv)
 {
 	struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
 	struct iwl_queue *q = &txq->q;
-	bool huge = false;
 	int i;
 
 	if (q->n_bd == 0)
 		return;
 
 	while (q->read_ptr != q->write_ptr) {
-		/* we have no way to tell if it is a huge cmd ATM */
 		i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0);
 
-		if (txq->meta[i].flags & CMD_SIZE_HUGE)
-			huge = true;
-		else
+		if (txq->meta[i].flags & CMD_MAPPED) {
 			pci_unmap_single(priv->pci_dev,
 					 dma_unmap_addr(&txq->meta[i], mapping),
 					 dma_unmap_len(&txq->meta[i], len),
 					 PCI_DMA_BIDIRECTIONAL);
+			txq->meta[i].flags = 0;
+		}
 
 		q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd);
 	}
 
-	if (huge) {
-		i = q->n_window;
+	i = q->n_window;
+	if (txq->meta[i].flags & CMD_MAPPED) {
 		pci_unmap_single(priv->pci_dev,
 				 dma_unmap_addr(&txq->meta[i], mapping),
 				 dma_unmap_len(&txq->meta[i], len),
 				 PCI_DMA_BIDIRECTIONAL);
+		txq->meta[i].flags = 0;
 	}
 }
 EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap);
@@ -467,29 +466,27 @@ int iwl_legacy_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 		return -EIO;
 	}
 
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
 	if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
-		IWL_ERR(priv, "No space in command queue\n");
-		IWL_ERR(priv, "Restarting adapter due to queue full\n");
+		spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+
+		IWL_ERR(priv, "Restarting adapter due to command queue full\n");
 		queue_work(priv->workqueue, &priv->restart);
 		return -ENOSPC;
 	}
 
-	spin_lock_irqsave(&priv->hcmd_lock, flags);
-
-	/* If this is a huge cmd, mark the huge flag also on the meta.flags
-	 * of the _original_ cmd. This is used for DMA mapping clean up.
-	 */
-	if (cmd->flags & CMD_SIZE_HUGE) {
-		idx = iwl_legacy_get_cmd_index(q, q->write_ptr, 0);
-		txq->meta[idx].flags = CMD_SIZE_HUGE;
-	}
-
 	idx = iwl_legacy_get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
 	out_cmd = txq->cmd[idx];
 	out_meta = &txq->meta[idx];
 
+	if (WARN_ON(out_meta->flags & CMD_MAPPED)) {
+		spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+		return -ENOSPC;
+	}
+
 	memset(out_meta, 0, sizeof(*out_meta));	/* re-initialize to NULL */
-	out_meta->flags = cmd->flags;
+	out_meta->flags = cmd->flags | CMD_MAPPED;
 	if (cmd->flags & CMD_WANT_SKB)
 		out_meta->source = cmd;
 	if (cmd->flags & CMD_ASYNC)
@@ -610,6 +607,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	struct iwl_device_cmd *cmd;
 	struct iwl_cmd_meta *meta;
 	struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
+	unsigned long flags;
 
 	/* If a Tx command is being handled and it isn't in the actual
 	 * command queue then there a command routing bug has been introduced
@@ -623,14 +621,6 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 		return;
 	}
 
-	/* If this is a huge cmd, clear the huge flag on the meta.flags
-	 * of the _original_ cmd. So that iwl_legacy_cmd_queue_free won't unmap
-	 * the DMA buffer for the scan (huge) command.
-	 */
-	if (huge) {
-		cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, 0);
-		txq->meta[cmd_index].flags = 0;
-	}
 	cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, huge);
 	cmd = txq->cmd[cmd_index];
 	meta = &txq->meta[cmd_index];
@@ -647,6 +637,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	} else if (meta->callback)
 		meta->callback(priv, cmd, pkt);
 
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
 	iwl_legacy_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
 
 	if (!(meta->flags & CMD_ASYNC)) {
@@ -655,6 +647,10 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 			       iwl_legacy_get_cmd_string(cmd->hdr.cmd));
 		wake_up_interruptible(&priv->wait_command_queue);
 	}
+
+	/* Mark as unmapped */
 	meta->flags = 0;
+
+	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
 }
 EXPORT_SYMBOL(iwl_legacy_tx_cmd_complete);
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c
index cc7ebcee60e5bd6e9d49f2a1ae8c17dee1c31f21..0ee6be6a9c5db74c4b8b603e8b5e705641393d8f 100644
--- a/drivers/net/wireless/iwlegacy/iwl3945-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c
@@ -2748,11 +2748,12 @@ static void iwl3945_bg_init_alive_start(struct work_struct *data)
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, init_alive_start.work);
 
+	mutex_lock(&priv->mutex);
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
+		goto out;
 
-	mutex_lock(&priv->mutex);
 	iwl3945_init_alive_start(priv);
+out:
 	mutex_unlock(&priv->mutex);
 }
 
@@ -2761,11 +2762,12 @@ static void iwl3945_bg_alive_start(struct work_struct *data)
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, alive_start.work);
 
+	mutex_lock(&priv->mutex);
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
+		goto out;
 
-	mutex_lock(&priv->mutex);
 	iwl3945_alive_start(priv);
+out:
 	mutex_unlock(&priv->mutex);
 }
 
@@ -2995,10 +2997,12 @@ static void iwl3945_bg_restart(struct work_struct *data)
 	} else {
 		iwl3945_down(priv);
 
-		if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		mutex_lock(&priv->mutex);
+		if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+			mutex_unlock(&priv->mutex);
 			return;
+		}
 
-		mutex_lock(&priv->mutex);
 		__iwl3945_up(priv);
 		mutex_unlock(&priv->mutex);
 	}
@@ -3009,11 +3013,12 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data)
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, rx_replenish);
 
+	mutex_lock(&priv->mutex);
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
+		goto out;
 
-	mutex_lock(&priv->mutex);
 	iwl3945_rx_replenish(priv);
+out:
 	mutex_unlock(&priv->mutex);
 }
 
@@ -3810,7 +3815,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
 	INIT_LIST_HEAD(&priv->free_frames);
 
 	mutex_init(&priv->mutex);
-	mutex_init(&priv->sync_cmd_mutex);
 
 	priv->ieee_channels = NULL;
 	priv->ieee_rates = NULL;
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c
index f8870543d68f8555025c1a26d094dfa91d4c3a8d..f781b7e225b466679d5a8738ae69ee74f01c833b 100644
--- a/drivers/net/wireless/iwlegacy/iwl4965-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c
@@ -1069,9 +1069,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
 	}
 
 	/* Re-enable all interrupts */
-	/* only Re-enable if diabled by irq */
+	/* only Re-enable if disabled by irq */
 	if (test_bit(STATUS_INT_ENABLED, &priv->status))
 		iwl_legacy_enable_interrupts(priv);
+	/* Re-enable RF_KILL if it occurred */
+	else if (handled & CSR_INT_BIT_RF_KILL)
+		iwl_legacy_enable_rfkill_int(priv);
 
 #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
 	if (iwl_legacy_get_debug_level(priv) & (IWL_DL_ISR)) {
@@ -2139,7 +2142,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv);
 static void __iwl4965_down(struct iwl_priv *priv)
 {
 	unsigned long flags;
-	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+	int exit_pending;
 
 	IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
 
@@ -2401,11 +2404,12 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data)
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, init_alive_start.work);
 
+	mutex_lock(&priv->mutex);
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
+		goto out;
 
-	mutex_lock(&priv->mutex);
 	priv->cfg->ops->lib->init_alive_start(priv);
+out:
 	mutex_unlock(&priv->mutex);
 }
 
@@ -2414,11 +2418,12 @@ static void iwl4965_bg_alive_start(struct work_struct *data)
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, alive_start.work);
 
+	mutex_lock(&priv->mutex);
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		return;
+		goto out;
 
-	mutex_lock(&priv->mutex);
 	iwl4965_alive_start(priv);
+out:
 	mutex_unlock(&priv->mutex);
 }
 
@@ -2468,10 +2473,12 @@ static void iwl4965_bg_restart(struct work_struct *data)
 	} else {
 		iwl4965_down(priv);
 
-		if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		mutex_lock(&priv->mutex);
+		if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+			mutex_unlock(&priv->mutex);
 			return;
+		}
 
-		mutex_lock(&priv->mutex);
 		__iwl4965_up(priv);
 		mutex_unlock(&priv->mutex);
 	}
@@ -2624,9 +2631,10 @@ void iwl4965_mac_stop(struct ieee80211_hw *hw)
 
 	flush_workqueue(priv->workqueue);
 
-	/* enable interrupts again in order to receive rfkill changes */
+	/* User space software may expect getting rfkill changes
+	 * even if interface is down */
 	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl_legacy_enable_interrupts(priv);
+	iwl_legacy_enable_rfkill_int(priv);
 
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 }
@@ -2847,21 +2855,22 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw,
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 
+	mutex_lock(&priv->mutex);
+
 	if (iwl_legacy_is_rfkill(priv))
-		goto out_exit;
+		goto out;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
 	    test_bit(STATUS_SCANNING, &priv->status))
-		goto out_exit;
+		goto out;
 
 	if (!iwl_legacy_is_associated_ctx(ctx))
-		goto out_exit;
+		goto out;
 
 	/* channel switch in progress */
 	if (priv->switch_rxon.switch_in_progress == true)
-		goto out_exit;
+		goto out;
 
-	mutex_lock(&priv->mutex);
 	if (priv->cfg->ops->lib->set_channel_switch) {
 
 		ch = channel->hw_value;
@@ -2917,7 +2926,6 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw,
 	}
 out:
 	mutex_unlock(&priv->mutex);
-out_exit:
 	if (!priv->switch_rxon.switch_in_progress)
 		ieee80211_chswitch_done(ctx->vif, false);
 	IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3116,7 +3124,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv)
 	INIT_LIST_HEAD(&priv->free_frames);
 
 	mutex_init(&priv->mutex);
-	mutex_init(&priv->sync_cmd_mutex);
 
 	priv->ieee_channels = NULL;
 	priv->ieee_rates = NULL;
@@ -3406,14 +3413,14 @@ iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	 * 8. Enable interrupts and read RFKILL state
 	 *********************************************/
 
-	/* enable interrupts if needed: hw bug w/a */
+	/* enable rfkill interrupt: hw bug w/a */
 	pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
 	if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
 		pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
 		pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
 	}
 
-	iwl_legacy_enable_interrupts(priv);
+	iwl_legacy_enable_rfkill_int(priv);
 
 	/* If platform's RF_KILL switch is NOT set to KILL */
 	if (iwl_read32(priv, CSR_GP_CNTRL) &
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index bb6a737de61fbd656abd534c464d72733c89affe..89a41d320c365901519a84bfe93e449d646d316f 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -14,7 +14,6 @@ iwlagn-objs             += iwl-6000.o
 iwlagn-objs             += iwl-1000.o
 iwlagn-objs             += iwl-2000.o
 
-iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
 iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index baf80111efaf7bfa6efcd47aad23b80996efd58b..3da8cf27dcb9da273ff3b5b2319b0273fef96565 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -45,7 +45,6 @@
 #include "iwl-agn.h"
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
-#include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
 #define IWL1000_UCODE_API_MAX 5
@@ -121,10 +120,10 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
 
 static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 {
-	if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-	    priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
+	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
 		priv->cfg->base_params->num_of_queues =
-			priv->cfg->mod_params->num_of_queues;
+			iwlagn_mod_params.num_of_queues;
 
 	priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
 	priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -197,21 +196,11 @@ static struct iwl_lib_ops iwl1000_lib = {
 			EEPROM_REG_BAND_24_HT40_CHANNELS,
 			EEPROM_REGULATORY_BAND_NO_HT40,
 		},
-		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
-	.debugfs_ops = {
-		.rx_stats_read = iwl_ucode_rx_stats_read,
-		.tx_stats_read = iwl_ucode_tx_stats_read,
-		.general_stats_read = iwl_ucode_general_stats_read,
-		.bt_stats_read = iwl_ucode_bt_stats_read,
-		.reply_tx_error = iwl_reply_tx_error_read,
-	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
@@ -249,7 +238,6 @@ static struct iwl_ht_params iwl1000_ht_params = {
 	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
 	.ops = &iwl1000_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl1000_base_params,			\
 	.led_mode = IWL_LED_BLINK
 
@@ -271,7 +259,6 @@ struct iwl_cfg iwl1000_bg_cfg = {
 	.eeprom_ver = EEPROM_1000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,	\
 	.ops = &iwl1000_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl1000_base_params,			\
 	.led_mode = IWL_LED_RF_STATE,				\
 	.rx_with_siso_diversity = true
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index e76e02c28928afe0b4b046c2c2c24b5bba942884..bca462c47e37fe7d90034997fc451a3bcc348e9c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -46,17 +46,16 @@
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
-#include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
 #define IWL2030_UCODE_API_MAX 5
 #define IWL2000_UCODE_API_MAX 5
-#define IWL200_UCODE_API_MAX 5
+#define IWL105_UCODE_API_MAX 5
 
 /* Lowest firmware API version supported */
 #define IWL2030_UCODE_API_MIN 5
 #define IWL2000_UCODE_API_MIN 5
-#define IWL200_UCODE_API_MIN 5
+#define IWL105_UCODE_API_MIN 5
 
 #define IWL2030_FW_PRE "iwlwifi-2030-"
 #define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode"
@@ -64,8 +63,8 @@
 #define IWL2000_FW_PRE "iwlwifi-2000-"
 #define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode"
 
-#define IWL200_FW_PRE "iwlwifi-200-"
-#define IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode"
+#define IWL105_FW_PRE "iwlwifi-105-"
+#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode"
 
 static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
 {
@@ -128,10 +127,10 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
 
 static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
 {
-	if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-	    priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
+	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
 		priv->cfg->base_params->num_of_queues =
-			priv->cfg->mod_params->num_of_queues;
+			iwlagn_mod_params.num_of_queues;
 
 	priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
 	priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -280,22 +279,12 @@ static struct iwl_lib_ops iwl2000_lib = {
 			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
 			EEPROM_REGULATORY_BAND_NO_HT40,
 		},
-		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.calib_version  = iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 		.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
 	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	},
-	.debugfs_ops = {
-		.rx_stats_read = iwl_ucode_rx_stats_read,
-		.tx_stats_read = iwl_ucode_tx_stats_read,
-		.general_stats_read = iwl_ucode_general_stats_read,
-		.bt_stats_read = iwl_ucode_bt_stats_read,
-		.reply_tx_error = iwl_reply_tx_error_read,
-	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
@@ -312,13 +301,13 @@ static const struct iwl_ops iwl2030_ops = {
 	.utils = &iwlagn_hcmd_utils,
 };
 
-static const struct iwl_ops iwl200_ops = {
+static const struct iwl_ops iwl105_ops = {
 	.lib = &iwl2000_lib,
 	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 };
 
-static const struct iwl_ops iwl230_ops = {
+static const struct iwl_ops iwl135_ops = {
 	.lib = &iwl2000_lib,
 	.hcmd = &iwlagn_bt_hcmd,
 	.utils = &iwlagn_hcmd_utils,
@@ -383,7 +372,6 @@ static struct iwl_bt_params iwl2030_bt_params = {
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.ops = &iwl2000_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl2000_base_params,			\
 	.need_dc_calib = true,					\
 	.need_temp_offset_calib = true,				\
@@ -409,7 +397,6 @@ struct iwl_cfg iwl2000_2bg_cfg = {
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.ops = &iwl2030_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl2030_base_params,			\
 	.bt_params = &iwl2030_bt_params,			\
 	.need_dc_calib = true,					\
@@ -429,14 +416,13 @@ struct iwl_cfg iwl2030_2bg_cfg = {
 	IWL_DEVICE_2030,
 };
 
-#define IWL_DEVICE_200						\
-	.fw_name_pre = IWL200_FW_PRE,				\
-	.ucode_api_max = IWL200_UCODE_API_MAX,			\
-	.ucode_api_min = IWL200_UCODE_API_MIN,			\
+#define IWL_DEVICE_105						\
+	.fw_name_pre = IWL105_FW_PRE,				\
+	.ucode_api_max = IWL105_UCODE_API_MAX,			\
+	.ucode_api_min = IWL105_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
-	.ops = &iwl200_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
+	.ops = &iwl105_ops,					\
 	.base_params = &iwl2000_base_params,			\
 	.need_dc_calib = true,					\
 	.need_temp_offset_calib = true,				\
@@ -444,25 +430,24 @@ struct iwl_cfg iwl2030_2bg_cfg = {
 	.adv_pm = true,						\
 	.rx_with_siso_diversity = true				\
 
-struct iwl_cfg iwl200_bg_cfg = {
-	.name = "200 Series 1x1 BG",
-	IWL_DEVICE_200,
+struct iwl_cfg iwl105_bg_cfg = {
+	.name = "105 Series 1x1 BG",
+	IWL_DEVICE_105,
 };
 
-struct iwl_cfg iwl200_bgn_cfg = {
-	.name = "200 Series 1x1 BGN",
-	IWL_DEVICE_200,
+struct iwl_cfg iwl105_bgn_cfg = {
+	.name = "105 Series 1x1 BGN",
+	IWL_DEVICE_105,
 	.ht_params = &iwl2000_ht_params,
 };
 
-#define IWL_DEVICE_230						\
-	.fw_name_pre = IWL200_FW_PRE,				\
-	.ucode_api_max = IWL200_UCODE_API_MAX,			\
-	.ucode_api_min = IWL200_UCODE_API_MIN,			\
+#define IWL_DEVICE_135						\
+	.fw_name_pre = IWL105_FW_PRE,				\
+	.ucode_api_max = IWL105_UCODE_API_MAX,			\
+	.ucode_api_min = IWL105_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
-	.ops = &iwl230_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
+	.ops = &iwl135_ops,					\
 	.base_params = &iwl2030_base_params,			\
 	.bt_params = &iwl2030_bt_params,			\
 	.need_dc_calib = true,					\
@@ -471,17 +456,17 @@ struct iwl_cfg iwl200_bgn_cfg = {
 	.adv_pm = true,						\
 	.rx_with_siso_diversity = true				\
 
-struct iwl_cfg iwl230_bg_cfg = {
-	.name = "200 Series 1x1 BG/BT",
-	IWL_DEVICE_230,
+struct iwl_cfg iwl135_bg_cfg = {
+	.name = "105 Series 1x1 BG/BT",
+	IWL_DEVICE_135,
 };
 
-struct iwl_cfg iwl230_bgn_cfg = {
-	.name = "200 Series 1x1 BGN/BT",
-	IWL_DEVICE_230,
+struct iwl_cfg iwl135_bgn_cfg = {
+	.name = "105 Series 1x1 BGN/BT",
+	IWL_DEVICE_135,
 	.ht_params = &iwl2000_ht_params,
 };
 
 MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 655afc19f68fa1c024767a9ed810a7f03b0d3411..561f2cd65dd4f9320f30c327ca243692266db225 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -47,7 +47,6 @@
 #include "iwl-agn.h"
 #include "iwl-agn-hw.h"
 #include "iwl-5000-hw.h"
-#include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
 #define IWL5000_UCODE_API_MAX 5
@@ -165,10 +164,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
 
 static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
-	if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-	    priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
+	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
 		priv->cfg->base_params->num_of_queues =
-			priv->cfg->mod_params->num_of_queues;
+			iwlagn_mod_params.num_of_queues;
 
 	priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
 	priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -210,10 +209,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 
 static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
 {
-	if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-	    priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
+	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
 		priv->cfg->base_params->num_of_queues =
-			priv->cfg->mod_params->num_of_queues;
+			iwlagn_mod_params.num_of_queues;
 
 	priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
 	priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -366,21 +365,11 @@ static struct iwl_lib_ops iwl5000_lib = {
 			EEPROM_REG_BAND_24_HT40_CHANNELS,
 			EEPROM_REG_BAND_52_HT40_CHANNELS
 		},
-		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
-	.debugfs_ops = {
-		.rx_stats_read = iwl_ucode_rx_stats_read,
-		.tx_stats_read = iwl_ucode_tx_stats_read,
-		.general_stats_read = iwl_ucode_general_stats_read,
-		.bt_stats_read = iwl_ucode_bt_stats_read,
-		.reply_tx_error = iwl_reply_tx_error_read,
-	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
@@ -413,21 +402,11 @@ static struct iwl_lib_ops iwl5150_lib = {
 			EEPROM_REG_BAND_24_HT40_CHANNELS,
 			EEPROM_REG_BAND_52_HT40_CHANNELS
 		},
-		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 	},
 	.temp_ops = {
 		.temperature = iwl5150_temperature,
 	 },
-	.debugfs_ops = {
-		.rx_stats_read = iwl_ucode_rx_stats_read,
-		.tx_stats_read = iwl_ucode_tx_stats_read,
-		.general_stats_read = iwl_ucode_general_stats_read,
-		.bt_stats_read = iwl_ucode_bt_stats_read,
-		.reply_tx_error = iwl_reply_tx_error_read,
-	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
@@ -468,7 +447,6 @@ static struct iwl_ht_params iwl5000_ht_params = {
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,	\
 	.ops = &iwl5000_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl5000_base_params,			\
 	.led_mode = IWL_LED_BLINK
 
@@ -512,7 +490,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
 	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
 	.ops = &iwl5000_ops,
-	.mod_params = &iwlagn_mod_params,
 	.base_params = &iwl5000_base_params,
 	.ht_params = &iwl5000_ht_params,
 	.led_mode = IWL_LED_BLINK,
@@ -526,7 +503,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
 	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,	\
 	.ops = &iwl5150_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl5000_base_params,			\
 	.need_dc_calib = true,					\
 	.led_mode = IWL_LED_BLINK,				\
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 905eb57f7cab14433aa35c5e1f56dd688a2d1915..6045457cc72298d4771810eee427a5d29a0646f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,7 +46,6 @@
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
-#include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
@@ -80,7 +79,7 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
 static void iwl6050_additional_nic_config(struct iwl_priv *priv)
 {
 	/* Indicate calibration version to uCode. */
-	if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+	if (iwlagn_eeprom_calib_version(priv) >= 6)
 		iwl_set_bit(priv, CSR_GP_DRIVER_REG,
 				CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
 }
@@ -88,7 +87,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv)
 static void iwl6150_additional_nic_config(struct iwl_priv *priv)
 {
 	/* Indicate calibration version to uCode. */
-	if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+	if (iwlagn_eeprom_calib_version(priv) >= 6)
 		iwl_set_bit(priv, CSR_GP_DRIVER_REG,
 				CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
 	iwl_set_bit(priv, CSR_GP_DRIVER_REG,
@@ -154,10 +153,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
 
 static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 {
-	if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-	    priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
+	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
 		priv->cfg->base_params->num_of_queues =
-			priv->cfg->mod_params->num_of_queues;
+			iwlagn_mod_params.num_of_queues;
 
 	priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
 	priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -305,22 +304,12 @@ static struct iwl_lib_ops iwl6000_lib = {
 			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
 			EEPROM_REG_BAND_52_HT40_CHANNELS
 		},
-		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 		.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
 	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
-	.debugfs_ops = {
-		.rx_stats_read = iwl_ucode_rx_stats_read,
-		.tx_stats_read = iwl_ucode_tx_stats_read,
-		.general_stats_read = iwl_ucode_general_stats_read,
-		.bt_stats_read = iwl_ucode_bt_stats_read,
-		.reply_tx_error = iwl_reply_tx_error_read,
-	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
@@ -354,22 +343,12 @@ static struct iwl_lib_ops iwl6030_lib = {
 			EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
 			EEPROM_REG_BAND_52_HT40_CHANNELS
 		},
-		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
-		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.calib_version	= iwlagn_eeprom_calib_version,
 		.query_addr = iwlagn_eeprom_query_addr,
 		.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
 	},
 	.temp_ops = {
 		.temperature = iwlagn_temperature,
 	 },
-	.debugfs_ops = {
-		.rx_stats_read = iwl_ucode_rx_stats_read,
-		.tx_stats_read = iwl_ucode_tx_stats_read,
-		.general_stats_read = iwl_ucode_general_stats_read,
-		.bt_stats_read = iwl_ucode_bt_stats_read,
-		.reply_tx_error = iwl_reply_tx_error_read,
-	},
 	.txfifo_flush = iwlagn_txfifo_flush,
 	.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
@@ -482,7 +461,6 @@ static struct iwl_bt_params iwl6000_bt_params = {
 	.eeprom_ver = EEPROM_6005_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,	\
 	.ops = &iwl6000_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl6000_g2_base_params,			\
 	.need_dc_calib = true,					\
 	.need_temp_offset_calib = true,				\
@@ -511,7 +489,6 @@ struct iwl_cfg iwl6005_2bg_cfg = {
 	.eeprom_ver = EEPROM_6030_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,	\
 	.ops = &iwl6030_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl6000_g2_base_params,			\
 	.bt_params = &iwl6000_bt_params,			\
 	.need_dc_calib = true,					\
@@ -593,7 +570,6 @@ struct iwl_cfg iwl130_bg_cfg = {
 	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,	\
 	.ops = &iwl6000_ops,					\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl6000_base_params,			\
 	.pa_type = IWL_PA_INTERNAL,				\
 	.led_mode = IWL_LED_BLINK
@@ -623,7 +599,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
 	.ops = &iwl6050_ops,					\
 	.eeprom_ver = EEPROM_6050_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,	\
-	.mod_params = &iwlagn_mod_params,			\
 	.base_params = &iwl6050_base_params,			\
 	.need_dc_calib = true,					\
 	.led_mode = IWL_LED_BLINK,				\
@@ -648,7 +623,6 @@ struct iwl_cfg iwl6150_bgn_cfg = {
 	.eeprom_ver = EEPROM_6150_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,
 	.ops = &iwl6150_ops,
-	.mod_params = &iwlagn_mod_params,
 	.base_params = &iwl6050_base_params,
 	.ht_params = &iwl6000_ht_params,
 	.need_dc_calib = true,
@@ -664,7 +638,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {
 	.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
 	.ops = &iwl6000_ops,
-	.mod_params = &iwlagn_mod_params,
 	.base_params = &iwl6000_base_params,
 	.ht_params = &iwl6000_ht_params,
 	.need_dc_calib = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
deleted file mode 100644
index 71a5f31cd7cc403ed5638cd5efdbea8805263201..0000000000000000000000000000000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ /dev/null
@@ -1,1025 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-#include "iwl-agn.h"
-#include "iwl-agn-debugfs.h"
-
-static const char *fmt_value = "  %-30s %10u\n";
-static const char *fmt_hex   = "  %-30s       0x%02X\n";
-static const char *fmt_table = "  %-30s %10u  %10u  %10u  %10u\n";
-static const char *fmt_header =
-	"%-32s    current  cumulative       delta         max\n";
-
-static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
-{
-	int p = 0;
-	u32 flag;
-
-	flag = le32_to_cpu(priv->statistics.flag);
-
-	p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
-	if (flag & UCODE_STATISTICS_CLEAR_MSK)
-		p += scnprintf(buf + p, bufsz - p,
-		"\tStatistics have been cleared\n");
-	p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
-		(flag & UCODE_STATISTICS_FREQUENCY_MSK)
-		? "2.4 GHz" : "5.2 GHz");
-	p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
-		(flag & UCODE_STATISTICS_NARROW_BAND_MSK)
-		 ? "enabled" : "disabled");
-
-	return p;
-}
-
-ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
-				size_t count, loff_t *ppos)
-  {
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = sizeof(struct statistics_rx_phy) * 40 +
-		    sizeof(struct statistics_rx_non_phy) * 40 +
-		    sizeof(struct statistics_rx_ht_phy) * 40 + 400;
-	ssize_t ret;
-	struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
-	struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
-	struct statistics_rx_non_phy *general, *accum_general;
-	struct statistics_rx_non_phy *delta_general, *max_general;
-	struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf) {
-		IWL_ERR(priv, "Can not allocate Buffer\n");
-		return -ENOMEM;
-	}
-
-	/*
-	 * the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-	ofdm = &priv->statistics.rx_ofdm;
-	cck = &priv->statistics.rx_cck;
-	general = &priv->statistics.rx_non_phy;
-	ht = &priv->statistics.rx_ofdm_ht;
-	accum_ofdm = &priv->accum_stats.rx_ofdm;
-	accum_cck = &priv->accum_stats.rx_cck;
-	accum_general = &priv->accum_stats.rx_non_phy;
-	accum_ht = &priv->accum_stats.rx_ofdm_ht;
-	delta_ofdm = &priv->delta_stats.rx_ofdm;
-	delta_cck = &priv->delta_stats.rx_cck;
-	delta_general = &priv->delta_stats.rx_non_phy;
-	delta_ht = &priv->delta_stats.rx_ofdm_ht;
-	max_ofdm = &priv->max_delta_stats.rx_ofdm;
-	max_cck = &priv->max_delta_stats.rx_cck;
-	max_general = &priv->max_delta_stats.rx_non_phy;
-	max_ht = &priv->max_delta_stats.rx_ofdm_ht;
-
-	pos += iwl_statistics_flag(priv, buf, bufsz);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - OFDM:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ina_cnt:",
-			 le32_to_cpu(ofdm->ina_cnt),
-			 accum_ofdm->ina_cnt,
-			 delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_cnt:",
-			 le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
-			 delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "plcp_err:",
-			 le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
-			 delta_ofdm->plcp_err, max_ofdm->plcp_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_err:",
-			 le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
-			 delta_ofdm->crc32_err, max_ofdm->crc32_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "overrun_err:",
-			 le32_to_cpu(ofdm->overrun_err),
-			 accum_ofdm->overrun_err, delta_ofdm->overrun_err,
-			 max_ofdm->overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "early_overrun_err:",
-			 le32_to_cpu(ofdm->early_overrun_err),
-			 accum_ofdm->early_overrun_err,
-			 delta_ofdm->early_overrun_err,
-			 max_ofdm->early_overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_good:",
-			 le32_to_cpu(ofdm->crc32_good),
-			 accum_ofdm->crc32_good, delta_ofdm->crc32_good,
-			 max_ofdm->crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "false_alarm_cnt:",
-			 le32_to_cpu(ofdm->false_alarm_cnt),
-			 accum_ofdm->false_alarm_cnt,
-			 delta_ofdm->false_alarm_cnt,
-			 max_ofdm->false_alarm_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_sync_err_cnt:",
-			 le32_to_cpu(ofdm->fina_sync_err_cnt),
-			 accum_ofdm->fina_sync_err_cnt,
-			 delta_ofdm->fina_sync_err_cnt,
-			 max_ofdm->fina_sync_err_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sfd_timeout:",
-			 le32_to_cpu(ofdm->sfd_timeout),
-			 accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
-			 max_ofdm->sfd_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_timeout:",
-			 le32_to_cpu(ofdm->fina_timeout),
-			 accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
-			 max_ofdm->fina_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "unresponded_rts:",
-			 le32_to_cpu(ofdm->unresponded_rts),
-			 accum_ofdm->unresponded_rts,
-			 delta_ofdm->unresponded_rts,
-			 max_ofdm->unresponded_rts);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rxe_frame_lmt_ovrun:",
-			 le32_to_cpu(ofdm->rxe_frame_limit_overrun),
-			 accum_ofdm->rxe_frame_limit_overrun,
-			 delta_ofdm->rxe_frame_limit_overrun,
-			 max_ofdm->rxe_frame_limit_overrun);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ack_cnt:",
-			 le32_to_cpu(ofdm->sent_ack_cnt),
-			 accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
-			 max_ofdm->sent_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_cts_cnt:",
-			 le32_to_cpu(ofdm->sent_cts_cnt),
-			 accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
-			 max_ofdm->sent_cts_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ba_rsp_cnt:",
-			 le32_to_cpu(ofdm->sent_ba_rsp_cnt),
-			 accum_ofdm->sent_ba_rsp_cnt,
-			 delta_ofdm->sent_ba_rsp_cnt,
-			 max_ofdm->sent_ba_rsp_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dsp_self_kill:",
-			 le32_to_cpu(ofdm->dsp_self_kill),
-			 accum_ofdm->dsp_self_kill,
-			 delta_ofdm->dsp_self_kill,
-			 max_ofdm->dsp_self_kill);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "mh_format_err:",
-			 le32_to_cpu(ofdm->mh_format_err),
-			 accum_ofdm->mh_format_err,
-			 delta_ofdm->mh_format_err,
-			 max_ofdm->mh_format_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "re_acq_main_rssi_sum:",
-			 le32_to_cpu(ofdm->re_acq_main_rssi_sum),
-			 accum_ofdm->re_acq_main_rssi_sum,
-			 delta_ofdm->re_acq_main_rssi_sum,
-			 max_ofdm->re_acq_main_rssi_sum);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - CCK:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ina_cnt:",
-			 le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
-			 delta_cck->ina_cnt, max_cck->ina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_cnt:",
-			 le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
-			 delta_cck->fina_cnt, max_cck->fina_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "plcp_err:",
-			 le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
-			 delta_cck->plcp_err, max_cck->plcp_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_err:",
-			 le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
-			 delta_cck->crc32_err, max_cck->crc32_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "overrun_err:",
-			 le32_to_cpu(cck->overrun_err),
-			 accum_cck->overrun_err, delta_cck->overrun_err,
-			 max_cck->overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "early_overrun_err:",
-			 le32_to_cpu(cck->early_overrun_err),
-			 accum_cck->early_overrun_err,
-			 delta_cck->early_overrun_err,
-			 max_cck->early_overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_good:",
-			 le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
-			 delta_cck->crc32_good, max_cck->crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "false_alarm_cnt:",
-			 le32_to_cpu(cck->false_alarm_cnt),
-			 accum_cck->false_alarm_cnt,
-			 delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_sync_err_cnt:",
-			 le32_to_cpu(cck->fina_sync_err_cnt),
-			 accum_cck->fina_sync_err_cnt,
-			 delta_cck->fina_sync_err_cnt,
-			 max_cck->fina_sync_err_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sfd_timeout:",
-			 le32_to_cpu(cck->sfd_timeout),
-			 accum_cck->sfd_timeout, delta_cck->sfd_timeout,
-			 max_cck->sfd_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "fina_timeout:",
-			 le32_to_cpu(cck->fina_timeout),
-			 accum_cck->fina_timeout, delta_cck->fina_timeout,
-			 max_cck->fina_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "unresponded_rts:",
-			 le32_to_cpu(cck->unresponded_rts),
-			 accum_cck->unresponded_rts, delta_cck->unresponded_rts,
-			 max_cck->unresponded_rts);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rxe_frame_lmt_ovrun:",
-			 le32_to_cpu(cck->rxe_frame_limit_overrun),
-			 accum_cck->rxe_frame_limit_overrun,
-			 delta_cck->rxe_frame_limit_overrun,
-			 max_cck->rxe_frame_limit_overrun);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ack_cnt:",
-			 le32_to_cpu(cck->sent_ack_cnt),
-			 accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
-			 max_cck->sent_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_cts_cnt:",
-			 le32_to_cpu(cck->sent_cts_cnt),
-			 accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
-			 max_cck->sent_cts_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sent_ba_rsp_cnt:",
-			 le32_to_cpu(cck->sent_ba_rsp_cnt),
-			 accum_cck->sent_ba_rsp_cnt,
-			 delta_cck->sent_ba_rsp_cnt,
-			 max_cck->sent_ba_rsp_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dsp_self_kill:",
-			 le32_to_cpu(cck->dsp_self_kill),
-			 accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
-			 max_cck->dsp_self_kill);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "mh_format_err:",
-			 le32_to_cpu(cck->mh_format_err),
-			 accum_cck->mh_format_err, delta_cck->mh_format_err,
-			 max_cck->mh_format_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "re_acq_main_rssi_sum:",
-			 le32_to_cpu(cck->re_acq_main_rssi_sum),
-			 accum_cck->re_acq_main_rssi_sum,
-			 delta_cck->re_acq_main_rssi_sum,
-			 max_cck->re_acq_main_rssi_sum);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - GENERAL:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bogus_cts:",
-			 le32_to_cpu(general->bogus_cts),
-			 accum_general->bogus_cts, delta_general->bogus_cts,
-			 max_general->bogus_cts);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bogus_ack:",
-			 le32_to_cpu(general->bogus_ack),
-			 accum_general->bogus_ack, delta_general->bogus_ack,
-			 max_general->bogus_ack);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "non_bssid_frames:",
-			 le32_to_cpu(general->non_bssid_frames),
-			 accum_general->non_bssid_frames,
-			 delta_general->non_bssid_frames,
-			 max_general->non_bssid_frames);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "filtered_frames:",
-			 le32_to_cpu(general->filtered_frames),
-			 accum_general->filtered_frames,
-			 delta_general->filtered_frames,
-			 max_general->filtered_frames);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "non_channel_beacons:",
-			 le32_to_cpu(general->non_channel_beacons),
-			 accum_general->non_channel_beacons,
-			 delta_general->non_channel_beacons,
-			 max_general->non_channel_beacons);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "channel_beacons:",
-			 le32_to_cpu(general->channel_beacons),
-			 accum_general->channel_beacons,
-			 delta_general->channel_beacons,
-			 max_general->channel_beacons);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "num_missed_bcon:",
-			 le32_to_cpu(general->num_missed_bcon),
-			 accum_general->num_missed_bcon,
-			 delta_general->num_missed_bcon,
-			 max_general->num_missed_bcon);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "adc_rx_saturation_time:",
-			 le32_to_cpu(general->adc_rx_saturation_time),
-			 accum_general->adc_rx_saturation_time,
-			 delta_general->adc_rx_saturation_time,
-			 max_general->adc_rx_saturation_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ina_detect_search_tm:",
-			 le32_to_cpu(general->ina_detection_search_time),
-			 accum_general->ina_detection_search_time,
-			 delta_general->ina_detection_search_time,
-			 max_general->ina_detection_search_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_silence_rssi_a:",
-			 le32_to_cpu(general->beacon_silence_rssi_a),
-			 accum_general->beacon_silence_rssi_a,
-			 delta_general->beacon_silence_rssi_a,
-			 max_general->beacon_silence_rssi_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_silence_rssi_b:",
-			 le32_to_cpu(general->beacon_silence_rssi_b),
-			 accum_general->beacon_silence_rssi_b,
-			 delta_general->beacon_silence_rssi_b,
-			 max_general->beacon_silence_rssi_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_silence_rssi_c:",
-			 le32_to_cpu(general->beacon_silence_rssi_c),
-			 accum_general->beacon_silence_rssi_c,
-			 delta_general->beacon_silence_rssi_c,
-			 max_general->beacon_silence_rssi_c);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "interference_data_flag:",
-			 le32_to_cpu(general->interference_data_flag),
-			 accum_general->interference_data_flag,
-			 delta_general->interference_data_flag,
-			 max_general->interference_data_flag);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "channel_load:",
-			 le32_to_cpu(general->channel_load),
-			 accum_general->channel_load,
-			 delta_general->channel_load,
-			 max_general->channel_load);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dsp_false_alarms:",
-			 le32_to_cpu(general->dsp_false_alarms),
-			 accum_general->dsp_false_alarms,
-			 delta_general->dsp_false_alarms,
-			 max_general->dsp_false_alarms);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_rssi_a:",
-			 le32_to_cpu(general->beacon_rssi_a),
-			 accum_general->beacon_rssi_a,
-			 delta_general->beacon_rssi_a,
-			 max_general->beacon_rssi_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_rssi_b:",
-			 le32_to_cpu(general->beacon_rssi_b),
-			 accum_general->beacon_rssi_b,
-			 delta_general->beacon_rssi_b,
-			 max_general->beacon_rssi_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_rssi_c:",
-			 le32_to_cpu(general->beacon_rssi_c),
-			 accum_general->beacon_rssi_c,
-			 delta_general->beacon_rssi_c,
-			 max_general->beacon_rssi_c);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_energy_a:",
-			 le32_to_cpu(general->beacon_energy_a),
-			 accum_general->beacon_energy_a,
-			 delta_general->beacon_energy_a,
-			 max_general->beacon_energy_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_energy_b:",
-			 le32_to_cpu(general->beacon_energy_b),
-			 accum_general->beacon_energy_b,
-			 delta_general->beacon_energy_b,
-			 max_general->beacon_energy_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "beacon_energy_c:",
-			 le32_to_cpu(general->beacon_energy_c),
-			 accum_general->beacon_energy_c,
-			 delta_general->beacon_energy_c,
-			 max_general->beacon_energy_c);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Rx - OFDM_HT:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "plcp_err:",
-			 le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
-			 delta_ht->plcp_err, max_ht->plcp_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "overrun_err:",
-			 le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
-			 delta_ht->overrun_err, max_ht->overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "early_overrun_err:",
-			 le32_to_cpu(ht->early_overrun_err),
-			 accum_ht->early_overrun_err,
-			 delta_ht->early_overrun_err,
-			 max_ht->early_overrun_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_good:",
-			 le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
-			 delta_ht->crc32_good, max_ht->crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "crc32_err:",
-			 le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
-			 delta_ht->crc32_err, max_ht->crc32_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "mh_format_err:",
-			 le32_to_cpu(ht->mh_format_err),
-			 accum_ht->mh_format_err,
-			 delta_ht->mh_format_err, max_ht->mh_format_err);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg_crc32_good:",
-			 le32_to_cpu(ht->agg_crc32_good),
-			 accum_ht->agg_crc32_good,
-			 delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg_mpdu_cnt:",
-			 le32_to_cpu(ht->agg_mpdu_cnt),
-			 accum_ht->agg_mpdu_cnt,
-			 delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg_cnt:",
-			 le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
-			 delta_ht->agg_cnt, max_ht->agg_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "unsupport_mcs:",
-			 le32_to_cpu(ht->unsupport_mcs),
-			 accum_ht->unsupport_mcs,
-			 delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-ssize_t iwl_ucode_tx_stats_read(struct file *file,
-				char __user *user_buf,
-				size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
-	ssize_t ret;
-	struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf) {
-		IWL_ERR(priv, "Can not allocate Buffer\n");
-		return -ENOMEM;
-	}
-
-	/* the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-	tx = &priv->statistics.tx;
-	accum_tx = &priv->accum_stats.tx;
-	delta_tx = &priv->delta_stats.tx;
-	max_tx = &priv->max_delta_stats.tx;
-
-	pos += iwl_statistics_flag(priv, buf, bufsz);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_Tx:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "preamble:",
-			 le32_to_cpu(tx->preamble_cnt),
-			 accum_tx->preamble_cnt,
-			 delta_tx->preamble_cnt, max_tx->preamble_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rx_detected_cnt:",
-			 le32_to_cpu(tx->rx_detected_cnt),
-			 accum_tx->rx_detected_cnt,
-			 delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bt_prio_defer_cnt:",
-			 le32_to_cpu(tx->bt_prio_defer_cnt),
-			 accum_tx->bt_prio_defer_cnt,
-			 delta_tx->bt_prio_defer_cnt,
-			 max_tx->bt_prio_defer_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "bt_prio_kill_cnt:",
-			 le32_to_cpu(tx->bt_prio_kill_cnt),
-			 accum_tx->bt_prio_kill_cnt,
-			 delta_tx->bt_prio_kill_cnt,
-			 max_tx->bt_prio_kill_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "few_bytes_cnt:",
-			 le32_to_cpu(tx->few_bytes_cnt),
-			 accum_tx->few_bytes_cnt,
-			 delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "cts_timeout:",
-			 le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
-			 delta_tx->cts_timeout, max_tx->cts_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ack_timeout:",
-			 le32_to_cpu(tx->ack_timeout),
-			 accum_tx->ack_timeout,
-			 delta_tx->ack_timeout, max_tx->ack_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "expected_ack_cnt:",
-			 le32_to_cpu(tx->expected_ack_cnt),
-			 accum_tx->expected_ack_cnt,
-			 delta_tx->expected_ack_cnt,
-			 max_tx->expected_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "actual_ack_cnt:",
-			 le32_to_cpu(tx->actual_ack_cnt),
-			 accum_tx->actual_ack_cnt,
-			 delta_tx->actual_ack_cnt,
-			 max_tx->actual_ack_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "dump_msdu_cnt:",
-			 le32_to_cpu(tx->dump_msdu_cnt),
-			 accum_tx->dump_msdu_cnt,
-			 delta_tx->dump_msdu_cnt,
-			 max_tx->dump_msdu_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "abort_nxt_frame_mismatch:",
-			 le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
-			 accum_tx->burst_abort_next_frame_mismatch_cnt,
-			 delta_tx->burst_abort_next_frame_mismatch_cnt,
-			 max_tx->burst_abort_next_frame_mismatch_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "abort_missing_nxt_frame:",
-			 le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
-			 accum_tx->burst_abort_missing_next_frame_cnt,
-			 delta_tx->burst_abort_missing_next_frame_cnt,
-			 max_tx->burst_abort_missing_next_frame_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "cts_timeout_collision:",
-			 le32_to_cpu(tx->cts_timeout_collision),
-			 accum_tx->cts_timeout_collision,
-			 delta_tx->cts_timeout_collision,
-			 max_tx->cts_timeout_collision);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "ack_ba_timeout_collision:",
-			 le32_to_cpu(tx->ack_or_ba_timeout_collision),
-			 accum_tx->ack_or_ba_timeout_collision,
-			 delta_tx->ack_or_ba_timeout_collision,
-			 max_tx->ack_or_ba_timeout_collision);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg ba_timeout:",
-			 le32_to_cpu(tx->agg.ba_timeout),
-			 accum_tx->agg.ba_timeout,
-			 delta_tx->agg.ba_timeout,
-			 max_tx->agg.ba_timeout);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg ba_resched_frames:",
-			 le32_to_cpu(tx->agg.ba_reschedule_frames),
-			 accum_tx->agg.ba_reschedule_frames,
-			 delta_tx->agg.ba_reschedule_frames,
-			 max_tx->agg.ba_reschedule_frames);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_agg_frame:",
-			 le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
-			 accum_tx->agg.scd_query_agg_frame_cnt,
-			 delta_tx->agg.scd_query_agg_frame_cnt,
-			 max_tx->agg.scd_query_agg_frame_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_no_agg:",
-			 le32_to_cpu(tx->agg.scd_query_no_agg),
-			 accum_tx->agg.scd_query_no_agg,
-			 delta_tx->agg.scd_query_no_agg,
-			 max_tx->agg.scd_query_no_agg);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_agg:",
-			 le32_to_cpu(tx->agg.scd_query_agg),
-			 accum_tx->agg.scd_query_agg,
-			 delta_tx->agg.scd_query_agg,
-			 max_tx->agg.scd_query_agg);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg scd_query_mismatch:",
-			 le32_to_cpu(tx->agg.scd_query_mismatch),
-			 accum_tx->agg.scd_query_mismatch,
-			 delta_tx->agg.scd_query_mismatch,
-			 max_tx->agg.scd_query_mismatch);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg frame_not_ready:",
-			 le32_to_cpu(tx->agg.frame_not_ready),
-			 accum_tx->agg.frame_not_ready,
-			 delta_tx->agg.frame_not_ready,
-			 max_tx->agg.frame_not_ready);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg underrun:",
-			 le32_to_cpu(tx->agg.underrun),
-			 accum_tx->agg.underrun,
-			 delta_tx->agg.underrun, max_tx->agg.underrun);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg bt_prio_kill:",
-			 le32_to_cpu(tx->agg.bt_prio_kill),
-			 accum_tx->agg.bt_prio_kill,
-			 delta_tx->agg.bt_prio_kill,
-			 max_tx->agg.bt_prio_kill);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "agg rx_ba_rsp_cnt:",
-			 le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
-			 accum_tx->agg.rx_ba_rsp_cnt,
-			 delta_tx->agg.rx_ba_rsp_cnt,
-			 max_tx->agg.rx_ba_rsp_cnt);
-
-	if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
-		pos += scnprintf(buf + pos, bufsz - pos,
-			"tx power: (1/2 dB step)\n");
-		if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					fmt_hex, "antenna A:",
-					tx->tx_power.ant_a);
-		if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					fmt_hex, "antenna B:",
-					tx->tx_power.ant_b);
-		if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
-			pos += scnprintf(buf + pos, bufsz - pos,
-					fmt_hex, "antenna C:",
-					tx->tx_power.ant_c);
-	}
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
-				     size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = sizeof(struct statistics_general) * 10 + 300;
-	ssize_t ret;
-	struct statistics_general_common *general, *accum_general;
-	struct statistics_general_common *delta_general, *max_general;
-	struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
-	struct statistics_div *div, *accum_div, *delta_div, *max_div;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf) {
-		IWL_ERR(priv, "Can not allocate Buffer\n");
-		return -ENOMEM;
-	}
-
-	/* the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-	general = &priv->statistics.common;
-	dbg = &priv->statistics.common.dbg;
-	div = &priv->statistics.common.div;
-	accum_general = &priv->accum_stats.common;
-	accum_dbg = &priv->accum_stats.common.dbg;
-	accum_div = &priv->accum_stats.common.div;
-	delta_general = &priv->delta_stats.common;
-	max_general = &priv->max_delta_stats.common;
-	delta_dbg = &priv->delta_stats.common.dbg;
-	max_dbg = &priv->max_delta_stats.common.dbg;
-	delta_div = &priv->delta_stats.common.div;
-	max_div = &priv->max_delta_stats.common.div;
-
-	pos += iwl_statistics_flag(priv, buf, bufsz);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_header, "Statistics_General:");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_value, "temperature:",
-			 le32_to_cpu(general->temperature));
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_value, "temperature_m:",
-			 le32_to_cpu(general->temperature_m));
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_value, "ttl_timestamp:",
-			 le32_to_cpu(general->ttl_timestamp));
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "burst_check:",
-			 le32_to_cpu(dbg->burst_check),
-			 accum_dbg->burst_check,
-			 delta_dbg->burst_check, max_dbg->burst_check);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "burst_count:",
-			 le32_to_cpu(dbg->burst_count),
-			 accum_dbg->burst_count,
-			 delta_dbg->burst_count, max_dbg->burst_count);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "wait_for_silence_timeout_count:",
-			 le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
-			 accum_dbg->wait_for_silence_timeout_cnt,
-			 delta_dbg->wait_for_silence_timeout_cnt,
-			 max_dbg->wait_for_silence_timeout_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "sleep_time:",
-			 le32_to_cpu(general->sleep_time),
-			 accum_general->sleep_time,
-			 delta_general->sleep_time, max_general->sleep_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "slots_out:",
-			 le32_to_cpu(general->slots_out),
-			 accum_general->slots_out,
-			 delta_general->slots_out, max_general->slots_out);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "slots_idle:",
-			 le32_to_cpu(general->slots_idle),
-			 accum_general->slots_idle,
-			 delta_general->slots_idle, max_general->slots_idle);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "tx_on_a:",
-			 le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
-			 delta_div->tx_on_a, max_div->tx_on_a);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "tx_on_b:",
-			 le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
-			 delta_div->tx_on_b, max_div->tx_on_b);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "exec_time:",
-			 le32_to_cpu(div->exec_time), accum_div->exec_time,
-			 delta_div->exec_time, max_div->exec_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "probe_time:",
-			 le32_to_cpu(div->probe_time), accum_div->probe_time,
-			 delta_div->probe_time, max_div->probe_time);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "rx_enable_counter:",
-			 le32_to_cpu(general->rx_enable_counter),
-			 accum_general->rx_enable_counter,
-			 delta_general->rx_enable_counter,
-			 max_general->rx_enable_counter);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 fmt_table, "num_of_sos_states:",
-			 le32_to_cpu(general->num_of_sos_states),
-			 accum_general->num_of_sos_states,
-			 delta_general->num_of_sos_states,
-			 max_general->num_of_sos_states);
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-ssize_t iwl_ucode_bt_stats_read(struct file *file,
-				char __user *user_buf,
-				size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200;
-	ssize_t ret;
-	struct statistics_bt_activity *bt, *accum_bt;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	if (!priv->bt_enable_flag)
-		return -EINVAL;
-
-	/* make request to uCode to retrieve statistics information */
-	mutex_lock(&priv->mutex);
-	ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
-	mutex_unlock(&priv->mutex);
-
-	if (ret) {
-		IWL_ERR(priv,
-			"Error sending statistics request: %zd\n", ret);
-		return -EAGAIN;
-	}
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf) {
-		IWL_ERR(priv, "Can not allocate Buffer\n");
-		return -ENOMEM;
-	}
-
-	/*
-	 * the statistic information display here is based on
-	 * the last statistics notification from uCode
-	 * might not reflect the current uCode activity
-	 */
-	bt = &priv->statistics.bt_activity;
-	accum_bt = &priv->accum_stats.bt_activity;
-
-	pos += iwl_statistics_flag(priv, buf, bufsz);
-	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			"\t\t\tcurrent\t\t\taccumulative\n");
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->hi_priority_tx_req_cnt),
-			 accum_bt->hi_priority_tx_req_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->hi_priority_tx_denied_cnt),
-			 accum_bt->hi_priority_tx_denied_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->lo_priority_tx_req_cnt),
-			 accum_bt->lo_priority_tx_req_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->lo_priority_tx_denied_cnt),
-			 accum_bt->lo_priority_tx_denied_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->hi_priority_rx_req_cnt),
-			 accum_bt->hi_priority_rx_req_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->hi_priority_rx_denied_cnt),
-			 accum_bt->hi_priority_rx_denied_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->lo_priority_rx_req_cnt),
-			 accum_bt->lo_priority_rx_req_cnt);
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
-			 le32_to_cpu(bt->lo_priority_rx_denied_cnt),
-			 accum_bt->lo_priority_rx_denied_cnt);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
-			 le32_to_cpu(priv->statistics.num_bt_kills),
-			 priv->statistics.accum_num_bt_kills);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
-
-ssize_t iwl_reply_tx_error_read(struct file *file,
-				char __user *user_buf,
-				size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-	int pos = 0;
-	char *buf;
-	int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) +
-		(sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
-	ssize_t ret;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	buf = kzalloc(bufsz, GFP_KERNEL);
-	if (!buf) {
-		IWL_ERR(priv, "Can not allocate Buffer\n");
-		return -ENOMEM;
-	}
-
-	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
-			 priv->_agn.reply_tx_stats.pp_delay);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
-			 priv->_agn.reply_tx_stats.pp_few_bytes);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
-			 priv->_agn.reply_tx_stats.pp_bt_prio);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
-			 priv->_agn.reply_tx_stats.pp_quiet_period);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
-			 priv->_agn.reply_tx_stats.pp_calc_ttak);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_tx_fail_reason(
-				TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
-			 priv->_agn.reply_tx_stats.int_crossed_retry);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
-			 priv->_agn.reply_tx_stats.short_limit);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
-			 priv->_agn.reply_tx_stats.long_limit);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
-			 priv->_agn.reply_tx_stats.fifo_underrun);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
-			 priv->_agn.reply_tx_stats.drain_flow);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
-			 priv->_agn.reply_tx_stats.rfkill_flush);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
-			 priv->_agn.reply_tx_stats.life_expire);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
-			 priv->_agn.reply_tx_stats.dest_ps);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
-			 priv->_agn.reply_tx_stats.host_abort);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
-			 priv->_agn.reply_tx_stats.pp_delay);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
-			 priv->_agn.reply_tx_stats.sta_invalid);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
-			 priv->_agn.reply_tx_stats.frag_drop);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
-			 priv->_agn.reply_tx_stats.tid_disable);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
-			 priv->_agn.reply_tx_stats.fifo_flush);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_tx_fail_reason(
-				TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
-			 priv->_agn.reply_tx_stats.insuff_cf_poll);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
-			 priv->_agn.reply_tx_stats.fail_hw_drop);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_tx_fail_reason(
-				TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
-			 priv->_agn.reply_tx_stats.sta_color_mismatch);
-	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
-			 priv->_agn.reply_tx_stats.unknown);
-
-	pos += scnprintf(buf + pos, bufsz - pos,
-			 "\nStatistics_Agg_TX_Error:\n");
-
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
-			 priv->_agn.reply_agg_tx_stats.underrun);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
-			 priv->_agn.reply_agg_tx_stats.bt_prio);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
-			 priv->_agn.reply_agg_tx_stats.few_bytes);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
-			 priv->_agn.reply_agg_tx_stats.abort);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_LAST_SENT_TTL_MSK),
-			 priv->_agn.reply_agg_tx_stats.last_sent_ttl);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
-			 priv->_agn.reply_agg_tx_stats.last_sent_try);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
-			 priv->_agn.reply_agg_tx_stats.last_sent_bt_kill);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
-			 priv->_agn.reply_agg_tx_stats.scd_query);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(
-				AGG_TX_STATE_TEST_BAD_CRC32_MSK),
-			 priv->_agn.reply_agg_tx_stats.bad_crc32);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
-			 priv->_agn.reply_agg_tx_stats.response);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
-			 priv->_agn.reply_agg_tx_stats.dump_tx);
-	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
-			 priv->_agn.reply_agg_tx_stats.delay_tx);
-	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
-			 priv->_agn.reply_agg_tx_stats.unknown);
-
-	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-	kfree(buf);
-	return ret;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
deleted file mode 100644
index 9a3f329e508f3e7f808c019159060d86e8ecd60b..0000000000000000000000000000000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-debug.h"
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
-				size_t count, loff_t *ppos);
-ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf,
-				size_t count, loff_t *ppos);
-ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
-				     size_t count, loff_t *ppos);
-ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
-				size_t count, loff_t *ppos);
-ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf,
-				size_t count, loff_t *ppos);
-#else
-static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
-				       size_t count, loff_t *ppos)
-{
-	return 0;
-}
-static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf,
-				       size_t count, loff_t *ppos)
-{
-	return 0;
-}
-static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
-					    size_t count, loff_t *ppos)
-{
-	return 0;
-}
-static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
-				       size_t count, loff_t *ppos)
-{
-	return 0;
-}
-static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf,
-				       size_t count, loff_t *ppos)
-{
-	return 0;
-}
-#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
index 3bcaa10f99299bba96a6ad4220d151e3e07e1c9f..2ef9448b1c201ac3063326d9777de22eb02faece 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
@@ -81,52 +81,13 @@
  *
 ******************************************************************************/
 
-/*
- * The device's EEPROM semaphore prevents conflicts between driver and uCode
- * when accessing the EEPROM; each access is a series of pulses to/from the
- * EEPROM chip, not a single event, so even reads could conflict if they
- * weren't arbitrated by the semaphore.
- */
-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv)
-{
-	u16 count;
-	int ret;
-
-	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
-		/* Request semaphore */
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-			    CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-		/* See if we got it */
-		ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
-				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
-				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
-				EEPROM_SEM_TIMEOUT);
-		if (ret >= 0) {
-			IWL_DEBUG_EEPROM(priv,
-				"Acquired semaphore after %d tries.\n",
-				count+1);
-			return ret;
-		}
-	}
-
-	return ret;
-}
-
-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv)
-{
-	iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
-		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-}
-
 int iwl_eeprom_check_version(struct iwl_priv *priv)
 {
 	u16 eeprom_ver;
 	u16 calib_ver;
 
 	eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-	calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv);
+	calib_ver = iwlagn_eeprom_calib_version(priv);
 
 	if (eeprom_ver < priv->cfg->eeprom_ver ||
 	    calib_ver < priv->cfg->eeprom_calib_ver)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 861cc93957a9b2cd78aa6ffd99aaa29e6f27d139..49dd03f9fedacf785277b36a0a9f2694164b5e44 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -37,54 +37,6 @@
 #include "iwl-io.h"
 #include "iwl-agn.h"
 
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
-			   struct iwl_rxon_context *ctx)
-{
-	int ret = 0;
-	struct iwl5000_rxon_assoc_cmd rxon_assoc;
-	const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
-	const struct iwl_rxon_cmd *rxon2 = &ctx->active;
-
-	if ((rxon1->flags == rxon2->flags) &&
-	    (rxon1->filter_flags == rxon2->filter_flags) &&
-	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
-	    (rxon1->ofdm_ht_single_stream_basic_rates ==
-	     rxon2->ofdm_ht_single_stream_basic_rates) &&
-	    (rxon1->ofdm_ht_dual_stream_basic_rates ==
-	     rxon2->ofdm_ht_dual_stream_basic_rates) &&
-	    (rxon1->ofdm_ht_triple_stream_basic_rates ==
-	     rxon2->ofdm_ht_triple_stream_basic_rates) &&
-	    (rxon1->acquisition_data == rxon2->acquisition_data) &&
-	    (rxon1->rx_chain == rxon2->rx_chain) &&
-	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
-		IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
-		return 0;
-	}
-
-	rxon_assoc.flags = ctx->staging.flags;
-	rxon_assoc.filter_flags = ctx->staging.filter_flags;
-	rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
-	rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
-	rxon_assoc.reserved1 = 0;
-	rxon_assoc.reserved2 = 0;
-	rxon_assoc.reserved3 = 0;
-	rxon_assoc.ofdm_ht_single_stream_basic_rates =
-	    ctx->staging.ofdm_ht_single_stream_basic_rates;
-	rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-	    ctx->staging.ofdm_ht_dual_stream_basic_rates;
-	rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
-	rxon_assoc.ofdm_ht_triple_stream_basic_rates =
-		 ctx->staging.ofdm_ht_triple_stream_basic_rates;
-	rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
-
-	ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
-				     sizeof(rxon_assoc), &rxon_assoc, NULL);
-	if (ret)
-		return ret;
-
-	return ret;
-}
-
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
 {
 	struct iwl_tx_ant_config_cmd tx_ant_cmd = {
@@ -364,7 +316,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
 }
 
 struct iwl_hcmd_ops iwlagn_hcmd = {
-	.rxon_assoc = iwlagn_send_rxon_assoc,
 	.commit_rxon = iwlagn_commit_rxon,
 	.set_rxon_chain = iwlagn_set_rxon_chain,
 	.set_tx_ant = iwlagn_send_tx_ant_config,
@@ -373,7 +324,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = {
 };
 
 struct iwl_hcmd_ops iwlagn_bt_hcmd = {
-	.rxon_assoc = iwlagn_send_rxon_assoc,
 	.commit_rxon = iwlagn_commit_rxon,
 	.set_rxon_chain = iwlagn_set_rxon_chain,
 	.set_tx_ant = iwlagn_send_tx_ant_config,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index e741128842bb25fb629ab416ed3ab5d58b26b7b2..8e79653aed9aa799eb169713d2cde2843e920ec7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -483,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
 	/* init calibration handlers */
 	priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
 					iwlagn_rx_calib_result;
-	priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
-					iwlagn_rx_calib_complete;
 	priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
 
 	/* set up notification wait support */
@@ -667,7 +665,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 
 	rb_timeout = RX_RB_TIMEOUT;
 
-	if (priv->cfg->mod_params->amsdu_size_8K)
+	if (iwlagn_mod_params.amsdu_size_8K)
 		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
 	else
 		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
@@ -1296,9 +1294,17 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 	 * mean we never reach it, but at the same time work around
 	 * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
 	 * here instead of IWL_GOOD_CRC_TH_DISABLED.
+	 *
+	 * This was fixed in later versions along with some other
+	 * scan changes, and the threshold behaves as a flag in those
+	 * versions.
 	 */
-	scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-					IWL_GOOD_CRC_TH_NEVER;
+	if (priv->new_scan_threshold_behaviour)
+		scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+						IWL_GOOD_CRC_TH_DISABLED;
+	else
+		scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+						IWL_GOOD_CRC_TH_NEVER;
 
 	band = priv->scan_band;
 
@@ -2256,34 +2262,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
 /* notification wait support */
 void iwlagn_init_notification_wait(struct iwl_priv *priv,
 				   struct iwl_notification_wait *wait_entry,
+				   u8 cmd,
 				   void (*fn)(struct iwl_priv *priv,
-					      struct iwl_rx_packet *pkt),
-				   u8 cmd)
+					      struct iwl_rx_packet *pkt,
+					      void *data),
+				   void *fn_data)
 {
 	wait_entry->fn = fn;
+	wait_entry->fn_data = fn_data;
 	wait_entry->cmd = cmd;
 	wait_entry->triggered = false;
+	wait_entry->aborted = false;
 
 	spin_lock_bh(&priv->_agn.notif_wait_lock);
 	list_add(&wait_entry->list, &priv->_agn.notif_waits);
 	spin_unlock_bh(&priv->_agn.notif_wait_lock);
 }
 
-signed long iwlagn_wait_notification(struct iwl_priv *priv,
-				     struct iwl_notification_wait *wait_entry,
-				     unsigned long timeout)
+int iwlagn_wait_notification(struct iwl_priv *priv,
+			     struct iwl_notification_wait *wait_entry,
+			     unsigned long timeout)
 {
 	int ret;
 
 	ret = wait_event_timeout(priv->_agn.notif_waitq,
-				 wait_entry->triggered,
+				 wait_entry->triggered || wait_entry->aborted,
 				 timeout);
 
 	spin_lock_bh(&priv->_agn.notif_wait_lock);
 	list_del(&wait_entry->list);
 	spin_unlock_bh(&priv->_agn.notif_wait_lock);
 
-	return ret;
+	if (wait_entry->aborted)
+		return -EIO;
+
+	/* return value is always >= 0 */
+	if (ret <= 0)
+		return -ETIMEDOUT;
+	return 0;
 }
 
 void iwlagn_remove_notification(struct iwl_priv *priv,
@@ -2293,3 +2309,87 @@ void iwlagn_remove_notification(struct iwl_priv *priv,
 	list_del(&wait_entry->list);
 	spin_unlock_bh(&priv->_agn.notif_wait_lock);
 }
+
+int iwlagn_start_device(struct iwl_priv *priv)
+{
+	int ret;
+
+	if (iwl_prepare_card_hw(priv)) {
+		IWL_WARN(priv, "Exit HW not ready\n");
+		return -EIO;
+	}
+
+	/* If platform's RF_KILL switch is NOT set to KILL */
+	if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+	else
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+
+	if (iwl_is_rfkill(priv)) {
+		wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
+		iwl_enable_interrupts(priv);
+		return -ERFKILL;
+	}
+
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	ret = iwlagn_hw_nic_init(priv);
+	if (ret) {
+		IWL_ERR(priv, "Unable to init nic\n");
+		return ret;
+	}
+
+	/* make sure rfkill handshake bits are cleared */
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+	/* clear (again), then enable host interrupts */
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl_enable_interrupts(priv);
+
+	/* really make sure rfkill handshake bits are cleared */
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	return 0;
+}
+
+void iwlagn_stop_device(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	/* stop and reset the on-board processor */
+	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+	/* tell the device to stop sending interrupts */
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_disable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	iwl_synchronize_irq(priv);
+
+	/* device going down, Stop using ICT table */
+	iwl_disable_ict(priv);
+
+	/*
+	 * If a HW restart happens during firmware loading,
+	 * then the firmware loading might call this function
+	 * and later it might be called again due to the
+	 * restart. So don't process again if the device is
+	 * already dead.
+	 */
+	if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) {
+                iwlagn_txq_ctx_stop(priv);
+                iwlagn_rxq_stop(priv);
+
+                /* Power-down device's busmaster DMA clocks */
+                iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+                udelay(5);
+        }
+
+	/* Make sure (redundant) we've released our request to stay awake */
+	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	/* Stop the device, and put it in low power state */
+	iwl_apm_stop(priv);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 90e12c17801ea4a3bec03a9c263f89a28bf59fa8..02387430f7fe0dddae5006aa80e59301c19ecaec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -58,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
 	u8 old_dev_type = send->dev_type;
 	int ret;
 
-	iwlagn_init_notification_wait(priv, &disable_wait, NULL,
-				      REPLY_WIPAN_DEACTIVATION_COMPLETE);
+	iwlagn_init_notification_wait(priv, &disable_wait,
+				      REPLY_WIPAN_DEACTIVATION_COMPLETE,
+				      NULL, NULL);
 
 	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	send->dev_type = RXON_DEV_TYPE_P2P;
@@ -72,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
 		IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
 		iwlagn_remove_notification(priv, &disable_wait);
 	} else {
-		signed long wait_res;
-
-		wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ);
-		if (wait_res == 0) {
+		ret = iwlagn_wait_notification(priv, &disable_wait, HZ);
+		if (ret)
 			IWL_ERR(priv, "Timed out waiting for PAN disable\n");
-			ret = -EIO;
-		}
 	}
 
 	return ret;
@@ -124,6 +121,151 @@ static int iwlagn_update_beacon(struct iwl_priv *priv,
 	return iwlagn_send_beacon_cmd(priv);
 }
 
+static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+			   struct iwl_rxon_context *ctx)
+{
+	int ret = 0;
+	struct iwl_rxon_assoc_cmd rxon_assoc;
+	const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+	const struct iwl_rxon_cmd *rxon2 = &ctx->active;
+
+	if ((rxon1->flags == rxon2->flags) &&
+	    (rxon1->filter_flags == rxon2->filter_flags) &&
+	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+	    (rxon1->ofdm_ht_single_stream_basic_rates ==
+	     rxon2->ofdm_ht_single_stream_basic_rates) &&
+	    (rxon1->ofdm_ht_dual_stream_basic_rates ==
+	     rxon2->ofdm_ht_dual_stream_basic_rates) &&
+	    (rxon1->ofdm_ht_triple_stream_basic_rates ==
+	     rxon2->ofdm_ht_triple_stream_basic_rates) &&
+	    (rxon1->acquisition_data == rxon2->acquisition_data) &&
+	    (rxon1->rx_chain == rxon2->rx_chain) &&
+	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+		IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
+		return 0;
+	}
+
+	rxon_assoc.flags = ctx->staging.flags;
+	rxon_assoc.filter_flags = ctx->staging.filter_flags;
+	rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+	rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
+	rxon_assoc.reserved1 = 0;
+	rxon_assoc.reserved2 = 0;
+	rxon_assoc.reserved3 = 0;
+	rxon_assoc.ofdm_ht_single_stream_basic_rates =
+	    ctx->staging.ofdm_ht_single_stream_basic_rates;
+	rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+	    ctx->staging.ofdm_ht_dual_stream_basic_rates;
+	rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
+	rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+		 ctx->staging.ofdm_ht_triple_stream_basic_rates;
+	rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
+
+	ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
+				     sizeof(rxon_assoc), &rxon_assoc, NULL);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int iwlagn_rxon_disconn(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx)
+{
+	int ret;
+	struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+	if (ctx->ctxid == IWL_RXON_CTX_BSS)
+		ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
+	else
+		ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+	if (ret)
+		return ret;
+
+	/*
+	 * Un-assoc RXON clears the station table and WEP
+	 * keys, so we have to restore those afterwards.
+	 */
+	iwl_clear_ucode_stations(priv, ctx);
+	iwl_restore_stations(priv, ctx);
+	ret = iwl_restore_default_wep_keys(priv, ctx);
+	if (ret) {
+		IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+		return ret;
+	}
+
+	memcpy(active, &ctx->staging, sizeof(*active));
+	return 0;
+}
+
+static int iwlagn_rxon_connect(struct iwl_priv *priv,
+			       struct iwl_rxon_context *ctx)
+{
+	int ret;
+	struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+	/* RXON timing must be before associated RXON */
+	ret = iwl_send_rxon_timing(priv, ctx);
+	if (ret) {
+		IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+		return ret;
+	}
+	/* QoS info may be cleared by previous un-assoc RXON */
+	iwlagn_update_qos(priv, ctx);
+
+	/*
+	 * We'll run into this code path when beaconing is
+	 * enabled, but then we also need to send the beacon
+	 * to the device.
+	 */
+	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
+		ret = iwlagn_update_beacon(priv, ctx->vif);
+		if (ret) {
+			IWL_ERR(priv,
+				"Error sending required beacon (%d)!\n",
+				ret);
+			return ret;
+		}
+	}
+
+	priv->start_calib = 0;
+	/*
+	 * Apply the new configuration.
+	 *
+	 * Associated RXON doesn't clear the station table in uCode,
+	 * so we don't need to restore stations etc. after this.
+	 */
+	ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+		      sizeof(struct iwl_rxon_cmd), &ctx->staging);
+	if (ret) {
+		IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
+		return ret;
+	}
+	memcpy(active, &ctx->staging, sizeof(*active));
+
+	iwl_reprogram_ap_sta(priv, ctx);
+
+	/* IBSS beacon needs to be sent after setting assoc */
+	if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
+		if (iwlagn_update_beacon(priv, ctx->vif))
+			IWL_ERR(priv, "Error sending IBSS beacon\n");
+	iwl_init_sensitivity(priv);
+
+	/*
+	 * If we issue a new RXON command which required a tune then
+	 * we must send a new TXPOWER command or we won't be able to
+	 * Tx any frames.
+	 *
+	 * It's expected we set power here if channel is changing.
+	 */
+	ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
+	if (ret) {
+		IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
 /**
  * iwlagn_commit_rxon - commit staging_rxon to hardware
  *
@@ -131,6 +273,16 @@ static int iwlagn_update_beacon(struct iwl_priv *priv,
  * the active_rxon structure is updated with the new data.  This
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
+ *
+ * The connect/disconnect flow should be as the following:
+ *
+ * 1. make sure send RXON command with association bit unset if not connect
+ *	this should include the channel and the band for the candidate
+ *	to be connected to
+ * 2. Add Station before RXON association with the AP
+ * 3. RXON_timing has to send before RXON for connection
+ * 4. full RXON command - associated bit set
+ * 5. use RXON_ASSOC command to update any flags changes
  */
 int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
@@ -180,6 +332,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 	else
 		ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
+	iwl_print_rx_config_cmd(priv, ctx);
 	ret = iwl_check_rxon_cmd(priv, ctx);
 	if (ret) {
 		IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
@@ -203,14 +356,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 	 * and other flags for the current radio configuration.
 	 */
 	if (!iwl_full_rxon_required(priv, ctx)) {
-		ret = iwl_send_rxon_assoc(priv, ctx);
+		ret = iwlagn_send_rxon_assoc(priv, ctx);
 		if (ret) {
 			IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
 			return ret;
 		}
 
 		memcpy(active, &ctx->staging, sizeof(*active));
-		iwl_print_rx_config_cmd(priv, ctx);
 		return 0;
 	}
 
@@ -220,7 +372,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 			return ret;
 	}
 
-	iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
+	iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto);
 
 	IWL_DEBUG_INFO(priv,
 		       "Going to commit RXON\n"
@@ -238,92 +390,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 	 * set up filters in the device.
 	 */
 	if ((old_assoc && new_assoc) || !new_assoc) {
-		if (ctx->ctxid == IWL_RXON_CTX_BSS)
-			ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
-		else
-			ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+		ret = iwlagn_rxon_disconn(priv, ctx);
 		if (ret)
 			return ret;
-
-		memcpy(active, &ctx->staging, sizeof(*active));
-
-		/*
-		 * Un-assoc RXON clears the station table and WEP
-		 * keys, so we have to restore those afterwards.
-		 */
-		iwl_clear_ucode_stations(priv, ctx);
-		iwl_restore_stations(priv, ctx);
-		ret = iwl_restore_default_wep_keys(priv, ctx);
-		if (ret) {
-			IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
-			return ret;
-		}
-	}
-
-	/* RXON timing must be before associated RXON */
-	ret = iwl_send_rxon_timing(priv, ctx);
-	if (ret) {
-		IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
-		return ret;
-	}
-
-	if (new_assoc) {
-		/* QoS info may be cleared by previous un-assoc RXON */
-		iwlagn_update_qos(priv, ctx);
-
-		/*
-		 * We'll run into this code path when beaconing is
-		 * enabled, but then we also need to send the beacon
-		 * to the device.
-		 */
-		if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
-			ret = iwlagn_update_beacon(priv, ctx->vif);
-			if (ret) {
-				IWL_ERR(priv,
-					"Error sending required beacon (%d)!\n",
-					ret);
-				return ret;
-			}
-		}
-
-		priv->start_calib = 0;
-		/*
-		 * Apply the new configuration.
-		 *
-		 * Associated RXON doesn't clear the station table in uCode,
-		 * so we don't need to restore stations etc. after this.
-		 */
-		ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
-			      sizeof(struct iwl_rxon_cmd), &ctx->staging);
-		if (ret) {
-			IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
-			return ret;
-		}
-		memcpy(active, &ctx->staging, sizeof(*active));
-
-		iwl_reprogram_ap_sta(priv, ctx);
-
-		/* IBSS beacon needs to be sent after setting assoc */
-		if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
-			if (iwlagn_update_beacon(priv, ctx->vif))
-				IWL_ERR(priv, "Error sending IBSS beacon\n");
 	}
 
-	iwl_print_rx_config_cmd(priv, ctx);
-
-	iwl_init_sensitivity(priv);
-
-	/*
-	 * If we issue a new RXON command which required a tune then we must
-	 * send a new TXPOWER command or we won't be able to Tx any frames.
-	 *
-	 * It's expected we set power here if channel is changing.
-	 */
-	ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
-	if (ret) {
-		IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
-		return ret;
-	}
+	if (new_assoc)
+		return iwlagn_rxon_connect(priv, ctx);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 5c30f6b19a7f00b7fd5e803b654088f0feb1ffe8..c3ae2e44fcc93626885dc651d46e281ad0ea8e71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
 }
 
 static int iwlagn_load_given_ucode(struct iwl_priv *priv,
-		struct fw_desc *inst_image,
-		struct fw_desc *data_image)
+				   struct fw_img *image)
 {
 	int ret = 0;
 
-	ret = iwlagn_load_section(priv, "INST", inst_image,
+	ret = iwlagn_load_section(priv, "INST", &image->code,
 				   IWLAGN_RTC_INST_LOWER_BOUND);
 	if (ret)
 		return ret;
 
-	return iwlagn_load_section(priv, "DATA", data_image,
+	return iwlagn_load_section(priv, "DATA", &image->data,
 				    IWLAGN_RTC_DATA_LOWER_BOUND);
 }
 
-int iwlagn_load_ucode(struct iwl_priv *priv)
-{
-	int ret = 0;
-
-	/* check whether init ucode should be loaded, or rather runtime ucode */
-	if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
-		IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
-		ret = iwlagn_load_given_ucode(priv,
-			&priv->ucode_init, &priv->ucode_init_data);
-		if (!ret) {
-			IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
-			priv->ucode_type = UCODE_INIT;
-		}
-	} else {
-		IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
-			"Loading runtime ucode...\n");
-		ret = iwlagn_load_given_ucode(priv,
-			&priv->ucode_code, &priv->ucode_data);
-		if (!ret) {
-			IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
-			priv->ucode_type = UCODE_RT;
-		}
-	}
-
-	return ret;
-}
-
 /*
  *  Calibration
  */
@@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv,
 	iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
 }
 
-void iwlagn_rx_calib_complete(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_init_alive_start(struct iwl_priv *priv)
 {
-	IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n");
-	queue_work(priv->workqueue, &priv->restart);
-}
-
-void iwlagn_init_alive_start(struct iwl_priv *priv)
-{
-	int ret = 0;
-
-	/* initialize uCode was loaded... verify inst image.
-	 * This is a paranoid check, because we would not have gotten the
-	 * "initialize" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv, &priv->ucode_init)) {
-		/* Runtime instruction load was bad;
-		 * take it all the way back down so we can try again */
-		IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
-		goto restart;
-	}
-
-	ret = iwlagn_alive_notify(priv);
-	if (ret) {
-		IWL_WARN(priv,
-			"Could not complete ALIVE transition: %d\n", ret);
-		goto restart;
-	}
+	int ret;
 
 	if (priv->cfg->bt_params &&
 	    priv->cfg->bt_params->advanced_bt_coexist) {
@@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv)
 		 * no need to close the envlope since we are going
 		 * to load the runtime uCode later.
 		 */
-		iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+		ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
 			BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+		if (ret)
+			return ret;
 
 	}
-	iwlagn_send_calib_cfg(priv);
+
+	ret = iwlagn_send_calib_cfg(priv);
+	if (ret)
+		return ret;
 
 	/**
 	 * temperature offset calibration is only needed for runtime ucode,
 	 * so prepare the value now.
 	 */
 	if (priv->cfg->need_temp_offset_calib)
-		iwlagn_set_temperature_offset_calib(priv);
-
-	return;
+		return iwlagn_set_temperature_offset_calib(priv);
 
-restart:
-	/* real restart (first load init_ucode) */
-	queue_work(priv->workqueue, &priv->restart);
+	return 0;
 }
 
 static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
@@ -413,19 +362,22 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv)
 		IWL_ERR(priv, "failed to send BT prio tbl command\n");
 }
 
-void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
+int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
 {
 	struct iwl_bt_coex_prot_env_cmd env_cmd;
+	int ret;
 
 	env_cmd.action = action;
 	env_cmd.type = type;
-	if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
-			     sizeof(env_cmd), &env_cmd))
+	ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
+			       sizeof(env_cmd), &env_cmd);
+	if (ret)
 		IWL_ERR(priv, "failed to send BT env command\n");
+	return ret;
 }
 
 
-int iwlagn_alive_notify(struct iwl_priv *priv)
+static int iwlagn_alive_notify(struct iwl_priv *priv)
 {
 	const struct queue_to_fifo_ac *queue_to_fifo;
 	struct iwl_rxon_context *ctx;
@@ -604,15 +556,164 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
  * iwl_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc)
+static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
 {
-	if (!iwlcore_verify_inst_sparse(priv, fw_desc)) {
+	if (!iwlcore_verify_inst_sparse(priv, &img->code)) {
 		IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n");
 		return 0;
 	}
 
 	IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
 
-	iwl_print_mismatch_inst(priv, fw_desc);
+	iwl_print_mismatch_inst(priv, &img->code);
 	return -EIO;
 }
+
+struct iwlagn_alive_data {
+	bool valid;
+	u8 subtype;
+};
+
+static void iwlagn_alive_fn(struct iwl_priv *priv,
+			    struct iwl_rx_packet *pkt,
+			    void *data)
+{
+	struct iwlagn_alive_data *alive_data = data;
+	struct iwl_alive_resp *palive;
+
+	palive = &pkt->u.alive_frame;
+
+	IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision "
+		       "0x%01X 0x%01X\n",
+		       palive->is_valid, palive->ver_type,
+		       palive->ver_subtype);
+
+	priv->device_pointers.error_event_table =
+		le32_to_cpu(palive->error_event_table_ptr);
+	priv->device_pointers.log_event_table =
+		le32_to_cpu(palive->log_event_table_ptr);
+
+	alive_data->subtype = palive->ver_subtype;
+	alive_data->valid = palive->is_valid == UCODE_VALID_OK;
+}
+
+#define UCODE_ALIVE_TIMEOUT	HZ
+#define UCODE_CALIB_TIMEOUT	(2*HZ)
+
+int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
+				 struct fw_img *image,
+				 int subtype, int alternate_subtype)
+{
+	struct iwl_notification_wait alive_wait;
+	struct iwlagn_alive_data alive_data;
+	int ret;
+	enum iwlagn_ucode_subtype old_type;
+
+	ret = iwlagn_start_device(priv);
+	if (ret)
+		return ret;
+
+	iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE,
+				      iwlagn_alive_fn, &alive_data);
+
+	old_type = priv->ucode_type;
+	priv->ucode_type = subtype;
+
+	ret = iwlagn_load_given_ucode(priv, image);
+	if (ret) {
+		priv->ucode_type = old_type;
+		iwlagn_remove_notification(priv, &alive_wait);
+		return ret;
+	}
+
+	/* Remove all resets to allow NIC to operate */
+	iwl_write32(priv, CSR_RESET, 0);
+
+	/*
+	 * Some things may run in the background now, but we
+	 * just wait for the ALIVE notification here.
+	 */
+	ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT);
+	if (ret) {
+		priv->ucode_type = old_type;
+		return ret;
+	}
+
+	if (!alive_data.valid) {
+		IWL_ERR(priv, "Loaded ucode is not valid!\n");
+		priv->ucode_type = old_type;
+		return -EIO;
+	}
+
+	if (alive_data.subtype != subtype &&
+	    alive_data.subtype != alternate_subtype) {
+		IWL_ERR(priv,
+			"Loaded ucode is not expected type (got %d, expected %d)!\n",
+			alive_data.subtype, subtype);
+		priv->ucode_type = old_type;
+		return -EIO;
+	}
+
+	ret = iwl_verify_ucode(priv, image);
+	if (ret) {
+		priv->ucode_type = old_type;
+		return ret;
+	}
+
+	/* delay a bit to give rfkill time to run */
+	msleep(5);
+
+	ret = iwlagn_alive_notify(priv);
+	if (ret) {
+		IWL_WARN(priv,
+			"Could not complete ALIVE transition: %d\n", ret);
+		priv->ucode_type = old_type;
+		return ret;
+	}
+
+	return 0;
+}
+
+int iwlagn_run_init_ucode(struct iwl_priv *priv)
+{
+	struct iwl_notification_wait calib_wait;
+	int ret;
+
+	lockdep_assert_held(&priv->mutex);
+
+	/* No init ucode required? Curious, but maybe ok */
+	if (!priv->ucode_init.code.len)
+		return 0;
+
+	if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED)
+		return 0;
+
+	iwlagn_init_notification_wait(priv, &calib_wait,
+				      CALIBRATION_COMPLETE_NOTIFICATION,
+				      NULL, NULL);
+
+	/* Will also start the device */
+	ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
+					   UCODE_SUBTYPE_INIT, -1);
+	if (ret)
+		goto error;
+
+	ret = iwlagn_init_alive_start(priv);
+	if (ret)
+		goto error;
+
+	/*
+	 * Some things may run in the background now, but we
+	 * just wait for the calibration complete notification.
+	 */
+	ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT);
+
+	goto out;
+
+ error:
+	iwlagn_remove_notification(priv, &calib_wait);
+ out:
+	/* Whatever happened, stop the device */
+	iwlagn_stop_device(priv);
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index cdeb09eee7396cfb87447ed517d6d1840c3afb21..003d5243542b247a32b47ba2080db2e7809db885 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -769,7 +769,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 				if (w->cmd == pkt->hdr.cmd) {
 					w->triggered = true;
 					if (w->fn)
-						w->fn(priv, pkt);
+						w->fn(priv, pkt, w->fn_data);
 				}
 			}
 			spin_unlock(&priv->_agn.notif_wait_lock);
@@ -846,14 +846,6 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 		iwlagn_rx_queue_restock(priv);
 }
 
-/* call this function to flush any scheduled tasklet */
-static inline void iwl_synchronize_irq(struct iwl_priv *priv)
-{
-	/* wait to make sure we flush pending tasklet*/
-	synchronize_irq(priv->pci_dev->irq);
-	tasklet_kill(&priv->irq_tasklet);
-}
-
 /* tasklet for iwlagn interrupt */
 static void iwl_irq_tasklet(struct iwl_priv *priv)
 {
@@ -1181,18 +1173,42 @@ static struct attribute_group iwl_attribute_group = {
  *
  ******************************************************************************/
 
-static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
 {
-	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
-	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
-	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
-	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+	if (desc->v_addr)
+		dma_free_coherent(&pci_dev->dev, desc->len,
+				  desc->v_addr, desc->p_addr);
+	desc->v_addr = NULL;
+	desc->len = 0;
 }
 
-static void iwl_nic_start(struct iwl_priv *priv)
+static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img)
 {
-	/* Remove all resets to allow NIC to operate */
-	iwl_write32(priv, CSR_RESET, 0);
+	iwl_free_fw_desc(pci_dev, &img->code);
+	iwl_free_fw_desc(pci_dev, &img->data);
+}
+
+static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc,
+			     const void *data, size_t len)
+{
+	if (!len) {
+		desc->v_addr = NULL;
+		return -EINVAL;
+	}
+
+	desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len,
+					  &desc->p_addr, GFP_KERNEL);
+	if (!desc->v_addr)
+		return -ENOMEM;
+	desc->len = len;
+	memcpy(desc->v_addr, data, len);
+	return 0;
+}
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+	iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt);
+	iwl_free_fw_img(priv->pci_dev, &priv->ucode_init);
 }
 
 struct iwlagn_ucode_capabilities {
@@ -1661,24 +1677,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	/* Runtime instructions and 2 copies of data:
 	 * 1) unmodified from disk
 	 * 2) backup cache for save/restore during power-downs */
-	priv->ucode_code.len = pieces.inst_size;
-	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
-
-	priv->ucode_data.len = pieces.data_size;
-	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
-
-	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr)
+	if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code,
+			      pieces.inst, pieces.inst_size))
+		goto err_pci_alloc;
+	if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data,
+			      pieces.data, pieces.data_size))
 		goto err_pci_alloc;
 
 	/* Initialization instructions and data */
 	if (pieces.init_size && pieces.init_data_size) {
-		priv->ucode_init.len = pieces.init_size;
-		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
-
-		priv->ucode_init_data.len = pieces.init_data_size;
-		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
-
-		if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
+		if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code,
+				      pieces.init, pieces.init_size))
+			goto err_pci_alloc;
+		if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data,
+				      pieces.init_data, pieces.init_data_size))
 			goto err_pci_alloc;
 	}
 
@@ -1704,6 +1716,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 			priv->cfg->base_params->max_event_log_size;
 	priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
 
+	priv->new_scan_threshold_behaviour =
+		!!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
+
 	if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) {
 		priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
 		priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
@@ -1715,39 +1730,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	else
 		priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
 
-	/* Copy images into buffers for card's bus-master reads ... */
-
-	/* Runtime instructions (first block of data in file) */
-	IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n",
-			pieces.inst_size);
-	memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size);
-
-	IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
-		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
-
-	/*
-	 * Runtime data
-	 * NOTE:  Copy into backup buffer will be done in iwl_up()
-	 */
-	IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
-			pieces.data_size);
-	memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
-
-	/* Initialization instructions */
-	if (pieces.init_size) {
-		IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
-				pieces.init_size);
-		memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
-	}
-
-	/* Initialization data */
-	if (pieces.init_data_size) {
-		IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
-			       pieces.init_data_size);
-		memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
-		       pieces.init_data_size);
-	}
-
 	/*
 	 * figure out the offset of chain noise reset and gain commands
 	 * base on the size of standard phy calibration commands table size
@@ -1878,9 +1860,10 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
 	u32 desc, time, count, base, data1;
 	u32 blink1, blink2, ilink1, ilink2;
 	u32 pc, hcmd;
+	struct iwl_error_event_table table;
 
 	base = priv->device_pointers.error_event_table;
-	if (priv->ucode_type == UCODE_INIT) {
+	if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
 		if (!base)
 			base = priv->_agn.init_errlog_ptr;
 	} else {
@@ -1891,11 +1874,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
 	if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
 		IWL_ERR(priv,
 			"Not valid error log pointer 0x%08X for %s uCode\n",
-			base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
+			base,
+			(priv->ucode_type == UCODE_SUBTYPE_INIT)
+					? "Init" : "RT");
 		return;
 	}
 
-	count = iwl_read_targ_mem(priv, base);
+	iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
+
+	count = table.valid;
 
 	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
 		IWL_ERR(priv, "Start IWL Error Log Dump:\n");
@@ -1903,18 +1890,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
 			priv->status, count);
 	}
 
-	desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+	desc = table.error_id;
 	priv->isr_stats.err_code = desc;
-	pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
-	blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
-	blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
-	ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
-	ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
-	data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
-	data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
-	line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
-	time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-	hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32));
+	pc = table.pc;
+	blink1 = table.blink1;
+	blink2 = table.blink2;
+	ilink1 = table.ilink1;
+	ilink2 = table.ilink2;
+	data1 = table.data1;
+	data2 = table.data2;
+	line = table.line;
+	time = table.tsf_low;
+	hcmd = table.hcmd;
 
 	trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
 				      blink1, blink2, ilink1, ilink2);
@@ -1949,7 +1936,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
 		return pos;
 
 	base = priv->device_pointers.log_event_table;
-	if (priv->ucode_type == UCODE_INIT) {
+	if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
 		if (!base)
 			base = priv->_agn.init_evtlog_ptr;
 	} else {
@@ -2062,7 +2049,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
 	size_t bufsz = 0;
 
 	base = priv->device_pointers.log_event_table;
-	if (priv->ucode_type == UCODE_INIT) {
+	if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
 		logsize = priv->_agn.init_evtlog_size;
 		if (!base)
 			base = priv->_agn.init_evtlog_ptr;
@@ -2075,7 +2062,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
 	if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
 		IWL_ERR(priv,
 			"Invalid event log pointer 0x%08X for %s uCode\n",
-			base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
+			base,
+			(priv->ucode_type == UCODE_SUBTYPE_INIT)
+					? "Init" : "RT");
 		return -EINVAL;
 	}
 
@@ -2222,30 +2211,14 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
  *                   from protocol/runtime uCode (initialization uCode's
  *                   Alive gets handled by iwl_init_alive_start()).
  */
-static void iwl_alive_start(struct iwl_priv *priv)
+static int iwl_alive_start(struct iwl_priv *priv)
 {
 	int ret = 0;
 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-	IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
-
-	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
-	 * This is a paranoid check, because we would not have gotten the
-	 * "runtime" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv, &priv->ucode_code)) {
-		/* Runtime instruction load was bad;
-		 * take it all the way back down so we can try again */
-		IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n");
-		goto restart;
-	}
-
-	ret = iwlagn_alive_notify(priv);
-	if (ret) {
-		IWL_WARN(priv,
-			"Could not complete ALIVE transition [ntf]: %d\n", ret);
-		goto restart;
-	}
+	iwl_reset_ict(priv);
 
+	IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
 
 	/* After the ALIVE response, we can send host commands to the uCode */
 	set_bit(STATUS_ALIVE, &priv->status);
@@ -2254,7 +2227,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	iwl_setup_watchdog(priv);
 
 	if (iwl_is_rfkill(priv))
-		return;
+		return -ERFKILL;
 
 	/* download priority table before any calibration request */
 	if (priv->cfg->bt_params &&
@@ -2268,10 +2241,14 @@ static void iwl_alive_start(struct iwl_priv *priv)
 		iwlagn_send_prio_tbl(priv);
 
 		/* FIXME: w/a to force change uCode BT state machine */
-		iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
-			BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
-		iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
-			BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+		ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+		if (ret)
+			return ret;
+		ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
+					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+		if (ret)
+			return ret;
 	}
 	if (priv->hw_params.calib_rt_cfg)
 		iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
@@ -2313,29 +2290,22 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	set_bit(STATUS_READY, &priv->status);
 
 	/* Configure the adapter for unassociated operation */
-	iwlcore_commit_rxon(priv, ctx);
+	ret = iwlcore_commit_rxon(priv, ctx);
+	if (ret)
+		return ret;
 
 	/* At this point, the NIC is initialized and operational */
 	iwl_rf_kill_ct_config(priv);
 
 	IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-	wake_up_interruptible(&priv->wait_command_queue);
-
-	iwl_power_update_mode(priv, true);
-	IWL_DEBUG_INFO(priv, "Updated power mode\n");
 
-
-	return;
-
- restart:
-	queue_work(priv->workqueue, &priv->restart);
+	return iwl_power_update_mode(priv, true);
 }
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv);
 
 static void __iwl_down(struct iwl_priv *priv)
 {
-	unsigned long flags;
 	int exit_pending;
 
 	IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
@@ -2367,32 +2337,10 @@ static void __iwl_down(struct iwl_priv *priv)
 	if (!exit_pending)
 		clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
-	/* stop and reset the on-board processor */
-	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
-	/* tell the device to stop sending interrupts */
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_disable_interrupts(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-	iwl_synchronize_irq(priv);
-
 	if (priv->mac80211_registered)
 		ieee80211_stop_queues(priv->hw);
 
-	/* If we have not previously called iwl_init() then
-	 * clear all bits but the RF Kill bit and return */
-	if (!iwl_is_init(priv)) {
-		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
-					STATUS_RF_KILL_HW |
-			       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
-					STATUS_GEO_CONFIGURED |
-			       test_bit(STATUS_EXIT_PENDING, &priv->status) <<
-					STATUS_EXIT_PENDING;
-		goto exit;
-	}
-
-	/* ...otherwise clear out all the status bits but the RF Kill
-	 * bit and continue taking the NIC down. */
+	/* Clear out all status bits but a few that are stable across reset */
 	priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
 				STATUS_RF_KILL_HW |
 			test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
@@ -2402,23 +2350,8 @@ static void __iwl_down(struct iwl_priv *priv)
 		       test_bit(STATUS_EXIT_PENDING, &priv->status) <<
 				STATUS_EXIT_PENDING;
 
-	/* device going down, Stop using ICT table */
-	iwl_disable_ict(priv);
-
-	iwlagn_txq_ctx_stop(priv);
-	iwlagn_rxq_stop(priv);
-
-	/* Power-down device's busmaster DMA clocks */
-	iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-	udelay(5);
-
-	/* Make sure (redundant) we've released our request to stay awake */
-	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-	/* Stop the device, and put it in low power state */
-	iwl_apm_stop(priv);
+	iwlagn_stop_device(priv);
 
- exit:
 	dev_kfree_skb(priv->beacon_skb);
 	priv->beacon_skb = NULL;
 
@@ -2437,9 +2370,10 @@ static void iwl_down(struct iwl_priv *priv)
 
 #define HW_READY_TIMEOUT (50)
 
+/* Note: returns poll_bit return value, which is >= 0 if success */
 static int iwl_set_hw_ready(struct iwl_priv *priv)
 {
-	int ret = 0;
+	int ret;
 
 	iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 		CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
@@ -2449,25 +2383,21 @@ static int iwl_set_hw_ready(struct iwl_priv *priv)
 				CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
 				CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
 				HW_READY_TIMEOUT);
-	if (ret != -ETIMEDOUT)
-		priv->hw_ready = true;
-	else
-		priv->hw_ready = false;
 
-	IWL_DEBUG_INFO(priv, "hardware %s\n",
-		      (priv->hw_ready == 1) ? "ready" : "not ready");
+	IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : "");
 	return ret;
 }
 
-static int iwl_prepare_card_hw(struct iwl_priv *priv)
+/* Note: returns standard 0/-ERROR code */
+int iwl_prepare_card_hw(struct iwl_priv *priv)
 {
-	int ret = 0;
+	int ret;
 
 	IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n");
 
 	ret = iwl_set_hw_ready(priv);
-	if (priv->hw_ready)
-		return ret;
+	if (ret >= 0)
+		return 0;
 
 	/* If HW is not ready, prepare the conditions to check again */
 	iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
@@ -2477,10 +2407,13 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
 			~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
 			CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
 
-	/* HW should be ready by now, check again. */
-	if (ret != -ETIMEDOUT)
-		iwl_set_hw_ready(priv);
+	if (ret < 0)
+		return ret;
 
+	/* HW should be ready by now, check again. */
+	ret = iwl_set_hw_ready(priv);
+	if (ret >= 0)
+		return 0;
 	return ret;
 }
 
@@ -2489,9 +2422,10 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
 static int __iwl_up(struct iwl_priv *priv)
 {
 	struct iwl_rxon_context *ctx;
-	int i;
 	int ret;
 
+	lockdep_assert_held(&priv->mutex);
+
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 		IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
 		return -EIO;
@@ -2505,77 +2439,33 @@ static int __iwl_up(struct iwl_priv *priv)
 		}
 	}
 
-	iwl_prepare_card_hw(priv);
-
-	if (!priv->hw_ready) {
-		IWL_WARN(priv, "Exit HW not ready\n");
-		return -EIO;
-	}
-
-	/* If platform's RF_KILL switch is NOT set to KILL */
-	if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-		clear_bit(STATUS_RF_KILL_HW, &priv->status);
-	else
-		set_bit(STATUS_RF_KILL_HW, &priv->status);
-
-	if (iwl_is_rfkill(priv)) {
-		wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
-
-		iwl_enable_interrupts(priv);
-		IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n");
-		return 0;
+	ret = iwlagn_run_init_ucode(priv);
+	if (ret) {
+		IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
+		goto error;
 	}
 
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-
-	ret = iwlagn_hw_nic_init(priv);
+	ret = iwlagn_load_ucode_wait_alive(priv,
+					   &priv->ucode_rt,
+					   UCODE_SUBTYPE_REGULAR,
+					   UCODE_SUBTYPE_REGULAR_NEW);
 	if (ret) {
-		IWL_ERR(priv, "Unable to init nic\n");
-		return ret;
+		IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
+		goto error;
 	}
 
-	/* make sure rfkill handshake bits are cleared */
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-	/* clear (again), then enable host interrupts */
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl_enable_interrupts(priv);
-
-	/* really make sure rfkill handshake bits are cleared */
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-	for (i = 0; i < MAX_HW_RESTARTS; i++) {
-
-		/* load bootstrap state machine,
-		 * load bootstrap program into processor's memory,
-		 * prepare to load the "initialize" uCode */
-		ret = iwlagn_load_ucode(priv);
-
-		if (ret) {
-			IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n",
-				ret);
-			continue;
-		}
-
-		/* start card; "initialize" will load runtime ucode */
-		iwl_nic_start(priv);
-
-		IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
-
-		return 0;
-	}
+	ret = iwl_alive_start(priv);
+	if (ret)
+		goto error;
+	return 0;
 
+ error:
 	set_bit(STATUS_EXIT_PENDING, &priv->status);
 	__iwl_down(priv);
 	clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
-	/* tried to restart and config the device for as long as our
-	 * patience could withstand */
-	IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i);
-	return -EIO;
+	IWL_ERR(priv, "Unable to initialize device.\n");
+	return ret;
 }
 
 
@@ -2585,39 +2475,6 @@ static int __iwl_up(struct iwl_priv *priv)
  *
  *****************************************************************************/
 
-static void iwl_bg_init_alive_start(struct work_struct *data)
-{
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, init_alive_start.work);
-
-	mutex_lock(&priv->mutex);
-
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-		mutex_unlock(&priv->mutex);
-		return;
-	}
-
-	iwlagn_init_alive_start(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_alive_start(struct work_struct *data)
-{
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, alive_start.work);
-
-	mutex_lock(&priv->mutex);
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		goto unlock;
-
-	/* enable dram interrupt */
-	iwl_reset_ict(priv);
-
-	iwl_alive_start(priv);
-unlock:
-	mutex_unlock(&priv->mutex);
-}
-
 static void iwl_bg_run_time_calib_work(struct work_struct *work)
 {
 	struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -2639,6 +2496,42 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
 	mutex_unlock(&priv->mutex);
 }
 
+static void iwlagn_prepare_restart(struct iwl_priv *priv)
+{
+	struct iwl_rxon_context *ctx;
+	bool bt_full_concurrent;
+	u8 bt_ci_compliance;
+	u8 bt_load;
+	u8 bt_status;
+
+	lockdep_assert_held(&priv->mutex);
+
+	for_each_context(priv, ctx)
+		ctx->vif = NULL;
+	priv->is_open = 0;
+
+	/*
+	 * __iwl_down() will clear the BT status variables,
+	 * which is correct, but when we restart we really
+	 * want to keep them so restore them afterwards.
+	 *
+	 * The restart process will later pick them up and
+	 * re-configure the hw when we reconfigure the BT
+	 * command.
+	 */
+	bt_full_concurrent = priv->bt_full_concurrent;
+	bt_ci_compliance = priv->bt_ci_compliance;
+	bt_load = priv->bt_traffic_load;
+	bt_status = priv->bt_status;
+
+	__iwl_down(priv);
+
+	priv->bt_full_concurrent = bt_full_concurrent;
+	priv->bt_ci_compliance = bt_ci_compliance;
+	priv->bt_traffic_load = bt_load;
+	priv->bt_status = bt_status;
+}
+
 static void iwl_bg_restart(struct work_struct *data)
 {
 	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
@@ -2647,50 +2540,13 @@ static void iwl_bg_restart(struct work_struct *data)
 		return;
 
 	if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
-		struct iwl_rxon_context *ctx;
-		bool bt_full_concurrent;
-		u8 bt_ci_compliance;
-		u8 bt_load;
-		u8 bt_status;
-
 		mutex_lock(&priv->mutex);
-		for_each_context(priv, ctx)
-			ctx->vif = NULL;
-		priv->is_open = 0;
-
-		/*
-		 * __iwl_down() will clear the BT status variables,
-		 * which is correct, but when we restart we really
-		 * want to keep them so restore them afterwards.
-		 *
-		 * The restart process will later pick them up and
-		 * re-configure the hw when we reconfigure the BT
-		 * command.
-		 */
-		bt_full_concurrent = priv->bt_full_concurrent;
-		bt_ci_compliance = priv->bt_ci_compliance;
-		bt_load = priv->bt_traffic_load;
-		bt_status = priv->bt_status;
-
-		__iwl_down(priv);
-
-		priv->bt_full_concurrent = bt_full_concurrent;
-		priv->bt_ci_compliance = bt_ci_compliance;
-		priv->bt_traffic_load = bt_load;
-		priv->bt_status = bt_status;
-
+		iwlagn_prepare_restart(priv);
 		mutex_unlock(&priv->mutex);
 		iwl_cancel_deferred_work(priv);
 		ieee80211_restart_hw(priv->hw);
 	} else {
-		iwl_down(priv);
-
-		if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-			return;
-
-		mutex_lock(&priv->mutex);
-		__iwl_up(priv);
-		mutex_unlock(&priv->mutex);
+		WARN_ON(1);
 	}
 }
 
@@ -2801,8 +2657,6 @@ unlock:
  *
  *****************************************************************************/
 
-#define UCODE_READY_TIMEOUT	(4 * HZ)
-
 /*
  * Not a mac80211 entry point function, but it fits in with all the
  * other mac80211 functions grouped here.
@@ -2895,31 +2749,17 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw)
 	mutex_lock(&priv->mutex);
 	ret = __iwl_up(priv);
 	mutex_unlock(&priv->mutex);
-
 	if (ret)
 		return ret;
 
-	if (iwl_is_rfkill(priv))
-		goto out;
-
 	IWL_DEBUG_INFO(priv, "Start UP work done.\n");
 
-	/* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
-	 * mac80211 will not be run successfully. */
-	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-			test_bit(STATUS_READY, &priv->status),
-			UCODE_READY_TIMEOUT);
-	if (!ret) {
-		if (!test_bit(STATUS_READY, &priv->status)) {
-			IWL_ERR(priv, "START_ALIVE timeout after %dms.\n",
-				jiffies_to_msecs(UCODE_READY_TIMEOUT));
-			return -ETIMEDOUT;
-		}
-	}
+	/* Now we should be done, and the READY bit should be set. */
+	if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
+		ret = -EIO;
 
 	iwlagn_led_enable(priv);
 
-out:
 	priv->is_open = 1;
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 	return 0;
@@ -2994,7 +2834,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 
-	if (priv->cfg->mod_params->sw_crypto) {
+	if (iwlagn_mod_params.sw_crypto) {
 		IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
 		return -EOPNOTSUPP;
 	}
@@ -3506,8 +3346,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 	INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
 	INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
 	INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
-	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
-	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
 	INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done);
 
 	iwl_setup_scan_deferred_work(priv);
@@ -3536,8 +3374,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 	if (priv->cfg->ops->lib->cancel_deferred_work)
 		priv->cfg->ops->lib->cancel_deferred_work(priv);
 
-	cancel_delayed_work_sync(&priv->init_alive_start);
-	cancel_delayed_work(&priv->alive_start);
 	cancel_work_sync(&priv->run_time_calib_work);
 	cancel_work_sync(&priv->beacon_update);
 
@@ -3617,12 +3453,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
 		priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
 	}
 
-	/* Set the tx_power_user_lmt to the lowest power level
-	 * this value will get overwritten by channel max power avg
-	 * from eeprom */
-	priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN;
-	priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN;
-
 	ret = iwl_init_channel_map(priv);
 	if (ret) {
 		IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
@@ -3692,14 +3522,14 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
 {
 	priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
 	priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
-	if (priv->cfg->mod_params->amsdu_size_8K)
+	if (iwlagn_mod_params.amsdu_size_8K)
 		priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
 	else
 		priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
 
 	priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
 
-	if (priv->cfg->mod_params->disable_11n)
+	if (iwlagn_mod_params.disable_11n)
 		priv->cfg->sku &= ~IWL_SKU_N;
 
 	/* Device-specific setup */
@@ -3772,6 +3602,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	priv = hw->priv;
 	/* At this point both hw and priv are allocated. */
 
+	priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED;
+
 	/*
 	 * The default context is always valid,
 	 * more may be discovered when firmware
@@ -3912,8 +3744,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	 * PCI Tx retries from interfering with C3 CPU state */
 	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
 
-	iwl_prepare_card_hw(priv);
-	if (!priv->hw_ready) {
+	if (iwl_prepare_card_hw(priv)) {
 		IWL_WARN(priv, "Failed, HW not ready\n");
 		goto out_iounmap;
 	}
@@ -4069,17 +3900,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 	if (priv->mac80211_registered) {
 		ieee80211_unregister_hw(priv->hw);
 		priv->mac80211_registered = 0;
-	} else {
-		iwl_down(priv);
 	}
 
-	/*
-	 * Make sure device is reset to low power before unloading driver.
-	 * This may be redundant with iwl_down(), but there are paths to
-	 * run iwl_down() without calling apm_ops.stop(), and there are
-	 * paths to avoid running iwl_down() at all before leaving driver.
-	 * This (inexpensive) call *makes sure* device is reset.
-	 */
+	/* Reset to low power before unloading driver. */
 	iwl_apm_stop(priv);
 
 	iwl_tt_exit(priv);
@@ -4306,21 +4129,21 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 	{IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)},
 	{IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)},
 
-/* 200 Series */
-	{IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)},
-
-/* 230 Series */
-	{IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)},
-	{IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)},
-	{IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)},
+/* 105 Series */
+	{IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)},
+
+/* 135 Series */
+	{IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
+	{IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)},
+	{IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)},
 
 	{0}
 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 078a23e5d99decfd05cd0a0081fcebe5a507a1a8..b477336ff53ae690bcdb81fafa809d357a61523f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -102,10 +102,10 @@ extern struct iwl_cfg iwl2030_2bg_cfg;
 extern struct iwl_cfg iwl6035_2agn_cfg;
 extern struct iwl_cfg iwl6035_2abg_cfg;
 extern struct iwl_cfg iwl6035_2bg_cfg;
-extern struct iwl_cfg iwl200_bg_cfg;
-extern struct iwl_cfg iwl200_bgn_cfg;
-extern struct iwl_cfg iwl230_bg_cfg;
-extern struct iwl_cfg iwl230_bgn_cfg;
+extern struct iwl_cfg iwl105_bg_cfg;
+extern struct iwl_cfg iwl105_bgn_cfg;
+extern struct iwl_cfg iwl135_bg_cfg;
+extern struct iwl_cfg iwl135_bgn_cfg;
 
 extern struct iwl_mod_params iwlagn_mod_params;
 extern struct iwl_hcmd_ops iwlagn_hcmd;
@@ -120,6 +120,19 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv);
 void iwl_free_isr_ict(struct iwl_priv *priv);
 irqreturn_t iwl_isr_ict(int irq, void *data);
 
+/* call this function to flush any scheduled tasklet */
+static inline void iwl_synchronize_irq(struct iwl_priv *priv)
+{
+	/* wait to make sure we flush pending tasklet*/
+	synchronize_irq(priv->pci_dev->irq);
+	tasklet_kill(&priv->irq_tasklet);
+}
+
+int iwl_prepare_card_hw(struct iwl_priv *priv);
+
+int iwlagn_start_device(struct iwl_priv *priv);
+void iwlagn_stop_device(struct iwl_priv *priv);
+
 /* tx queue */
 void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
 		     int txq_id, u32 index);
@@ -145,16 +158,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
 			     u32 changes);
 
 /* uCode */
-int iwlagn_load_ucode(struct iwl_priv *priv);
 void iwlagn_rx_calib_result(struct iwl_priv *priv,
 			 struct iwl_rx_mem_buffer *rxb);
-void iwlagn_rx_calib_complete(struct iwl_priv *priv,
-			   struct iwl_rx_mem_buffer *rxb);
-void iwlagn_init_alive_start(struct iwl_priv *priv);
-int iwlagn_alive_notify(struct iwl_priv *priv);
-int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc);
-void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
+int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
 void iwlagn_send_prio_tbl(struct iwl_priv *priv);
+int iwlagn_run_init_ucode(struct iwl_priv *priv);
+int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
+				 struct fw_img *image,
+				 int subtype, int alternate_subtype);
 
 /* lib */
 void iwl_check_abort_status(struct iwl_priv *priv,
@@ -245,8 +256,6 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
 			       struct ieee80211_vif *vif, bool add);
 
 /* hcmd */
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
-			   struct iwl_rxon_context *ctx);
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
 
@@ -318,17 +327,17 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
 /* eeprom */
 void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
 void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
 
 /* notification wait support */
 void __acquires(wait_entry)
 iwlagn_init_notification_wait(struct iwl_priv *priv,
 			      struct iwl_notification_wait *wait_entry,
+			      u8 cmd,
 			      void (*fn)(struct iwl_priv *priv,
-					 struct iwl_rx_packet *pkt),
-			      u8 cmd);
-signed long __releases(wait_entry)
+					 struct iwl_rx_packet *pkt,
+					 void *data),
+			      void *fn_data);
+int __must_check __releases(wait_entry)
 iwlagn_wait_notification(struct iwl_priv *priv,
 			 struct iwl_notification_wait *wait_entry,
 			 unsigned long timeout);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 0edba8a6419b315d7cd5f3ecff04bddc3bc9cd23..5fdad6532118884aebdbf9854597cbf2e0928ad6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -386,7 +386,18 @@ struct iwl_tx_ant_config_cmd {
  *****************************************************************************/
 
 #define UCODE_VALID_OK	cpu_to_le32(0x1)
-#define INITIALIZE_SUBTYPE    (9)
+
+enum iwlagn_ucode_subtype {
+	UCODE_SUBTYPE_REGULAR	= 0,
+	UCODE_SUBTYPE_REGULAR_NEW = 1,
+	UCODE_SUBTYPE_INIT	= 9,
+
+	/*
+	 * Not a valid subtype, the ucode has just a u8, so
+	 * we can use something > 0xff for this value.
+	 */
+	UCODE_SUBTYPE_NONE_LOADED = 0x100,
+};
 
 /**
  * REPLY_ALIVE = 0x1 (response only, not a command)
@@ -422,49 +433,61 @@ struct iwl_tx_ant_config_cmd {
  *
  * 2)  error_event_table_ptr indicates base of the error log.  This contains
  *     information about any uCode error that occurs.  For agn, the format
- *     of the error log is:
- *
- *	__le32 valid;        (nonzero) valid, (0) log is empty
- *	__le32 error_id;     type of error
- *	__le32 pc;           program counter
- *	__le32 blink1;       branch link
- *	__le32 blink2;       branch link
- *	__le32 ilink1;       interrupt link
- *	__le32 ilink2;       interrupt link
- *	__le32 data1;        error-specific data
- *	__le32 data2;        error-specific data
- *	__le32 line;         source code line of error
- *	__le32 bcon_time;    beacon timer
- *	__le32 tsf_low;      network timestamp function timer
- *	__le32 tsf_hi;       network timestamp function timer
- *	__le32 gp1;          GP1 timer register
- *	__le32 gp2;          GP2 timer register
- *	__le32 gp3;          GP3 timer register
- *	__le32 ucode_ver;    uCode version
- *	__le32 hw_ver;       HW Silicon version
- *	__le32 brd_ver;      HW board version
- *	__le32 log_pc;       log program counter
- *	__le32 frame_ptr;    frame pointer
- *	__le32 stack_ptr;    stack pointer
- *	__le32 hcmd;         last host command
- *	__le32 isr0;         isr status register LMPM_NIC_ISR0: rxtx_flag
- *	__le32 isr1;         isr status register LMPM_NIC_ISR1: host_flag
- *	__le32 isr2;         isr status register LMPM_NIC_ISR2: enc_flag
- *	__le32 isr3;         isr status register LMPM_NIC_ISR3: time_flag
- *	__le32 isr4;         isr status register LMPM_NIC_ISR4: wico interrupt
- *	__le32 isr_pref;     isr status register LMPM_NIC_PREF_STAT
- *	__le32 wait_event;   wait event() caller address
- *	__le32 l2p_control;  L2pControlField
- *	__le32 l2p_duration; L2pDurationField
- *	__le32 l2p_mhvalid;  L2pMhValidBits
- *	__le32 l2p_addr_match; L2pAddrMatchStat
- *	__le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL)
- *	__le32 u_timestamp;  indicate when the date and time of the compilation
- *	__le32 reserved;
+ *     of the error log is defined by struct iwl_error_event_table.
  *
  * The Linux driver can print both logs to the system log when a uCode error
  * occurs.
  */
+
+/*
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_error_event_table {
+	u32 valid;		/* (nonzero) valid, (0) log is empty */
+	u32 error_id;		/* type of error */
+	u32 pc;			/* program counter */
+	u32 blink1;		/* branch link */
+	u32 blink2;		/* branch link */
+	u32 ilink1;		/* interrupt link */
+	u32 ilink2;		/* interrupt link */
+	u32 data1;		/* error-specific data */
+	u32 data2;		/* error-specific data */
+	u32 line;		/* source code line of error */
+	u32 bcon_time;		/* beacon timer */
+	u32 tsf_low;		/* network timestamp function timer */
+	u32 tsf_hi;		/* network timestamp function timer */
+	u32 gp1;		/* GP1 timer register */
+	u32 gp2;		/* GP2 timer register */
+	u32 gp3;		/* GP3 timer register */
+	u32 ucode_ver;		/* uCode version */
+	u32 hw_ver;		/* HW Silicon version */
+	u32 brd_ver;		/* HW board version */
+	u32 log_pc;		/* log program counter */
+	u32 frame_ptr;		/* frame pointer */
+	u32 stack_ptr;		/* stack pointer */
+	u32 hcmd;		/* last host command header */
+#if 0
+	/* no need to read the remainder, we don't use the values */
+	u32 isr0;		/* isr status register LMPM_NIC_ISR0: rxtx_flag */
+	u32 isr1;		/* isr status register LMPM_NIC_ISR1: host_flag */
+	u32 isr2;		/* isr status register LMPM_NIC_ISR2: enc_flag */
+	u32 isr3;		/* isr status register LMPM_NIC_ISR3: time_flag */
+	u32 isr4;		/* isr status register LMPM_NIC_ISR4: wico interrupt */
+	u32 isr_pref;		/* isr status register LMPM_NIC_PREF_STAT */
+	u32 wait_event;		/* wait event() caller address */
+	u32 l2p_control;	/* L2pControlField */
+	u32 l2p_duration;	/* L2pDurationField */
+	u32 l2p_mhvalid;	/* L2pMhValidBits */
+	u32 l2p_addr_match;	/* L2pAddrMatchStat */
+	u32 lmpm_pmg_sel;	/* indicate which clocks are turned on (LMPM_PMG_SEL) */
+	u32 u_timestamp;	/* indicate when the date and time of the compilation */
+	u32 flow_handler;	/* FH read/write pointers, RX credit */
+#endif
+} __packed;
+
 struct iwl_alive_resp {
 	u8 ucode_minor;
 	u8 ucode_major;
@@ -638,7 +661,7 @@ struct iwl_rxon_cmd {
 /*
  * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
  */
-struct iwl5000_rxon_assoc_cmd {
+struct iwl_rxon_assoc_cmd {
 	__le32 flags;
 	__le32 filter_flags;
 	u8 ofdm_basic_rates;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 885167f8168d7b23aa5993d88acdfdc96850e0b8..4653deada05b48b1383f1cda6b33c7477a1717d3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -41,6 +41,7 @@
 #include "iwl-power.h"
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
+#include "iwl-agn.h"
 
 
 /*
@@ -94,7 +95,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
 		max_bit_rate = MAX_BIT_RATE_40_MHZ;
 	}
 
-	if (priv->cfg->mod_params->amsdu_size_8K)
+	if (iwlagn_mod_params.amsdu_size_8K)
 		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
 	ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
@@ -135,6 +136,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
 	struct ieee80211_channel *geo_ch;
 	struct ieee80211_rate *rates;
 	int i = 0;
+	s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
 
 	if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
 	    priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
@@ -208,8 +210,8 @@ int iwlcore_init_geos(struct iwl_priv *priv)
 
 			geo_ch->flags |= ch->ht40_extension_channel;
 
-			if (ch->max_power_avg > priv->tx_power_device_lmt)
-				priv->tx_power_device_lmt = ch->max_power_avg;
+			if (ch->max_power_avg > max_tx_power)
+				max_tx_power = ch->max_power_avg;
 		} else {
 			geo_ch->flags |= IEEE80211_CHAN_DISABLED;
 		}
@@ -222,6 +224,10 @@ int iwlcore_init_geos(struct iwl_priv *priv)
 				 geo_ch->flags);
 	}
 
+	priv->tx_power_device_lmt = max_tx_power;
+	priv->tx_power_user_lmt = max_tx_power;
+	priv->tx_power_next = max_tx_power;
+
 	if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
 	     priv->cfg->sku & IWL_SKU_A) {
 		IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
@@ -410,72 +416,72 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
 	struct iwl_rxon_cmd *rxon = &ctx->staging;
-	bool error = false;
+	u32 errors = 0;
 
 	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
 		if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
 			IWL_WARN(priv, "check 2.4G: wrong narrow\n");
-			error = true;
+			errors |= BIT(0);
 		}
 		if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
 			IWL_WARN(priv, "check 2.4G: wrong radar\n");
-			error = true;
+			errors |= BIT(1);
 		}
 	} else {
 		if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
 			IWL_WARN(priv, "check 5.2G: not short slot!\n");
-			error = true;
+			errors |= BIT(2);
 		}
 		if (rxon->flags & RXON_FLG_CCK_MSK) {
 			IWL_WARN(priv, "check 5.2G: CCK!\n");
-			error = true;
+			errors |= BIT(3);
 		}
 	}
 	if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
 		IWL_WARN(priv, "mac/bssid mcast!\n");
-		error = true;
+		errors |= BIT(4);
 	}
 
 	/* make sure basic rates 6Mbps and 1Mbps are supported */
 	if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
 	    (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
 		IWL_WARN(priv, "neither 1 nor 6 are basic\n");
-		error = true;
+		errors |= BIT(5);
 	}
 
 	if (le16_to_cpu(rxon->assoc_id) > 2007) {
 		IWL_WARN(priv, "aid > 2007\n");
-		error = true;
+		errors |= BIT(6);
 	}
 
 	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
 			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
 		IWL_WARN(priv, "CCK and short slot\n");
-		error = true;
+		errors |= BIT(7);
 	}
 
 	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
 			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
 		IWL_WARN(priv, "CCK and auto detect");
-		error = true;
+		errors |= BIT(8);
 	}
 
 	if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
 			    RXON_FLG_TGG_PROTECT_MSK)) ==
 			    RXON_FLG_TGG_PROTECT_MSK) {
 		IWL_WARN(priv, "TGg but no auto-detect\n");
-		error = true;
+		errors |= BIT(9);
 	}
 
-	if (error)
-		IWL_WARN(priv, "Tuning to channel %d\n",
-			    le16_to_cpu(rxon->channel));
-
-	if (error) {
-		IWL_ERR(priv, "Invalid RXON\n");
-		return -EINVAL;
+	if (rxon->channel == 0) {
+		IWL_WARN(priv, "zero channel is invalid\n");
+		errors |= BIT(10);
 	}
-	return 0;
+
+	WARN(errors, "Invalid RXON (%#x), channel %d",
+	     errors, le16_to_cpu(rxon->channel));
+
+	return errors ? -EINVAL : 0;
 }
 
 /**
@@ -867,6 +873,19 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
 }
 #endif
 
+static void iwlagn_abort_notification_waits(struct iwl_priv *priv)
+{
+	unsigned long flags;
+	struct iwl_notification_wait *wait_entry;
+
+	spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags);
+	list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list)
+		wait_entry->aborted = true;
+	spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags);
+
+	wake_up_all(&priv->_agn.notif_waitq);
+}
+
 void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 {
 	unsigned int reload_msec;
@@ -878,6 +897,8 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 	/* Cancel currently queued command. */
 	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
+	iwlagn_abort_notification_waits(priv);
+
 	/* Keep the restart process from trying to send host
 	 * commands by clearing the ready bit */
 	clear_bit(STATUS_READY, &priv->status);
@@ -906,7 +927,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 	}
 
 	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-		if (priv->cfg->mod_params->restart_fw) {
+		if (iwlagn_mod_params.restart_fw) {
 			IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
 				  "Restarting adapter due to uCode error.\n");
 			queue_work(priv->workqueue, &priv->restart);
@@ -975,6 +996,8 @@ void iwl_apm_stop(struct iwl_priv *priv)
 {
 	IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
 
+	clear_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
 	/* Stop device's DMA activity */
 	iwl_apm_stop_master(priv);
 
@@ -1089,6 +1112,8 @@ int iwl_apm_init(struct iwl_priv *priv)
 	iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
+	set_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
 out:
 	return ret;
 }
@@ -1723,7 +1748,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
 		 * detect failure), then fw_restart module parameter
 		 * need to be check before performing firmware reload
 		 */
-		if (!external && !priv->cfg->mod_params->restart_fw) {
+		if (!external && !iwlagn_mod_params.restart_fw) {
 			IWL_DEBUG_INFO(priv, "Cancel firmware reload based on "
 				       "module parameter setting\n");
 			break;
@@ -1740,6 +1765,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 {
 	struct iwl_priv *priv = hw->priv;
 	struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+	struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 	struct iwl_rxon_context *tmp;
 	u32 interface_modes;
 	int err;
@@ -1764,6 +1790,19 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		goto out;
 	}
 
+	/*
+	 * Refuse a change that should be done by moving from the PAN
+	 * context to the BSS context instead, if the BSS context is
+	 * available and can support the new interface type.
+	 */
+	if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
+	    (bss_ctx->interface_modes & BIT(newtype) ||
+	     bss_ctx->exclusive_interface_modes & BIT(newtype))) {
+		BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+		err = -EBUSY;
+		goto out;
+	}
+
 	if (ctx->exclusive_interface_modes & BIT(newtype)) {
 		for_each_context(priv, tmp) {
 			if (ctx == tmp)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 32a990ff09ae1c32a8552ddfc2887d982c0c42b3..dec9820753f8d8aa43db0180dab6d301efa1180e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -90,7 +90,6 @@ struct iwl_cmd;
 #define IWL_CMD(x) case x: return #x
 
 struct iwl_hcmd_ops {
-	int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
 	int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
 	void (*set_rxon_chain)(struct iwl_priv *priv,
 			       struct iwl_rxon_context *ctx);
@@ -122,19 +121,6 @@ struct iwl_apm_ops {
 	void (*config)(struct iwl_priv *priv);
 };
 
-struct iwl_debugfs_ops {
-	ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf,
-				 size_t count, loff_t *ppos);
-	ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf,
-				 size_t count, loff_t *ppos);
-	ssize_t (*general_stats_read)(struct file *file, char __user *user_buf,
-				      size_t count, loff_t *ppos);
-	ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf,
-				 size_t count, loff_t *ppos);
-	ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf,
-				 size_t count, loff_t *ppos);
-};
-
 struct iwl_temp_ops {
 	void (*temperature)(struct iwl_priv *priv);
 };
@@ -183,7 +169,6 @@ struct iwl_lib_ops {
 	int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
 	void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
 
-	struct iwl_debugfs_ops debugfs_ops;
 };
 
 /* NIC specific ops */
@@ -326,8 +311,6 @@ struct iwl_cfg {
 	u16  eeprom_ver;
 	u16  eeprom_calib_ver;
 	const struct iwl_ops *ops;
-	/* module based parameters which can be set from modprobe cmd */
-	const struct iwl_mod_params *mod_params;
 	/* params not likely to change within a device family */
 	struct iwl_base_params *base_params;
 	/* params likely to change within a device family */
@@ -592,6 +575,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_SCAN_HW		15
 #define STATUS_POWER_PMI	16
 #define STATUS_FW_ERROR		17
+#define STATUS_DEVICE_ENABLED	18
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)
@@ -644,11 +628,6 @@ void iwl_apm_stop(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 
 int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-static inline int iwl_send_rxon_assoc(struct iwl_priv *priv,
-				      struct iwl_rxon_context *ctx)
-{
-	return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx);
-}
 static inline int iwlcore_commit_rxon(struct iwl_priv *priv,
 				      struct iwl_rxon_context *ctx)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index c272204fccffe319c5118000e4a04d9091d68d0d..0e6a04b739ad36568f9f09112eaf6c66ce8f2ee8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -39,6 +39,7 @@
 #include "iwl-debug.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
+#include "iwl-agn.h"
 
 /* create and remove of files */
 #define DEBUGFS_ADD_FILE(name, parent, mode) do {			\
@@ -226,10 +227,10 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
 	/* default is to dump the entire data segment */
 	if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
 		priv->dbgfs_sram_offset = 0x800000;
-		if (priv->ucode_type == UCODE_INIT)
-			priv->dbgfs_sram_len = priv->ucode_init_data.len;
+		if (priv->ucode_type == UCODE_SUBTYPE_INIT)
+			priv->dbgfs_sram_len = priv->ucode_init.data.len;
 		else
-			priv->dbgfs_sram_len = priv->ucode_data.len;
+			priv->dbgfs_sram_len = priv->ucode_rt.data.len;
 	}
 	len = priv->dbgfs_sram_len;
 
@@ -1037,13 +1038,463 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
+static const char *fmt_value = "  %-30s %10u\n";
+static const char *fmt_hex   = "  %-30s       0x%02X\n";
+static const char *fmt_table = "  %-30s %10u  %10u  %10u  %10u\n";
+static const char *fmt_header =
+	"%-32s    current  cumulative       delta         max\n";
+
+static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+	int p = 0;
+	u32 flag;
+
+	flag = le32_to_cpu(priv->statistics.flag);
+
+	p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
+	if (flag & UCODE_STATISTICS_CLEAR_MSK)
+		p += scnprintf(buf + p, bufsz - p,
+		"\tStatistics have been cleared\n");
+	p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+		(flag & UCODE_STATISTICS_FREQUENCY_MSK)
+		? "2.4 GHz" : "5.2 GHz");
+	p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+		(flag & UCODE_STATISTICS_NARROW_BAND_MSK)
+		 ? "enabled" : "disabled");
+
+	return p;
+}
+
 static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
 					char __user *user_buf,
 					size_t count, loff_t *ppos)
 {
 	struct iwl_priv *priv = file->private_data;
-	return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
-			user_buf, count, ppos);
+	int pos = 0;
+	char *buf;
+	int bufsz = sizeof(struct statistics_rx_phy) * 40 +
+		    sizeof(struct statistics_rx_non_phy) * 40 +
+		    sizeof(struct statistics_rx_ht_phy) * 40 + 400;
+	ssize_t ret;
+	struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+	struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+	struct statistics_rx_non_phy *general, *accum_general;
+	struct statistics_rx_non_phy *delta_general, *max_general;
+	struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	ofdm = &priv->statistics.rx_ofdm;
+	cck = &priv->statistics.rx_cck;
+	general = &priv->statistics.rx_non_phy;
+	ht = &priv->statistics.rx_ofdm_ht;
+	accum_ofdm = &priv->accum_stats.rx_ofdm;
+	accum_cck = &priv->accum_stats.rx_cck;
+	accum_general = &priv->accum_stats.rx_non_phy;
+	accum_ht = &priv->accum_stats.rx_ofdm_ht;
+	delta_ofdm = &priv->delta_stats.rx_ofdm;
+	delta_cck = &priv->delta_stats.rx_cck;
+	delta_general = &priv->delta_stats.rx_non_phy;
+	delta_ht = &priv->delta_stats.rx_ofdm_ht;
+	max_ofdm = &priv->max_delta_stats.rx_ofdm;
+	max_cck = &priv->max_delta_stats.rx_cck;
+	max_general = &priv->max_delta_stats.rx_non_phy;
+	max_ht = &priv->max_delta_stats.rx_ofdm_ht;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - OFDM:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ina_cnt:",
+			 le32_to_cpu(ofdm->ina_cnt),
+			 accum_ofdm->ina_cnt,
+			 delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_cnt:",
+			 le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+			 delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "plcp_err:",
+			 le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+			 delta_ofdm->plcp_err, max_ofdm->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_err:",
+			 le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+			 delta_ofdm->crc32_err, max_ofdm->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "overrun_err:",
+			 le32_to_cpu(ofdm->overrun_err),
+			 accum_ofdm->overrun_err, delta_ofdm->overrun_err,
+			 max_ofdm->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "early_overrun_err:",
+			 le32_to_cpu(ofdm->early_overrun_err),
+			 accum_ofdm->early_overrun_err,
+			 delta_ofdm->early_overrun_err,
+			 max_ofdm->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_good:",
+			 le32_to_cpu(ofdm->crc32_good),
+			 accum_ofdm->crc32_good, delta_ofdm->crc32_good,
+			 max_ofdm->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "false_alarm_cnt:",
+			 le32_to_cpu(ofdm->false_alarm_cnt),
+			 accum_ofdm->false_alarm_cnt,
+			 delta_ofdm->false_alarm_cnt,
+			 max_ofdm->false_alarm_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_sync_err_cnt:",
+			 le32_to_cpu(ofdm->fina_sync_err_cnt),
+			 accum_ofdm->fina_sync_err_cnt,
+			 delta_ofdm->fina_sync_err_cnt,
+			 max_ofdm->fina_sync_err_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sfd_timeout:",
+			 le32_to_cpu(ofdm->sfd_timeout),
+			 accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
+			 max_ofdm->sfd_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_timeout:",
+			 le32_to_cpu(ofdm->fina_timeout),
+			 accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
+			 max_ofdm->fina_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "unresponded_rts:",
+			 le32_to_cpu(ofdm->unresponded_rts),
+			 accum_ofdm->unresponded_rts,
+			 delta_ofdm->unresponded_rts,
+			 max_ofdm->unresponded_rts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rxe_frame_lmt_ovrun:",
+			 le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+			 accum_ofdm->rxe_frame_limit_overrun,
+			 delta_ofdm->rxe_frame_limit_overrun,
+			 max_ofdm->rxe_frame_limit_overrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ack_cnt:",
+			 le32_to_cpu(ofdm->sent_ack_cnt),
+			 accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
+			 max_ofdm->sent_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_cts_cnt:",
+			 le32_to_cpu(ofdm->sent_cts_cnt),
+			 accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
+			 max_ofdm->sent_cts_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ba_rsp_cnt:",
+			 le32_to_cpu(ofdm->sent_ba_rsp_cnt),
+			 accum_ofdm->sent_ba_rsp_cnt,
+			 delta_ofdm->sent_ba_rsp_cnt,
+			 max_ofdm->sent_ba_rsp_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dsp_self_kill:",
+			 le32_to_cpu(ofdm->dsp_self_kill),
+			 accum_ofdm->dsp_self_kill,
+			 delta_ofdm->dsp_self_kill,
+			 max_ofdm->dsp_self_kill);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "mh_format_err:",
+			 le32_to_cpu(ofdm->mh_format_err),
+			 accum_ofdm->mh_format_err,
+			 delta_ofdm->mh_format_err,
+			 max_ofdm->mh_format_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "re_acq_main_rssi_sum:",
+			 le32_to_cpu(ofdm->re_acq_main_rssi_sum),
+			 accum_ofdm->re_acq_main_rssi_sum,
+			 delta_ofdm->re_acq_main_rssi_sum,
+			 max_ofdm->re_acq_main_rssi_sum);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - CCK:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ina_cnt:",
+			 le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+			 delta_cck->ina_cnt, max_cck->ina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_cnt:",
+			 le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+			 delta_cck->fina_cnt, max_cck->fina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "plcp_err:",
+			 le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+			 delta_cck->plcp_err, max_cck->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_err:",
+			 le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+			 delta_cck->crc32_err, max_cck->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "overrun_err:",
+			 le32_to_cpu(cck->overrun_err),
+			 accum_cck->overrun_err, delta_cck->overrun_err,
+			 max_cck->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "early_overrun_err:",
+			 le32_to_cpu(cck->early_overrun_err),
+			 accum_cck->early_overrun_err,
+			 delta_cck->early_overrun_err,
+			 max_cck->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_good:",
+			 le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+			 delta_cck->crc32_good, max_cck->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "false_alarm_cnt:",
+			 le32_to_cpu(cck->false_alarm_cnt),
+			 accum_cck->false_alarm_cnt,
+			 delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_sync_err_cnt:",
+			 le32_to_cpu(cck->fina_sync_err_cnt),
+			 accum_cck->fina_sync_err_cnt,
+			 delta_cck->fina_sync_err_cnt,
+			 max_cck->fina_sync_err_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sfd_timeout:",
+			 le32_to_cpu(cck->sfd_timeout),
+			 accum_cck->sfd_timeout, delta_cck->sfd_timeout,
+			 max_cck->sfd_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "fina_timeout:",
+			 le32_to_cpu(cck->fina_timeout),
+			 accum_cck->fina_timeout, delta_cck->fina_timeout,
+			 max_cck->fina_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "unresponded_rts:",
+			 le32_to_cpu(cck->unresponded_rts),
+			 accum_cck->unresponded_rts, delta_cck->unresponded_rts,
+			 max_cck->unresponded_rts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rxe_frame_lmt_ovrun:",
+			 le32_to_cpu(cck->rxe_frame_limit_overrun),
+			 accum_cck->rxe_frame_limit_overrun,
+			 delta_cck->rxe_frame_limit_overrun,
+			 max_cck->rxe_frame_limit_overrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ack_cnt:",
+			 le32_to_cpu(cck->sent_ack_cnt),
+			 accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
+			 max_cck->sent_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_cts_cnt:",
+			 le32_to_cpu(cck->sent_cts_cnt),
+			 accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
+			 max_cck->sent_cts_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sent_ba_rsp_cnt:",
+			 le32_to_cpu(cck->sent_ba_rsp_cnt),
+			 accum_cck->sent_ba_rsp_cnt,
+			 delta_cck->sent_ba_rsp_cnt,
+			 max_cck->sent_ba_rsp_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dsp_self_kill:",
+			 le32_to_cpu(cck->dsp_self_kill),
+			 accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
+			 max_cck->dsp_self_kill);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "mh_format_err:",
+			 le32_to_cpu(cck->mh_format_err),
+			 accum_cck->mh_format_err, delta_cck->mh_format_err,
+			 max_cck->mh_format_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "re_acq_main_rssi_sum:",
+			 le32_to_cpu(cck->re_acq_main_rssi_sum),
+			 accum_cck->re_acq_main_rssi_sum,
+			 delta_cck->re_acq_main_rssi_sum,
+			 max_cck->re_acq_main_rssi_sum);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - GENERAL:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bogus_cts:",
+			 le32_to_cpu(general->bogus_cts),
+			 accum_general->bogus_cts, delta_general->bogus_cts,
+			 max_general->bogus_cts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bogus_ack:",
+			 le32_to_cpu(general->bogus_ack),
+			 accum_general->bogus_ack, delta_general->bogus_ack,
+			 max_general->bogus_ack);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "non_bssid_frames:",
+			 le32_to_cpu(general->non_bssid_frames),
+			 accum_general->non_bssid_frames,
+			 delta_general->non_bssid_frames,
+			 max_general->non_bssid_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "filtered_frames:",
+			 le32_to_cpu(general->filtered_frames),
+			 accum_general->filtered_frames,
+			 delta_general->filtered_frames,
+			 max_general->filtered_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "non_channel_beacons:",
+			 le32_to_cpu(general->non_channel_beacons),
+			 accum_general->non_channel_beacons,
+			 delta_general->non_channel_beacons,
+			 max_general->non_channel_beacons);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "channel_beacons:",
+			 le32_to_cpu(general->channel_beacons),
+			 accum_general->channel_beacons,
+			 delta_general->channel_beacons,
+			 max_general->channel_beacons);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "num_missed_bcon:",
+			 le32_to_cpu(general->num_missed_bcon),
+			 accum_general->num_missed_bcon,
+			 delta_general->num_missed_bcon,
+			 max_general->num_missed_bcon);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "adc_rx_saturation_time:",
+			 le32_to_cpu(general->adc_rx_saturation_time),
+			 accum_general->adc_rx_saturation_time,
+			 delta_general->adc_rx_saturation_time,
+			 max_general->adc_rx_saturation_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ina_detect_search_tm:",
+			 le32_to_cpu(general->ina_detection_search_time),
+			 accum_general->ina_detection_search_time,
+			 delta_general->ina_detection_search_time,
+			 max_general->ina_detection_search_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_silence_rssi_a:",
+			 le32_to_cpu(general->beacon_silence_rssi_a),
+			 accum_general->beacon_silence_rssi_a,
+			 delta_general->beacon_silence_rssi_a,
+			 max_general->beacon_silence_rssi_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_silence_rssi_b:",
+			 le32_to_cpu(general->beacon_silence_rssi_b),
+			 accum_general->beacon_silence_rssi_b,
+			 delta_general->beacon_silence_rssi_b,
+			 max_general->beacon_silence_rssi_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_silence_rssi_c:",
+			 le32_to_cpu(general->beacon_silence_rssi_c),
+			 accum_general->beacon_silence_rssi_c,
+			 delta_general->beacon_silence_rssi_c,
+			 max_general->beacon_silence_rssi_c);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "interference_data_flag:",
+			 le32_to_cpu(general->interference_data_flag),
+			 accum_general->interference_data_flag,
+			 delta_general->interference_data_flag,
+			 max_general->interference_data_flag);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "channel_load:",
+			 le32_to_cpu(general->channel_load),
+			 accum_general->channel_load,
+			 delta_general->channel_load,
+			 max_general->channel_load);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dsp_false_alarms:",
+			 le32_to_cpu(general->dsp_false_alarms),
+			 accum_general->dsp_false_alarms,
+			 delta_general->dsp_false_alarms,
+			 max_general->dsp_false_alarms);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_rssi_a:",
+			 le32_to_cpu(general->beacon_rssi_a),
+			 accum_general->beacon_rssi_a,
+			 delta_general->beacon_rssi_a,
+			 max_general->beacon_rssi_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_rssi_b:",
+			 le32_to_cpu(general->beacon_rssi_b),
+			 accum_general->beacon_rssi_b,
+			 delta_general->beacon_rssi_b,
+			 max_general->beacon_rssi_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_rssi_c:",
+			 le32_to_cpu(general->beacon_rssi_c),
+			 accum_general->beacon_rssi_c,
+			 delta_general->beacon_rssi_c,
+			 max_general->beacon_rssi_c);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_energy_a:",
+			 le32_to_cpu(general->beacon_energy_a),
+			 accum_general->beacon_energy_a,
+			 delta_general->beacon_energy_a,
+			 max_general->beacon_energy_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_energy_b:",
+			 le32_to_cpu(general->beacon_energy_b),
+			 accum_general->beacon_energy_b,
+			 delta_general->beacon_energy_b,
+			 max_general->beacon_energy_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "beacon_energy_c:",
+			 le32_to_cpu(general->beacon_energy_c),
+			 accum_general->beacon_energy_c,
+			 delta_general->beacon_energy_c,
+			 max_general->beacon_energy_c);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Rx - OFDM_HT:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "plcp_err:",
+			 le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
+			 delta_ht->plcp_err, max_ht->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "overrun_err:",
+			 le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
+			 delta_ht->overrun_err, max_ht->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "early_overrun_err:",
+			 le32_to_cpu(ht->early_overrun_err),
+			 accum_ht->early_overrun_err,
+			 delta_ht->early_overrun_err,
+			 max_ht->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_good:",
+			 le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
+			 delta_ht->crc32_good, max_ht->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "crc32_err:",
+			 le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
+			 delta_ht->crc32_err, max_ht->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "mh_format_err:",
+			 le32_to_cpu(ht->mh_format_err),
+			 accum_ht->mh_format_err,
+			 delta_ht->mh_format_err, max_ht->mh_format_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg_crc32_good:",
+			 le32_to_cpu(ht->agg_crc32_good),
+			 accum_ht->agg_crc32_good,
+			 delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg_mpdu_cnt:",
+			 le32_to_cpu(ht->agg_mpdu_cnt),
+			 accum_ht->agg_mpdu_cnt,
+			 delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg_cnt:",
+			 le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
+			 delta_ht->agg_cnt, max_ht->agg_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "unsupport_mcs:",
+			 le32_to_cpu(ht->unsupport_mcs),
+			 accum_ht->unsupport_mcs,
+			 delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
 }
 
 static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
@@ -1051,8 +1502,190 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
 					size_t count, loff_t *ppos)
 {
 	struct iwl_priv *priv = file->private_data;
-	return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
-			user_buf, count, ppos);
+	int pos = 0;
+	char *buf;
+	int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
+	ssize_t ret;
+	struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/* the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	tx = &priv->statistics.tx;
+	accum_tx = &priv->accum_stats.tx;
+	delta_tx = &priv->delta_stats.tx;
+	max_tx = &priv->max_delta_stats.tx;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_Tx:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "preamble:",
+			 le32_to_cpu(tx->preamble_cnt),
+			 accum_tx->preamble_cnt,
+			 delta_tx->preamble_cnt, max_tx->preamble_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rx_detected_cnt:",
+			 le32_to_cpu(tx->rx_detected_cnt),
+			 accum_tx->rx_detected_cnt,
+			 delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bt_prio_defer_cnt:",
+			 le32_to_cpu(tx->bt_prio_defer_cnt),
+			 accum_tx->bt_prio_defer_cnt,
+			 delta_tx->bt_prio_defer_cnt,
+			 max_tx->bt_prio_defer_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "bt_prio_kill_cnt:",
+			 le32_to_cpu(tx->bt_prio_kill_cnt),
+			 accum_tx->bt_prio_kill_cnt,
+			 delta_tx->bt_prio_kill_cnt,
+			 max_tx->bt_prio_kill_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "few_bytes_cnt:",
+			 le32_to_cpu(tx->few_bytes_cnt),
+			 accum_tx->few_bytes_cnt,
+			 delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "cts_timeout:",
+			 le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+			 delta_tx->cts_timeout, max_tx->cts_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ack_timeout:",
+			 le32_to_cpu(tx->ack_timeout),
+			 accum_tx->ack_timeout,
+			 delta_tx->ack_timeout, max_tx->ack_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "expected_ack_cnt:",
+			 le32_to_cpu(tx->expected_ack_cnt),
+			 accum_tx->expected_ack_cnt,
+			 delta_tx->expected_ack_cnt,
+			 max_tx->expected_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "actual_ack_cnt:",
+			 le32_to_cpu(tx->actual_ack_cnt),
+			 accum_tx->actual_ack_cnt,
+			 delta_tx->actual_ack_cnt,
+			 max_tx->actual_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "dump_msdu_cnt:",
+			 le32_to_cpu(tx->dump_msdu_cnt),
+			 accum_tx->dump_msdu_cnt,
+			 delta_tx->dump_msdu_cnt,
+			 max_tx->dump_msdu_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "abort_nxt_frame_mismatch:",
+			 le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
+			 accum_tx->burst_abort_next_frame_mismatch_cnt,
+			 delta_tx->burst_abort_next_frame_mismatch_cnt,
+			 max_tx->burst_abort_next_frame_mismatch_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "abort_missing_nxt_frame:",
+			 le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
+			 accum_tx->burst_abort_missing_next_frame_cnt,
+			 delta_tx->burst_abort_missing_next_frame_cnt,
+			 max_tx->burst_abort_missing_next_frame_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "cts_timeout_collision:",
+			 le32_to_cpu(tx->cts_timeout_collision),
+			 accum_tx->cts_timeout_collision,
+			 delta_tx->cts_timeout_collision,
+			 max_tx->cts_timeout_collision);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "ack_ba_timeout_collision:",
+			 le32_to_cpu(tx->ack_or_ba_timeout_collision),
+			 accum_tx->ack_or_ba_timeout_collision,
+			 delta_tx->ack_or_ba_timeout_collision,
+			 max_tx->ack_or_ba_timeout_collision);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg ba_timeout:",
+			 le32_to_cpu(tx->agg.ba_timeout),
+			 accum_tx->agg.ba_timeout,
+			 delta_tx->agg.ba_timeout,
+			 max_tx->agg.ba_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg ba_resched_frames:",
+			 le32_to_cpu(tx->agg.ba_reschedule_frames),
+			 accum_tx->agg.ba_reschedule_frames,
+			 delta_tx->agg.ba_reschedule_frames,
+			 max_tx->agg.ba_reschedule_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_agg_frame:",
+			 le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
+			 accum_tx->agg.scd_query_agg_frame_cnt,
+			 delta_tx->agg.scd_query_agg_frame_cnt,
+			 max_tx->agg.scd_query_agg_frame_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_no_agg:",
+			 le32_to_cpu(tx->agg.scd_query_no_agg),
+			 accum_tx->agg.scd_query_no_agg,
+			 delta_tx->agg.scd_query_no_agg,
+			 max_tx->agg.scd_query_no_agg);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_agg:",
+			 le32_to_cpu(tx->agg.scd_query_agg),
+			 accum_tx->agg.scd_query_agg,
+			 delta_tx->agg.scd_query_agg,
+			 max_tx->agg.scd_query_agg);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg scd_query_mismatch:",
+			 le32_to_cpu(tx->agg.scd_query_mismatch),
+			 accum_tx->agg.scd_query_mismatch,
+			 delta_tx->agg.scd_query_mismatch,
+			 max_tx->agg.scd_query_mismatch);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg frame_not_ready:",
+			 le32_to_cpu(tx->agg.frame_not_ready),
+			 accum_tx->agg.frame_not_ready,
+			 delta_tx->agg.frame_not_ready,
+			 max_tx->agg.frame_not_ready);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg underrun:",
+			 le32_to_cpu(tx->agg.underrun),
+			 accum_tx->agg.underrun,
+			 delta_tx->agg.underrun, max_tx->agg.underrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg bt_prio_kill:",
+			 le32_to_cpu(tx->agg.bt_prio_kill),
+			 accum_tx->agg.bt_prio_kill,
+			 delta_tx->agg.bt_prio_kill,
+			 max_tx->agg.bt_prio_kill);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "agg rx_ba_rsp_cnt:",
+			 le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
+			 accum_tx->agg.rx_ba_rsp_cnt,
+			 delta_tx->agg.rx_ba_rsp_cnt,
+			 max_tx->agg.rx_ba_rsp_cnt);
+
+	if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
+		pos += scnprintf(buf + pos, bufsz - pos,
+			"tx power: (1/2 dB step)\n");
+		if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					fmt_hex, "antenna A:",
+					tx->tx_power.ant_a);
+		if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					fmt_hex, "antenna B:",
+					tx->tx_power.ant_b);
+		if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
+			pos += scnprintf(buf + pos, bufsz - pos,
+					fmt_hex, "antenna C:",
+					tx->tx_power.ant_c);
+	}
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
 }
 
 static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
@@ -1060,8 +1693,347 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
 					size_t count, loff_t *ppos)
 {
 	struct iwl_priv *priv = file->private_data;
-	return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
-			user_buf, count, ppos);
+	int pos = 0;
+	char *buf;
+	int bufsz = sizeof(struct statistics_general) * 10 + 300;
+	ssize_t ret;
+	struct statistics_general_common *general, *accum_general;
+	struct statistics_general_common *delta_general, *max_general;
+	struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+	struct statistics_div *div, *accum_div, *delta_div, *max_div;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/* the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	general = &priv->statistics.common;
+	dbg = &priv->statistics.common.dbg;
+	div = &priv->statistics.common.div;
+	accum_general = &priv->accum_stats.common;
+	accum_dbg = &priv->accum_stats.common.dbg;
+	accum_div = &priv->accum_stats.common.div;
+	delta_general = &priv->delta_stats.common;
+	max_general = &priv->max_delta_stats.common;
+	delta_dbg = &priv->delta_stats.common.dbg;
+	max_dbg = &priv->max_delta_stats.common.dbg;
+	delta_div = &priv->delta_stats.common.div;
+	max_div = &priv->max_delta_stats.common.div;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_header, "Statistics_General:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_value, "temperature:",
+			 le32_to_cpu(general->temperature));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_value, "temperature_m:",
+			 le32_to_cpu(general->temperature_m));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_value, "ttl_timestamp:",
+			 le32_to_cpu(general->ttl_timestamp));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "burst_check:",
+			 le32_to_cpu(dbg->burst_check),
+			 accum_dbg->burst_check,
+			 delta_dbg->burst_check, max_dbg->burst_check);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "burst_count:",
+			 le32_to_cpu(dbg->burst_count),
+			 accum_dbg->burst_count,
+			 delta_dbg->burst_count, max_dbg->burst_count);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "wait_for_silence_timeout_count:",
+			 le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
+			 accum_dbg->wait_for_silence_timeout_cnt,
+			 delta_dbg->wait_for_silence_timeout_cnt,
+			 max_dbg->wait_for_silence_timeout_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "sleep_time:",
+			 le32_to_cpu(general->sleep_time),
+			 accum_general->sleep_time,
+			 delta_general->sleep_time, max_general->sleep_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "slots_out:",
+			 le32_to_cpu(general->slots_out),
+			 accum_general->slots_out,
+			 delta_general->slots_out, max_general->slots_out);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "slots_idle:",
+			 le32_to_cpu(general->slots_idle),
+			 accum_general->slots_idle,
+			 delta_general->slots_idle, max_general->slots_idle);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "tx_on_a:",
+			 le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+			 delta_div->tx_on_a, max_div->tx_on_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "tx_on_b:",
+			 le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+			 delta_div->tx_on_b, max_div->tx_on_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "exec_time:",
+			 le32_to_cpu(div->exec_time), accum_div->exec_time,
+			 delta_div->exec_time, max_div->exec_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "probe_time:",
+			 le32_to_cpu(div->probe_time), accum_div->probe_time,
+			 delta_div->probe_time, max_div->probe_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "rx_enable_counter:",
+			 le32_to_cpu(general->rx_enable_counter),
+			 accum_general->rx_enable_counter,
+			 delta_general->rx_enable_counter,
+			 max_general->rx_enable_counter);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 fmt_table, "num_of_sos_states:",
+			 le32_to_cpu(general->num_of_sos_states),
+			 accum_general->num_of_sos_states,
+			 delta_general->num_of_sos_states,
+			 max_general->num_of_sos_states);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200;
+	ssize_t ret;
+	struct statistics_bt_activity *bt, *accum_bt;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	if (!priv->bt_enable_flag)
+		return -EINVAL;
+
+	/* make request to uCode to retrieve statistics information */
+	mutex_lock(&priv->mutex);
+	ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
+	mutex_unlock(&priv->mutex);
+
+	if (ret) {
+		IWL_ERR(priv,
+			"Error sending statistics request: %zd\n", ret);
+		return -EAGAIN;
+	}
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * the statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	bt = &priv->statistics.bt_activity;
+	accum_bt = &priv->accum_stats.bt_activity;
+
+	pos += iwl_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"\t\t\tcurrent\t\t\taccumulative\n");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_tx_req_cnt),
+			 accum_bt->hi_priority_tx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_tx_denied_cnt),
+			 accum_bt->hi_priority_tx_denied_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_tx_req_cnt),
+			 accum_bt->lo_priority_tx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_tx_denied_cnt),
+			 accum_bt->lo_priority_tx_denied_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_rx_req_cnt),
+			 accum_bt->hi_priority_rx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->hi_priority_rx_denied_cnt),
+			 accum_bt->hi_priority_rx_denied_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_rx_req_cnt),
+			 accum_bt->lo_priority_rx_req_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+			 le32_to_cpu(bt->lo_priority_rx_denied_cnt),
+			 accum_bt->lo_priority_rx_denied_cnt);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
+			 le32_to_cpu(priv->statistics.num_bt_kills),
+			 priv->statistics.accum_num_bt_kills);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) +
+		(sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
+	ssize_t ret;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
+			 priv->_agn.reply_tx_stats.pp_delay);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
+			 priv->_agn.reply_tx_stats.pp_few_bytes);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
+			 priv->_agn.reply_tx_stats.pp_bt_prio);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
+			 priv->_agn.reply_tx_stats.pp_quiet_period);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
+			 priv->_agn.reply_tx_stats.pp_calc_ttak);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_tx_fail_reason(
+				TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
+			 priv->_agn.reply_tx_stats.int_crossed_retry);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
+			 priv->_agn.reply_tx_stats.short_limit);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
+			 priv->_agn.reply_tx_stats.long_limit);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
+			 priv->_agn.reply_tx_stats.fifo_underrun);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
+			 priv->_agn.reply_tx_stats.drain_flow);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
+			 priv->_agn.reply_tx_stats.rfkill_flush);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
+			 priv->_agn.reply_tx_stats.life_expire);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
+			 priv->_agn.reply_tx_stats.dest_ps);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
+			 priv->_agn.reply_tx_stats.host_abort);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
+			 priv->_agn.reply_tx_stats.pp_delay);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
+			 priv->_agn.reply_tx_stats.sta_invalid);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
+			 priv->_agn.reply_tx_stats.frag_drop);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
+			 priv->_agn.reply_tx_stats.tid_disable);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
+			 priv->_agn.reply_tx_stats.fifo_flush);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_tx_fail_reason(
+				TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
+			 priv->_agn.reply_tx_stats.insuff_cf_poll);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
+			 priv->_agn.reply_tx_stats.fail_hw_drop);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_tx_fail_reason(
+				TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
+			 priv->_agn.reply_tx_stats.sta_color_mismatch);
+	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+			 priv->_agn.reply_tx_stats.unknown);
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "\nStatistics_Agg_TX_Error:\n");
+
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
+			 priv->_agn.reply_agg_tx_stats.underrun);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
+			 priv->_agn.reply_agg_tx_stats.bt_prio);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
+			 priv->_agn.reply_agg_tx_stats.few_bytes);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
+			 priv->_agn.reply_agg_tx_stats.abort);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_LAST_SENT_TTL_MSK),
+			 priv->_agn.reply_agg_tx_stats.last_sent_ttl);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
+			 priv->_agn.reply_agg_tx_stats.last_sent_try);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
+			 priv->_agn.reply_agg_tx_stats.last_sent_bt_kill);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
+			 priv->_agn.reply_agg_tx_stats.scd_query);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(
+				AGG_TX_STATE_TEST_BAD_CRC32_MSK),
+			 priv->_agn.reply_agg_tx_stats.bad_crc32);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
+			 priv->_agn.reply_agg_tx_stats.response);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
+			 priv->_agn.reply_agg_tx_stats.dump_tx);
+	pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+			 iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
+			 priv->_agn.reply_agg_tx_stats.delay_tx);
+	pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+			 priv->_agn.reply_agg_tx_stats.unknown);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
 }
 
 static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
@@ -1526,16 +2498,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
 	return count;
 }
 
-static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-
-	return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file,
-			user_buf, count, ppos);
-}
-
 static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
 					const char __user *user_buf,
 					size_t count, loff_t *ppos) {
@@ -1650,18 +2612,6 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
 	return count;
 }
 
-static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
-					char __user *user_buf,
-					size_t count, loff_t *ppos)
-{
-	struct iwl_priv *priv = file->private_data;
-
-	if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error)
-		return priv->cfg->ops->lib->debugfs_ops.reply_tx_error(
-			file, user_buf, count, ppos);
-	else
-		return -ENODATA;
-}
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index e84534c4d9560b7374bc00f7605580604a512f75..f098eff263f87704dc8657d202e81be176daffe5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -479,6 +479,10 @@ struct fw_desc {
 	u32 len;		/* bytes */
 };
 
+struct fw_img {
+	struct fw_desc code, data;
+};
+
 /* v1/v2 uCode file layout */
 struct iwl_ucode_header {
 	__le32 ver;	/* major/minor/API/serial */
@@ -543,12 +547,13 @@ enum iwl_ucode_tlv_type {
  * enum iwl_ucode_tlv_flag - ucode API flags
  * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
  *	was a separate TLV but moved here to save space.
- * @IWL_UCODE_TLV_FLAGS_RESERVED_1: reserved
+ * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID,
+ *	treats good CRC threshold as a boolean
  * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
  */
 enum iwl_ucode_tlv_flag {
 	IWL_UCODE_TLV_FLAGS_PAN		= BIT(0),
-	IWL_UCODE_TLV_FLAGS_RESERVED_1	= BIT(1),
+	IWL_UCODE_TLV_FLAGS_NEWSCAN	= BIT(1),
 	IWL_UCODE_TLV_FLAGS_MFP		= BIT(2),
 };
 
@@ -794,12 +799,6 @@ struct iwl_calib_result {
 	size_t buf_len;
 };
 
-enum ucode_type {
-	UCODE_NONE = 0,
-	UCODE_INIT,
-	UCODE_RT
-};
-
 /* Sensitivity calib data */
 struct iwl_sensitivity_data {
 	u32 auto_corr_ofdm;
@@ -1105,10 +1104,12 @@ struct iwl_force_reset {
 struct iwl_notification_wait {
 	struct list_head list;
 
-	void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt);
+	void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt,
+		   void *data);
+	void *fn_data;
 
 	u8 cmd;
-	bool triggered;
+	bool triggered, aborted;
 };
 
 enum iwl_rxon_context_id {
@@ -1263,6 +1264,8 @@ struct iwl_priv {
 	/* max number of station keys */
 	u8 sta_key_max_num;
 
+	bool new_scan_threshold_behaviour;
+
 	/* EEPROM MAC addresses */
 	struct mac_address addresses[2];
 
@@ -1270,11 +1273,10 @@ struct iwl_priv {
 	int fw_index;			/* firmware we're trying to load */
 	u32 ucode_ver;			/* version of ucode, copy of
 					   iwl_ucode.ver */
-	struct fw_desc ucode_code;	/* runtime inst */
-	struct fw_desc ucode_data;	/* runtime data original */
-	struct fw_desc ucode_init;	/* initialization inst */
-	struct fw_desc ucode_init_data;	/* initialization data */
-	enum ucode_type ucode_type;
+	struct fw_img ucode_rt;
+	struct fw_img ucode_init;
+
+	enum iwlagn_ucode_subtype ucode_type;
 	u8 ucode_write_complete;	/* the image write is complete */
 	char firmware_name[25];
 
@@ -1472,8 +1474,6 @@ struct iwl_priv {
 
 	struct tasklet_struct irq_tasklet;
 
-	struct delayed_work init_alive_start;
-	struct delayed_work alive_start;
 	struct delayed_work scan_check;
 
 	/* TX Power */
@@ -1506,7 +1506,6 @@ struct iwl_priv {
 	struct timer_list statistics_periodic;
 	struct timer_list ucode_trace;
 	struct timer_list watchdog;
-	bool hw_ready;
 
 	struct iwl_event_log event_log;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 402733638f50719907e6bbd4727203bf6182f5a5..c8397962632c97f2a830205390a0c7350c54a48e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -142,6 +142,45 @@ static const u8 iwl_eeprom_band_7[] = {       /* 5.2 ht40 channel */
  *
 ******************************************************************************/
 
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
+{
+	u16 count;
+	int ret;
+
+	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+		/* Request semaphore */
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+		/* See if we got it */
+		ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+				EEPROM_SEM_TIMEOUT);
+		if (ret >= 0) {
+			IWL_DEBUG_EEPROM(priv,
+				"Acquired semaphore after %d tries.\n",
+				count+1);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+{
+	iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+}
+
 static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
 {
 	u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
@@ -421,7 +460,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
 	}
 
 	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
-	ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv);
+	ret = iwl_eeprom_acquire_semaphore(priv);
 	if (ret < 0) {
 		IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
 		ret = -ENOENT;
@@ -488,7 +527,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
 
 	ret = 0;
 done:
-	priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
+	iwl_eeprom_release_semaphore(priv);
 
 err:
 	if (ret)
@@ -711,13 +750,6 @@ int iwl_init_channel_map(struct iwl_priv *priv)
 					     flags & EEPROM_CHANNEL_RADAR))
 				       ? "" : "not ");
 
-			/* Set the tx_power_user_lmt to the highest power
-			 * supported by any channel */
-			if (eeprom_ch_info[ch].max_power_avg >
-						priv->tx_power_user_lmt)
-				priv->tx_power_user_lmt =
-				    eeprom_ch_info[ch].max_power_avg;
-
 			ch_info++;
 		}
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 9ce052573c6afb1d967159fbfef1f29b1c6b941e..c960c6fa009b32105be1233d9fa9062a74328fa0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -294,9 +294,6 @@ extern const u8 iwl_eeprom_band_1[14];
 
 struct iwl_eeprom_ops {
 	const u32 regulatory_bands[7];
-	int (*acquire_semaphore) (struct iwl_priv *priv);
-	void (*release_semaphore) (struct iwl_priv *priv);
-	u16 (*calib_version) (struct iwl_priv *priv);
 	const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
 	void (*update_enhanced_txpower) (struct iwl_priv *priv);
 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 9309ff2df4c219e1b44fc882edab4e16c728300e..41207a3645b81540c0d4d84aeff81e5e25ae4b44 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)
 	return --index & (n_bd - 1);
 }
 
-/* TODO: Move fw_desc functions to iwl-pci.ko */
-static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
-				    struct fw_desc *desc)
-{
-	if (desc->v_addr)
-		dma_free_coherent(&pci_dev->dev, desc->len,
-				  desc->v_addr, desc->p_addr);
-	desc->v_addr = NULL;
-	desc->len = 0;
-}
-
-static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
-				    struct fw_desc *desc)
-{
-	if (!desc->len) {
-		desc->v_addr = NULL;
-		return -EINVAL;
-	}
-
-	desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
-					  &desc->p_addr, GFP_KERNEL);
-	return (desc->v_addr != NULL) ? 0 : -ENOMEM;
-}
-
 /*
  * we have 8 bits used like this:
  *
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 51337416e4ca76b8e630b1337afaa26b2b203e21..aa4a90674452ef218c68262d748e835a9b9bc2be 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -73,10 +73,9 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
 	return -ETIMEDOUT;
 }
 
-int iwl_grab_nic_access(struct iwl_priv *priv)
+int iwl_grab_nic_access_silent(struct iwl_priv *priv)
 {
 	int ret;
-	u32 val;
 
 	lockdep_assert_held(&priv->reg_lock);
 
@@ -107,9 +106,6 @@ int iwl_grab_nic_access(struct iwl_priv *priv)
 			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
 			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
 	if (ret < 0) {
-		val = iwl_read32(priv, CSR_GP_CNTRL);
-		IWL_ERR(priv,
-			"MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
 		iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
 		return -EIO;
 	}
@@ -117,6 +113,18 @@ int iwl_grab_nic_access(struct iwl_priv *priv)
 	return 0;
 }
 
+int iwl_grab_nic_access(struct iwl_priv *priv)
+{
+	int ret = iwl_grab_nic_access_silent(priv);
+	if (ret) {
+		u32 val = iwl_read32(priv, CSR_GP_CNTRL);
+		IWL_ERR(priv,
+			"MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
+	}
+
+	return ret;
+}
+
 void iwl_release_nic_access(struct iwl_priv *priv)
 {
 	lockdep_assert_held(&priv->reg_lock);
@@ -242,20 +250,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
 	spin_unlock_irqrestore(&priv->reg_lock, flags);
 }
 
-u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
+void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
+			      void *buf, int words)
 {
 	unsigned long flags;
-	u32 value;
+	int offs;
+	u32 *vals = buf;
 
 	spin_lock_irqsave(&priv->reg_lock, flags);
 	iwl_grab_nic_access(priv);
 
 	iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr);
 	rmb();
-	value = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+
+	for (offs = 0; offs < words; offs++)
+		vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
 
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
+{
+	u32 value;
+
+	_iwl_read_targ_mem_words(priv, addr, &value, 1);
+
 	return value;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index ab632baf49d51d9347f963558dc22bb8ef4d1800..869edc580ec6c461ae0f01da7b968a0de5af868e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -62,6 +62,7 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
 int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
 			int timeout);
 
+int iwl_grab_nic_access_silent(struct iwl_priv *priv);
 int iwl_grab_nic_access(struct iwl_priv *priv);
 void iwl_release_nic_access(struct iwl_priv *priv);
 
@@ -76,6 +77,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
 			    u32 bits, u32 mask);
 void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
 
+void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
+			      void *buf, int words);
+
+#define iwl_read_targ_mem_words(priv, addr, buf, bufsize)	\
+	do {							\
+		BUILD_BUG_ON((bufsize) % sizeof(u32));		\
+		_iwl_read_targ_mem_words(priv, addr, buf,	\
+					 (bufsize) / sizeof(u32));\
+	} while (0)
+
 u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr);
 void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val);
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index b49819ca2cd68d7a1fcf9bb2e431dc3f4c4db1c4..0053e9ea9021a433b98025701fcc1e9d703ea1f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -225,55 +225,6 @@ err_bd:
  *
  ******************************************************************************/
 
-static void iwl_rx_reply_alive(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = rxb_addr(rxb);
-	struct iwl_alive_resp *palive;
-	struct delayed_work *pwork;
-
-	palive = &pkt->u.alive_frame;
-
-	IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision "
-		       "0x%01X 0x%01X\n",
-		       palive->is_valid, palive->ver_type,
-		       palive->ver_subtype);
-
-	priv->device_pointers.log_event_table =
-		le32_to_cpu(palive->log_event_table_ptr);
-	priv->device_pointers.error_event_table =
-		le32_to_cpu(palive->error_event_table_ptr);
-
-	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
-		IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
-		pwork = &priv->init_alive_start;
-	} else {
-		IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
-		pwork = &priv->alive_start;
-	}
-
-	/* We delay the ALIVE response by 5ms to
-	 * give the HW RF Kill time to activate... */
-	if (palive->is_valid == UCODE_VALID_OK)
-		queue_delayed_work(priv->workqueue, pwork,
-				   msecs_to_jiffies(5));
-	else {
-		IWL_WARN(priv, "%s uCode did not respond OK.\n",
-			(palive->ver_subtype == INITIALIZE_SUBTYPE) ?
-			"init" : "runtime");
-		/*
-		 * If fail to load init uCode,
-		 * let's try to load the init uCode again.
-		 * We should not get into this situation, but if it
-		 * does happen, we should not move on and loading "runtime"
-		 * without proper calibrate the device.
-		 */
-		if (palive->ver_subtype == INITIALIZE_SUBTYPE)
-			priv->ucode_type = UCODE_NONE;
-		queue_work(priv->workqueue, &priv->restart);
-	}
-}
-
 static void iwl_rx_reply_error(struct iwl_priv *priv,
 			       struct iwl_rx_mem_buffer *rxb)
 {
@@ -482,7 +433,6 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv,
 					struct statistics_tx *tx,
 					unsigned long stamp)
 {
-	const struct iwl_mod_params *mod_params = priv->cfg->mod_params;
 	unsigned int msecs;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -498,13 +448,13 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv,
 	if (msecs < 99)
 		return;
 
-	if (mod_params->ack_check && !iwl_good_ack_health(priv, tx)) {
+	if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) {
 		IWL_ERR(priv, "low ack count detected, restart firmware\n");
 		if (!iwl_force_reset(priv, IWL_FW_RESET, false))
 			return;
 	}
 
-	if (mod_params->plcp_check &&
+	if (iwlagn_mod_params.plcp_check &&
 	    !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
 		iwl_force_reset(priv, IWL_RF_RESET, false);
 }
@@ -895,7 +845,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
 	}
 
 	/* In case of HW accelerated crypto and bad decryption, drop */
-	if (!priv->cfg->mod_params->sw_crypto &&
+	if (!iwlagn_mod_params.sw_crypto &&
 	    iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
 		return;
 
@@ -1125,7 +1075,6 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
 
 	handlers = priv->rx_handlers;
 
-	handlers[REPLY_ALIVE]			= iwl_rx_reply_alive;
 	handlers[REPLY_ERROR]			= iwl_rx_reply_error;
 	handlers[CHANNEL_SWITCH_NOTIFICATION]	= iwl_rx_csa;
 	handlers[SPECTRUM_MEASURE_NOTIFICATION]	= iwl_rx_spectrum_measure_notif;
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
deleted file mode 100644
index cb80bb4ce45ee3d380485abac0fee25c299f6145..0000000000000000000000000000000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwl_spectrum_h__
-#define __iwl_spectrum_h__
-enum {				/* ieee80211_basic_report.map */
-	IEEE80211_BASIC_MAP_BSS = (1 << 0),
-	IEEE80211_BASIC_MAP_OFDM = (1 << 1),
-	IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
-	IEEE80211_BASIC_MAP_RADAR = (1 << 3),
-	IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
-	/* Bits 5-7 are reserved */
-
-};
-struct ieee80211_basic_report {
-	u8 channel;
-	__le64 start_time;
-	__le16 duration;
-	u8 map;
-} __packed;
-
-enum {				/* ieee80211_measurement_request.mode */
-	/* Bit 0 is reserved */
-	IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
-	IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
-	IEEE80211_MEASUREMENT_REPORT = (1 << 3),
-	/* Bits 4-7 are reserved */
-};
-
-enum {
-	IEEE80211_REPORT_BASIC = 0,	/* required */
-	IEEE80211_REPORT_CCA = 1,	/* optional */
-	IEEE80211_REPORT_RPI = 2,	/* optional */
-	/* 3-255 reserved */
-};
-
-struct ieee80211_measurement_params {
-	u8 channel;
-	__le64 start_time;
-	__le16 duration;
-} __packed;
-
-struct ieee80211_info_element {
-	u8 id;
-	u8 len;
-	u8 data[0];
-} __packed;
-
-struct ieee80211_measurement_request {
-	struct ieee80211_info_element ie;
-	u8 token;
-	u8 mode;
-	u8 type;
-	struct ieee80211_measurement_params params[0];
-} __packed;
-
-struct ieee80211_measurement_report {
-	struct ieee80211_info_element ie;
-	u8 token;
-	u8 mode;
-	u8 type;
-	union {
-		struct ieee80211_basic_report basic[0];
-	} u;
-} __packed;
-
-#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 80c3565a66ae5361810d87de034f1284b3ed94d8..52b1b66f32d0c026e6fe84d1d606d76e7ed8b995 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -621,9 +621,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	struct iwl_cmd_meta *meta;
 	struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
 	unsigned long flags;
-	void (*callback) (struct iwl_priv *priv, struct iwl_device_cmd *cmd,
-			  struct iwl_rx_packet *pkt);
-
 
 	/* If a Tx command is being handled and it isn't in the actual
 	 * command queue then there a command routing bug has been introduced
@@ -637,8 +634,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 		return;
 	}
 
-	spin_lock_irqsave(&priv->hcmd_lock, flags);
-
 	cmd_index = get_cmd_index(&txq->q, index, huge);
 	cmd = txq->cmd[cmd_index];
 	meta = &txq->meta[cmd_index];
@@ -648,13 +643,14 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 			 dma_unmap_len(meta, len),
 			 PCI_DMA_BIDIRECTIONAL);
 
-	callback = NULL;
 	/* Input error checking is done when commands are added to queue. */
 	if (meta->flags & CMD_WANT_SKB) {
 		meta->source->reply_page = (unsigned long)rxb_addr(rxb);
 		rxb->page = NULL;
-	} else
-		callback = meta->callback;
+	} else if (meta->callback)
+		meta->callback(priv, cmd, pkt);
+
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
 
 	iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
 
@@ -669,7 +665,4 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	meta->flags = 0;
 
 	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
-
-	if (callback)
-		callback(priv, cmd, pkt);
 }
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 5caa2ac14d61083042c5cc841742c359742a9e1b..486544e01a56f2c9832f69b7fda7638d4e2a154a 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -122,8 +122,10 @@ static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
 }
 
 
-/* Various firmware commands need the list of supported rates, but with
-   the hight-bit set for basic rates */
+/*
+ * Various firmware commands need the list of supported rates, but with
+ * the hight-bit set for basic rates
+ */
 static int lbs_add_rates(u8 *rates)
 {
 	size_t i;
@@ -425,7 +427,7 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
 	return ie_len + 2;
 }
 
-/***************************************************************************
+/*
  * Set Channel
  */
 
@@ -452,7 +454,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
 
 
 
-/***************************************************************************
+/*
  * Scanning
  */
 
@@ -538,8 +540,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
 		goto done;
 	}
 
-	/* Validity check: the TLV holds TSF values with 8 bytes each, so
-	 * the size in the TLV must match the nr_sets value */
+	/*
+	 * Validity check: the TLV holds TSF values with 8 bytes each, so
+	 * the size in the TLV must match the nr_sets value
+	 */
 	i = get_unaligned_le16(tsfdesc);
 	tsfdesc += 2;
 	if (i / 8 != scanresp->nr_sets) {
@@ -581,8 +585,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
 
 		/* To find out the channel, we must parse the IEs */
 		ie = pos;
-		/* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
-		   interval, capabilities */
+		/*
+		 * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
+		 * interval, capabilities
+		 */
 		ielen = left = len - (6 + 1 + 8 + 2 + 2);
 		while (left >= 2) {
 			u8 id, elen;
@@ -790,7 +796,7 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
 
 
 
-/***************************************************************************
+/*
  * Events
  */
 
@@ -825,7 +831,7 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
 
 
 
-/***************************************************************************
+/*
  * Connect/disconnect
  */
 
@@ -950,8 +956,10 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable)
  * Set WPA/WPA key material
  */
 
-/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
- * get rid of WEXT, this should go into host.h */
+/*
+ * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
+ * get rid of WEXT, this should go into host.h
+ */
 
 struct cmd_key_material {
 	struct cmd_header hdr;
@@ -1536,7 +1544,7 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
 }
 
 
-/***************************************************************************
+/*
  * Get station
  */
 
@@ -1581,7 +1589,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
 
 
 
-/***************************************************************************
+/*
  * "Site survey", here just current channel and noise level
  */
 
@@ -1614,7 +1622,7 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
 
 
 
-/***************************************************************************
+/*
  * Change interface
  */
 
@@ -1656,11 +1664,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
 
 
 
-/***************************************************************************
+/*
  * IBSS (Ad-Hoc)
  */
 
-/* The firmware needs the following bits masked out of the beacon-derived
+/*
+ * The firmware needs the following bits masked out of the beacon-derived
  * capability field when associating/joining to a BSS:
  *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
  */
@@ -1999,7 +2008,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 
 
 
-/***************************************************************************
+/*
  * Initialization
  */
 
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 7e8a658b7670ee580b5a8a84094beb9c6de86dd7..6a96fc9c1cea4d7fc9d9359d6c50c7f7c15219fe 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1,7 +1,7 @@
-/**
-  * This file contains the handling of command.
-  * It prepares command and sends it to firmware when it is ready.
-  */
+/*
+ * This file contains the handling of command.
+ * It prepares command and sends it to firmware when it is ready.
+ */
 
 #include <linux/kfifo.h>
 #include <linux/sched.h>
@@ -16,14 +16,14 @@
 #define CAL_RSSI(snr, nf)	((s32)((s32)(snr) + CAL_NF(nf)))
 
 /**
- *  @brief Simple callback that copies response back into command
+ * lbs_cmd_copyback - Simple callback that copies response back into command
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param extra  	A pointer to the original command structure for which
- *                      'resp' is a response
- *  @param resp         A pointer to the command response
+ * @priv:	A pointer to &struct lbs_private structure
+ * @extra:	A pointer to the original command structure for which
+ *		'resp' is a response
+ * @resp:	A pointer to the command response
  *
- *  @return 	   	0 on success, error on failure
+ * returns:	0 on success, error on failure
  */
 int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
 		     struct cmd_header *resp)
@@ -38,15 +38,15 @@ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
 EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
 
 /**
- *  @brief Simple callback that ignores the result. Use this if
- *  you just want to send a command to the hardware, but don't
+ *  lbs_cmd_async_callback - Simple callback that ignores the result.
+ *  Use this if you just want to send a command to the hardware, but don't
  *  care for the result.
  *
- *  @param priv         ignored
- *  @param extra        ignored
- *  @param resp         ignored
+ *  @priv:	ignored
+ *  @extra:	ignored
+ *  @resp:	ignored
  *
- *  @return 	   	0 for success
+ *  returns:	0 for success
  */
 static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
 		     struct cmd_header *resp)
@@ -56,10 +56,11 @@ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
 
 
 /**
- *  @brief Checks whether a command is allowed in Power Save mode
+ *  is_command_allowed_in_ps - tests if a command is allowed in Power Save mode
+ *
+ *  @cmd:	the command ID
  *
- *  @param command the command ID
- *  @return 	   1 if allowed, 0 if not allowed
+ *  returns:	1 if allowed, 0 if not allowed
  */
 static u8 is_command_allowed_in_ps(u16 cmd)
 {
@@ -75,11 +76,12 @@ static u8 is_command_allowed_in_ps(u16 cmd)
 }
 
 /**
- *  @brief Updates the hardware details like MAC address and regulatory region
+ *  lbs_update_hw_spec - Updates the hardware details like MAC address
+ *  and regulatory region
  *
- *  @param priv    	A pointer to struct lbs_private structure
+ *  @priv:	A pointer to &struct lbs_private structure
  *
- *  @return 	   	0 on success, error on failure
+ *  returns:	0 on success, error on failure
  */
 int lbs_update_hw_spec(struct lbs_private *priv)
 {
@@ -217,14 +219,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
 EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
 
 /**
- *  @brief Sets the Power Save mode
+ *  lbs_set_ps_mode - Sets the Power Save mode
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param cmd_action	The Power Save operation (PS_MODE_ACTION_ENTER_PS or
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or
  *                         PS_MODE_ACTION_EXIT_PS)
- *  @param block	Whether to block on a response or not
+ *  @block:	Whether to block on a response or not
  *
- *  @return 	   	0 on success, error on failure
+ *  returns:	0 on success, error on failure
  */
 int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
 {
@@ -417,13 +419,13 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
 }
 
 /**
- *  @brief Set an SNMP MIB value
+ *  lbs_set_snmp_mib - Set an SNMP MIB value
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param oid  	The OID to set in the firmware
- *  @param val  	Value to set the OID to
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  @oid:	The OID to set in the firmware
+ *  @val:	Value to set the OID to
  *
- *  @return 	   	0 on success, error on failure
+ *  returns: 	   	0 on success, error on failure
  */
 int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
 {
@@ -467,13 +469,13 @@ out:
 }
 
 /**
- *  @brief Get an SNMP MIB value
+ *  lbs_get_snmp_mib - Get an SNMP MIB value
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param oid  	The OID to retrieve from the firmware
- *  @param out_val  	Location for the returned value
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  @oid:	The OID to retrieve from the firmware
+ *  @out_val:	Location for the returned value
  *
- *  @return 	   	0 on success, error on failure
+ *  returns:	0 on success, error on failure
  */
 int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
 {
@@ -510,14 +512,14 @@ out:
 }
 
 /**
- *  @brief Get the min, max, and current TX power
+ *  lbs_get_tx_power - Get the min, max, and current TX power
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param curlevel  	Current power level in dBm
- *  @param minlevel  	Minimum supported power level in dBm (optional)
- *  @param maxlevel  	Maximum supported power level in dBm (optional)
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  @curlevel:	Current power level in dBm
+ *  @minlevel:	Minimum supported power level in dBm (optional)
+ *  @maxlevel:	Maximum supported power level in dBm (optional)
  *
- *  @return 	   	0 on success, error on failure
+ *  returns:	0 on success, error on failure
  */
 int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
 		     s16 *maxlevel)
@@ -545,12 +547,12 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
 }
 
 /**
- *  @brief Set the TX power
+ *  lbs_set_tx_power - Set the TX power
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param dbm  	The desired power level in dBm
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  @dbm:	The desired power level in dBm
  *
- *  @return 	   	0 on success, error on failure
+ *  returns: 	   	0 on success, error on failure
  */
 int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
 {
@@ -573,12 +575,13 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
 }
 
 /**
- *  @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW)
+ *  lbs_set_monitor_mode - Enable or disable monitor mode
+ *  (only implemented on OLPC usb8388 FW)
  *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param enable      1 to enable monitor mode, 0 to disable
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  @enable:	1 to enable monitor mode, 0 to disable
  *
- *  @return            0 on success, error on failure
+ *  returns:	0 on success, error on failure
  */
 int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
 {
@@ -604,11 +607,11 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
 }
 
 /**
- *  @brief Get the radio channel
+ *  lbs_get_channel - Get the radio channel
  *
- *  @param priv    	A pointer to struct lbs_private structure
+ *  @priv:	A pointer to &struct lbs_private structure
  *
- *  @return 	   	The channel on success, error on failure
+ *  returns:	The channel on success, error on failure
  */
 static int lbs_get_channel(struct lbs_private *priv)
 {
@@ -650,12 +653,12 @@ int lbs_update_channel(struct lbs_private *priv)
 }
 
 /**
- *  @brief Set the radio channel
+ *  lbs_set_channel - Set the radio channel
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param channel  	The desired channel, or 0 to clear a locked channel
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  @channel:	The desired channel, or 0 to clear a locked channel
  *
- *  @return 	   	0 on success, error on failure
+ *  returns:	0 on success, error on failure
  */
 int lbs_set_channel(struct lbs_private *priv, u8 channel)
 {
@@ -686,12 +689,13 @@ out:
 }
 
 /**
- *  @brief Get current RSSI and noise floor
+ * lbs_get_rssi - Get current RSSI and noise floor
  *
- *  @param priv		A pointer to struct lbs_private structure
- *  @param rssi		On successful return, signal level in mBm
+ * @priv:	A pointer to &struct lbs_private structure
+ * @rssi:	On successful return, signal level in mBm
+ * @nf:		On successful return, Noise floor
  *
- *  @return 	   	The channel on success, error on failure
+ * returns:	The channel on success, error on failure
  */
 int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
 {
@@ -719,13 +723,14 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
 }
 
 /**
- *  @brief Send regulatory and 802.11d domain information to the firmware
+ *  lbs_set_11d_domain_info - Send regulatory and 802.11d domain information
+ *  to the firmware
  *
- *  @param priv		pointer to struct lbs_private
- *  @param request	cfg80211 regulatory request structure
- *  @param bands	the device's supported bands and channels
+ *  @priv:	pointer to &struct lbs_private
+ *  @request:	cfg80211 regulatory request structure
+ *  @bands:	the device's supported bands and channels
  *
- *  @return		0 on success, error code on failure
+ *  returns:	0 on success, error code on failure
 */
 int lbs_set_11d_domain_info(struct lbs_private *priv,
 			    struct regulatory_request *request,
@@ -842,15 +847,15 @@ int lbs_set_11d_domain_info(struct lbs_private *priv,
 }
 
 /**
- *  @brief Read a MAC, Baseband, or RF register
+ *  lbs_get_reg - Read a MAC, Baseband, or RF register
  *
- *  @param priv		pointer to struct lbs_private
- *  @param cmd		register command, one of CMD_MAC_REG_ACCESS,
- *                        CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
- *  @param offset       byte offset of the register to get
- *  @param value        on success, the value of the register at 'offset'
+ *  @priv:	pointer to &struct lbs_private
+ *  @reg:	register command, one of CMD_MAC_REG_ACCESS,
+ *		CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ *  @offset:	byte offset of the register to get
+ *  @value:	on success, the value of the register at 'offset'
  *
- *  @return		0 on success, error code on failure
+ *  returns:	0 on success, error code on failure
 */
 int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
 {
@@ -886,15 +891,15 @@ out:
 }
 
 /**
- *  @brief Write a MAC, Baseband, or RF register
+ *  lbs_set_reg - Write a MAC, Baseband, or RF register
  *
- *  @param priv		pointer to struct lbs_private
- *  @param cmd		register command, one of CMD_MAC_REG_ACCESS,
- *                        CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
- *  @param offset       byte offset of the register to set
- *  @param value        the value to write to the register at 'offset'
+ *  @priv:	pointer to &struct lbs_private
+ *  @reg:	register command, one of CMD_MAC_REG_ACCESS,
+ *		CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ *  @offset:	byte offset of the register to set
+ *  @value:	the value to write to the register at 'offset'
  *
- *  @return		0 on success, error code on failure
+ *  returns:	0 on success, error code on failure
 */
 int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
 {
@@ -1023,7 +1028,7 @@ static void lbs_submit_command(struct lbs_private *priv,
 	lbs_deb_leave(LBS_DEB_HOST);
 }
 
-/**
+/*
  *  This function inserts command node to cmdfreeq
  *  after cleans it. Requires priv->driver_lock held.
  */
@@ -1125,11 +1130,12 @@ void lbs_set_mac_control(struct lbs_private *priv)
 }
 
 /**
- *  @brief This function allocates the command buffer and link
- *  it to command free queue.
+ *  lbs_allocate_cmd_buffer - allocates the command buffer and links
+ *  it to command free queue
+ *
+ *  @priv:	A pointer to &struct lbs_private structure
  *
- *  @param priv		A pointer to struct lbs_private structure
- *  @return 		0 or -1
+ *  returns:	0 for success or -1 on error
  */
 int lbs_allocate_cmd_buffer(struct lbs_private *priv)
 {
@@ -1171,10 +1177,11 @@ done:
 }
 
 /**
- *  @brief This function frees the command buffer.
+ *  lbs_free_cmd_buffer - free the command buffer
  *
- *  @param priv		A pointer to struct lbs_private structure
- *  @return 		0 or -1
+ *  @priv:	A pointer to &struct lbs_private structure
+ *
+ *  returns:	0 for success
  */
 int lbs_free_cmd_buffer(struct lbs_private *priv)
 {
@@ -1211,11 +1218,13 @@ done:
 }
 
 /**
- *  @brief This function gets a free command node if available in
- *  command free queue.
+ *  lbs_get_free_cmd_node - gets a free command node if available in
+ *  command free queue
+ *
+ *  @priv:	A pointer to &struct lbs_private structure
  *
- *  @param priv		A pointer to struct lbs_private structure
- *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ *  returns:	A pointer to &cmd_ctrl_node structure on success
+ *		or %NULL on error
  */
 static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
 {
@@ -1245,12 +1254,12 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
 }
 
 /**
- *  @brief This function executes next command in command
- *  pending queue. It will put firmware back to PS mode
- *  if applicable.
+ *  lbs_execute_next_command - execute next command in command
+ *  pending queue. Will put firmware back to PS mode if applicable.
  *
- *  @param priv     A pointer to struct lbs_private structure
- *  @return 	   0 or -1
+ *  @priv:	A pointer to &struct lbs_private structure
+ *
+ *  returns:	0 on success or -1 on error
  */
 int lbs_execute_next_command(struct lbs_private *priv)
 {
@@ -1454,12 +1463,12 @@ out:
 }
 
 /**
- *  @brief This function checks condition and prepares to
- *  send sleep confirm command to firmware if ok.
+ * lbs_ps_confirm_sleep - checks condition and prepares to
+ * send sleep confirm command to firmware if ok
+ *
+ * @priv:	A pointer to &struct lbs_private structure
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param psmode  	Power Saving mode
- *  @return 	   	n/a
+ * returns:	n/a
  */
 void lbs_ps_confirm_sleep(struct lbs_private *priv)
 {
@@ -1499,16 +1508,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
 
 
 /**
- * @brief Configures the transmission power control functionality.
+ * lbs_set_tpc_cfg - Configures the transmission power control functionality
  *
- * @param priv		A pointer to struct lbs_private structure
- * @param enable	Transmission power control enable
- * @param p0		Power level when link quality is good (dBm).
- * @param p1		Power level when link quality is fair (dBm).
- * @param p2		Power level when link quality is poor (dBm).
- * @param usesnr	Use Signal to Noise Ratio in TPC
+ * @priv:	A pointer to &struct lbs_private structure
+ * @enable:	Transmission power control enable
+ * @p0:		Power level when link quality is good (dBm).
+ * @p1:		Power level when link quality is fair (dBm).
+ * @p2:		Power level when link quality is poor (dBm).
+ * @usesnr:	Use Signal to Noise Ratio in TPC
  *
- * @return 0 on success
+ * returns:	0 on success
  */
 int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
 		int8_t p2, int usesnr)
@@ -1531,15 +1540,15 @@ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
 }
 
 /**
- * @brief Configures the power adaptation settings.
+ * lbs_set_power_adapt_cfg - Configures the power adaptation settings
  *
- * @param priv		A pointer to struct lbs_private structure
- * @param enable	Power adaptation enable
- * @param p0		Power level for 1, 2, 5.5 and 11 Mbps (dBm).
- * @param p1		Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
- * @param p2		Power level for 48 and 54 Mbps (dBm).
+ * @priv:	A pointer to &struct lbs_private structure
+ * @enable:	Power adaptation enable
+ * @p0:		Power level for 1, 2, 5.5 and 11 Mbps (dBm).
+ * @p1:		Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
+ * @p2:		Power level for 48 and 54 Mbps (dBm).
  *
- * @return 0 on Success
+ * returns:	0 on Success
  */
 
 int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 5e95da9dcc2e2c99064d26d07264e06c1a272cfd..03e528994a9ea43f6f44b096739e887c7031f0bc 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -1,7 +1,7 @@
-/**
-  * This file contains the handling of command
-  * responses as well as events generated by firmware.
-  */
+/*
+ * This file contains the handling of command
+ * responses as well as events generated by firmware.
+ */
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
@@ -12,12 +12,13 @@
 #include "cmd.h"
 
 /**
- *  @brief This function handles disconnect event. it
- *  reports disconnect to upper layer, clean tx/rx packets,
- *  reset link state etc.
+ * lbs_mac_event_disconnected - handles disconnect event. It
+ * reports disconnect to upper layer, clean tx/rx packets,
+ * reset link state etc.
+ *
+ * @priv:	A pointer to struct lbs_private structure
  *
- *  @param priv    A pointer to struct lbs_private structure
- *  @return 	   n/a
+ * returns:	n/a
  */
 void lbs_mac_event_disconnected(struct lbs_private *priv)
 {
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index fbf3b0332bb76c4957d066f90478106ae001d42a..851fe7bd4ba4838346102d5c072a3bdeeff4c7f5 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -849,15 +849,14 @@ static struct debug_data items[] = {
 static int num_of_items = ARRAY_SIZE(items);
 
 /**
- *  @brief proc read function
+ * lbs_debugfs_read - proc read function
  *
- *  @param page	   pointer to buffer
- *  @param s       read data starting position
- *  @param off     offset
- *  @param cnt     counter
- *  @param eof     end of file flag
- *  @param data    data to output
- *  @return 	   number of output data
+ * @file:	file to read
+ * @userbuf:	pointer to buffer
+ * @count:	number of bytes to read
+ * @ppos:	read data starting position
+ *
+ * returns:	amount of data read or negative error code
  */
 static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
 			size_t count, loff_t *ppos)
@@ -897,13 +896,14 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
 }
 
 /**
- *  @brief proc write function
+ * lbs_debugfs_write - proc write function
+ *
+ * @f:		file pointer
+ * @buf:	pointer to data buffer
+ * @cnt:	data number to write
+ * @ppos:	file position
  *
- *  @param f	   file pointer
- *  @param buf     pointer to data buffer
- *  @param cnt     data number to write
- *  @param data    data to write
- *  @return 	   number of data
+ * returns:	amount of data written
  */
 static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
 			    size_t cnt, loff_t *ppos)
@@ -966,11 +966,11 @@ static const struct file_operations lbs_debug_fops = {
 };
 
 /**
- *  @brief create debug proc file
+ * lbs_debug_init - create debug proc file
+ *
+ * @priv:	pointer to &struct lbs_private
  *
- *  @param priv	   pointer struct lbs_private
- *  @param dev     pointer net_device
- *  @return 	   N/A
+ * returns:	N/A
  */
 static void lbs_debug_init(struct lbs_private *priv)
 {
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 2ae752d1006555318bb421b39fea2a9b6d37d735..da0b05bb89fe838d0b4591c3cb4529b4953fa46b 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -1,8 +1,8 @@
 
-/**
-  *  This file contains declaration referring to
-  *  functions defined in other source files
-  */
+/*
+ *  This file contains declaration referring to
+ *  functions defined in other source files
+ */
 
 #ifndef _LBS_DECL_H_
 #define _LBS_DECL_H_
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index d00c728cec47cdd731c68ff64190c7054d374e5e..92b5b1f8fd75d6dc499665f09de923eb691d6e8a 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -1,7 +1,7 @@
-/**
-  * This header file contains global constant/enum definitions,
-  * global variable declaration.
-  */
+/*
+ * This header file contains global constant/enum definitions,
+ * global variable declaration.
+ */
 #ifndef _LBS_DEFS_H_
 #define _LBS_DEFS_H_
 
@@ -123,19 +123,19 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 
 
 
-/** Buffer Constants */
+/* Buffer Constants */
 
 /*	The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
-*	addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
-*	driver has more local TxPDs. Each TxPD on the host memory is associated
-*	with a Tx control node. The driver maintains 8 RxPD descriptors for
-*	station firmware to store Rx packet information.
-*
-*	Current version of MAC has a 32x6 multicast address buffer.
-*
-*	802.11b can have up to  14 channels, the driver keeps the
-*	BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
-*/
+ *	addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+ *	driver has more local TxPDs. Each TxPD on the host memory is associated
+ *	with a Tx control node. The driver maintains 8 RxPD descriptors for
+ *	station firmware to store Rx packet information.
+ *
+ *	Current version of MAC has a 32x6 multicast address buffer.
+ *
+ *	802.11b can have up to  14 channels, the driver keeps the
+ *	BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+ */
 
 #define MRVDRV_MAX_MULTICAST_LIST_SIZE	32
 #define LBS_NUM_CMD_BUFFERS             10
@@ -166,7 +166,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 #define WOL_RESULT_NOSPC_ERR		1
 #define WOL_RESULT_EEXIST_ERR		2
 
-/** Misc constants */
+/* Misc constants */
 /* This section defines 802.11 specific contants */
 
 #define MRVDRV_MAX_BSS_DESCRIPTS		16
@@ -183,7 +183,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 
 #define MARVELL_MESH_IE_LENGTH		9
 
-/* Values used to populate the struct mrvl_mesh_ie.  The only time you need this
+/*
+ * Values used to populate the struct mrvl_mesh_ie.  The only time you need this
  * is when enabling the mesh using CMD_MESH_CONFIG.
  */
 #define MARVELL_MESH_IE_TYPE		4
@@ -193,7 +194,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 #define MARVELL_MESH_METRIC_ID		0
 #define MARVELL_MESH_CAPABILITY		0
 
-/** INT status Bit Definition*/
+/* INT status Bit Definition */
 #define MRVDRV_TX_DNLD_RDY		0x0001
 #define MRVDRV_RX_UPLD_RDY		0x0002
 #define MRVDRV_CMD_DNLD_RDY		0x0004
@@ -208,59 +209,63 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 #define TPC_DEFAULT_P1 10
 #define TPC_DEFAULT_P2 13
 
-/** TxPD status */
+/* TxPD status */
 
-/*	Station firmware use TxPD status field to report final Tx transmit
-*	result, Bit masks are used to present combined situations.
-*/
+/*
+ *	Station firmware use TxPD status field to report final Tx transmit
+ *	result, Bit masks are used to present combined situations.
+ */
 
 #define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
 #define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
 
-/** Tx mesh flag */
-/* Currently we are using normal WDS flag as mesh flag.
+/* Tx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
  * TODO: change to proper mesh flag when MAC understands it.
  */
 #define TxPD_CONTROL_WDS_FRAME (1<<17)
 #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
 
-/** Mesh interface ID */
+/* Mesh interface ID */
 #define MESH_IFACE_ID					0x0001
-/** Mesh id should be in bits 14-13-12 */
+/* Mesh id should be in bits 14-13-12 */
 #define MESH_IFACE_BIT_OFFSET				0x000c
-/** Mesh enable bit in FW capability */
+/* Mesh enable bit in FW capability */
 #define MESH_CAPINFO_ENABLE_MASK			(1<<16)
 
-/** FW definition from Marvell v4 */
+/* FW definition from Marvell v4 */
 #define MRVL_FW_V4					(0x04)
-/** FW definition from Marvell v5 */
+/* FW definition from Marvell v5 */
 #define MRVL_FW_V5					(0x05)
-/** FW definition from Marvell v10 */
+/* FW definition from Marvell v10 */
 #define MRVL_FW_V10					(0x0a)
-/** FW major revision definition */
+/* FW major revision definition */
 #define MRVL_FW_MAJOR_REV(x)				((x)>>24)
 
-/** RxPD status */
+/* RxPD status */
 
 #define MRVDRV_RXPD_STATUS_OK                0x0001
 
-/** RxPD status - Received packet types */
-/** Rx mesh flag */
-/* Currently we are using normal WDS flag as mesh flag.
+/* RxPD status - Received packet types */
+/* Rx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
  * TODO: change to proper mesh flag when MAC understands it.
  */
 #define RxPD_CONTROL_WDS_FRAME (0x40)
 #define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
 
-/** RSSI-related defines */
-/*	RSSI constants are used to implement 802.11 RSSI threshold
-*	indication. if the Rx packet signal got too weak for 5 consecutive
-*	times, miniport driver (driver) will report this event to wrapper
-*/
+/* RSSI-related defines */
+/*
+ *	RSSI constants are used to implement 802.11 RSSI threshold
+ *	indication. if the Rx packet signal got too weak for 5 consecutive
+ *	times, miniport driver (driver) will report this event to wrapper
+ */
 
 #define MRVDRV_NF_DEFAULT_SCAN_VALUE		(-96)
 
-/** RTS/FRAG related defines */
+/* RTS/FRAG related defines */
 #define MRVDRV_RTS_MIN_VALUE		0
 #define MRVDRV_RTS_MAX_VALUE		2347
 #define MRVDRV_FRAG_MIN_VALUE		256
@@ -300,36 +305,36 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 
 #define	MAX_LEDS			8
 
-/** Global Variable Declaration */
+/* Global Variable Declaration */
 extern const char lbs_driver_version[];
 extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
 
 
-/** ENUM definition*/
-/** SNRNF_TYPE */
+/* ENUM definition */
+/* SNRNF_TYPE */
 enum SNRNF_TYPE {
 	TYPE_BEACON = 0,
 	TYPE_RXPD,
 	MAX_TYPE_B
 };
 
-/** SNRNF_DATA*/
+/* SNRNF_DATA */
 enum SNRNF_DATA {
 	TYPE_NOAVG = 0,
 	TYPE_AVG,
 	MAX_TYPE_AVG
 };
 
-/** LBS_802_11_POWER_MODE */
+/* LBS_802_11_POWER_MODE */
 enum LBS_802_11_POWER_MODE {
 	LBS802_11POWERMODECAM,
 	LBS802_11POWERMODEMAX_PSP,
 	LBS802_11POWERMODEFAST_PSP,
-	/*not a real mode, defined as an upper bound */
+	/* not a real mode, defined as an upper bound */
 	LBS802_11POWEMODEMAX
 };
 
-/** PS_STATE */
+/* PS_STATE */
 enum PS_STATE {
 	PS_STATE_FULL_POWER,
 	PS_STATE_AWAKE,
@@ -337,7 +342,7 @@ enum PS_STATE {
 	PS_STATE_SLEEP
 };
 
-/** DNLD_STATE */
+/* DNLD_STATE */
 enum DNLD_STATE {
 	DNLD_RES_RECEIVED,
 	DNLD_DATA_SENT,
@@ -345,19 +350,19 @@ enum DNLD_STATE {
 	DNLD_BOOTCMD_SENT,
 };
 
-/** LBS_MEDIA_STATE */
+/* LBS_MEDIA_STATE */
 enum LBS_MEDIA_STATE {
 	LBS_CONNECTED,
 	LBS_DISCONNECTED
 };
 
-/** LBS_802_11_PRIVACY_FILTER */
+/* LBS_802_11_PRIVACY_FILTER */
 enum LBS_802_11_PRIVACY_FILTER {
 	LBS802_11PRIVFILTERACCEPTALL,
 	LBS802_11PRIVFILTER8021XWEP
 };
 
-/** mv_ms_type */
+/* mv_ms_type */
 enum mv_ms_type {
 	MVMS_DAT = 0,
 	MVMS_CMD = 1,
@@ -365,14 +370,14 @@ enum mv_ms_type {
 	MVMS_EVENT
 };
 
-/** KEY_TYPE_ID */
+/* KEY_TYPE_ID */
 enum KEY_TYPE_ID {
 	KEY_TYPE_ID_WEP = 0,
 	KEY_TYPE_ID_TKIP,
 	KEY_TYPE_ID_AES
 };
 
-/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
 enum KEY_INFO_WPA {
 	KEY_INFO_WPA_MCAST = 0x01,
 	KEY_INFO_WPA_UNICAST = 0x02,
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index bc461eb396604cb746b3259c4656ee693caa1dd2..76d018beebf42e61d4e222ccfd053dd9105b649a 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -1,8 +1,8 @@
-/**
-  * This file contains definitions and data structures specific
-  * to Marvell 802.11 NIC. It contains the Device Information
-  * structure struct lbs_private..
-  */
+/*
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+ * structure struct lbs_private..
+ */
 #ifndef _LBS_DEV_H_
 #define _LBS_DEV_H_
 
@@ -12,7 +12,7 @@
 
 #include <linux/kfifo.h>
 
-/** sleep_params */
+/* sleep_params */
 struct sleep_params {
 	uint16_t sp_error;
 	uint16_t sp_offset;
@@ -23,7 +23,7 @@ struct sleep_params {
 };
 
 
-/** Private structure for the MV device */
+/* Private structure for the MV device */
 struct lbs_private {
 
 	/* Basic networking */
@@ -125,12 +125,12 @@ struct lbs_private {
 	/* Events sent from hardware to driver */
 	struct kfifo event_fifo;
 
-	/** thread to service interrupts */
+	/* thread to service interrupts */
 	struct task_struct *main_thread;
 	wait_queue_head_t waitq;
 	struct workqueue_struct *work_thread;
 
-	/** Encryption stuff */
+	/* Encryption stuff */
 	u8 authtype_auto;
 	u8 wep_tx_key;
 	u8 wep_key[4][WLAN_KEY_LEN_WEP104];
@@ -162,7 +162,7 @@ struct lbs_private {
 	s16 txpower_min;
 	s16 txpower_max;
 
-	/** Scanning */
+	/* Scanning */
 	struct delayed_work scan_work;
 	int scan_channel;
 	/* Queue of things waiting for scan completion */
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 50193aac679e81b5c0a157e933db006958fa4463..29dbce4a9f86e15b9f5eaf112bf152185ba91941 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -20,7 +20,8 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev,
 	strcpy(info->version, lbs_driver_version);
 }
 
-/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+/*
+ * All 8388 parts have 16KiB EEPROM size at the time of writing.
  * In case that changes this needs fixing.
  */
 #define LBS_EEPROM_LEN 16384
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 6cb6935ee4a395e4eedc89183392b71f80fd3966..2e2dbfa2ee500f8072f8696df7f8d6711d58fbd9 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -1,7 +1,7 @@
-/**
-  * This file function prototypes, data structure
-  * and  definitions for all the host/station commands
-  */
+/*
+ * This file function prototypes, data structure
+ * and  definitions for all the host/station commands
+ */
 
 #ifndef _LBS_HOST_H_
 #define _LBS_HOST_H_
@@ -13,9 +13,10 @@
 
 #define CMD_OPTION_WAITFORRSP                   0x0002
 
-/** Host command IDs */
+/* Host command IDs */
 
-/* Return command are almost always the same as the host command, but with
+/*
+ * Return command are almost always the same as the host command, but with
  * bit 15 set high.  There are a few exceptions, though...
  */
 #define CMD_RET(cmd)                            (0x8000 | cmd)
@@ -251,7 +252,7 @@ enum cmd_mesh_config_types {
 	CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
 };
 
-/** Card Event definition */
+/* Card Event definition */
 #define MACREG_INT_CODE_TX_PPA_FREE		0
 #define MACREG_INT_CODE_TX_DMA_DONE		1
 #define MACREG_INT_CODE_LINK_LOST_W_SCAN	2
@@ -624,12 +625,14 @@ struct cmd_ds_802_11_rf_channel {
 struct cmd_ds_802_11_rssi {
 	struct cmd_header hdr;
 
-	/* request:  number of beacons (N) to average the SNR and NF over
+	/*
+	 * request:  number of beacons (N) to average the SNR and NF over
 	 * response: SNR of most recent beacon
 	 */
 	__le16 n_or_snr;
 
-	/* The following fields are only set in the response.
+	/*
+	 * The following fields are only set in the response.
 	 * In the request these are reserved and should be set to 0.
 	 */
 	__le16 nf;       /* most recent beacon noise floor */
@@ -680,14 +683,16 @@ struct cmd_ds_802_11_ps_mode {
 
 	__le16 action;
 
-	/* Interval for keepalive in PS mode:
+	/*
+	 * Interval for keepalive in PS mode:
 	 * 0x0000 = don't change
 	 * 0x001E = firmware default
 	 * 0xFFFF = disable
 	 */
 	__le16 nullpktinterval;
 
-	/* Number of DTIM intervals to wake up for:
+	/*
+	 * Number of DTIM intervals to wake up for:
 	 * 0 = don't change
 	 * 1 = firmware default
 	 * 5 = max
@@ -697,7 +702,8 @@ struct cmd_ds_802_11_ps_mode {
 	__le16 reserved;
 	__le16 locallisteninterval;
 
-	/* AdHoc awake period (FW v9+ only):
+	/*
+	 * AdHoc awake period (FW v9+ only):
 	 * 0 = don't change
 	 * 1 = always awake (IEEE standard behavior)
 	 * 2 - 31 = sleep for (n - 1) periods and awake for 1 period
@@ -771,7 +777,8 @@ struct adhoc_bssdesc {
 	__le16 capability;
 	u8 rates[MAX_RATES];
 
-	/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+	/*
+	 * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
 	 * Adhoc join command and will cause a binary layout mismatch with
 	 * the firmware
 	 */
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 8712cb213f2fa938d81793582c28048a95ce6328..4dfd48fe8b6e1b1759f0169c72ebc9ac160ca704 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -312,7 +312,8 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
 #define CF8385_MANFID		0x02df
 #define CF8385_CARDID		0x8103
 
-/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
+/*
+ * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
  * that gets fixed.  Currently there's no way to access it from the probe hook.
  */
 static inline u32 get_model(u16 manf_id, u16 card_id)
@@ -621,8 +622,10 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
 		if (remain < count)
 			count = remain;
 
-		/* "write the number of bytes to be sent to the I/O Command
-		 * write length register" */
+		/*
+		 * "write the number of bytes to be sent to the I/O Command
+		 * write length register"
+		 */
 		if_cs_write16(card, IF_CS_CMD_LEN, count);
 
 		/* "write this to I/O Command port register as 16 bit writes */
@@ -631,16 +634,22 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
 				&fw->data[sent],
 				count >> 1);
 
-		/* "Assert the download over interrupt command in the Host
-		 * status register" */
+		/*
+		 * "Assert the download over interrupt command in the Host
+		 * status register"
+		 */
 		if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
 
-		/* "Assert the download over interrupt command in the Card
-		 * interrupt case register" */
+		/*
+		 * "Assert the download over interrupt command in the Card
+		 * interrupt case register"
+		 */
 		if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
 
-		/* "The host polls the Card Status register ... for 50 ms before
-		   declaring a failure */
+		/*
+		 * "The host polls the Card Status register ... for 50 ms before
+		 * declaring a failure"
+		 */
 		ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
 			IF_CS_BIT_COMMAND);
 		if (ret < 0) {
@@ -841,7 +850,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
 
 	/*
 	 * Most of the libertas cards can do unaligned register access, but some
-	 * weird ones can not. That's especially true for the CF8305 card.
+	 * weird ones cannot. That's especially true for the CF8305 card.
 	 */
 	card->align_regs = 0;
 
@@ -913,8 +922,10 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
 		goto out3;
 	}
 
-	/* Clear any interrupt cause that happened while sending
-	 * firmware/initializing card */
+	/*
+	 * Clear any interrupt cause that happened while sending
+	 * firmware/initializing card
+	 */
 	if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
 	if_cs_enable_ints(card);
 
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 078ef43d957d4ae217f151cca06e1ee23cecd5b3..67de5b3c68b29eb9c43324b0159f68186fb0490a 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -143,8 +143,10 @@ static void spu_transaction_finish(struct if_spi_card *card)
 	card->prev_xfer_time = jiffies;
 }
 
-/* Write out a byte buffer to an SPI register,
- * using a series of 16-bit transfers. */
+/*
+ * Write out a byte buffer to an SPI register,
+ * using a series of 16-bit transfers.
+ */
 static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
 {
 	int err = 0;
@@ -208,8 +210,10 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
 	struct spi_transfer dummy_trans;
 	struct spi_transfer data_trans;
 
-	/* You must take an even number of bytes from the SPU, even if you
-	 * don't care about the last one.  */
+	/*
+	 * You must take an even number of bytes from the SPU, even if you
+	 * don't care about the last one.
+	 */
 	BUG_ON(len & 0x1);
 
 	spu_transaction_init(card);
@@ -258,8 +262,10 @@ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
 	return ret;
 }
 
-/* Read 32 bits from an SPI register.
- * The low 16 bits are read first. */
+/*
+ * Read 32 bits from an SPI register.
+ * The low 16 bits are read first.
+ */
 static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
 {
 	__le32 buf;
@@ -271,13 +277,15 @@ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
 	return err;
 }
 
-/* Keep reading 16 bits from an SPI register until you get the correct result.
+/*
+ * Keep reading 16 bits from an SPI register until you get the correct result.
  *
  * If mask = 0, the correct result is any non-zero number.
  * If mask != 0, the correct result is any number where
  * number & target_mask == target
  *
- * Returns -ETIMEDOUT if a second passes without the correct result. */
+ * Returns -ETIMEDOUT if a second passes without the correct result.
+ */
 static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
 			u16 target_mask, u16 target)
 {
@@ -305,8 +313,10 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
 	}
 }
 
-/* Read 16 bits from an SPI register until you receive a specific value.
- * Returns -ETIMEDOUT if a 4 tries pass without success. */
+/*
+ * Read 16 bits from an SPI register until you receive a specific value.
+ * Returns -ETIMEDOUT if a 4 tries pass without success.
+ */
 static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target)
 {
 	int err, try;
@@ -328,8 +338,10 @@ static int spu_set_interrupt_mode(struct if_spi_card *card,
 {
 	int err = 0;
 
-	/* We can suppress a host interrupt by clearing the appropriate
-	 * bit in the "host interrupt status mask" register */
+	/*
+	 * We can suppress a host interrupt by clearing the appropriate
+	 * bit in the "host interrupt status mask" register
+	 */
 	if (suppress_host_int) {
 		err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
 		if (err)
@@ -345,10 +357,12 @@ static int spu_set_interrupt_mode(struct if_spi_card *card,
 			return err;
 	}
 
-	/* If auto-interrupts are on, the completion of certain transactions
+	/*
+	 * If auto-interrupts are on, the completion of certain transactions
 	 * will trigger an interrupt automatically. If auto-interrupts
 	 * are off, we need to set the "Card Interrupt Cause" register to
-	 * trigger a card interrupt. */
+	 * trigger a card interrupt.
+	 */
 	if (auto_int) {
 		err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG,
 				IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO |
@@ -402,8 +416,10 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes)
 	int err = 0;
 	u32 delay;
 
-	/* We have to start up in timed delay mode so that we can safely
-	 * read the Delay Read Register. */
+	/*
+	 * We have to start up in timed delay mode so that we can safely
+	 * read the Delay Read Register.
+	 */
 	card->use_dummy_writes = 0;
 	err = spu_set_bus_mode(card,
 				IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
@@ -459,8 +475,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
 
 	/* Load helper firmware image */
 	while (bytes_remaining > 0) {
-		/* Scratch pad 1 should contain the number of bytes we
-		 * want to download to the firmware */
+		/*
+		 * Scratch pad 1 should contain the number of bytes we
+		 * want to download to the firmware
+		 */
 		err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
 					HELPER_FW_LOAD_CHUNK_SZ);
 		if (err)
@@ -472,8 +490,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
 		if (err)
 			goto out;
 
-		/* Feed the data into the command read/write port reg
-		 * in chunks of 64 bytes */
+		/*
+		 * Feed the data into the command read/write port reg
+		 * in chunks of 64 bytes
+		 */
 		memset(temp, 0, sizeof(temp));
 		memcpy(temp, fw,
 		       min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ));
@@ -495,9 +515,11 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
 		fw += HELPER_FW_LOAD_CHUNK_SZ;
 	}
 
-	/* Once the helper / single stage firmware download is complete,
+	/*
+	 * Once the helper / single stage firmware download is complete,
 	 * write 0 to scratch pad 1 and interrupt the
-	 * bootloader. This completes the helper download. */
+	 * bootloader. This completes the helper download.
+	 */
 	err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
 	if (err)
 		goto out;
@@ -517,16 +539,20 @@ out:
 	return err;
 }
 
-/* Returns the length of the next packet the firmware expects us to send
- * Sets crc_err if the previous transfer had a CRC error. */
+/*
+ * Returns the length of the next packet the firmware expects us to send.
+ * Sets crc_err if the previous transfer had a CRC error.
+ */
 static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
 						int *crc_err)
 {
 	u16 len;
 	int err = 0;
 
-	/* wait until the host interrupt status register indicates
-	 * that we are ready to download */
+	/*
+	 * wait until the host interrupt status register indicates
+	 * that we are ready to download
+	 */
 	err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
 				IF_SPI_HIST_CMD_DOWNLOAD_RDY,
 				IF_SPI_HIST_CMD_DOWNLOAD_RDY);
@@ -587,8 +613,10 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
 			goto out;
 		}
 		if (bytes < 0) {
-			/* If there are no more bytes left, we would normally
-			 * expect to have terminated with len = 0 */
+			/*
+			 * If there are no more bytes left, we would normally
+			 * expect to have terminated with len = 0
+			 */
 			lbs_pr_err("Firmware load wants more bytes "
 				   "than we have to offer.\n");
 			break;
@@ -660,14 +688,18 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
 	u16 len;
 	u8 i;
 
-	/* We need a buffer big enough to handle whatever people send to
-	 * hw_host_to_card */
+	/*
+	 * We need a buffer big enough to handle whatever people send to
+	 * hw_host_to_card
+	 */
 	BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE);
 	BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE);
 
-	/* It's just annoying if the buffer size isn't a multiple of 4, because
-	 * then we might have len <  IF_SPI_CMD_BUF_SIZE but
-	 * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */
+	/*
+	 * It's just annoying if the buffer size isn't a multiple of 4, because
+	 * then we might have len < IF_SPI_CMD_BUF_SIZE but
+	 * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE
+	 */
 	BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0);
 
 	lbs_deb_enter(LBS_DEB_SPI);
@@ -838,8 +870,10 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
 
 	lbs_deb_enter(LBS_DEB_SPI);
 
-	/* Read the host interrupt status register to see what we
-	 * can do. */
+	/*
+	 * Read the host interrupt status register to see what we
+	 * can do.
+	 */
 	err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
 				&hiStatus);
 	if (err) {
@@ -858,12 +892,15 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
 			goto err;
 	}
 
-	/* workaround: in PS mode, the card does not set the Command
-	 * Download Ready bit, but it sets TX Download Ready. */
+	/*
+	 * workaround: in PS mode, the card does not set the Command
+	 * Download Ready bit, but it sets TX Download Ready.
+	 */
 	if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY ||
 	   (card->priv->psstate != PS_STATE_FULL_POWER &&
 	    (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) {
-		/* This means two things. First of all,
+		/*
+		 * This means two things. First of all,
 		 * if there was a previous command sent, the card has
 		 * successfully received it.
 		 * Secondly, it is now ready to download another
@@ -871,8 +908,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
 		 */
 		lbs_host_to_card_done(card->priv);
 
-		/* Do we have any command packets from the host to
-		 * send? */
+		/* Do we have any command packets from the host to send? */
 		packet = NULL;
 		spin_lock_irqsave(&card->buffer_lock, flags);
 		if (!list_empty(&card->cmd_packet_list)) {
@@ -886,8 +922,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
 			if_spi_h2c(card, packet, MVMS_CMD);
 	}
 	if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) {
-		/* Do we have any data packets from the host to
-		 * send? */
+		/* Do we have any data packets from the host to send? */
 		packet = NULL;
 		spin_lock_irqsave(&card->buffer_lock, flags);
 		if (!list_empty(&card->data_packet_list)) {
@@ -914,7 +949,8 @@ err:
  * Host to Card
  *
  * Called from Libertas to transfer some data to the WLAN device
- * We can't sleep here. */
+ * We can't sleep here.
+ */
 static int if_spi_host_to_card(struct lbs_private *priv,
 				u8 type, u8 *buf, u16 nb)
 {
@@ -1125,8 +1161,10 @@ static int __devinit if_spi_probe(struct spi_device *spi)
 	if (err)
 		goto free_card;
 
-	/* Register our card with libertas.
-	 * This will call alloc_etherdev */
+	/*
+	 * Register our card with libertas.
+	 * This will call alloc_etherdev.
+	 */
 	priv = lbs_add_card(card, &spi->dev);
 	if (!priv) {
 		err = -ENOMEM;
@@ -1153,9 +1191,11 @@ static int __devinit if_spi_probe(struct spi_device *spi)
 		goto terminate_workqueue;
 	}
 
-	/* Start the card.
+	/*
+	 * Start the card.
 	 * This will call register_netdev, and we'll start
-	 * getting interrupts... */
+	 * getting interrupts...
+	 */
 	err = lbs_start_card(priv);
 	if (err)
 		goto release_irq;
diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h
index d2ac1dcd7e2e2eb26248a92f803b20f98b7850c9..e450e31fd11dce84b2a6544759ee34befc77a567 100644
--- a/drivers/net/wireless/libertas/if_spi.h
+++ b/drivers/net/wireless/libertas/if_spi.h
@@ -86,34 +86,34 @@
 #define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff)
 
 /***************** IF_SPI_HOST_INT_CTRL_REG *****************/
-/** Host Interrupt Control bit : Wake up */
+/* Host Interrupt Control bit : Wake up */
 #define IF_SPI_HICT_WAKE_UP				(1<<0)
-/** Host Interrupt Control bit : WLAN ready */
+/* Host Interrupt Control bit : WLAN ready */
 #define IF_SPI_HICT_WLAN_READY				(1<<1)
 /*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY		(1<<2) */
 /*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY		(1<<3) */
 /*#define IF_SPI_HICT_IRQSRC_WLAN			(1<<4) */
-/** Host Interrupt Control bit : Tx auto download */
+/* Host Interrupt Control bit : Tx auto download */
 #define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO		(1<<5)
-/** Host Interrupt Control bit : Rx auto upload */
+/* Host Interrupt Control bit : Rx auto upload */
 #define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO			(1<<6)
-/** Host Interrupt Control bit : Command auto download */
+/* Host Interrupt Control bit : Command auto download */
 #define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO		(1<<7)
-/** Host Interrupt Control bit : Command auto upload */
+/* Host Interrupt Control bit : Command auto upload */
 #define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO		(1<<8)
 
 /***************** IF_SPI_CARD_INT_CAUSE_REG *****************/
-/** Card Interrupt Case bit : Tx download over */
+/* Card Interrupt Case bit : Tx download over */
 #define IF_SPI_CIC_TX_DOWNLOAD_OVER			(1<<0)
-/** Card Interrupt Case bit : Rx upload over */
+/* Card Interrupt Case bit : Rx upload over */
 #define IF_SPI_CIC_RX_UPLOAD_OVER			(1<<1)
-/** Card Interrupt Case bit : Command download over */
+/* Card Interrupt Case bit : Command download over */
 #define IF_SPI_CIC_CMD_DOWNLOAD_OVER			(1<<2)
-/** Card Interrupt Case bit : Host event */
+/* Card Interrupt Case bit : Host event */
 #define IF_SPI_CIC_HOST_EVENT				(1<<3)
-/** Card Interrupt Case bit : Command upload over */
+/* Card Interrupt Case bit : Command upload over */
 #define IF_SPI_CIC_CMD_UPLOAD_OVER			(1<<4)
-/** Card Interrupt Case bit : Power down */
+/* Card Interrupt Case bit : Power down */
 #define IF_SPI_CIC_POWER_DOWN				(1<<5)
 
 /***************** IF_SPI_CARD_INT_STATUS_REG *****************/
@@ -138,51 +138,51 @@
 #define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW		(1<<10)
 
 /***************** IF_SPI_HOST_INT_STATUS_REG *****************/
-/** Host Interrupt Status bit : Tx download ready */
+/* Host Interrupt Status bit : Tx download ready */
 #define IF_SPI_HIST_TX_DOWNLOAD_RDY			(1<<0)
-/** Host Interrupt Status bit : Rx upload ready */
+/* Host Interrupt Status bit : Rx upload ready */
 #define IF_SPI_HIST_RX_UPLOAD_RDY			(1<<1)
-/** Host Interrupt Status bit : Command download ready */
+/* Host Interrupt Status bit : Command download ready */
 #define IF_SPI_HIST_CMD_DOWNLOAD_RDY			(1<<2)
-/** Host Interrupt Status bit : Card event */
+/* Host Interrupt Status bit : Card event */
 #define IF_SPI_HIST_CARD_EVENT				(1<<3)
-/** Host Interrupt Status bit : Command upload ready */
+/* Host Interrupt Status bit : Command upload ready */
 #define IF_SPI_HIST_CMD_UPLOAD_RDY			(1<<4)
-/** Host Interrupt Status bit : I/O write FIFO overflow */
+/* Host Interrupt Status bit : I/O write FIFO overflow */
 #define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW			(1<<5)
-/** Host Interrupt Status bit : I/O read FIFO underflow */
+/* Host Interrupt Status bit : I/O read FIFO underflow */
 #define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW			(1<<6)
-/** Host Interrupt Status bit : Data write FIFO overflow */
+/* Host Interrupt Status bit : Data write FIFO overflow */
 #define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW		(1<<7)
-/** Host Interrupt Status bit : Data read FIFO underflow */
+/* Host Interrupt Status bit : Data read FIFO underflow */
 #define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW		(1<<8)
-/** Host Interrupt Status bit : Command write FIFO overflow */
+/* Host Interrupt Status bit : Command write FIFO overflow */
 #define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW		(1<<9)
-/** Host Interrupt Status bit : Command read FIFO underflow */
+/* Host Interrupt Status bit : Command read FIFO underflow */
 #define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW		(1<<10)
 
 /***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/
-/** Host Interrupt Status Mask bit : Tx download ready */
+/* Host Interrupt Status Mask bit : Tx download ready */
 #define IF_SPI_HISM_TX_DOWNLOAD_RDY			(1<<0)
-/** Host Interrupt Status Mask bit : Rx upload ready */
+/* Host Interrupt Status Mask bit : Rx upload ready */
 #define IF_SPI_HISM_RX_UPLOAD_RDY			(1<<1)
-/** Host Interrupt Status Mask bit : Command download ready */
+/* Host Interrupt Status Mask bit : Command download ready */
 #define IF_SPI_HISM_CMD_DOWNLOAD_RDY			(1<<2)
-/** Host Interrupt Status Mask bit : Card event */
+/* Host Interrupt Status Mask bit : Card event */
 #define IF_SPI_HISM_CARDEVENT				(1<<3)
-/** Host Interrupt Status Mask bit : Command upload ready */
+/* Host Interrupt Status Mask bit : Command upload ready */
 #define IF_SPI_HISM_CMD_UPLOAD_RDY			(1<<4)
-/** Host Interrupt Status Mask bit : I/O write FIFO overflow */
+/* Host Interrupt Status Mask bit : I/O write FIFO overflow */
 #define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW			(1<<5)
-/** Host Interrupt Status Mask bit : I/O read FIFO underflow */
+/* Host Interrupt Status Mask bit : I/O read FIFO underflow */
 #define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW		(1<<6)
-/** Host Interrupt Status Mask bit : Data write FIFO overflow */
+/* Host Interrupt Status Mask bit : Data write FIFO overflow */
 #define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW		(1<<7)
-/** Host Interrupt Status Mask bit : Data write FIFO underflow */
+/* Host Interrupt Status Mask bit : Data write FIFO underflow */
 #define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW		(1<<8)
-/** Host Interrupt Status Mask bit : Command write FIFO overflow */
+/* Host Interrupt Status Mask bit : Command write FIFO overflow */
 #define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW		(1<<9)
-/** Host Interrupt Status Mask bit : Command write FIFO underflow */
+/* Host Interrupt Status Mask bit : Command write FIFO underflow */
 #define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW		(1<<10)
 
 /***************** IF_SPI_SPU_BUS_MODE_REG *****************/
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 6524c70363d9f507ac137c0482d3ff6094fd0ffd..e1e2128f4113fc65d0471b2e90f08f791ddf8545 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -1,6 +1,6 @@
-/**
-  * This file contains functions used in USB interface module.
-  */
+/*
+ * This file contains functions used in USB interface module.
+ */
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
@@ -66,7 +66,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
 
 /* sysfs hooks */
 
-/**
+/*
  *  Set function to write firmware to device's persistent memory
  */
 static ssize_t if_usb_firmware_set(struct device *dev,
@@ -85,7 +85,7 @@ static ssize_t if_usb_firmware_set(struct device *dev,
 	return ret;
 }
 
-/**
+/*
  * lbs_flash_fw attribute to be exported per ethX interface through sysfs
  * (/sys/class/net/ethX/lbs_flash_fw).  Use this like so to write firmware to
  * the device's persistent memory:
@@ -94,7 +94,14 @@ static ssize_t if_usb_firmware_set(struct device *dev,
 static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set);
 
 /**
- *  Set function to write firmware to device's persistent memory
+ * if_usb_boot2_set - write firmware to device's persistent memory
+ *
+ * @dev: target device
+ * @attr: device attributes
+ * @buf: firmware buffer to write
+ * @count: number of bytes to write
+ *
+ * returns: number of bytes written or negative error code
  */
 static ssize_t if_usb_boot2_set(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
@@ -112,7 +119,7 @@ static ssize_t if_usb_boot2_set(struct device *dev,
 	return ret;
 }
 
-/**
+/*
  * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs
  * (/sys/class/net/ethX/lbs_flash_boot2).  Use this like so to write firmware
  * to the device's persistent memory:
@@ -121,9 +128,10 @@ static ssize_t if_usb_boot2_set(struct device *dev,
 static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set);
 
 /**
- *  @brief  call back function to handle the status of the URB
- *  @param urb 		pointer to urb structure
- *  @return 	   	N/A
+ * if_usb_write_bulk_callback - callback function to handle the status
+ * of the URB
+ * @urb:	pointer to &urb structure
+ * returns:	N/A
  */
 static void if_usb_write_bulk_callback(struct urb *urb)
 {
@@ -150,9 +158,9 @@ static void if_usb_write_bulk_callback(struct urb *urb)
 }
 
 /**
- *  @brief  free tx/rx urb, skb and rx buffer
- *  @param cardp	pointer if_usb_card
- *  @return 	   	N/A
+ * if_usb_free - free tx/rx urb, skb and rx buffer
+ * @cardp:	pointer to &if_usb_card
+ * returns:	N/A
  */
 static void if_usb_free(struct if_usb_card *cardp)
 {
@@ -231,10 +239,10 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv)
 #endif
 
 /**
- *  @brief sets the configuration values
- *  @param ifnum	interface number
- *  @param id		pointer to usb_device_id
- *  @return 	   	0 on success, error code on failure
+ * if_usb_probe - sets the configuration values
+ * @intf:	&usb_interface pointer
+ * @id:	pointer to usb_device_id
+ * returns:	0 on success, error code on failure
  */
 static int if_usb_probe(struct usb_interface *intf,
 			const struct usb_device_id *id)
@@ -366,9 +374,9 @@ error:
 }
 
 /**
- *  @brief free resource and cleanup
- *  @param intf		USB interface structure
- *  @return 	   	N/A
+ * if_usb_disconnect - free resource and cleanup
+ * @intf:	USB interface structure
+ * returns:	N/A
  */
 static void if_usb_disconnect(struct usb_interface *intf)
 {
@@ -398,9 +406,9 @@ static void if_usb_disconnect(struct usb_interface *intf)
 }
 
 /**
- *  @brief  This function download FW
- *  @param priv		pointer to struct lbs_private
- *  @return 	   	0
+ * if_usb_send_fw_pkt - download FW
+ * @cardp:	pointer to &struct if_usb_card
+ * returns:	0
  */
 static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
 {
@@ -486,11 +494,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
 }
 
 /**
- *  @brief This function transfer the data to the device.
- *  @param priv 	pointer to struct lbs_private
- *  @param payload	pointer to payload data
- *  @param nb		data length
- *  @return 	   	0 or -1
+ *  usb_tx_block - transfer the data to the device
+ *  @cardp: 	pointer to &struct if_usb_card
+ *  @payload:	pointer to payload data
+ *  @nb:	data length
+ *  returns:	0 for success or negative error code
  */
 static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
 {
@@ -727,11 +735,11 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
 }
 
 /**
- *  @brief This function reads of the packet into the upload buff,
- *  wake up the main thread and initialise the Rx callack.
+ *  if_usb_receive - read the packet into the upload buffer,
+ *  wake up the main thread and initialise the Rx callack
  *
- *  @param urb		pointer to struct urb
- *  @return 	   	N/A
+ *  @urb:	pointer to &struct urb
+ *  returns:	N/A
  */
 static void if_usb_receive(struct urb *urb)
 {
@@ -802,12 +810,12 @@ rx_exit:
 }
 
 /**
- *  @brief This function downloads data to FW
- *  @param priv		pointer to struct lbs_private structure
- *  @param type		type of data
- *  @param buf		pointer to data buffer
- *  @param len		number of bytes
- *  @return 	   	0 or -1
+ *  if_usb_host_to_card - downloads data to FW
+ *  @priv:	pointer to &struct lbs_private structure
+ *  @type:	type of data
+ *  @payload:	pointer to data buffer
+ *  @nb:	number of bytes
+ *  returns:	0 for success or negative error code
  */
 static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
 			       uint8_t *payload, uint16_t nb)
@@ -831,10 +839,11 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
 }
 
 /**
- *  @brief This function issues Boot command to the Boot2 code
- *  @param ivalue   1:Boot from FW by USB-Download
- *                  2:Boot from FW in EEPROM
- *  @return 	   	0
+ *  if_usb_issue_boot_command - issues Boot command to the Boot2 code
+ *  @cardp:	pointer to &if_usb_card
+ *  @ivalue:	1:Boot from FW by USB-Download
+ *		2:Boot from FW in EEPROM
+ *  returns:	0 for success or negative error code
  */
 static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
 {
@@ -853,11 +862,11 @@ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
 
 
 /**
- *  @brief This function checks the validity of Boot2/FW image.
+ *  check_fwfile_format - check the validity of Boot2/FW image
  *
- *  @param data              pointer to image
- *         len               image length
- *  @return     0 or -1
+ *  @data:	pointer to image
+ *  @totlen:	image length
+ *  returns:     0 (good) or 1 (failure)
  */
 static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
 {
@@ -901,13 +910,13 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
 
 
 /**
-*  @brief This function programs the firmware subject to cmd
+*  if_usb_prog_firmware - programs the firmware subject to cmd
 *
-*  @param cardp             the if_usb_card descriptor
-*         fwname            firmware or boot2 image file name
-*         cmd               either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
-*                           or BOOT_CMD_UPDATE_BOOT2.
-*  @return     0 or error code
+*  @cardp:	the if_usb_card descriptor
+*  @fwname:	firmware or boot2 image file name
+*  @cmd:	either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
+*		or BOOT_CMD_UPDATE_BOOT2.
+*  returns:	0 or error code
 */
 static int if_usb_prog_firmware(struct if_usb_card *cardp,
 				const char *fwname, int cmd)
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index d819e7e3c9aaff43c53d866d73547e6fdc0373fc..6e42eac331deb502bbb4a9fd943c0cac82ef6870 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -6,9 +6,9 @@
 
 struct lbs_private;
 
-/**
-  * This file contains definition for USB interface.
-  */
+/*
+ * This file contains definition for USB interface.
+ */
 #define CMD_TYPE_REQUEST		0xF00DFACE
 #define CMD_TYPE_DATA			0xBEADC0DE
 #define CMD_TYPE_INDICATION		0xBEEFFACE
@@ -40,7 +40,7 @@ struct bootcmdresp
 	uint8_t	pad[2];
 };
 
-/** USB card description structure*/
+/* USB card description structure*/
 struct if_usb_card {
 	struct usb_device *udev;
 	uint32_t model;  /* MODEL_* */
@@ -77,7 +77,7 @@ struct if_usb_card {
 	__le16 boot2_version;
 };
 
-/** fwheader */
+/* fwheader */
 struct fwheader {
 	__le32 dnldcmd;
 	__le32 baseaddr;
@@ -86,14 +86,14 @@ struct fwheader {
 };
 
 #define FW_MAX_DATA_BLK_SIZE	600
-/** FWData */
+/* FWData */
 struct fwdata {
 	struct fwheader hdr;
 	__le32 seqnum;
 	uint8_t data[0];
 };
 
-/** fwsyncheader */
+/* fwsyncheader */
 struct fwsyncheader {
 	__le32 cmd;
 	__le32 seqnum;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index ca8149cd5bd9803b2bd55c05f81266647ac28d20..ed57cf863b6981230b372810cfc8ef948acac738 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1,8 +1,8 @@
-/**
-  * This file contains the major functions in WLAN
-  * driver. It includes init, exit, open, close and main
-  * thread etc..
-  */
+/*
+ * This file contains the major functions in WLAN
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ */
 
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
@@ -35,18 +35,20 @@ EXPORT_SYMBOL_GPL(lbs_debug);
 module_param_named(libertas_debug, lbs_debug, int, 0644);
 
 
-/* This global structure is used to send the confirm_sleep command as
- * fast as possible down to the firmware. */
+/*
+ * This global structure is used to send the confirm_sleep command as
+ * fast as possible down to the firmware.
+ */
 struct cmd_confirm_sleep confirm_sleep;
 
 
-/**
+/*
  * the table to keep region code
  */
 u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
     { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
 
-/**
+/*
  * FW rate table.  FW refers to rates by their index in this table, not by the
  * rate value itself.  Values of 0x00 are
  * reserved positions.
@@ -57,10 +59,10 @@ static u8 fw_data_rates[MAX_RATES] =
 };
 
 /**
- *  @brief use index to get the data rate
+ *  lbs_fw_index_to_data_rate - use index to get the data rate
  *
- *  @param idx                The index of data rate
- *  @return 	   		data rate or 0
+ *  @idx:	The index of data rate
+ *  returns:	data rate or 0
  */
 u32 lbs_fw_index_to_data_rate(u8 idx)
 {
@@ -70,10 +72,10 @@ u32 lbs_fw_index_to_data_rate(u8 idx)
 }
 
 /**
- *  @brief use rate to get the index
+ *  lbs_data_rate_to_fw_index - use rate to get the index
  *
- *  @param rate                 data rate
- *  @return 	   		index or 0
+ *  @rate:	data rate
+ *  returns:	index or 0
  */
 u8 lbs_data_rate_to_fw_index(u32 rate)
 {
@@ -91,10 +93,10 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
 
 
 /**
- *  @brief This function opens the ethX interface
+ *  lbs_dev_open - open the ethX interface
  *
- *  @param dev     A pointer to net_device structure
- *  @return 	   0 or -EBUSY if monitor mode active
+ *  @dev:	A pointer to &net_device structure
+ *  returns:	0 or -EBUSY if monitor mode active
  */
 static int lbs_dev_open(struct net_device *dev)
 {
@@ -120,10 +122,10 @@ static int lbs_dev_open(struct net_device *dev)
 }
 
 /**
- *  @brief This function closes the ethX interface
+ *  lbs_eth_stop - close the ethX interface
  *
- *  @param dev     A pointer to net_device structure
- *  @return 	   0
+ *  @dev:	A pointer to &net_device structure
+ *  returns:	0
  */
 static int lbs_eth_stop(struct net_device *dev)
 {
@@ -336,12 +338,12 @@ void lbs_set_multicast_list(struct net_device *dev)
 }
 
 /**
- *  @brief This function handles the major jobs in the LBS driver.
+ *  lbs_thread - handles the major jobs in the LBS driver.
  *  It handles all events generated by firmware, RX data received
  *  from firmware and TX data sent from kernel.
  *
- *  @param data    A pointer to lbs_thread structure
- *  @return 	   0
+ *  @data:	A pointer to &lbs_thread structure
+ *  returns:	0
  */
 static int lbs_thread(void *data)
 {
@@ -540,11 +542,11 @@ static int lbs_thread(void *data)
 }
 
 /**
- * @brief This function gets the HW spec from the firmware and sets
- *        some basic parameters.
+ * lbs_setup_firmware - gets the HW spec from the firmware and sets
+ *        some basic parameters
  *
- *  @param priv    A pointer to struct lbs_private structure
- *  @return        0 or -1
+ *  @priv:	A pointer to &struct lbs_private structure
+ *  returns:	0 or -1
  */
 static int lbs_setup_firmware(struct lbs_private *priv)
 {
@@ -630,8 +632,10 @@ int lbs_resume(struct lbs_private *priv)
 EXPORT_SYMBOL_GPL(lbs_resume);
 
 /**
- *  This function handles the timeout of command sending.
- *  It will re-send the same command again.
+ * lbs_cmd_timeout_handler - handles the timeout of command sending.
+ * It will re-send the same command again.
+ *
+ * @data: &struct lbs_private pointer
  */
 static void lbs_cmd_timeout_handler(unsigned long data)
 {
@@ -655,8 +659,10 @@ out:
 }
 
 /**
- *  This function put the device back to deep sleep mode when timer expires
- *  and no activity (command, event, data etc.) is detected.
+ * auto_deepsleep_timer_fn - put the device back to deep sleep mode when
+ * timer expires and no activity (command, event, data etc.) is detected.
+ * @data:	&struct lbs_private pointer
+ * returns:	N/A
  */
 static void auto_deepsleep_timer_fn(unsigned long data)
 {
@@ -792,11 +798,12 @@ static const struct net_device_ops lbs_netdev_ops = {
 };
 
 /**
- * @brief This function adds the card. it will probe the
+ * lbs_add_card - adds the card. It will probe the
  * card, allocate the lbs_priv and initialize the device.
  *
- *  @param card    A pointer to card
- *  @return 	   A pointer to struct lbs_private structure
+ * @card:	A pointer to card
+ * @dmdev:	A pointer to &struct device
+ * returns:	A pointer to &struct lbs_private structure
  */
 struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
 {
@@ -1057,19 +1064,19 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
 EXPORT_SYMBOL_GPL(lbs_notify_command_response);
 
 /**
- *  @brief Retrieves two-stage firmware
+ *  lbs_get_firmware - Retrieves two-stage firmware
  *
- *  @param dev     	A pointer to device structure
- *  @param user_helper	User-defined helper firmware file
- *  @param user_mainfw	User-defined main firmware file
- *  @param card_model	Bus-specific card model ID used to filter firmware table
- *                         elements
- *  @param fw_table	Table of firmware file names and device model numbers
- *                         terminated by an entry with a NULL helper name
- *  @param helper	On success, the helper firmware; caller must free
- *  @param mainfw	On success, the main firmware; caller must free
+ *  @dev:     	A pointer to &device structure
+ *  @user_helper: User-defined helper firmware file
+ *  @user_mainfw: User-defined main firmware file
+ *  @card_model: Bus-specific card model ID used to filter firmware table
+ *		elements
+ *  @fw_table:	Table of firmware file names and device model numbers
+ *		terminated by an entry with a NULL helper name
+ *  @helper:	On success, the helper firmware; caller must free
+ *  @mainfw:	On success, the main firmware; caller must free
  *
- *  @return		0 on success, non-zero on failure
+ *  returns:		0 on success, non-zero on failure
  */
 int lbs_get_firmware(struct device *dev, const char *user_helper,
 			const char *user_mainfw, u32 card_model,
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 9d097b9c8005b5e22e264ddcce8c1a5fb30343ce..a0804d12bf20589d5f2fef0dd57a645706e7772e 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -16,12 +16,15 @@
  * Mesh sysfs support
  */
 
-/**
+/*
  * Attributes exported through sysfs
  */
 
 /**
- * @brief Get function for sysfs attribute anycast_mask
+ * lbs_anycast_get - Get function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t lbs_anycast_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
@@ -40,7 +43,11 @@ static ssize_t lbs_anycast_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute anycast_mask
+ * lbs_anycast_set - Set function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t lbs_anycast_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
@@ -62,7 +69,10 @@ static ssize_t lbs_anycast_set(struct device *dev,
 }
 
 /**
- * @brief Get function for sysfs attribute prb_rsp_limit
+ * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -85,7 +95,11 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute prb_rsp_limit
+ * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
@@ -114,7 +128,10 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
 }
 
 /**
- * Get function for sysfs attribute mesh
+ * lbs_mesh_get - Get function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t lbs_mesh_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
@@ -124,7 +141,11 @@ static ssize_t lbs_mesh_get(struct device *dev,
 }
 
 /**
- *  Set function for sysfs attribute mesh
+ * lbs_mesh_set - Set function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t lbs_mesh_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
@@ -151,19 +172,19 @@ static ssize_t lbs_mesh_set(struct device *dev,
 	return count;
 }
 
-/**
+/*
  * lbs_mesh attribute to be exported per ethX interface
  * through sysfs (/sys/class/net/ethX/lbs_mesh)
  */
 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
 
-/**
+/*
  * anycast_mask attribute to be exported per mshX interface
  * through sysfs (/sys/class/net/mshX/anycast_mask)
  */
 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
 
-/**
+/*
  * prb_rsp_limit attribute to be exported per mshX interface
  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
  */
@@ -274,10 +295,10 @@ int lbs_deinit_mesh(struct lbs_private *priv)
 
 
 /**
- *  @brief This function closes the mshX interface
+ * lbs_mesh_stop - close the mshX interface
  *
- *  @param dev     A pointer to net_device structure
- *  @return 	   0
+ * @dev:	A pointer to &net_device structure
+ * returns:	0
  */
 static int lbs_mesh_stop(struct net_device *dev)
 {
@@ -301,10 +322,10 @@ static int lbs_mesh_stop(struct net_device *dev)
 }
 
 /**
- *  @brief This function opens the mshX interface
+ * lbs_mesh_dev_open - open the mshX interface
  *
- *  @param dev     A pointer to net_device structure
- *  @return 	   0 or -EBUSY if monitor mode active
+ * @dev:	A pointer to &net_device structure
+ * returns:	0 or -EBUSY if monitor mode active
  */
 static int lbs_mesh_dev_open(struct net_device *dev)
 {
@@ -342,10 +363,10 @@ static const struct net_device_ops mesh_netdev_ops = {
 };
 
 /**
- * @brief This function adds mshX interface
+ * lbs_add_mesh - add mshX interface
  *
- *  @param priv    A pointer to the struct lbs_private structure
- *  @return 	   0 if successful, -X otherwise
+ * @priv:	A pointer to the &struct lbs_private structure
+ * returns:	0 if successful, -X otherwise
  */
 int lbs_add_mesh(struct lbs_private *priv)
 {
@@ -456,13 +477,13 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
  */
 
 /**
- *  @brief Add or delete Mesh Blinding Table entries
+ * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param add  	TRUE to add the entry, FALSE to delete it
- *  @param addr1        Destination address to blind or unblind
+ * @priv:	A pointer to &struct lbs_private structure
+ * @add:	TRUE to add the entry, FALSE to delete it
+ * @addr1:	Destination address to blind or unblind
  *
- *  @return 	   	0 on success, error on failure
+ * returns:	0 on success, error on failure
  */
 int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
 {
@@ -493,11 +514,11 @@ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
 }
 
 /**
- *  @brief Reset/clear the mesh blinding table
+ * lbs_mesh_bt_reset - Reset/clear the mesh blinding table
  *
- *  @param priv    	A pointer to struct lbs_private structure
+ * @priv:	A pointer to &struct lbs_private structure
  *
- *  @return 	   	0 on success, error on failure
+ * returns:	0 on success, error on failure
  */
 int lbs_mesh_bt_reset(struct lbs_private *priv)
 {
@@ -517,17 +538,18 @@ int lbs_mesh_bt_reset(struct lbs_private *priv)
 }
 
 /**
- *  @brief Gets the inverted status of the mesh blinding table
+ * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh
+ * blinding table
  *
- *  Normally the firmware "blinds" or ignores traffic from mesh nodes in the
- *  table, but an inverted table allows *only* traffic from nodes listed in
- *  the table.
+ * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
+ * table, but an inverted table allows *only* traffic from nodes listed in
+ * the table.
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param invert  	On success, TRUE if the blinding table is inverted,
- *                        FALSE if it is not inverted
+ * @priv:	A pointer to &struct lbs_private structure
+ * @inverted:  	On success, TRUE if the blinding table is inverted,
+ *		FALSE if it is not inverted
  *
- *  @return 	   	0 on success, error on failure
+ * returns:	0 on success, error on failure
  */
 int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
 {
@@ -551,18 +573,19 @@ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
 }
 
 /**
- *  @brief Sets the inverted status of the mesh blinding table
+ * lbs_mesh_bt_set_inverted - Sets the inverted status of the mesh
+ * blinding table
  *
- *  Normally the firmware "blinds" or ignores traffic from mesh nodes in the
- *  table, but an inverted table allows *only* traffic from nodes listed in
- *  the table.
+ * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
+ * table, but an inverted table allows *only* traffic from nodes listed in
+ * the table.
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param invert  	TRUE to invert the blinding table (only traffic from
- *                         listed nodes allowed), FALSE to return it
- *                         to normal state (listed nodes ignored)
+ * @priv:	A pointer to &struct lbs_private structure
+ * @inverted:	TRUE to invert the blinding table (only traffic from
+ *		listed nodes allowed), FALSE to return it
+ *		to normal state (listed nodes ignored)
  *
- *  @return 	   	0 on success, error on failure
+ * returns:	0 on success, error on failure
  */
 int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
 {
@@ -583,13 +606,13 @@ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
 }
 
 /**
- *  @brief List an entry in the mesh blinding table
+ * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param id		The ID of the entry to list
- *  @param addr1	MAC address associated with the table entry
+ * @priv:	A pointer to &struct lbs_private structure
+ * @id:		The ID of the entry to list
+ * @addr1:	MAC address associated with the table entry
  *
- *  @return 	   	0 on success, error on failure
+ * returns: 	   	0 on success, error on failure
  */
 int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
 {
@@ -614,14 +637,14 @@ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
 }
 
 /**
- *  @brief Access the mesh forwarding table
+ * lbs_cmd_fwt_access - Access the mesh forwarding table
  *
- *  @param priv    	A pointer to struct lbs_private structure
- *  @param cmd_action	The forwarding table action to perform
- *  @param cmd		The pre-filled FWT_ACCESS command
+ * @priv:	A pointer to &struct lbs_private structure
+ * @cmd_action:	The forwarding table action to perform
+ * @cmd:	The pre-filled FWT_ACCESS command
  *
- *  @return 	   	0 on success and 'cmd' will be filled with the
- *                        firmware's response
+ * returns:	0 on success and 'cmd' will be filled with the
+ *		firmware's response
  */
 int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
 			struct cmd_ds_fwt_access *cmd)
@@ -774,7 +797,10 @@ static int mesh_get_default_parameters(struct device *dev,
 }
 
 /**
- * @brief Get function for sysfs attribute bootflag
+ * bootflag_get - Get function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t bootflag_get(struct device *dev,
 			    struct device_attribute *attr, char *buf)
@@ -791,7 +817,11 @@ static ssize_t bootflag_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute bootflag
+ * bootflag_set - Set function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
@@ -817,7 +847,10 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
 }
 
 /**
- * @brief Get function for sysfs attribute boottime
+ * boottime_get - Get function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t boottime_get(struct device *dev,
 			    struct device_attribute *attr, char *buf)
@@ -834,7 +867,11 @@ static ssize_t boottime_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute boottime
+ * boottime_set - Set function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t boottime_set(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
@@ -869,7 +906,10 @@ static ssize_t boottime_set(struct device *dev,
 }
 
 /**
- * @brief Get function for sysfs attribute channel
+ * channel_get - Get function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t channel_get(struct device *dev,
 			   struct device_attribute *attr, char *buf)
@@ -886,7 +926,11 @@ static ssize_t channel_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute channel
+ * channel_set - Set function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
 			   const char *buf, size_t count)
@@ -912,7 +956,10 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
 }
 
 /**
- * @brief Get function for sysfs attribute mesh_id
+ * mesh_id_get - Get function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
 			   char *buf)
@@ -938,7 +985,11 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
 }
 
 /**
- * @brief Set function for sysfs attribute mesh_id
+ * mesh_id_set - Set function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
 			   const char *buf, size_t count)
@@ -980,7 +1031,10 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
 }
 
 /**
- * @brief Get function for sysfs attribute protocol_id
+ * protocol_id_get - Get function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t protocol_id_get(struct device *dev,
 			       struct device_attribute *attr, char *buf)
@@ -997,7 +1051,11 @@ static ssize_t protocol_id_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute protocol_id
+ * protocol_id_set - Set function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t protocol_id_set(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
@@ -1034,7 +1092,10 @@ static ssize_t protocol_id_set(struct device *dev,
 }
 
 /**
- * @brief Get function for sysfs attribute metric_id
+ * metric_id_get - Get function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t metric_id_get(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -1051,7 +1112,11 @@ static ssize_t metric_id_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute metric_id
+ * metric_id_set - Set function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
 			     const char *buf, size_t count)
@@ -1088,7 +1153,10 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
 }
 
 /**
- * @brief Get function for sysfs attribute capability
+ * capability_get - Get function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
  */
 static ssize_t capability_get(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -1105,7 +1173,11 @@ static ssize_t capability_get(struct device *dev,
 }
 
 /**
- * @brief Set function for sysfs attribute capability
+ * capability_set - Set function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
  */
 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index afb2e8dead3f25c38fd4dedc8f12531bcccb2774..ee95c73ed5f47d3031c8ad6d2ed6040d9a9edecb 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -1,6 +1,6 @@
-/**
-  * Contains all definitions needed for the Libertas' MESH implementation.
-  */
+/*
+ * Contains all definitions needed for the Libertas' MESH implementation.
+ */
 #ifndef _LBS_MESH_H_
 #define _LBS_MESH_H_
 
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index a2b1df21d286a60c22d5658d79a1b98e7ea6b97a..a3f4b55aa41f7be653f73d55ae7054b34dc3dccc 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -1,6 +1,6 @@
-/**
-  * This file contains the handling of RX in wlan driver.
-  */
+/*
+ * This file contains the handling of RX in wlan driver.
+ */
 #include <linux/etherdevice.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -40,12 +40,12 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
 	struct sk_buff *skb);
 
 /**
- *  @brief This function processes received packet and forwards it
- *  to kernel/upper layer
+ * lbs_process_rxed_packet - processes received packet and forwards it
+ * to kernel/upper layer
  *
- *  @param	priv	A pointer to struct lbs_private
- *  @param	skb		A pointer to skb which includes the received packet
- *  @return	0 or -1
+ * @priv:	A pointer to &struct lbs_private
+ * @skb:	A pointer to skb which includes the received packet
+ * returns:	0 or -1
  */
 int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
 {
@@ -156,11 +156,11 @@ done:
 EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
 
 /**
- *  @brief This function converts Tx/Rx rates from the Marvell WLAN format
- *  (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format
+ * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
  *
- *  @param	rate	Input rate
- *  @return	Output Rate (0 if invalid)
+ * @rate:	Input rate
+ * returns:	Output Rate (0 if invalid)
  */
 static u8 convert_mv_rate_to_radiotap(u8 rate)
 {
@@ -196,12 +196,12 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
 }
 
 /**
- *  @brief This function processes a received 802.11 packet and forwards it
- *  to kernel/upper layer
+ * process_rxed_802_11_packet - processes a received 802.11 packet and forwards
+ * it to kernel/upper layer
  *
- *  @param	priv	A pointer to struct lbs_private
- *  @param	skb		A pointer to skb which includes the received packet
- *  @return	0 or -1
+ * @priv:	A pointer to &struct lbs_private
+ * @skb:	A pointer to skb which includes the received packet
+ * returns:	0 or -1
  */
 static int process_rxed_802_11_packet(struct lbs_private *priv,
 	struct sk_buff *skb)
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 8000ca6165d0b4e619f6fafb5a5ef1f9e7a73367..bbb95f88dc01f0e40a9bfd61bdb21b6cb6191a46 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -1,6 +1,6 @@
-/**
-  * This file contains the handling of TX in wlan driver.
-  */
+/*
+ * This file contains the handling of TX in wlan driver.
+ */
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/sched.h>
@@ -13,11 +13,11 @@
 #include "dev.h"
 
 /**
- *  @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
- *  units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
  *
- *  @param rate    Input rate
- *  @return      Output Rate (0 if invalid)
+ * @rate:	Input rate
+ * returns:	Output Rate (0 if invalid)
  */
 static u32 convert_radiotap_rate_to_mv(u8 rate)
 {
@@ -51,12 +51,12 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
 }
 
 /**
- *  @brief This function checks the conditions and sends packet to IF
- *  layer if everything is ok.
+ * lbs_hard_start_xmit - checks the conditions and sends packet to IF
+ * layer if everything is ok
  *
- *  @param priv    A pointer to struct lbs_private structure
- *  @param skb     A pointer to skb which includes TX packet
- *  @return 	   0 or -1
+ * @skb:	A pointer to skb which includes TX packet
+ * @dev:	A pointer to the &struct net_device
+ * returns:	0 or -1
  */
 netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -168,13 +168,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 }
 
 /**
- *  @brief This function sends to the host the last transmitted packet,
- *  filling the radiotap headers with transmission information.
+ * lbs_send_tx_feedback - sends to the host the last transmitted packet,
+ * filling the radiotap headers with transmission information.
  *
- *  @param priv     A pointer to struct lbs_private structure
- *  @param status   A 32 bit value containing transmission status.
+ * @priv:	A pointer to &struct lbs_private structure
+ * @try_count:	A 32-bit value containing transmission retry status.
  *
- *  @returns void
+ * returns:	void
  */
 void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
 {
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 462fbb4cb743b839f17e061739b83e9f2b499d2b..cf1d9b047ee6121c6c429039892ad6967dc9b93f 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -1,6 +1,6 @@
-/**
-  * This header file contains definition for global types
-  */
+/*
+ * This header file contains definition for global types
+ */
 #ifndef _LBS_TYPES_H_
 #define _LBS_TYPES_H_
 
@@ -54,7 +54,7 @@ union ieee_phy_param_set {
 	struct ieee_ie_ds_param_set ds;
 } __packed;
 
-/** TLV  type ID definition */
+/* TLV  type ID definition */
 #define PROPRIETARY_TLV_BASE_ID		0x0100
 
 /* Terminating TLV type */
@@ -96,7 +96,7 @@ union ieee_phy_param_set {
 #define TLV_TYPE_MESH_ID            (PROPRIETARY_TLV_BASE_ID + 37)
 #define TLV_TYPE_OLD_MESH_ID        (PROPRIETARY_TLV_BASE_ID + 291)
 
-/** TLV related data structures*/
+/* TLV related data structures */
 struct mrvl_ie_header {
 	__le16 type;
 	__le16 len;
@@ -177,7 +177,7 @@ struct mrvl_ie_auth_type {
 	__le16 auth;
 } __packed;
 
-/**  Local Power capability */
+/*  Local Power capability */
 struct mrvl_ie_power_capability {
 	struct mrvl_ie_header header;
 	s8 minpower;
@@ -235,9 +235,11 @@ struct mrvl_ie_ledbhv {
 	struct led_bhv ledbhv[1];
 } __packed;
 
-/* Meant to be packed as the value member of a struct ieee80211_info_element.
+/*
+ * Meant to be packed as the value member of a struct ieee80211_info_element.
  * Note that the len member of the ieee80211_info_element varies depending on
- * the mesh_id_len */
+ * the mesh_id_len
+ */
 struct mrvl_meshie_val {
 	uint8_t oui[3];
 	uint8_t type;
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index e22d761f2ef22f560fcc4c08696e94afbddda768..1d294cfa6c9bd16f40486e21a34699c1658fee2b 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -29,95 +29,38 @@
  * Fills HT capability information field, AMPDU Parameters field, HT extended
  * capability field, and supported MCS set fields.
  *
- * Only the following HT capability information fields are used, all other
- * fields are always turned off.
+ * HT capability information field, AMPDU Parameters field, supported MCS set
+ * fields are retrieved from cfg80211 stack
  *
- *  Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz)
- *  Bit 4 : Greenfield support (0: Not supported, 1: Supported)
- *  Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported)
- *  Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported)
- *  Bit 7 : Tx STBC (0: Not supported, 1: Supported)
- *  Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams)
- *  Bit 10 : Delayed BA support (0: Not supported, 1: Supported)
- *  Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets)
- *  Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported)
- *
- *  In addition, the following AMPDU Parameters are set -
- *      - Maximum AMPDU length exponent (set to 3)
- *      - Minimum AMPDU start spacing (set to 0 - No restrictions)
- *
- *  MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz
- *  support.
- *
- *  RD responder bit to set to clear in the extended capability header.
+ * RD responder bit to set to clear in the extended capability header.
  */
 void
-mwifiex_fill_cap_info(struct mwifiex_private *priv,
+mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
 		      struct mwifiex_ie_types_htcap *ht_cap)
 {
-	struct mwifiex_adapter *adapter = priv->adapter;
-	u8 *mcs;
-	int rx_mcs_supp;
-	uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
 	uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info);
+	struct ieee80211_supported_band *sband =
+					priv->wdev->wiphy->bands[radio_type];
 
-	/* Convert dev_cap to IEEE80211_HT_CAP */
-	if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
-		ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-	else
-		ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-
-	if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
-		ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
-	else
-		ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20;
-
-	if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
-		ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
-	else
-		ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40;
-
-	if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
-		ht_cap_info |= IEEE80211_HT_CAP_TX_STBC;
-	else
-		ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC;
-
-	if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
-		ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
-	else
-		ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-
-	if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap))
-		ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD;
-	else
-		ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD;
-
-	ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU;
-	ht_cap_info |= IEEE80211_HT_CAP_SM_PS;
+	ht_cap->ht_cap.ampdu_params_info =
+		(sband->ht_cap.ampdu_factor &
+		 IEEE80211_HT_AMPDU_PARM_FACTOR)|
+		((sband->ht_cap.ampdu_density <<
+		 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) &
+		 IEEE80211_HT_AMPDU_PARM_DENSITY);
 
-	ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR;
-	ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY;
-
-	rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
-
-	mcs = (u8 *)&ht_cap->ht_cap.mcs;
-
-	/* Set MCS for 1x1 */
-	memset(mcs, 0xff, rx_mcs_supp);
-
-	/* Clear all the other values */
-	memset(&mcs[rx_mcs_supp], 0,
-			sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
+	memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs,
+						sizeof(sband->ht_cap.mcs));
 
 	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
-			(ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+			(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 		/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
 		SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
 
 	/* Clear RD responder bit */
 	ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER;
 
-	ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info);
+	ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap);
 	ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
 }
 
@@ -391,10 +334,15 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 	struct mwifiex_ie_types_2040bssco *bss_co_2040;
 	struct mwifiex_ie_types_extcap *ext_cap;
 	int ret_len = 0;
+	struct ieee80211_supported_band *sband;
+	u8 radio_type;
 
 	if (!buffer || !*buffer)
 		return ret_len;
 
+	radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+	sband = priv->wdev->wiphy->bands[radio_type];
+
 	if (bss_desc->bcn_ht_cap) {
 		ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
 		memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
@@ -406,7 +354,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 		       sizeof(struct ieee_types_header),
 		       le16_to_cpu(ht_cap->header.len));
 
-		mwifiex_fill_cap_info(priv, ht_cap);
+		mwifiex_fill_cap_info(priv, radio_type, ht_cap);
 
 		*buffer += sizeof(struct mwifiex_ie_types_htcap);
 		ret_len += sizeof(struct mwifiex_ie_types_htcap);
@@ -428,8 +376,8 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 			       sizeof(struct ieee_types_header),
 			       le16_to_cpu(ht_info->header.len));
 
-			if (!ISSUPP_CHANWIDTH40
-					(priv->adapter->hw_dot_11n_dev_cap))
+			if (!(sband->ht_cap.cap &
+					IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 				ht_info->ht_info.ht_param &=
 					~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY |
 					IEEE80211_HT_PARAM_CHA_SEC_OFFSET);
@@ -451,7 +399,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 		chan_list->chan_scan_param[0].radio_type =
 			mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
 
-		if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap)
+		if ((sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 			&& (bss_desc->bcn_ht_info->ht_param &
 				IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
 			SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
index 02602ff30cbf2ac6a7d474d5967d4e04edac94cc..a4390a1a2a9fbb214b89fcb9fc3d47d7133cfc01 100644
--- a/drivers/net/wireless/mwifiex/11n.h
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -38,7 +38,7 @@ int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 			       u8 **buffer);
 void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
 			struct mwifiex_bssdescriptor *bss_desc);
-void mwifiex_fill_cap_info(struct mwifiex_private *,
+void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
 			   struct mwifiex_ie_types_htcap *);
 int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
 				  u16 action, int *htcap_cfg);
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index b99ae2677d78982266105f73ba873df02a9d6723..98009e2194c5f76752086425ed517f0a75cbd7d5 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1150,9 +1150,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
  *
  * The following default values are set -
  *      - HT Supported = True
- *      - Maximum AMPDU length factor = 0x3
- *      - Minimum AMPDU spacing = 0x6
- *      - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002)
+ *      - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K
+ *      - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE
+ *      - HT Capabilities supported by firmware
  *      - MCS information, Rx mask = 0xff
  *      - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01)
  */
@@ -1166,13 +1166,41 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
 	struct mwifiex_adapter *adapter = priv->adapter;
 
 	ht_info->ht_supported = true;
-	ht_info->ampdu_factor = 0x3;
-	ht_info->ampdu_density = 0x6;
+	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
 
 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 
-	rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support);
+	/* Fill HT capability information */
+	if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
+		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+	else
+		ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+	if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
+		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+	else
+		ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20;
+
+	if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
+		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+	else
+		ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40;
+
+	if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
+		ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
+	else
+		ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
+	if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
+		ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+	else
+		ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC;
+
+	ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
+	ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
+
+	rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
 	/* Set MCS for 1x1 */
 	memset(mcs, 0xff, rx_mcs_supp);
 	/* Clear all the other values */
@@ -1235,20 +1263,23 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
 	wdev->wiphy->max_scan_ssids = 10;
 	wdev->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
+
 	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
-	wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
+	mwifiex_setup_ht_caps(
+		&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
+
+	if (priv->adapter->config_bands & BAND_A) {
+		wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
+		mwifiex_setup_ht_caps(
+			&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
+	} else {
+		wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+	}
 
 	/* Initialize cipher suits */
 	wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
 	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
 
-	/* Initialize parameters for 2GHz band */
-
-	mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
-									priv);
-	mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap,
-									priv);
-
 	memcpy(wdev->wiphy->perm_addr, mac, 6);
 	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 23d2d0b9a52784531fafb86e4e8d72a6befaa7cf..85fca5eb4195f5c9a7f268247b5dec685d212d82 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -100,7 +100,7 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
 			   struct mwifiex_bssdescriptor *bss_desc)
 {
 	struct mwifiex_ie_types_tsf_timestamp tsf_tlv;
-	long long tsf_val;
+	__le64 tsf_val;
 
 	/* Null Checks */
 	if (buffer == NULL)
@@ -116,6 +116,8 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
 	memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header));
 	*buffer += sizeof(tsf_tlv.header);
 
+	/* TSF at the time when beacon/probe_response was received */
+	tsf_val = cpu_to_le64(bss_desc->network_tsf);
 	memcpy(*buffer, &tsf_val, sizeof(tsf_val));
 	*buffer += sizeof(tsf_val);
 
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 1b503038270e4aa96ccc08263bd5c152fff5eeb8..5043fcd22565135720f845950a7e96007c99ad0c 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -280,7 +280,7 @@ struct mwifiex_bssdescriptor {
 	 * BAND_A(0X04): 'a' band
 	 */
 	u16 bss_band;
-	long long network_tsf;
+	u64 network_tsf;
 	u8 time_stamp[8];
 	union ieee_types_phy_param_set phy_param_set;
 	union ieee_types_ss_param_set ss_param_set;
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 68d905d58606b135cb8acc8787e4d4403374037d..31a529578805e7823a378ce022a208e2f8fda735 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1007,7 +1007,9 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
 		ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
 		ht_cap->header.len =
 				cpu_to_le16(sizeof(struct ieee80211_ht_cap));
-		mwifiex_fill_cap_info(priv, ht_cap);
+		radio_type =
+			mwifiex_band_to_radio_type(priv->adapter->config_bands);
+		mwifiex_fill_cap_info(priv, radio_type, ht_cap);
 		tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
 	}
 
@@ -2988,32 +2990,28 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
 	struct mwifiex_bssdescriptor *curr_bss =
 		&priv->curr_bss_params.bss_descriptor;
 
-	/* save the beacon buffer if it is not saved or updated */
-	if ((priv->curr_bcn_buf == NULL) ||
-	    (priv->curr_bcn_size != curr_bss->beacon_buf_size) ||
-	    (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf,
-		    curr_bss->beacon_buf_size))) {
-
-		kfree(priv->curr_bcn_buf);
-		priv->curr_bcn_buf = NULL;
+	if (!curr_bss->beacon_buf_size)
+		return;
 
+	/* allocate beacon buffer at 1st time; or if it's size has changed */
+	if (!priv->curr_bcn_buf ||
+			priv->curr_bcn_size != curr_bss->beacon_buf_size) {
 		priv->curr_bcn_size = curr_bss->beacon_buf_size;
-		if (!priv->curr_bcn_size)
-			return;
 
+		kfree(priv->curr_bcn_buf);
 		priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size,
 						GFP_KERNEL);
 		if (!priv->curr_bcn_buf) {
 			dev_err(priv->adapter->dev,
 					"failed to alloc curr_bcn_buf\n");
-		} else {
-			memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
-			       curr_bss->beacon_buf_size);
-			dev_dbg(priv->adapter->dev,
-				"info: current beacon saved %d\n",
-			       priv->curr_bcn_size);
+			return;
 		}
 	}
+
+	memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
+		curr_bss->beacon_buf_size);
+	dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
+		priv->curr_bcn_size);
 }
 
 /*
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 28ebaec80be6b5cc439fe5208ba007fa1c0a3496..9f5ecef297e5db5f9723d7a18a07e49e35e334c9 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -74,6 +74,14 @@ MODULE_PARM_DESC(ap_mode_default,
 #define  MWL8K_A2H_INT_RX_READY			 (1 << 1)
 #define  MWL8K_A2H_INT_TX_DONE			 (1 << 0)
 
+/* HW micro second timer register
+ * located at offset 0xA600. This
+ * will be used to timestamp tx
+ * packets.
+ */
+
+#define	MWL8K_HW_TIMER_REGISTER			0x0000a600
+
 #define MWL8K_A2H_EVENTS	(MWL8K_A2H_INT_DUMMY | \
 				 MWL8K_A2H_INT_CHNL_SWITCHED | \
 				 MWL8K_A2H_INT_QUEUE_EMPTY | \
@@ -773,8 +781,10 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
 		skb_pull(skb, sizeof(*tr) - hdrlen);
 }
 
+#define REDUCED_TX_HEADROOM	8
+
 static void
-mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad)
+mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad)
 {
 	struct ieee80211_hdr *wh;
 	int hdrlen;
@@ -790,6 +800,22 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad)
 	wh = (struct ieee80211_hdr *)skb->data;
 
 	hdrlen = ieee80211_hdrlen(wh->frame_control);
+
+	/*
+	 * Check if skb_resize is required because of
+	 * tx_headroom adjustment.
+	 */
+	if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts)
+						+ REDUCED_TX_HEADROOM))) {
+		if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) {
+
+			wiphy_err(priv->hw->wiphy,
+					"Failed to reallocate TX buffer\n");
+			return;
+		}
+		skb->truesize += REDUCED_TX_HEADROOM;
+	}
+
 	reqd_hdrlen = sizeof(*tr);
 
 	if (hdrlen != reqd_hdrlen)
@@ -812,7 +838,8 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad)
 	tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad);
 }
 
-static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
+static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv,
+		struct sk_buff *skb)
 {
 	struct ieee80211_hdr *wh;
 	struct ieee80211_tx_info *tx_info;
@@ -853,7 +880,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
 			break;
 		}
 	}
-	mwl8k_add_dma_header(skb, data_pad);
+	mwl8k_add_dma_header(priv, skb, data_pad);
 }
 
 /*
@@ -1554,24 +1581,11 @@ static int mwl8k_tid_queue_mapping(u8 tid)
 
 /* The firmware will fill in the rate information
  * for each packet that gets queued in the hardware
- * in this structure
+ * and these macros will interpret that info.
  */
 
-struct rateinfo {
-	__le16  format:1;
-	__le16  short_gi:1;
-	__le16  band_width:1;
-	__le16  rate_id_mcs:6;
-	__le16  adv_coding:2;
-	__le16  antenna:2;
-	__le16  act_sub_chan:2;
-	__le16  preamble_type:1;
-	__le16  power_id:4;
-	__le16  antenna2:1;
-	__le16  reserved:1;
-	__le16  tx_bf_frame:1;
-	__le16  green_field:1;
-} __packed;
+#define RI_FORMAT(a)		  (a & 0x0001)
+#define RI_RATE_ID_MCS(a)	 ((a & 0x01f8) >> 3)
 
 static int
 mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
@@ -1592,7 +1606,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
 		struct ieee80211_sta *sta;
 		struct mwl8k_sta *sta_info = NULL;
 		u16 rate_info;
-		struct rateinfo *rate;
 		struct ieee80211_hdr *wh;
 
 		tx = txq->head;
@@ -1635,14 +1648,13 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
 				sta_info = MWL8K_STA(sta);
 				BUG_ON(sta_info == NULL);
 				rate_info = le16_to_cpu(tx_desc->rate_info);
-				rate = (struct rateinfo *)&rate_info;
 				/* If rate is < 6.5 Mpbs for an ht station
 				 * do not form an ampdu. If the station is a
 				 * legacy station (format = 0), do not form an
 				 * ampdu
 				 */
-				if (rate->rate_id_mcs < 1 ||
-				    rate->format == 0) {
+				if (RI_RATE_ID_MCS(rate_info) < 1 ||
+				    RI_FORMAT(rate_info) == 0) {
 					sta_info->is_ampdu_allowed = false;
 				} else {
 					sta_info->is_ampdu_allowed = true;
@@ -1666,10 +1678,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
 		processed++;
 	}
 
-	if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on &&
-	    !mutex_is_locked(&priv->fw_mutex))
-		ieee80211_wake_queue(hw, index);
-
 	return processed;
 }
 
@@ -1814,6 +1822,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	u8 tid = 0;
 	struct mwl8k_ampdu_stream *stream = NULL;
 	bool start_ba_session = false;
+	bool mgmtframe = false;
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 
 	wh = (struct ieee80211_hdr *)skb->data;
@@ -1822,10 +1831,13 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	else
 		qos = 0;
 
+	if (ieee80211_is_mgmt(wh->frame_control))
+		mgmtframe = true;
+
 	if (priv->ap_fw)
-		mwl8k_encapsulate_tx_frame(skb);
+		mwl8k_encapsulate_tx_frame(priv, skb);
 	else
-		mwl8k_add_dma_header(skb, 0);
+		mwl8k_add_dma_header(priv, skb, 0);
 
 	wh = &((struct mwl8k_dma_data *)skb->data)->wh;
 
@@ -1951,14 +1963,26 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 
 	txq = priv->txq + index;
 
-	if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) {
-		/* This is the case in which the tx packet is destined for an
-		 * AMPDU queue and that AMPDU queue is full.  Because we don't
-		 * start and stop the AMPDU queues, we must drop these packets.
-		 */
-		dev_kfree_skb(skb);
-		spin_unlock_bh(&priv->tx_lock);
-		return;
+	/* Mgmt frames that go out frequently are probe
+	 * responses. Other mgmt frames got out relatively
+	 * infrequently. Hence reserve 2 buffers so that
+	 * other mgmt frames do not get dropped due to an
+	 * already queued probe response in one of the
+	 * reserved buffers.
+	 */
+
+	if (txq->len >= MWL8K_TX_DESCS - 2) {
+		if (mgmtframe == false ||
+			txq->len == MWL8K_TX_DESCS) {
+			if (start_ba_session) {
+				spin_lock(&priv->stream_lock);
+				mwl8k_remove_stream(hw, stream);
+				spin_unlock(&priv->stream_lock);
+			}
+			spin_unlock_bh(&priv->tx_lock);
+			dev_kfree_skb(skb);
+			return;
+		}
 	}
 
 	BUG_ON(txq->skb[txq->tail] != NULL);
@@ -1975,6 +1999,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 		tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id;
 	else
 		tx->peer_id = 0;
+
+	if (priv->ap_fw)
+		tx->timestamp = cpu_to_le32(ioread32(priv->regs +
+						MWL8K_HW_TIMER_REGISTER));
+
 	wmb();
 	tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
 
@@ -1985,9 +2014,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	if (txq->tail == MWL8K_TX_DESCS)
 		txq->tail = 0;
 
-	if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES)
-		ieee80211_stop_queue(hw, index);
-
 	mwl8k_tx_start(priv);
 
 	spin_unlock_bh(&priv->tx_lock);
@@ -2482,7 +2508,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
 
 	cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT |
 				 MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP |
-				 MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON);
+				 MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON |
+				 MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY);
 	cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
 	cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
 
@@ -5466,6 +5493,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
 	hw->extra_tx_headroom =
 		sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
 
+	hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0;
+
 	hw->channel_change_time = 10;
 
 	hw->queues = MWL8K_TX_WMM_QUEUES;
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 13d750da930119bc7bdfc4faf4ad322c6cf467e2..54cc0bba66b958ed88003b2cf256b76145c81d6a 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -491,7 +491,7 @@ static int p54_parse_rssical(struct ieee80211_hw *dev,
 		struct pda_rssi_cal_entry *cal = (void *) &data[offset];
 
 		for (i = 0; i < entries; i++) {
-			u16 freq;
+			u16 freq = 0;
 			switch (i) {
 			case IEEE80211_BAND_2GHZ:
 				freq = 2437;
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 2fab7d20ffc2621bed540373ca05468c8c0669af..b6a061cbbdec1651f4fec04ecceac4539dd75ba7 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -727,3 +727,34 @@ int p54_fetch_statistics(struct p54_common *priv)
 	p54_tx(priv, skb);
 	return 0;
 }
+
+int p54_set_groupfilter(struct p54_common *priv)
+{
+	struct p54_group_address_table *grp;
+	struct sk_buff *skb;
+	bool on = false;
+
+	skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp),
+			    P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp));
+
+	on = !(priv->filter_flags & FIF_ALLMULTI) &&
+	     (priv->mc_maclist_num > 0 &&
+	      priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM);
+
+	if (on) {
+		grp->filter_enable = cpu_to_le16(1);
+		grp->num_address = cpu_to_le16(priv->mc_maclist_num);
+		memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list));
+	} else {
+		grp->filter_enable = cpu_to_le16(0);
+		grp->num_address = cpu_to_le16(0);
+		memset(grp->mac_list, 0, sizeof(grp->mac_list));
+	}
+
+	p54_tx(priv, skb);
+	return 0;
+}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
index eb581abc107906d6b3b9a9cd2317cec158c10801..3d8d622bec55d394543cf1a563b2163573e3b4f8 100644
--- a/drivers/net/wireless/p54/lmac.h
+++ b/drivers/net/wireless/p54/lmac.h
@@ -540,6 +540,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
 int p54_setup_mac(struct p54_common *priv);
 int p54_set_ps(struct p54_common *priv);
 int p54_fetch_statistics(struct p54_common *priv);
+int p54_set_groupfilter(struct p54_common *priv);
 
 /* e/v DCF setup */
 int p54_set_edcf(struct p54_common *priv);
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index a946991989c6f714805d734139cd0bd542b81e63..a5a6d9e647bbe31fcf6909e504b570543c584115 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -308,6 +308,31 @@ out:
 	return ret;
 }
 
+static u64 p54_prepare_multicast(struct ieee80211_hw *dev,
+				 struct netdev_hw_addr_list *mc_list)
+{
+	struct p54_common *priv = dev->priv;
+	struct netdev_hw_addr *ha;
+	int i;
+
+	BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) !=
+		ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list));
+	/*
+	 * The first entry is reserved for the global broadcast MAC.
+	 * Otherwise the firmware will drop it and ARP will no longer work.
+	 */
+	i = 1;
+	priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i;
+	netdev_hw_addr_list_for_each(ha, mc_list) {
+		memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN);
+		i++;
+		if (i >= ARRAY_SIZE(priv->mc_maclist))
+			break;
+	}
+
+	return 1; /* update */
+}
+
 static void p54_configure_filter(struct ieee80211_hw *dev,
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
@@ -316,12 +341,16 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
 	struct p54_common *priv = dev->priv;
 
 	*total_flags &= FIF_PROMISC_IN_BSS |
+			FIF_ALLMULTI |
 			FIF_OTHER_BSS;
 
 	priv->filter_flags = *total_flags;
 
 	if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
 		p54_setup_mac(priv);
+
+	if (changed_flags & FIF_ALLMULTI || multicast)
+		p54_set_groupfilter(priv);
 }
 
 static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
@@ -591,6 +620,7 @@ static const struct ieee80211_ops p54_ops = {
 	.config			= p54_config,
 	.flush			= p54_flush,
 	.bss_info_changed	= p54_bss_info_changed,
+	.prepare_multicast	= p54_prepare_multicast,
 	.configure_filter	= p54_configure_filter,
 	.conf_tx		= p54_conf_tx,
 	.get_stats		= p54_get_stats,
@@ -660,6 +690,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 	init_completion(&priv->beacon_comp);
 	INIT_DELAYED_WORK(&priv->work, p54_work);
 
+	memset(&priv->mc_maclist[0], ~0, ETH_ALEN);
 	return dev;
 }
 EXPORT_SYMBOL_GPL(p54_init_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 50730fc23fe57ba8c0cb6e849690a66859ae3c44..799d05e12595d0865c251ebe75383245253ea806 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -211,8 +211,10 @@ struct p54_common {
 	/* BBP/MAC state */
 	u8 mac_addr[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
+	u8 mc_maclist[4][ETH_ALEN];
 	u16 wakeup_timer;
 	unsigned int filter_flags;
+	int mc_maclist_num;
 	int mode;
 	u32 tsf_low32, tsf_high32;
 	u32 basic_rate_mask;
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index b21f81231a09df260f35d81d85317cb90b6f9d83..15237c275486467b7971a8495480c01863dbcf9e 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1797,6 +1797,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 		__set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags);
 	}
 	__set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 5cd096e2ae36a606f82220dde23d141812c28756..790afd3ed946f623f3e91f6c73a7a57fca4fd11b 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1640,7 +1640,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
 					 struct channel_info *info)
 {
 	u8 rfcsr;
-	u16 eeprom;
 
 	rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
 	rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
@@ -1670,11 +1669,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
 		rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
 	rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
 
-	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
 	if (rf->channel <= 14) {
 		int idx = rf->channel-1;
 
-		if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) {
+		if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
 			if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
 				/* r55/r59 value array of channel 1~14 */
 				static const char r55_bt_rev[] = {0x83, 0x83,
@@ -2917,8 +2915,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 		ant = (div_mode == 3) ? 1 : 0;
 
 		/* check if this is a Bluetooth combo card */
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-		if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) {
+		if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
 			u32 reg;
 
 			rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
@@ -3727,16 +3724,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	}
 
 	/*
-	 * Read frequency offset and RF programming sequence.
-	 */
-	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
-	rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
-
-	/*
-	 * Read external LNA informations.
+	 * Determine external LNA informations.
 	 */
-	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G))
 		__set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G))
@@ -3748,6 +3737,18 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO))
 		__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
 
+	/*
+	 * Detect if this device has Bluetooth co-existence.
+	 */
+	if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST))
+		__set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags);
+
+	/*
+	 * Read frequency offset and RF programming sequence.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+	rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
 	/*
 	 * Store led settings, for correct led behaviour.
 	 */
@@ -3756,7 +3757,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
 	rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
 
-	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg);
+	rt2x00dev->led_mcu_reg = eeprom;
 #endif /* CONFIG_RT2X00_LIB_LEDS */
 
 	/*
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 08d3947fcb26b7e4e75ee6f9228adc77c3c56557..cc4a54f571b8df13ab173846ef77e12ae31634e5 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -302,8 +302,8 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Write firmware to device.
 	 */
-	rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
-				   data, len);
+	rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+				      data, len);
 
 	rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
 	rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 0d4e8fa3e1f8e065b15752093d106415e7427407..0eb44cf2f44ac5f9e5cc87add612b8d1437fd6da 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -114,12 +114,12 @@ static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)
 	return false;
 }
 
-static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
+static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
 						 int urb_status, u32 tx_status)
 {
 	if (urb_status) {
 		WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status);
-		return;
+		return false;
 	}
 
 	/* try to read all TX_STA_FIFO entries before scheduling txdone_work */
@@ -129,13 +129,14 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
 				"drop tx status report.\n");
 			queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
 		} else
-			rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
-						      rt2800usb_tx_sta_fifo_read_completed);
+			return true;
 	} else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
 		queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
 	} else if (rt2800usb_txstatus_pending(rt2x00dev)) {
-		mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20));
+		mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2));
 	}
+
+	return false;
 }
 
 static void rt2800usb_tx_dma_done(struct queue_entry *entry)
@@ -493,7 +494,7 @@ static void rt2800usb_work_txdone(struct work_struct *work)
 	 * also delayed -> use a timer to retrieve it.
 	 */
 	if (rt2800usb_txstatus_pending(rt2x00dev))
-		mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20));
+		mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2));
 }
 
 /*
@@ -633,6 +634,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 	__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
 	__set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
 	__set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
 
 	setup_timer(&rt2x00dev->txstatus_timer,
 		    rt2800usb_tx_sta_fifo_timeout,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 9d1a158e2c333f330ba3bdf8b2a78b1879b54ec3..c446db69bd3c12418ae09b35cf14e1261e2b00cb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -662,6 +662,7 @@ enum rt2x00_state_flags {
 	 * Driver configuration
 	 */
 	CONFIG_CHANNEL_HT40,
+	CONFIG_POWERSAVING,
 };
 
 /*
@@ -681,6 +682,7 @@ enum rt2x00_capability_flags {
 	REQUIRE_TASKLET_CONTEXT,
 	REQUIRE_SW_SEQNO,
 	REQUIRE_HT_TX_DESC,
+	REQUIRE_PS_AUTOWAKE,
 
 	/*
 	 * Capabilities
@@ -697,6 +699,7 @@ enum rt2x00_capability_flags {
 	CAPABILITY_EXTERNAL_LNA_A,
 	CAPABILITY_EXTERNAL_LNA_BG,
 	CAPABILITY_DOUBLE_ANTENNA,
+	CAPABILITY_BT_COEXIST,
 };
 
 /*
@@ -873,11 +876,21 @@ struct rt2x00_dev {
 	 */
 	u8 calibration[2];
 
+	/*
+	 * Association id.
+	 */
+	u16 aid;
+
 	/*
 	 * Beacon interval.
 	 */
 	u16 beacon_int;
 
+	/**
+	 * Timestamp of last received beacon
+	 */
+	unsigned long last_beacon;
+
 	/*
 	 * Low level statistics which will have
 	 * to be kept up to date while device is running.
@@ -905,6 +918,11 @@ struct rt2x00_dev {
 	struct work_struct rxdone_work;
 	struct work_struct txdone_work;
 
+	/*
+	 * Powersaving work
+	 */
+	struct delayed_work autowakeup_work;
+
 	/*
 	 * Data queue arrays for RX, TX, Beacon and ATIM.
 	 */
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index f7872640459278d6ec69f788fa5f2019429d891a..555180d8f4aa7055aa77a417b75fa894898964a8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -100,6 +100,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 	erp.basic_rates = bss_conf->basic_rates;
 	erp.beacon_int = bss_conf->beacon_int;
 
+	/* Update the AID, this is needed for dynamic PS support */
+	rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0;
+	rt2x00dev->last_beacon = bss_conf->timestamp;
+
 	/* Update global beacon interval time, this is needed for PS support */
 	rt2x00dev->beacon_int = bss_conf->beacon_int;
 
@@ -204,6 +208,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 {
 	struct rt2x00lib_conf libconf;
 	u16 hw_value;
+	u16 autowake_timeout;
+	u16 beacon_int;
+	u16 beacon_diff;
 
 	memset(&libconf, 0, sizeof(libconf));
 
@@ -227,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 		       sizeof(libconf.channel));
 	}
 
+	if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+	    (ieee80211_flags & IEEE80211_CONF_CHANGE_PS))
+		cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
+
 	/*
 	 * Start configuration.
 	 */
@@ -239,6 +250,26 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2x00link_reset_tuner(rt2x00dev, false);
 
+	if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+	    (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
+	    (conf->flags & IEEE80211_CONF_PS)) {
+		beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
+		beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int);
+
+		if (beacon_diff > beacon_int)
+			beacon_diff = 0;
+
+		autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff;
+		queue_delayed_work(rt2x00dev->workqueue,
+				   &rt2x00dev->autowakeup_work,
+				   autowake_timeout - 15);
+	}
+
+	if (conf->flags & IEEE80211_CONF_PS)
+		set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
+	else
+		clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
+
 	rt2x00dev->curr_band = conf->channel->band;
 	rt2x00dev->curr_freq = conf->channel->center_freq;
 	rt2x00dev->tx_power = conf->power_level;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 7776d9f1f29750ee3d4669e29c1bd708c8315888..2eb5196977fd09573efece428af2b039c5984393 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -141,6 +141,16 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
 					    rt2x00dev);
 }
 
+static void rt2x00lib_autowakeup(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, autowakeup_work.work);
+
+	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+		ERROR(rt2x00dev, "Device failed to wakeup.\n");
+	clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
+}
+
 /*
  * Interrupt context handlers.
  */
@@ -416,6 +426,77 @@ void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status)
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
 
+static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie)
+{
+	struct ieee80211_mgmt *mgmt = (void *)data;
+	u8 *pos, *end;
+
+	pos = (u8 *)mgmt->u.beacon.variable;
+	end = data + len;
+	while (pos < end) {
+		if (pos + 2 + pos[1] > end)
+			return NULL;
+
+		if (pos[0] == ie)
+			return pos;
+
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
+				      struct sk_buff *skb,
+				      struct rxdone_entry_desc *rxdesc)
+{
+	struct ieee80211_hdr *hdr = (void *) skb->data;
+	struct ieee80211_tim_ie *tim_ie;
+	u8 *tim;
+	u8 tim_len;
+	bool cam;
+
+	/* If this is not a beacon, or if mac80211 has no powersaving
+	 * configured, or if the device is already in powersaving mode
+	 * we can exit now. */
+	if (likely(!ieee80211_is_beacon(hdr->frame_control) ||
+		   !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS)))
+		return;
+
+	/* min. beacon length + FCS_LEN */
+	if (skb->len <= 40 + FCS_LEN)
+		return;
+
+	/* and only beacons from the associated BSSID, please */
+	if (!(rxdesc->dev_flags & RXDONE_MY_BSS) ||
+	    !rt2x00dev->aid)
+		return;
+
+	rt2x00dev->last_beacon = jiffies;
+
+	tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM);
+	if (!tim)
+		return;
+
+	if (tim[1] < sizeof(*tim_ie))
+		return;
+
+	tim_len = tim[1];
+	tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+	/* Check whenever the PHY can be turned off again. */
+
+	/* 1. What about buffered unicast traffic for our AID? */
+	cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid);
+
+	/* 2. Maybe the AP wants to send multicast/broadcast data? */
+	cam |= (tim_ie->bitmap_ctrl & 0x01);
+
+	if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
+		rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf,
+				 IEEE80211_CONF_CHANGE_PS);
+}
+
 static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
 					struct rxdone_entry_desc *rxdesc)
 {
@@ -530,6 +611,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
 	    rxdesc.rate_mode == RATE_MODE_HT_GREENFIELD)
 		rxdesc.flags |= RX_FLAG_HT;
 
+	/*
+	 * Check if this is a beacon, and more frames have been
+	 * buffered while we were in powersaving mode.
+	 */
+	rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc);
+
 	/*
 	 * Update extra components
 	 */
@@ -1017,6 +1104,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 	}
 
 	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
+	INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
 
 	/*
 	 * Let the driver probe the device to detect the capabilities.
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index cb208d589ff87d48dd8f9260dcddbf0bfa33ab6d..39e1052123e30391ffd3603c7c03aa947ce6e83d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -170,19 +170,22 @@ struct rt2x00_async_read_data {
 	__le32 reg;
 	struct usb_ctrlrequest cr;
 	struct rt2x00_dev *rt2x00dev;
-	void (*callback)(struct rt2x00_dev *,int,u32);
+	bool (*callback)(struct rt2x00_dev *, int, u32);
 };
 
 static void rt2x00usb_register_read_async_cb(struct urb *urb)
 {
 	struct rt2x00_async_read_data *rd = urb->context;
-	rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg));
-	kfree(urb->context);
+	if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) {
+		if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
+			kfree(rd);
+	} else
+		kfree(rd);
 }
 
 void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
 				   const unsigned int offset,
-				   void (*callback)(struct rt2x00_dev*,int,u32))
+				   bool (*callback)(struct rt2x00_dev*, int, u32))
 {
 	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
 	struct urb *urb;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 64be34f612f6b10f59ee99a83383f26815260f58..323ca7b2b095516f622ac7badfaa99ef3ed444f2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -349,10 +349,12 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
  * be called from atomic context.  The callback will be called
  * when the URB completes. Otherwise the function is similar
  * to rt2x00usb_register_read().
+ * When the callback function returns false, the memory will be cleaned up,
+ * when it returns true, the urb will be fired again.
  */
 void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
 				   const unsigned int offset,
-				   void (*callback)(struct rt2x00_dev*,int,u32));
+				   bool (*callback)(struct rt2x00_dev*, int, u32));
 
 /*
  * Radio handlers
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index a6ce7d6cbdfae3c7e30b174cf1961b2940a4df51..ad20953cbf05860c9d26f97604b1bae91cc9fafd 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2209,6 +2209,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 	if (!modparam_nohwcrypt)
 		__set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
 	__set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
+	__set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
 
 	/*
 	 * Set the rssi offset.
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index b259f807ad27b461bd7dccc75ce3b4d9c25001fd..ccb6da38fe22aff9938b4af119385756fa487210 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -50,8 +50,9 @@
  *3) functions called by core.c
  *4) wq & timer callback functions
  *5) frame process functions
- *6) sysfs functions
- *7) ...
+ *6) IOT functions
+ *7) sysfs functions
+ *8) ...
  */
 
 /*********************************************************
@@ -59,7 +60,7 @@
  * mac80211 init functions
  *
  *********************************************************/
-static struct ieee80211_channel rtl_channeltable[] = {
+static struct ieee80211_channel rtl_channeltable_2g[] = {
 	{.center_freq = 2412, .hw_value = 1,},
 	{.center_freq = 2417, .hw_value = 2,},
 	{.center_freq = 2422, .hw_value = 3,},
@@ -76,7 +77,34 @@ static struct ieee80211_channel rtl_channeltable[] = {
 	{.center_freq = 2484, .hw_value = 14,},
 };
 
-static struct ieee80211_rate rtl_ratetable[] = {
+static struct ieee80211_channel rtl_channeltable_5g[] = {
+	{.center_freq = 5180, .hw_value = 36,},
+	{.center_freq = 5200, .hw_value = 40,},
+	{.center_freq = 5220, .hw_value = 44,},
+	{.center_freq = 5240, .hw_value = 48,},
+	{.center_freq = 5260, .hw_value = 52,},
+	{.center_freq = 5280, .hw_value = 56,},
+	{.center_freq = 5300, .hw_value = 60,},
+	{.center_freq = 5320, .hw_value = 64,},
+	{.center_freq = 5500, .hw_value = 100,},
+	{.center_freq = 5520, .hw_value = 104,},
+	{.center_freq = 5540, .hw_value = 108,},
+	{.center_freq = 5560, .hw_value = 112,},
+	{.center_freq = 5580, .hw_value = 116,},
+	{.center_freq = 5600, .hw_value = 120,},
+	{.center_freq = 5620, .hw_value = 124,},
+	{.center_freq = 5640, .hw_value = 128,},
+	{.center_freq = 5660, .hw_value = 132,},
+	{.center_freq = 5680, .hw_value = 136,},
+	{.center_freq = 5700, .hw_value = 140,},
+	{.center_freq = 5745, .hw_value = 149,},
+	{.center_freq = 5765, .hw_value = 153,},
+	{.center_freq = 5785, .hw_value = 157,},
+	{.center_freq = 5805, .hw_value = 161,},
+	{.center_freq = 5825, .hw_value = 165,},
+};
+
+static struct ieee80211_rate rtl_ratetable_2g[] = {
 	{.bitrate = 10, .hw_value = 0x00,},
 	{.bitrate = 20, .hw_value = 0x01,},
 	{.bitrate = 55, .hw_value = 0x02,},
@@ -91,18 +119,57 @@ static struct ieee80211_rate rtl_ratetable[] = {
 	{.bitrate = 540, .hw_value = 0x0b,},
 };
 
+static struct ieee80211_rate rtl_ratetable_5g[] = {
+	{.bitrate = 60, .hw_value = 0x04,},
+	{.bitrate = 90, .hw_value = 0x05,},
+	{.bitrate = 120, .hw_value = 0x06,},
+	{.bitrate = 180, .hw_value = 0x07,},
+	{.bitrate = 240, .hw_value = 0x08,},
+	{.bitrate = 360, .hw_value = 0x09,},
+	{.bitrate = 480, .hw_value = 0x0a,},
+	{.bitrate = 540, .hw_value = 0x0b,},
+};
+
 static const struct ieee80211_supported_band rtl_band_2ghz = {
 	.band = IEEE80211_BAND_2GHZ,
 
-	.channels = rtl_channeltable,
-	.n_channels = ARRAY_SIZE(rtl_channeltable),
+	.channels = rtl_channeltable_2g,
+	.n_channels = ARRAY_SIZE(rtl_channeltable_2g),
+
+	.bitrates = rtl_ratetable_2g,
+	.n_bitrates = ARRAY_SIZE(rtl_ratetable_2g),
+
+	.ht_cap = {0},
+};
+
+static struct ieee80211_supported_band rtl_band_5ghz = {
+	.band = IEEE80211_BAND_5GHZ,
+
+	.channels = rtl_channeltable_5g,
+	.n_channels = ARRAY_SIZE(rtl_channeltable_5g),
 
-	.bitrates = rtl_ratetable,
-	.n_bitrates = ARRAY_SIZE(rtl_ratetable),
+	.bitrates = rtl_ratetable_5g,
+	.n_bitrates = ARRAY_SIZE(rtl_ratetable_5g),
 
 	.ht_cap = {0},
 };
 
+static const u8 tid_to_ac[] = {
+	2, /* IEEE80211_AC_BE */
+	3, /* IEEE80211_AC_BK */
+	3, /* IEEE80211_AC_BK */
+	2, /* IEEE80211_AC_BE */
+	1, /* IEEE80211_AC_VI */
+	1, /* IEEE80211_AC_VI */
+	0, /* IEEE80211_AC_VO */
+	0, /* IEEE80211_AC_VO */
+};
+
+u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid)
+{
+	return tid_to_ac[tid];
+}
+
 static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
 				  struct ieee80211_sta_ht_cap *ht_cap)
 {
@@ -115,6 +182,9 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
 	    IEEE80211_HT_CAP_SGI_20 |
 	    IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
 
+	if (rtlpriv->rtlhal.disable_amsdu_8k)
+		ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
+
 	/*
 	 *Maximum length of AMPDU that the STA can receive.
 	 *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
@@ -159,37 +229,99 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
 
 static void _rtl_init_mac80211(struct ieee80211_hw *hw)
 {
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct ieee80211_supported_band *sband;
 
-	/* <1> use  mac->bands as mem for hw->wiphy->bands */
-	sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
 
-	/*
-	 * <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
-	 * to default value(1T1R)
-	 */
-	memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz,
-	       sizeof(struct ieee80211_supported_band));
+	if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset ==
+	    BAND_ON_BOTH) {
+		/* 1: 2.4 G bands */
+		/* <1> use  mac->bands as mem for hw->wiphy->bands */
+		sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
 
-	/* <3> init ht cap base on ant_num */
-	_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+		/* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+		 * to default value(1T1R) */
+		memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz,
+				sizeof(struct ieee80211_supported_band));
 
-	/* <4> set mac->sband to wiphy->sband */
-	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+		/* <3> init ht cap base on ant_num */
+		_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
 
+		/* <4> set mac->sband to wiphy->sband */
+		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+
+		/* 2: 5 G bands */
+		/* <1> use  mac->bands as mem for hw->wiphy->bands */
+		sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
+
+		/* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ]
+		 * to default value(1T1R) */
+		memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz,
+				sizeof(struct ieee80211_supported_band));
+
+		/* <3> init ht cap base on ant_num */
+		_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+		/* <4> set mac->sband to wiphy->sband */
+		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
+	} else {
+		if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+			/* <1> use  mac->bands as mem for hw->wiphy->bands */
+			sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
+
+			/* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+			 * to default value(1T1R) */
+			memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]),
+				 &rtl_band_2ghz,
+				 sizeof(struct ieee80211_supported_band));
+
+			/* <3> init ht cap base on ant_num */
+			_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+			/* <4> set mac->sband to wiphy->sband */
+			hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+		} else if (rtlhal->current_bandtype == BAND_ON_5G) {
+			/* <1> use  mac->bands as mem for hw->wiphy->bands */
+			sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
+
+			/* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ]
+			 * to default value(1T1R) */
+			memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]),
+				 &rtl_band_5ghz,
+				 sizeof(struct ieee80211_supported_band));
+
+			/* <3> init ht cap base on ant_num */
+			_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+			/* <4> set mac->sband to wiphy->sband */
+			hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
+		} else {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+				 ("Err BAND %d\n",
+				 rtlhal->current_bandtype));
+		}
+	}
 	/* <5> set hw caps */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
 	    IEEE80211_HW_RX_INCLUDES_FCS |
-	    IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/
-	    /*IEEE80211_HW_SUPPORTS_PS | */
-	    /*IEEE80211_HW_PS_NULLFUNC_STACK | */
-	    /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
+	    IEEE80211_HW_BEACON_FILTER |
+	    IEEE80211_HW_AMPDU_AGGREGATION |
 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
 
+	/* swlps or hwlps has been set in diff chip in init_sw_vars */
+	if (rtlpriv->psc.swctrl_lps)
+		hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+			IEEE80211_HW_PS_NULLFUNC_STACK |
+			/* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
+			0;
+
 	hw->wiphy->interface_modes =
-	    BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
+	    BIT(NL80211_IFTYPE_AP) |
+	    BIT(NL80211_IFTYPE_STATION) |
+	    BIT(NL80211_IFTYPE_ADHOC);
 
 	hw->wiphy->rts_threshold = 2347;
 
@@ -199,9 +331,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
 	/* TODO: Correct this value for our hw */
 	/* TODO: define these hard code value */
 	hw->channel_change_time = 100;
-	hw->max_listen_interval = 5;
+	hw->max_listen_interval = 10;
 	hw->max_rate_tries = 4;
 	/* hw->max_rates = 1; */
+	hw->sta_data_size = sizeof(struct rtl_sta_info);
 
 	/* <6> mac address */
 	if (is_valid_ether_addr(rtlefuse->dev_addr)) {
@@ -230,6 +363,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
 			  (void *)rtl_watchdog_wq_callback);
 	INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
 			  (void *)rtl_ips_nic_off_wq_callback);
+	INIT_DELAYED_WORK(&rtlpriv->works.ps_work,
+			  (void *)rtl_swlps_wq_callback);
+	INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
+			  (void *)rtl_swlps_rfon_wq_callback);
 
 }
 
@@ -241,6 +378,8 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
 
 	cancel_delayed_work(&rtlpriv->works.watchdog_wq);
 	cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
+	cancel_delayed_work(&rtlpriv->works.ps_work);
+	cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
 }
 
 void rtl_init_rfkill(struct ieee80211_hw *hw)
@@ -310,6 +449,8 @@ int rtl_init_core(struct ieee80211_hw *hw)
 	spin_lock_init(&rtlpriv->locks.rf_ps_lock);
 	spin_lock_init(&rtlpriv->locks.rf_lock);
 	spin_lock_init(&rtlpriv->locks.lps_lock);
+	spin_lock_init(&rtlpriv->locks.waitq_lock);
+	spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
 
 	rtlmac->link_state = MAC80211_NOLINK;
 
@@ -329,12 +470,6 @@ void rtl_init_rx_config(struct ieee80211_hw *hw)
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
-	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER,
-				      (u8 *) (&mac->rx_mgt_filter));
-	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER,
-				      (u8 *) (&mac->rx_ctrl_filter));
-	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER,
-				      (u8 *) (&mac->rx_data_filter));
 }
 
 /*********************************************************
@@ -361,28 +496,40 @@ static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw,
 }
 
 static void _rtl_query_shortgi(struct ieee80211_hw *hw,
+			       struct ieee80211_sta *sta,
 			       struct rtl_tcb_desc *tcb_desc,
 			       struct ieee80211_tx_info *info)
 {
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	u8 rate_flag = info->control.rates[0].flags;
-
+	u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0;
 	tcb_desc->use_shortgi = false;
 
-	if (!mac->ht_enable)
+	if (sta == NULL)
 		return;
 
-	if (!mac->sgi_40 && !mac->sgi_20)
+	sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+	sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+
+	if (!(sta->ht_cap.ht_supported))
+		return;
+
+	if (!sgi_40 && !sgi_20)
 		return;
 
-	if ((mac->bw_40 == true) && mac->sgi_40)
+	if (mac->opmode == NL80211_IFTYPE_STATION)
+		bw_40 = mac->bw_40;
+	else if (mac->opmode == NL80211_IFTYPE_AP ||
+		mac->opmode == NL80211_IFTYPE_ADHOC)
+		bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+	if ((bw_40 == true) && sgi_40)
 		tcb_desc->use_shortgi = true;
-	else if ((mac->bw_40 == false) && mac->sgi_20)
+	else if ((bw_40 == false) && sgi_20)
 		tcb_desc->use_shortgi = true;
 
 	if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI))
 		tcb_desc->use_shortgi = false;
-
 }
 
 static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
@@ -410,19 +557,25 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
 		tcb_desc->rts_enable = true;
 		tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
 	}
-
 }
 
 static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
+				   struct ieee80211_sta *sta,
 				   struct rtl_tcb_desc *tcb_desc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry = NULL;
+	u8 ratr_index = 7;
 
+	if (sta) {
+		sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+		ratr_index = sta_entry->ratr_index;
+	}
 	if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
-		if (mac->opmode == NL80211_IFTYPE_STATION)
+		if (mac->opmode == NL80211_IFTYPE_STATION) {
 			tcb_desc->ratr_index = 0;
-		else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+		} else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
 			if (tcb_desc->multicast || tcb_desc->broadcast) {
 				tcb_desc->hw_rate =
 				    rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
@@ -430,36 +583,61 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
 			} else {
 				/* TODO */
 			}
+			tcb_desc->ratr_index = ratr_index;
+		} else if (mac->opmode == NL80211_IFTYPE_AP) {
+			tcb_desc->ratr_index = ratr_index;
 		}
 	}
 
 	if (rtlpriv->dm.useramask) {
-		/* TODO adhoc and station handled differently in the future */
-		tcb_desc->mac_id = 0;
-
-		if ((mac->mode == WIRELESS_MODE_N_24G) ||
-		    (mac->mode == WIRELESS_MODE_N_5G)) {
-			tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
-		} else if (mac->mode & WIRELESS_MODE_G) {
-			tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
-		} else if (mac->mode & WIRELESS_MODE_B) {
-			tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
+		/* TODO we will differentiate adhoc and station futrue  */
+		if (mac->opmode == NL80211_IFTYPE_STATION) {
+			tcb_desc->mac_id = 0;
+
+			if (mac->mode == WIRELESS_MODE_N_24G)
+				tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
+			else if (mac->mode == WIRELESS_MODE_N_5G)
+				tcb_desc->ratr_index = RATR_INX_WIRELESS_NG;
+			else if (mac->mode & WIRELESS_MODE_G)
+				tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
+			else if (mac->mode & WIRELESS_MODE_B)
+				tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
+			else if (mac->mode & WIRELESS_MODE_A)
+				tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
+		} else if (mac->opmode == NL80211_IFTYPE_AP ||
+			mac->opmode == NL80211_IFTYPE_ADHOC) {
+			if (NULL != sta) {
+				if (sta->aid > 0)
+					tcb_desc->mac_id = sta->aid + 1;
+				else
+					tcb_desc->mac_id = 1;
+			} else {
+				tcb_desc->mac_id = 0;
+			}
 		}
 	}
 
 }
 
 static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
+				      struct ieee80211_sta *sta,
 				      struct rtl_tcb_desc *tcb_desc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
 	tcb_desc->packet_bw = false;
-
-	if (!mac->bw_40 || !mac->ht_enable)
+	if (!sta)
 		return;
-
+	if (mac->opmode == NL80211_IFTYPE_AP ||
+	    mac->opmode == NL80211_IFTYPE_ADHOC) {
+		if (!(sta->ht_cap.ht_supported) ||
+		    !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+			return;
+	} else if (mac->opmode == NL80211_IFTYPE_STATION) {
+		if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
+			return;
+	}
 	if (tcb_desc->multicast || tcb_desc->broadcast)
 		return;
 
@@ -486,22 +664,21 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw)
 
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
 		      struct ieee80211_tx_info *info,
+		      struct ieee80211_sta *sta,
 		      struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
 	struct ieee80211_rate *txrate;
 	__le16 fc = hdr->frame_control;
 
-	memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+	txrate = ieee80211_get_tx_rate(hw, info);
+	tcb_desc->hw_rate = txrate->hw_value;
 
 	if (ieee80211_is_data(fc)) {
-		txrate = ieee80211_get_tx_rate(hw, info);
-		tcb_desc->hw_rate = txrate->hw_value;
-
 		/*
-		 *we set data rate RTL_RC_CCK_RATE1M
+		 *we set data rate INX 0
 		 *in rtl_rc.c   if skb is special data or
 		 *mgt which need low data rate.
 		 */
@@ -510,12 +687,11 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
 		 *So tcb_desc->hw_rate is just used for
 		 *special data and mgt frames
 		 */
-		if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) {
+		if (info->control.rates[0].idx == 0 &&
+				ieee80211_is_nullfunc(fc)) {
 			tcb_desc->use_driver_rate = true;
-			tcb_desc->ratr_index = 7;
+			tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
 
-			tcb_desc->hw_rate =
-			    rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
 			tcb_desc->disable_ratefallback = 1;
 		} else {
 			/*
@@ -525,7 +701,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
 			 *and N rate will all be controlled by FW
 			 *when tcb_desc->use_driver_rate = false
 			 */
-			if (rtlmac->ht_enable) {
+			if (sta && (sta->ht_cap.ht_supported)) {
 				tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw);
 			} else {
 				if (rtlmac->mode == WIRELESS_MODE_B) {
@@ -543,43 +719,25 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
 		else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
 			tcb_desc->broadcast = 1;
 
-		_rtl_txrate_selectmode(hw, tcb_desc);
-		_rtl_query_bandwidth_mode(hw, tcb_desc);
+		_rtl_txrate_selectmode(hw, sta, tcb_desc);
+		_rtl_query_bandwidth_mode(hw, sta, tcb_desc);
 		_rtl_qurey_shortpreamble_mode(hw, tcb_desc, info);
-		_rtl_query_shortgi(hw, tcb_desc, info);
+		_rtl_query_shortgi(hw, sta, tcb_desc, info);
 		_rtl_query_protection_mode(hw, tcb_desc, info);
 	} else {
 		tcb_desc->use_driver_rate = true;
-		tcb_desc->ratr_index = 7;
+		tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
 		tcb_desc->disable_ratefallback = 1;
 		tcb_desc->mac_id = 0;
-
-		tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+		tcb_desc->packet_bw = false;
 	}
 }
 EXPORT_SYMBOL(rtl_get_tcb_desc);
 
-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
-	__le16 fc = hdr->frame_control;
-
-	if (ieee80211_is_auth(fc)) {
-		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
-		rtl_ips_nic_on(hw);
-
-		mac->link_state = MAC80211_LINKING;
-	}
-
-	return true;
-}
-
 bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 {
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	__le16 fc = hdr->frame_control;
 	u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN));
@@ -624,9 +782,8 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	__le16 fc = hdr->frame_control;
+	__le16 fc = rtl_get_fc(skb);
 	u16 ether_type;
 	u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
 	const struct iphdr *ip;
@@ -634,12 +791,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 	if (!ieee80211_is_data(fc))
 		return false;
 
-	if (ieee80211_is_nullfunc(fc))
-		return true;
 
 	ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len +
 			      SNAP_SIZE + PROTOC_TYPE_SIZE);
 	ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE);
+	/*	ether_type = ntohs(ether_type); */
 
 	if (ETH_P_IP == ether_type) {
 		if (IPPROTO_UDP == ip->protocol) {
@@ -696,61 +852,92 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
  * functions called by core.c
  *
  *********************************************************/
-int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn)
+int rtl_tx_agg_start(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_tid_data *tid_data;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry = NULL;
 
-	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
-		 ("on ra = %pM tid = %d\n", ra, tid));
+	if (sta == NULL)
+		return -EINVAL;
 
 	if (unlikely(tid >= MAX_TID_COUNT))
 		return -EINVAL;
 
-	if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 ("Start AGG when state is not RTL_AGG_OFF !\n"));
+	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+	if (!sta_entry)
 		return -ENXIO;
-	}
-
-	tid_data = &mac->tids[tid];
-	*ssn = SEQ_TO_SN(tid_data->seq_number);
+	tid_data = &sta_entry->tids[tid];
 
 	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
-		 ("HW queue is empty tid:%d\n", tid));
-	tid_data->agg.agg_state = RTL_AGG_ON;
+		 ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
+		 tid_data->seq_number));
+
+	*ssn = tid_data->seq_number;
+	tid_data->agg.agg_state = RTL_AGG_START;
 
-	ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid);
+	ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
 
 	return 0;
 }
 
-int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid)
+int rtl_tx_agg_stop(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u16 tid)
 {
-	int ssn = -1;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_tid_data *tid_data;
+	struct rtl_sta_info *sta_entry = NULL;
 
-	if (!ra) {
+	if (sta == NULL)
+		return -EINVAL;
+
+	if (!sta->addr) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
 		return -EINVAL;
 	}
 
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+		 ("on ra = %pM tid = %d\n", sta->addr, tid));
+
 	if (unlikely(tid >= MAX_TID_COUNT))
 		return -EINVAL;
 
-	if (mac->tids[tid].agg.agg_state != RTL_AGG_ON)
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 ("Stopping AGG while state not ON or starting\n"));
+	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+	tid_data = &sta_entry->tids[tid];
+	sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP;
+
+	ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
+
+	return 0;
+}
+
+int rtl_tx_agg_oper(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u16 tid)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_tid_data *tid_data;
+	struct rtl_sta_info *sta_entry = NULL;
+
+	if (sta == NULL)
+		return -EINVAL;
+
+	if (!sta->addr) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
+		return -EINVAL;
+	}
 
-	tid_data = &mac->tids[tid];
-	ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+		 ("on ra = %pM tid = %d\n", sta->addr, tid));
 
-	mac->tids[tid].agg.agg_state = RTL_AGG_OFF;
+	if (unlikely(tid >= MAX_TID_COUNT))
+		return -EINVAL;
 
-	ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid);
+	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+	tid_data = &sta_entry->tids[tid];
+	sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL;
 
 	return 0;
 }
@@ -769,18 +956,16 @@ void rtl_watchdog_wq_callback(void *data)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-
 	bool busytraffic = false;
 	bool higher_busytraffic = false;
 	bool higher_busyrxtraffic = false;
-	bool higher_busytxtraffic = false;
-
-	u8 idx = 0;
+	u8 idx, tid;
 	u32 rx_cnt_inp4eriod = 0;
 	u32 tx_cnt_inp4eriod = 0;
 	u32 aver_rx_cnt_inperiod = 0;
 	u32 aver_tx_cnt_inperiod = 0;
-
+	u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
+	u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
 	bool enter_ps = false;
 
 	if (is_hal_stop(rtlhal))
@@ -794,9 +979,6 @@ void rtl_watchdog_wq_callback(void *data)
 		mac->cnt_after_linked = 0;
 	}
 
-	/* <2> DM */
-	rtlpriv->cfg->ops->dm_watchdog(hw);
-
 	/*
 	 *<3> to check if traffic busy, if
 	 * busytraffic we don't change channel
@@ -835,8 +1017,27 @@ void rtl_watchdog_wq_callback(void *data)
 			/* Extremely high Rx data. */
 			if (aver_rx_cnt_inperiod > 5000)
 				higher_busyrxtraffic = true;
+		}
+
+		/* check every tid's tx traffic */
+		for (tid = 0; tid <= 7; tid++) {
+			for (idx = 0; idx <= 2; idx++)
+				rtlpriv->link_info.tidtx_in4period[tid][idx] =
+				  rtlpriv->link_info.tidtx_in4period[tid]
+				  [idx + 1];
+			rtlpriv->link_info.tidtx_in4period[tid][3] =
+				rtlpriv->link_info.tidtx_inperiod[tid];
+
+			for (idx = 0; idx <= 3; idx++)
+				tidtx_inp4eriod[tid] +=
+				  rtlpriv->link_info.tidtx_in4period[tid][idx];
+			aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4;
+			if (aver_tidtx_inperiod[tid] > 5000)
+				rtlpriv->link_info.higher_busytxtraffic[tid] =
+						   true;
 			else
-				higher_busytxtraffic = false;
+				rtlpriv->link_info.higher_busytxtraffic[tid] =
+						   false;
 		}
 
 		if (((rtlpriv->link_info.num_rx_inperiod +
@@ -855,11 +1056,15 @@ void rtl_watchdog_wq_callback(void *data)
 
 	rtlpriv->link_info.num_rx_inperiod = 0;
 	rtlpriv->link_info.num_tx_inperiod = 0;
+	for (tid = 0; tid <= 7; tid++)
+		rtlpriv->link_info.tidtx_inperiod[tid] = 0;
 
 	rtlpriv->link_info.busytraffic = busytraffic;
 	rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
 	rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
 
+	/* <3> DM */
+	rtlpriv->cfg->ops->dm_watchdog(hw);
 }
 
 void rtl_watch_dog_timer_callback(unsigned long data)
@@ -874,6 +1079,268 @@ void rtl_watch_dog_timer_callback(unsigned long data)
 		  jiffies + MSECS(RTL_WATCH_DOG_TIME));
 }
 
+/*********************************************************
+ *
+ * frame process functions
+ *
+ *********************************************************/
+u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie)
+{
+	struct ieee80211_mgmt *mgmt = (void *)data;
+	u8 *pos, *end;
+
+	pos = (u8 *)mgmt->u.beacon.variable;
+	end = data + len;
+	while (pos < end) {
+		if (pos + 2 + pos[1] > end)
+			return NULL;
+
+		if (pos[0] == ie)
+			return pos;
+
+		pos += 2 + pos[1];
+	}
+	return NULL;
+}
+
+/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */
+/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */
+static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
+		enum ieee80211_smps_mode smps, u8 *da, u8 *bssid)
+{
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *action_frame;
+
+	/* 27 = header + category + action + smps mode */
+	skb = dev_alloc_skb(27 + hw->extra_tx_headroom);
+	if (!skb)
+		return NULL;
+
+	skb_reserve(skb, hw->extra_tx_headroom);
+	action_frame = (void *)skb_put(skb, 27);
+	memset(action_frame, 0, 27);
+	memcpy(action_frame->da, da, ETH_ALEN);
+	memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN);
+	memcpy(action_frame->bssid, bssid, ETH_ALEN);
+	action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						  IEEE80211_STYPE_ACTION);
+	action_frame->u.action.category = WLAN_CATEGORY_HT;
+	action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
+	switch (smps) {
+	case IEEE80211_SMPS_AUTOMATIC:/* 0 */
+	case IEEE80211_SMPS_NUM_MODES:/* 4 */
+		WARN_ON(1);
+	case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/
+		action_frame->u.action.u.ht_smps.smps_control =
+				WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */
+		break;
+	case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/
+		action_frame->u.action.u.ht_smps.smps_control =
+				WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */
+		break;
+	case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/
+		action_frame->u.action.u.ht_smps.smps_control =
+				WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */
+		break;
+	}
+
+	return skb;
+}
+
+int rtl_send_smps_action(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u8 *da, u8 *bssid,
+		enum ieee80211_smps_mode smps)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid);
+	struct rtl_tcb_desc tcb_desc;
+	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+	if (rtlpriv->mac80211.act_scanning)
+		goto err_free;
+
+	if (!sta)
+		goto err_free;
+
+	if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
+		goto err_free;
+
+	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+		goto err_free;
+
+	/* this is a type = mgmt * stype = action frame */
+	if (skb) {
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+		struct rtl_sta_info *sta_entry =
+			(struct rtl_sta_info *) sta->drv_priv;
+		sta_entry->mimo_ps = smps;
+		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+
+		info->control.rates[0].idx = 0;
+		info->control.sta = sta;
+		info->band = hw->conf.channel->band;
+		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+	}
+err_free:
+	return 0;
+}
+
+/*********************************************************
+ *
+ * IOT functions
+ *
+ *********************************************************/
+static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw,
+		struct octet_string vendor_ie)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	bool matched = false;
+	static u8 athcap_1[] = { 0x00, 0x03, 0x7F };
+	static u8 athcap_2[] = { 0x00, 0x13, 0x74 };
+	static u8 broadcap_1[] = { 0x00, 0x10, 0x18 };
+	static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 };
+	static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 };
+	static u8 racap[] = { 0x00, 0x0c, 0x43 };
+	static u8 ciscocap[] = { 0x00, 0x40, 0x96 };
+	static u8 marvcap[] = { 0x00, 0x50, 0x43 };
+
+	if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 ||
+		memcmp(vendor_ie.octet, athcap_2, 3) == 0) {
+		rtlpriv->mac80211.vendor = PEER_ATH;
+		matched = true;
+	} else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 ||
+		memcmp(vendor_ie.octet, broadcap_2, 3) == 0 ||
+		memcmp(vendor_ie.octet, broadcap_3, 3) == 0) {
+		rtlpriv->mac80211.vendor = PEER_BROAD;
+		matched = true;
+	} else if (memcmp(vendor_ie.octet, racap, 3) == 0) {
+		rtlpriv->mac80211.vendor = PEER_RAL;
+		matched = true;
+	} else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) {
+		rtlpriv->mac80211.vendor = PEER_CISCO;
+		matched = true;
+	} else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) {
+		rtlpriv->mac80211.vendor = PEER_MARV;
+		matched = true;
+	}
+
+	return matched;
+}
+
+static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data,
+		unsigned int len)
+{
+	struct ieee80211_mgmt *mgmt = (void *)data;
+	struct octet_string vendor_ie;
+	u8 *pos, *end;
+
+	pos = (u8 *)mgmt->u.beacon.variable;
+	end = data + len;
+	while (pos < end) {
+		if (pos[0] == 221) {
+			vendor_ie.length = pos[1];
+			vendor_ie.octet = &pos[2];
+			if (rtl_chk_vendor_ouisub(hw, vendor_ie))
+				return true;
+		}
+
+		if (pos + 2 + pos[1] > end)
+			return false;
+
+		pos += 2 + pos[1];
+	}
+	return false;
+}
+
+void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct ieee80211_hdr *hdr = (void *)data;
+	u32 vendor = PEER_UNKNOWN;
+
+	static u8 ap3_1[3] = { 0x00, 0x14, 0xbf };
+	static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 };
+	static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e };
+	static u8 ap4_1[3] = { 0x00, 0x90, 0xcc };
+	static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e };
+	static u8 ap4_3[3] = { 0x00, 0x18, 0x02 };
+	static u8 ap4_4[3] = { 0x00, 0x17, 0x3f };
+	static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf };
+	static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 };
+	static u8 ap5_2[3] = { 0x00, 0x21, 0x91 };
+	static u8 ap5_3[3] = { 0x00, 0x24, 0x01 };
+	static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 };
+	static u8 ap5_5[3] = { 0x00, 0x17, 0x9A };
+	static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 };
+	static u8 ap6_1[3] = { 0x00, 0x17, 0x94 };
+	static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 };
+
+	if (mac->opmode != NL80211_IFTYPE_STATION)
+		return;
+
+	if (mac->link_state == MAC80211_NOLINK) {
+		mac->vendor = PEER_UNKNOWN;
+		return;
+	}
+
+	if (mac->cnt_after_linked > 2)
+		return;
+
+	/* check if this really is a beacon */
+	if (!ieee80211_is_beacon(hdr->frame_control))
+		return;
+
+	/* min. beacon length + FCS_LEN */
+	if (len <= 40 + FCS_LEN)
+		return;
+
+	/* and only beacons from the associated BSSID, please */
+	if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+		return;
+
+	if (rtl_find_221_ie(hw, data, len))
+		vendor = mac->vendor;
+
+	if ((memcmp(mac->bssid, ap5_1, 3) == 0) ||
+		(memcmp(mac->bssid, ap5_2, 3) == 0) ||
+		(memcmp(mac->bssid, ap5_3, 3) == 0) ||
+		(memcmp(mac->bssid, ap5_4, 3) == 0) ||
+		(memcmp(mac->bssid, ap5_5, 3) == 0) ||
+		(memcmp(mac->bssid, ap5_6, 3) == 0) ||
+		vendor == PEER_ATH) {
+		vendor = PEER_ATH;
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ath find\n"));
+	} else if ((memcmp(mac->bssid, ap4_4, 3) == 0) ||
+		(memcmp(mac->bssid, ap4_5, 3) == 0) ||
+		(memcmp(mac->bssid, ap4_1, 3) == 0) ||
+		(memcmp(mac->bssid, ap4_2, 3) == 0) ||
+		(memcmp(mac->bssid, ap4_3, 3) == 0) ||
+		vendor == PEER_RAL) {
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ral findn\n"));
+		vendor = PEER_RAL;
+	} else if (memcmp(mac->bssid, ap6_1, 3) == 0 ||
+		vendor == PEER_CISCO) {
+		vendor = PEER_CISCO;
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>cisco find\n"));
+	} else if ((memcmp(mac->bssid, ap3_1, 3) == 0) ||
+		(memcmp(mac->bssid, ap3_2, 3) == 0) ||
+		(memcmp(mac->bssid, ap3_3, 3) == 0) ||
+		vendor == PEER_BROAD) {
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>broad find\n"));
+		vendor = PEER_BROAD;
+	} else if (memcmp(mac->bssid, ap7_1, 3) == 0 ||
+		vendor == PEER_MARV) {
+		vendor = PEER_MARV;
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>marv find\n"));
+	}
+
+	mac->vendor = vendor;
+}
+
 /*********************************************************
  *
  * sysfs functions
@@ -941,12 +1408,13 @@ static int __init rtl_core_module_init(void)
 	if (rtl_rate_control_register())
 		printk(KERN_ERR "rtlwifi: Unable to register rtl_rc,"
 		       "use default RC !!\n");
+
 	return 0;
 }
 
 static void __exit rtl_core_module_exit(void)
 {
-	 /*RC*/
+	/*RC*/
 	rtl_rate_control_unregister();
 }
 
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 043045342bc7e91a5dd77b655f344e048bc85b95..a91f3eee59c88ff2de80337ab3891cf9d35d0322 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -24,13 +24,26 @@
  * Hsinchu 300, Taiwan.
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
+ *
  *****************************************************************************/
 
 #ifndef __RTL_BASE_H__
 #define __RTL_BASE_H__
 
+enum ap_peer {
+	PEER_UNKNOWN = 0,
+	PEER_RTL = 1,
+	PEER_RTL_92SE = 2,
+	PEER_BROAD = 3,
+	PEER_RAL = 4,
+	PEER_ATH = 5,
+	PEER_CISCO = 6,
+	PEER_MARV = 7,
+	PEER_AIRGO = 9,
+	PEER_MAX = 10,
+} ;
+
 #define RTL_DUMMY_OFFSET	0
-#define RTL_RX_DESC_SIZE	24
 #define RTL_DUMMY_UNIT		8
 #define RTL_TX_DUMMY_SIZE	(RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT)
 #define RTL_TX_DESC_SIZE	32
@@ -53,6 +66,14 @@
 #define FRAME_OFFSET_SEQUENCE		22
 #define FRAME_OFFSET_ADDRESS4		24
 
+#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val)		\
+	WRITEEF2BYTE(_hdr, _val)
+#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val)	\
+	WRITEEF1BYTE(_hdr, _val)
+#define SET_80211_HDR_PWR_MGNT(_hdr, _val)		\
+	SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val)
+#define SET_80211_HDR_TO_DS(_hdr, _val)			\
+	SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val)
 
 #define SET_80211_PS_POLL_AID(_hdr, _val)		\
 	(*(u16 *)((u8 *)(_hdr) + 2) = le16_to_cpu(_val))
@@ -64,11 +85,27 @@
 #define SET_80211_HDR_DURATION(_hdr, _val)	\
 	(*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val))
 #define SET_80211_HDR_ADDRESS1(_hdr, _val)	\
-	memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val), ETH_ALEN)
+	CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val))
 #define SET_80211_HDR_ADDRESS2(_hdr, _val)	\
-	memcpy((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val), ETH_ALEN)
+	CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val))
 #define SET_80211_HDR_ADDRESS3(_hdr, _val)	\
-	memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val), ETH_ALEN)
+	CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val))
+#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val)  \
+	WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val)
+
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val)	\
+	WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val)
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \
+	WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val)
+#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \
+	WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val)
+#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr)		\
+	READEF2BYTE(((u8 *)(__phdr)) + 34)
+#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+	WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val)
+#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+	SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \
+	(GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val))))
 
 int rtl_init_core(struct ieee80211_hw *hw);
 void rtl_deinit_core(struct ieee80211_hw *hw);
@@ -80,18 +117,27 @@ void rtl_watch_dog_timer_callback(unsigned long data);
 void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
 
 bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
 u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
 
 void rtl_watch_dog_timer_callback(unsigned long data);
-int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra,
+int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
 		     u16 tid, u16 *ssn);
-int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid);
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+		    u16 tid);
+int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+		    u16 tid);
 void rtl_watchdog_wq_callback(void *data);
 
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
 		      struct ieee80211_tx_info *info,
+		      struct ieee80211_sta *sta,
 		      struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
 
+int rtl_send_smps_action(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u8 *da, u8 *bssid,
+		enum ieee80211_smps_mode smps);
+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;
 #endif
diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c
index 52c9c1367cacb4ecb12fd035d9e1ace35b76db03..7295af0536b716553458902f3ef60d8832bd3faa 100644
--- a/drivers/net/wireless/rtlwifi/cam.c
+++ b/drivers/net/wireless/rtlwifi/cam.c
@@ -23,6 +23,8 @@
  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  * Hsinchu 300, Taiwan.
  *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
  *****************************************************************************/
 
 #include "wifi.h"
@@ -49,7 +51,7 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
 	u32 target_content = 0;
 	u8 entry_i;
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 		 ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n",
 		  key_cont_128[0], key_cont_128[1],
 		  key_cont_128[2], key_cont_128[3],
@@ -68,15 +70,13 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
 			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
 					target_command);
 
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 ("rtl_cam_program_entry(): "
-				  "WRITE %x: %x\n",
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 ("WRITE %x: %x\n",
 				  rtlpriv->cfg->maps[WCAMI], target_content));
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 				 ("The Key ID is %d\n", entry_no));
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 ("rtl_cam_program_entry(): "
-				  "WRITE %x: %x\n",
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 ("WRITE %x: %x\n",
 				  rtlpriv->cfg->maps[RWCAM], target_command));
 
 		} else if (entry_i == 1) {
@@ -91,12 +91,10 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
 			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
 					target_command);
 
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 ("rtl_cam_program_entry(): WRITE A4: %x\n",
-				  target_content));
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 ("rtl_cam_program_entry(): WRITE A0: %x\n",
-				  target_command));
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 ("WRITE A4: %x\n", target_content));
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 ("WRITE A0: %x\n", target_command));
 
 		} else {
 
@@ -113,16 +111,14 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
 					target_command);
 			udelay(100);
 
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 ("rtl_cam_program_entry(): WRITE A4: %x\n",
-				  target_content));
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 ("rtl_cam_program_entry(): WRITE A0: %x\n",
-				  target_command));
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 ("WRITE A4: %x\n", target_content));
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 ("WRITE A0: %x\n", target_command));
 		}
 	}
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 		 ("after set key, usconfig:%x\n", us_config));
 }
 
@@ -289,3 +285,71 @@ void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
 
 }
 EXPORT_SYMBOL(rtl_cam_empty_entry);
+
+u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4;
+	u8 entry_idx = 0;
+	u8 i, *addr;
+
+	if (NULL == sta_addr) {
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+			("sta_addr is NULL.\n"));
+		return TOTAL_CAM_ENTRY;
+	}
+	/* Does STA already exist? */
+	for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
+		addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
+		if (memcmp(addr, sta_addr, ETH_ALEN) == 0)
+			return i;
+	}
+	/* Get a free CAM entry. */
+	for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) {
+		if ((bitmap & BIT(0)) == 0) {
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+				("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n",
+				 rtlpriv->sec.hwsec_cam_bitmap, entry_idx));
+			rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx;
+			memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx],
+			       sta_addr, ETH_ALEN);
+			return entry_idx;
+		}
+		bitmap = bitmap >> 1;
+	}
+	return TOTAL_CAM_ENTRY;
+}
+EXPORT_SYMBOL(rtl_cam_get_free_entry);
+
+void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 bitmap;
+	u8 i, *addr;
+
+	if (NULL == sta_addr) {
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+			("sta_addr is NULL.\n"));
+	}
+
+	if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\
+				sta_addr[4]|sta_addr[5]) == 0) {
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+			("sta_addr is 00:00:00:00:00:00.\n"));
+		return;
+	}
+	/* Does STA already exist? */
+	for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
+		addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
+		bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i;
+		if (((bitmap & BIT(0)) == BIT(0)) &&
+		    (memcmp(addr, sta_addr, ETH_ALEN) == 0)) {
+			/* Remove from HW Security CAM */
+			memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN);
+			rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
+			printk(KERN_INFO "&&&&&&&&&del entry %d\n", i);
+		}
+	}
+	return;
+}
+EXPORT_SYMBOL(rtl_cam_del_entry);
diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h
index dd82f057d53dcb3ad49dea28f60a4db36cb842a7..c62da4eefc75e85f11d6aea2d9b9afbb5e111482 100644
--- a/drivers/net/wireless/rtlwifi/cam.h
+++ b/drivers/net/wireless/rtlwifi/cam.h
@@ -23,12 +23,13 @@
  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  * Hsinchu 300, Taiwan.
  *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
  *****************************************************************************/
 
 #ifndef __RTL_CAM_H_
 #define __RTL_CAM_H_
 
-#define TOTAL_CAM_ENTRY					32
 #define CAM_CONTENT_COUNT				8
 
 #define CFG_DEFAULT_KEY					BIT(5)
@@ -49,5 +50,7 @@ int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
 void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index);
 void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index);
 void rtl_cam_reset_sec_info(struct ieee80211_hw *hw);
+u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr);
+void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 8fed3c687619accb1bec267b246e2dce506b3f97..fc89cd8c8320e0d7b934fbaafd00b09694cb40ed 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -24,6 +24,7 @@
  * Hsinchu 300, Taiwan.
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
+ *
  *****************************************************************************/
 
 #include "wifi.h"
@@ -70,6 +71,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
 
 	mac->link_state = MAC80211_NOLINK;
 	memset(mac->bssid, 0, 6);
+	mac->vendor = PEER_UNKNOWN;
 
 	/*reset sec info */
 	rtl_cam_reset_sec_info(hw);
@@ -85,6 +87,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_tcb_desc tcb_desc;
+	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
 
 	if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
 		goto err_free;
@@ -92,8 +96,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
 		goto err_free;
 
-
-	rtlpriv->intf_ops->adapter_tx(hw, skb);
+	if (!rtlpriv->intf_ops->waitq_insert(hw, skb))
+		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
 
 	return;
 
@@ -134,10 +138,26 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
 
 		mac->link_state = MAC80211_LINKED;
 		rtlpriv->cfg->ops->set_bcn_reg(hw);
+		if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+			mac->basic_rates = 0xfff;
+		else
+			mac->basic_rates = 0xff0;
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+				(u8 *) (&mac->basic_rates));
+
 		break;
 	case NL80211_IFTYPE_AP:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 			 ("NL80211_IFTYPE_AP\n"));
+
+		mac->link_state = MAC80211_LINKED;
+		rtlpriv->cfg->ops->set_bcn_reg(hw);
+		if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+			mac->basic_rates = 0xfff;
+		else
+			mac->basic_rates = 0xff0;
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+				(u8 *) (&mac->basic_rates));
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -184,13 +204,12 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
 	mac->vif = NULL;
 	mac->link_state = MAC80211_NOLINK;
 	memset(mac->bssid, 0, 6);
+	mac->vendor = PEER_UNKNOWN;
 	mac->opmode = NL80211_IFTYPE_UNSPECIFIED;
 	rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
-
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
 }
 
-
 static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -222,10 +241,25 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 
 	/*For LPS */
 	if (changed & IEEE80211_CONF_CHANGE_PS) {
-		if (conf->flags & IEEE80211_CONF_PS)
-			rtl_lps_enter(hw);
-		else
-			rtl_lps_leave(hw);
+		cancel_delayed_work(&rtlpriv->works.ps_work);
+		cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
+		if (conf->flags & IEEE80211_CONF_PS) {
+			rtlpriv->psc.sw_ps_enabled = true;
+			/* sleep here is must, or we may recv the beacon and
+			 * cause mac80211 into wrong ps state, this will cause
+			 * power save nullfunc send fail, and further cause
+			 * pkt loss, So sleep must quickly but not immediatly
+			 * because that will cause nullfunc send by mac80211
+			 * fail, and cause pkt loss, we have tested that 5mA
+			 * is worked very well */
+			if (!rtlpriv->psc.multi_buffered)
+				queue_delayed_work(rtlpriv->works.rtl_wq,
+						&rtlpriv->works.ps_work,
+						MSECS(5));
+		} else {
+			rtl_swlps_rf_awake(hw);
+			rtlpriv->psc.sw_ps_enabled = false;
+		}
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
@@ -257,7 +291,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 		case NL80211_CHAN_NO_HT:
 			/* SC */
 			mac->cur_40_prime_sc =
-			    PRIME_CHNL_OFFSET_DONT_CARE;
+				PRIME_CHNL_OFFSET_DONT_CARE;
 			rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20;
 			mac->bw_40 = false;
 			break;
@@ -265,7 +299,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 			/* SC */
 			mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER;
 			rtlphy->current_chan_bw =
-			    HT_CHANNEL_WIDTH_20_40;
+				HT_CHANNEL_WIDTH_20_40;
 			mac->bw_40 = true;
 
 			/*wide channel */
@@ -276,7 +310,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 			/* SC */
 			mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER;
 			rtlphy->current_chan_bw =
-			    HT_CHANNEL_WIDTH_20_40;
+				HT_CHANNEL_WIDTH_20_40;
 			mac->bw_40 = true;
 
 			/*wide channel */
@@ -286,16 +320,29 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 		default:
 			mac->bw_40 = false;
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 ("switch case not processed\n"));
+					("switch case not processed\n"));
 			break;
 		}
 
 		if (wide_chan <= 0)
 			wide_chan = 1;
+
+		/* In scanning, before we go offchannel we may send a ps=1 null
+		 * to AP, and then we may send a ps = 0 null to AP quickly, but
+		 * first null may have caused AP to put lots of packet to hw tx
+		 * buffer. These packets must be tx'd before we go off channel
+		 * so we must delay more time to let AP flush these packets
+		 * before going offchannel, or dis-association or delete BA will
+		 * happen by AP
+		 */
+		if (rtlpriv->mac80211.offchan_deley) {
+			rtlpriv->mac80211.offchan_deley = false;
+			mdelay(50);
+		}
 		rtlphy->current_channel = wide_chan;
 
-		rtlpriv->cfg->ops->set_channel_access(hw);
 		rtlpriv->cfg->ops->switch_channel(hw);
+		rtlpriv->cfg->ops->set_channel_access(hw);
 		rtlpriv->cfg->ops->set_bw_mode(hw,
 					       hw->conf.channel_type);
 	}
@@ -343,27 +390,28 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
 		}
 	}
 
-	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-		/*
-		 *TODO: BIT(5) is probe response BIT(8) is beacon
-		 *TODO: Use define for BIT(5) and BIT(8)
-		 */
-		if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
-			mac->rx_mgt_filter |= (BIT(5) | BIT(8));
-		else
-			mac->rx_mgt_filter &= ~(BIT(5) | BIT(8));
+	/* if ssid not set to hw don't check bssid
+	 * here just used for linked scanning, & linked
+	 * and nolink check bssid is set in set network_type */
+	if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
+		(mac->link_state >= MAC80211_LINKED)) {
+		if (mac->opmode != NL80211_IFTYPE_AP) {
+			if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
+				rtlpriv->cfg->ops->set_chk_bssid(hw, false);
+			} else {
+				rtlpriv->cfg->ops->set_chk_bssid(hw, true);
+			}
+		}
 	}
 
 	if (changed_flags & FIF_CONTROL) {
 		if (*new_flags & FIF_CONTROL) {
 			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
-			mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER;
 
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 				 ("Enable receive control frame.\n"));
 		} else {
 			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
-			mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER;
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 				 ("Disable receive control frame.\n"));
 		}
@@ -380,14 +428,54 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
 				 ("Disable receive other BSS's frame.\n"));
 		}
 	}
-
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER,
-				      (u8 *) (&mac->rx_mgt_filter));
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER,
-				      (u8 *) (&mac->rx_ctrl_filter));
 }
+static int rtl_op_sta_add(struct ieee80211_hw *hw,
+			 struct ieee80211_vif *vif,
+			 struct ieee80211_sta *sta)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry;
+
+	if (sta) {
+		sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+		if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+			sta_entry->wireless_mode = WIRELESS_MODE_G;
+			if (sta->supp_rates[0] <= 0xf)
+				sta_entry->wireless_mode = WIRELESS_MODE_B;
+			if (sta->ht_cap.ht_supported == true)
+				sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+		} else if (rtlhal->current_bandtype == BAND_ON_5G) {
+			sta_entry->wireless_mode = WIRELESS_MODE_A;
+			if (sta->ht_cap.ht_supported == true)
+				sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+		}
+
+		/* I found some times mac80211 give wrong supp_rates for adhoc*/
+		if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+			sta_entry->wireless_mode = WIRELESS_MODE_G;
 
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+			("Add sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr)));
+		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+	}
+	return 0;
+}
+static int rtl_op_sta_remove(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				struct ieee80211_sta *sta)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_sta_info *sta_entry;
+	if (sta) {
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+			("Remove sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr)));
+		sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+		sta_entry->wireless_mode = 0;
+		sta_entry->ratr_index = 0;
+	}
+	return 0;
+}
 static int _rtl_get_hal_qnum(u16 queue)
 {
 	int qnum;
@@ -444,19 +532,18 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 			     struct ieee80211_bss_conf *bss_conf, u32 changed)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct ieee80211_sta *sta = NULL;
 
 	mutex_lock(&rtlpriv->locks.conf_mutex);
-
 	if ((vif->type == NL80211_IFTYPE_ADHOC) ||
 	    (vif->type == NL80211_IFTYPE_AP) ||
 	    (vif->type == NL80211_IFTYPE_MESH_POINT)) {
-
 		if ((changed & BSS_CHANGED_BEACON) ||
 		    (changed & BSS_CHANGED_BEACON_ENABLED &&
 		     bss_conf->enable_beacon)) {
-
 			if (mac->beacon_enabled == 0) {
 				RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 					 ("BSS_CHANGED_BEACON_ENABLED\n"));
@@ -468,8 +555,13 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 						rtlpriv->cfg->maps
 						[RTL_IBSS_INT_MASKS],
 						0);
+
+				if (rtlpriv->cfg->ops->linked_set_reg)
+					rtlpriv->cfg->ops->linked_set_reg(hw);
 			}
-		} else {
+		}
+		if ((changed & BSS_CHANGED_BEACON_ENABLED &&
+			!bss_conf->enable_beacon)) {
 			if (mac->beacon_enabled == 1) {
 				RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 					 ("ADHOC DISABLE BEACON\n"));
@@ -480,7 +572,6 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 						[RTL_IBSS_INT_MASKS]);
 			}
 		}
-
 		if (changed & BSS_CHANGED_BEACON_INT) {
 			RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE,
 				 ("BSS_CHANGED_BEACON_INT\n"));
@@ -492,11 +583,25 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 	/*TODO: reference to enum ieee80211_bss_change */
 	if (changed & BSS_CHANGED_ASSOC) {
 		if (bss_conf->assoc) {
+			/* we should reset all sec info & cam
+			 * before set cam after linked, we should not
+			 * reset in disassoc, that will cause tkip->wep
+			 * fail because some flag will be wrong */
+			/* reset sec info */
+			rtl_cam_reset_sec_info(hw);
+			/* reset cam to fix wep fail issue
+			 * when change from wpa to wep */
+			rtl_cam_reset_all_entry(hw);
+
 			mac->link_state = MAC80211_LINKED;
 			mac->cnt_after_linked = 0;
 			mac->assoc_id = bss_conf->aid;
 			memcpy(mac->bssid, bss_conf->bssid, 6);
 
+			if (rtlpriv->cfg->ops->linked_set_reg)
+				rtlpriv->cfg->ops->linked_set_reg(hw);
+			if (mac->opmode == NL80211_IFTYPE_STATION && sta)
+				rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 				 ("BSS_CHANGED_ASSOC\n"));
 		} else {
@@ -505,9 +610,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 
 			mac->link_state = MAC80211_NOLINK;
 			memset(mac->bssid, 0, 6);
-
-			/* reset sec info */
-			rtl_cam_reset_sec_info(hw);
+			mac->vendor = PEER_UNKNOWN;
 
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 				 ("BSS_CHANGED_UN_ASSOC\n"));
@@ -544,14 +647,10 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 	}
 
 	if (changed & BSS_CHANGED_HT) {
-		struct ieee80211_sta *sta = NULL;
-
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 ("BSS_CHANGED_HT\n"));
-
 		rcu_read_lock();
-		sta = ieee80211_find_sta(mac->vif, mac->bssid);
-
+		sta = get_sta(hw, vif, (u8 *)bss_conf->bssid);
 		if (sta) {
 			if (sta->ht_cap.ampdu_density >
 			    mac->current_ampdu_density)
@@ -573,9 +672,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 	}
 
 	if (changed & BSS_CHANGED_BSSID) {
-		struct ieee80211_sta *sta = NULL;
 		u32 basic_rates;
-		u8 i;
 
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID,
 					      (u8 *) bss_conf->bssid);
@@ -583,96 +680,65 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 			 (MAC_FMT "\n", MAC_ARG(bss_conf->bssid)));
 
+		mac->vendor = PEER_UNKNOWN;
 		memcpy(mac->bssid, bss_conf->bssid, 6);
-		if (is_valid_ether_addr(bss_conf->bssid)) {
-			switch (vif->type) {
-			case NL80211_IFTYPE_UNSPECIFIED:
-				break;
-			case NL80211_IFTYPE_ADHOC:
-				break;
-			case NL80211_IFTYPE_STATION:
-				break;
-			case NL80211_IFTYPE_AP:
-				break;
-			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-					 ("switch case not process\n"));
-				break;
-			}
-			rtlpriv->cfg->ops->set_network_type(hw, vif->type);
-		} else
-			rtlpriv->cfg->ops->set_network_type(hw,
-					NL80211_IFTYPE_UNSPECIFIED);
-
-		memset(mac->mcs, 0, 16);
-		mac->ht_enable = false;
-		mac->sgi_40 = false;
-		mac->sgi_20 = false;
-
-		if (!bss_conf->use_short_slot)
-			mac->mode = WIRELESS_MODE_B;
-		else
-			mac->mode = WIRELESS_MODE_G;
+		rtlpriv->cfg->ops->set_network_type(hw, vif->type);
 
 		rcu_read_lock();
-		sta = ieee80211_find_sta(mac->vif, mac->bssid);
+		sta = get_sta(hw, vif, (u8 *)bss_conf->bssid);
+		if (!sta) {
+			rcu_read_unlock();
+			goto out;
+		}
 
-		if (sta) {
-			if (sta->ht_cap.ht_supported) {
+		if (rtlhal->current_bandtype == BAND_ON_5G) {
+			mac->mode = WIRELESS_MODE_A;
+		} else {
+			if (sta->supp_rates[0] <= 0xf)
+				mac->mode = WIRELESS_MODE_B;
+			else
+				mac->mode = WIRELESS_MODE_G;
+		}
+
+		if (sta->ht_cap.ht_supported) {
+			if (rtlhal->current_bandtype == BAND_ON_2_4G)
 				mac->mode = WIRELESS_MODE_N_24G;
-				mac->ht_enable = true;
-			}
+			else
+				mac->mode = WIRELESS_MODE_N_5G;
+		}
 
-			if (mac->ht_enable) {
-				u16 ht_cap = sta->ht_cap.cap;
-				memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16);
-
-				for (i = 0; i < 16; i++)
-					RT_TRACE(rtlpriv, COMP_MAC80211,
-						 DBG_LOUD, ("%x ",
-							    mac->mcs[i]));
-				RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
-					 ("\n"));
-
-				if (ht_cap & IEEE80211_HT_CAP_SGI_40)
-					mac->sgi_40 = true;
-
-				if (ht_cap & IEEE80211_HT_CAP_SGI_20)
-					mac->sgi_20 = true;
-
-				/*
-				 * for cisco 1252 bw20 it's wrong
-				 * if (ht_cap &
-				 *     IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
-				 *	mac->bw_40 = true;
-				 * }
-				 */
-			}
+		/* just station need it, because ibss & ap mode will
+		 * set in sta_add, and will be NULL here */
+		if (mac->opmode == NL80211_IFTYPE_STATION) {
+			struct rtl_sta_info *sta_entry;
+			sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+			sta_entry->wireless_mode = mac->mode;
+		}
+
+		if (sta->ht_cap.ht_supported) {
+			mac->ht_enable = true;
+
+			/*
+			 * for cisco 1252 bw20 it's wrong
+			 * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+			 *	mac->bw_40 = true;
+			 * }
+			 * */
 		}
-		rcu_read_unlock();
 
-		/*mac80211 just give us CCK rates any time
-		 *So we add G rate in basic rates when
-		 not in B mode*/
 		if (changed & BSS_CHANGED_BASIC_RATES) {
-			if (mac->mode == WIRELESS_MODE_B)
-				basic_rates = bss_conf->basic_rates | 0x00f;
+			/* for 5G must << RATE_6M_INDEX=4,
+			 * because 5G have no cck rate*/
+			if (rtlhal->current_bandtype == BAND_ON_5G)
+				basic_rates = sta->supp_rates[1] << 4;
 			else
-				basic_rates = bss_conf->basic_rates | 0xff0;
-
-			if (!vif)
-				goto out;
+				basic_rates = sta->supp_rates[0];
 
 			mac->basic_rates = basic_rates;
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
 					(u8 *) (&basic_rates));
-
-			if (rtlpriv->dm.useramask)
-				rtlpriv->cfg->ops->update_rate_mask(hw, 0);
-			else
-				rtlpriv->cfg->ops->update_rate_table(hw);
-
 		}
+		rcu_read_unlock();
 	}
 
 	/*
@@ -758,16 +824,17 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
 	case IEEE80211_AMPDU_TX_START:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid));
-		return rtl_tx_agg_start(hw, sta->addr, tid, ssn);
+		return rtl_tx_agg_start(hw, sta, tid, ssn);
 		break;
 	case IEEE80211_AMPDU_TX_STOP:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid));
-		return rtl_tx_agg_stop(hw, sta->addr, tid);
+		return rtl_tx_agg_stop(hw, sta, tid);
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid));
+		rtl_tx_agg_oper(hw, sta, tid);
 		break;
 	case IEEE80211_AMPDU_RX_START:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
@@ -797,8 +864,12 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
 	if (mac->link_state == MAC80211_LINKED) {
 		rtl_lps_leave(hw);
 		mac->link_state = MAC80211_LINKED_SCANNING;
-	} else
+	} else {
 		rtl_ips_nic_on(hw);
+	}
+
+	/* Dual mac */
+	rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
 
 	rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY);
 	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP);
@@ -810,22 +881,19 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
 	RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n"));
-
-	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
 	mac->act_scanning = false;
+	/* Dual mac */
+	rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
+
 	if (mac->link_state == MAC80211_LINKED_SCANNING) {
 		mac->link_state = MAC80211_LINKED;
-
-		/* fix fwlps issue */
-		rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
-
-		if (rtlpriv->dm.useramask)
-			rtlpriv->cfg->ops->update_rate_mask(hw, 0);
-		else
-			rtlpriv->cfg->ops->update_rate_table(hw);
-
+		if (mac->opmode == NL80211_IFTYPE_STATION) {
+			/* fix fwlps issue */
+			rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+		}
 	}
 
+	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
 }
 
 static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -856,49 +924,73 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	rtl_ips_nic_on(hw);
 	mutex_lock(&rtlpriv->locks.conf_mutex);
 	/* <1> get encryption alg */
+
 	switch (key->cipher) {
 	case WLAN_CIPHER_SUITE_WEP40:
 		key_type = WEP40_ENCRYPTION;
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n"));
-		rtlpriv->sec.use_defaultkey = true;
 		break;
 	case WLAN_CIPHER_SUITE_WEP104:
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 			 ("alg:WEP104\n"));
 		key_type = WEP104_ENCRYPTION;
-		rtlpriv->sec.use_defaultkey = true;
 		break;
 	case WLAN_CIPHER_SUITE_TKIP:
 		key_type = TKIP_ENCRYPTION;
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n"));
-		if (mac->opmode == NL80211_IFTYPE_ADHOC)
-			rtlpriv->sec.use_defaultkey = true;
 		break;
 	case WLAN_CIPHER_SUITE_CCMP:
 		key_type = AESCCMP_ENCRYPTION;
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n"));
-		if (mac->opmode == NL80211_IFTYPE_ADHOC)
-			rtlpriv->sec.use_defaultkey = true;
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 ("alg_err:%x!!!!:\n", key->cipher));
 		goto out_unlock;
 	}
+	if (key_type == WEP40_ENCRYPTION ||
+			key_type == WEP104_ENCRYPTION ||
+			mac->opmode == NL80211_IFTYPE_ADHOC)
+		rtlpriv->sec.use_defaultkey = true;
+
 	/* <2> get key_idx */
 	key_idx = (u8) (key->keyidx);
 	if (key_idx > 3)
 		goto out_unlock;
 	/* <3> if pairwise key enable_hw_sec */
 	group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
-	if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) ||
-	    rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
-		if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION &&
-		    (key_type == WEP40_ENCRYPTION ||
-		     key_type == WEP104_ENCRYPTION))
-			wep_only = true;
-		rtlpriv->sec.pairwise_enc_algorithm = key_type;
-		rtlpriv->cfg->ops->enable_hw_sec(hw);
+
+	/* wep always be group key, but there are two conditions:
+	 * 1) wep only: is just for wep enc, in this condition
+	 * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
+	 * will be true & enable_hw_sec will be set when wep
+	 * ke setting.
+	 * 2) wep(group) + AES(pairwise): some AP like cisco
+	 * may use it, in this condition enable_hw_sec will not
+	 * be set when wep key setting */
+	/* we must reset sec_info after lingked before set key,
+	 * or some flag will be wrong*/
+	if (mac->opmode == NL80211_IFTYPE_AP) {
+		if (!group_key || key_type == WEP40_ENCRYPTION ||
+			key_type == WEP104_ENCRYPTION) {
+			if (group_key)
+				wep_only = true;
+			rtlpriv->cfg->ops->enable_hw_sec(hw);
+		}
+	} else {
+		if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) ||
+		     rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
+			if (rtlpriv->sec.pairwise_enc_algorithm ==
+			    NO_ENCRYPTION &&
+			    (key_type == WEP40_ENCRYPTION ||
+			    key_type == WEP104_ENCRYPTION))
+				wep_only = true;
+			rtlpriv->sec.pairwise_enc_algorithm = key_type;
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+				("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1"
+				" TKIP:2 AES:4 WEP104:5)\n", key_type));
+			rtlpriv->cfg->ops->enable_hw_sec(hw);
+		}
 	}
 	/* <4> set key based on cmd */
 	switch (cmd) {
@@ -930,6 +1022,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			if (!sta) {
 				RT_ASSERT(false, ("pairwise key withnot"
 						  "mac_addr\n"));
+
 				err = -EOPNOTSUPP;
 				goto out_unlock;
 			}
@@ -957,6 +1050,10 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 			 ("disable key delete one entry\n"));
 		/*set local buf about wep key. */
+		if (mac->opmode == NL80211_IFTYPE_AP) {
+			if (sta)
+				rtl_cam_del_entry(hw, sta->addr);
+		}
 		memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen);
 		rtlpriv->sec.key_len[key_idx] = 0;
 		memcpy(mac_addr, zero_addr, ETH_ALEN);
@@ -1009,6 +1106,18 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
 }
 
+/* this function is called by mac80211 to flush tx buffer
+ * before switch channle or power save, or tx buffer packet
+ * maybe send after offchannel or rf sleep, this may cause
+ * dis-association by AP */
+static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->intf_ops->flush)
+		rtlpriv->intf_ops->flush(hw, drop);
+}
+
 const struct ieee80211_ops rtl_ops = {
 	.start = rtl_op_start,
 	.stop = rtl_op_stop,
@@ -1017,6 +1126,8 @@ const struct ieee80211_ops rtl_ops = {
 	.remove_interface = rtl_op_remove_interface,
 	.config = rtl_op_config,
 	.configure_filter = rtl_op_configure_filter,
+	.sta_add = rtl_op_sta_add,
+	.sta_remove = rtl_op_sta_remove,
 	.set_key = rtl_op_set_key,
 	.conf_tx = rtl_op_conf_tx,
 	.bss_info_changed = rtl_op_bss_info_changed,
@@ -1028,4 +1139,5 @@ const struct ieee80211_ops rtl_ops = {
 	.sw_scan_start = rtl_op_sw_scan_start,
 	.sw_scan_complete = rtl_op_sw_scan_complete,
 	.rfkill_poll = rtl_op_rfkill_poll,
+	.flush = rtl_op_flush,
 };
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
index 0ef31c3c6196478ac266d867ab69dd2c72d5a0f8..4b247db2861d67ea023f02653b48625b2a48a864 100644
--- a/drivers/net/wireless/rtlwifi/core.h
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -24,6 +24,7 @@
  * Hsinchu 300, Taiwan.
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
+ *
  *****************************************************************************/
 
 #ifndef __RTL_CORE_H__
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 5d73c0f7012cbc19f37a4a12296b4d92750f0bff..510d42edb8caba62ca1ace18d057f87794aa6318 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -52,8 +52,6 @@ static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
 	{11, 0, 0, 28}
 };
 
-static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset,
-					u8 *pbuf);
 static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset,
 				    u8 *value);
 static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset,
@@ -79,7 +77,7 @@ static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,
 					u8 *targetdata);
 static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
 				       u16 efuse_addr, u8 word_en, u8 *data);
-static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite,
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 write,
 					u8 pwrstate);
 static u16 efuse_get_current_size(struct ieee80211_hw *hw);
 static u8 efuse_calculate_word_cnts(u8 word_en);
@@ -115,8 +113,10 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address)
 	u8 bytetemp;
 	u8 temp;
 	u32 k = 0;
+	const u32 efuse_len =
+		rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
 
-	if (address < EFUSE_REAL_CONTENT_LEN) {
+	if (address < efuse_len) {
 		temp = address & 0xFF;
 		rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
 			       temp);
@@ -158,11 +158,13 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
 	u8 bytetemp;
 	u8 temp;
 	u32 k = 0;
+	const u32 efuse_len =
+		rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
 
 	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
 		 ("Addr=%x Data =%x\n", address, value));
 
-	if (address < EFUSE_REAL_CONTENT_LEN) {
+	if (address < efuse_len) {
 		rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value);
 
 		temp = address & 0xFF;
@@ -198,7 +200,7 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
 
 }
 
-static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
+void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 value32;
@@ -233,24 +235,28 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u8 efuse_tbl[EFUSE_MAP_LEN];
+	u8 efuse_tbl[HWSET_MAX_SIZE];
 	u8 rtemp8[1];
 	u16 efuse_addr = 0;
 	u8 offset, wren;
 	u16 i;
 	u16 j;
+	const u16 efuse_max_section =
+		rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP];
+	const u32 efuse_len =
+		rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
 	u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT];
 	u16 efuse_utilized = 0;
 	u8 efuse_usage;
 
-	if ((_offset + _size_byte) > EFUSE_MAP_LEN) {
+	if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) {
 		RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
 			 ("read_efuse(): Invalid offset(%#x) with read "
 			  "bytes(%#x)!!\n", _offset, _size_byte));
 		return;
 	}
 
-	for (i = 0; i < EFUSE_MAX_SECTION; i++)
+	for (i = 0; i < efuse_max_section; i++)
 		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
 			efuse_word[i][j] = 0xFFFF;
 
@@ -262,10 +268,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 		efuse_addr++;
 	}
 
-	while ((*rtemp8 != 0xFF) && (efuse_addr < EFUSE_REAL_CONTENT_LEN)) {
+	while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) {
 		offset = ((*rtemp8 >> 4) & 0x0f);
 
-		if (offset < EFUSE_MAX_SECTION) {
+		if (offset < efuse_max_section) {
 			wren = (*rtemp8 & 0x0f);
 			RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
 				("offset-%d Worden=%x\n", offset, wren));
@@ -281,7 +287,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 					efuse_utilized++;
 					efuse_word[offset][i] = (*rtemp8 & 0xff);
 
-					if (efuse_addr >= EFUSE_REAL_CONTENT_LEN)
+					if (efuse_addr >= efuse_len)
 						break;
 
 					RTPRINT(rtlpriv, FEEPROM,
@@ -294,7 +300,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 					efuse_word[offset][i] |=
 					    (((u16)*rtemp8 << 8) & 0xff00);
 
-					if (efuse_addr >= EFUSE_REAL_CONTENT_LEN)
+					if (efuse_addr >= efuse_len)
 						break;
 				}
 
@@ -305,13 +311,13 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 		RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
 			("Addr=%d\n", efuse_addr));
 		read_efuse_byte(hw, efuse_addr, rtemp8);
-		if (*rtemp8 != 0xFF && (efuse_addr < 512)) {
+		if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) {
 			efuse_utilized++;
 			efuse_addr++;
 		}
 	}
 
-	for (i = 0; i < EFUSE_MAX_SECTION; i++) {
+	for (i = 0; i < efuse_max_section; i++) {
 		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
 			efuse_tbl[(i * 8) + (j * 2)] =
 			    (efuse_word[i][j] & 0xff);
@@ -324,7 +330,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 		pbuf[i] = efuse_tbl[_offset + i];
 
 	rtlefuse->efuse_usedbytes = efuse_utilized;
-	efuse_usage = (u8)((efuse_utilized * 100) / EFUSE_REAL_CONTENT_LEN);
+	efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len);
 	rtlefuse->efuse_usedpercentage = efuse_usage;
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES,
 				      (u8 *)&efuse_utilized);
@@ -478,9 +484,10 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 
-	if (rtlefuse->autoload_failflag == true) {
-		memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128);
-	} else
+	if (rtlefuse->autoload_failflag == true)
+		memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF,
+			rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+	else
 		efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
 
 	memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
@@ -632,8 +639,9 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
 
 static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse)
 {
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	efuse_power_switch(hw, false, true);
-	read_efuse(hw, 0, 128, efuse);
+	read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse);
 	efuse_power_switch(hw, false, false);
 }
 
@@ -641,7 +649,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
 				u8 efuse_data, u8 offset, u8 *tmpdata,
 				u8 *readstate)
 {
-	bool bdataempty = true;
+	bool dataempty = true;
 	u8 hoffset;
 	u8 tmpidx;
 	u8 hworden;
@@ -657,13 +665,13 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
 			    &efuse_data)) {
 				tmpdata[tmpidx] = efuse_data;
 				if (efuse_data != 0xff)
-					bdataempty = true;
+					dataempty = true;
 			}
 		}
 
-		if (bdataempty == true)
+		if (dataempty == true) {
 			*readstate = PG_STATE_DATA;
-		else {
+		} else {
 			*efuse_addr = *efuse_addr + (word_cnts * 2) + 1;
 			*readstate = PG_STATE_HEADER;
 		}
@@ -677,9 +685,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
 static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
 {
 	u8 readstate = PG_STATE_HEADER;
-
 	bool continual = true;
-
 	u8 efuse_data, word_cnts = 0;
 	u16 efuse_addr = 0;
 	u8 tmpdata[8];
@@ -795,19 +801,20 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
 					tmp_word_en &= (~BIT(1));
 
 				if ((target_pkt->word_en & BIT(2)) ^
-					(match_word_en & BIT(2)))
+				     (match_word_en & BIT(2)))
 					tmp_word_en &= (~BIT(2));
 
 				if ((target_pkt->word_en & BIT(3)) ^
-				    (match_word_en & BIT(3)))
+				     (match_word_en & BIT(3)))
 					tmp_word_en &= (~BIT(3));
 
 				if ((tmp_word_en & 0x0F) != 0x0F) {
 					*efuse_addr = efuse_get_current_size(hw);
 					target_pkt->offset = offset;
 					target_pkt->word_en = tmp_word_en;
-				} else
+				} else {
 					*continual = false;
+				}
 				*write_state = PG_STATE_HEADER;
 				*repeat_times += 1;
 				if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
@@ -842,9 +849,9 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
 	efuse_one_byte_write(hw, *efuse_addr, pg_header);
 	efuse_one_byte_read(hw, *efuse_addr, &tmp_header);
 
-	if (tmp_header == pg_header)
+	if (tmp_header == pg_header) {
 		*write_state = PG_STATE_DATA;
-	else if (tmp_header == 0xFF) {
+	} else if (tmp_header == 0xFF) {
 		*write_state = PG_STATE_HEADER;
 		*repeat_times += 1;
 		if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
@@ -871,11 +878,13 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
 						      reorg_worden,
 						      originaldata);
 				*efuse_addr = efuse_get_current_size(hw);
-			 } else
+			} else {
 				*efuse_addr = *efuse_addr + (tmp_word_cnts * 2)
 					      + 1;
-		} else
+			}
+		} else {
 			*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
+		}
 
 		*write_state = PG_STATE_HEADER;
 		*repeat_times += 1;
@@ -1069,10 +1078,12 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
 static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 tempval;
 	u16 tmpV16;
 
-	if (pwrstate) {
+	if (pwrstate && (rtlhal->hw_type !=
+		HARDWARE_TYPE_RTL8192SE)) {
 		tmpV16 = rtl_read_word(rtlpriv,
 				       rtlpriv->cfg->maps[SYS_ISO_CTRL]);
 		if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
@@ -1105,13 +1116,22 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
 			tempval = rtl_read_byte(rtlpriv,
 						rtlpriv->cfg->maps[EFUSE_TEST] +
 						3);
-			tempval &= 0x0F;
-			tempval |= (VOLTAGE_V25 << 4);
+
+			if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) {
+				tempval &= 0x0F;
+				tempval |= (VOLTAGE_V25 << 4);
+			}
+
 			rtl_write_byte(rtlpriv,
 				       rtlpriv->cfg->maps[EFUSE_TEST] + 3,
 				       (tempval | 0x80));
 		}
 
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+			rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
+						0x03);
+		}
+
 	} else {
 		if (write) {
 			tempval = rtl_read_byte(rtlpriv,
@@ -1122,6 +1142,11 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
 				       (tempval & 0x7F));
 		}
 
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+			rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
+						0x02);
+		}
+
 	}
 
 }
diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h
index 47774dd4c2a6c945ebf5386ba04320557c492b29..164dabaa76159cc14690c535258d3982357e3ac4 100644
--- a/drivers/net/wireless/rtlwifi/efuse.h
+++ b/drivers/net/wireless/rtlwifi/efuse.h
@@ -30,9 +30,10 @@
 #ifndef __RTL_EFUSE_H_
 #define __RTL_EFUSE_H_
 
+#define EFUSE_IC_ID_OFFSET		506
+
 #define EFUSE_REAL_CONTENT_LEN		512
 #define EFUSE_MAP_LEN			128
-#define EFUSE_MAX_SECTION		16
 #define EFUSE_MAX_WORD_UNIT		4
 
 #define EFUSE_INIT_MAP			0
@@ -52,6 +53,7 @@
 #define _PRE_EXECUTE_READ_CMD_
 
 #define EFUSE_REPEAT_THRESHOLD_		3
+#define EFUSE_ERROE_HANDLE		1
 
 struct efuse_map {
 	u8 offset;
@@ -103,6 +105,7 @@ struct efuse_priv {
 	u8 tx_power_g[14];
 };
 
+extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf);
 extern void efuse_initialize(struct ieee80211_hw *hw);
 extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address);
 extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value);
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index c3dd4cc678ba52f326263768de28e19d7c5a4647..3550c9fb96e5ff9fb58012c5942677a84a85bb31 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -32,6 +32,7 @@
 #include "pci.h"
 #include "base.h"
 #include "ps.h"
+#include "efuse.h"
 
 static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
 	INTEL_VENDOR_ID,
@@ -40,6 +41,31 @@ static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
 	SIS_VENDOR_ID
 };
 
+static const u8 ac_to_hwq[] = {
+	VO_QUEUE,
+	VI_QUEUE,
+	BE_QUEUE,
+	BK_QUEUE
+};
+
+static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
+		       struct sk_buff *skb)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	__le16 fc = rtl_get_fc(skb);
+	u8 queue_index = skb_get_queue_mapping(skb);
+
+	if (unlikely(ieee80211_is_beacon(fc)))
+		return BEACON_QUEUE;
+	if (ieee80211_is_mgmt(fc))
+		return MGNT_QUEUE;
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+		if (ieee80211_is_nullfunc(fc))
+			return HIGH_QUEUE;
+
+	return ac_to_hwq[queue_index];
+}
+
 /* Update PCI dependent default settings*/
 static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
 {
@@ -48,6 +74,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+	u8 init_aspm;
 
 	ppsc->reg_rfps_level = 0;
 	ppsc->support_aspm = 0;
@@ -113,25 +140,45 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
 
 	/*Set HW definition to determine if it supports ASPM. */
 	switch (rtlpci->const_support_pciaspm) {
-	case 0:
-		/*Not support ASPM. */
-		ppsc->support_aspm = false;
-		break;
-	case 1:
-		/*Support ASPM. */
-		ppsc->support_aspm = true;
-		ppsc->support_backdoor = true;
-		break;
+	case 0:{
+			/*Not support ASPM. */
+			bool support_aspm = false;
+			ppsc->support_aspm = support_aspm;
+			break;
+		}
+	case 1:{
+			/*Support ASPM. */
+			bool support_aspm = true;
+			bool support_backdoor = true;
+			ppsc->support_aspm = support_aspm;
+
+			/*if (priv->oem_id == RT_CID_TOSHIBA &&
+			   !priv->ndis_adapter.amd_l1_patch)
+			   support_backdoor = false; */
+
+			ppsc->support_backdoor = support_backdoor;
+
+			break;
+		}
 	case 2:
 		/*ASPM value set by chipset. */
-		if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
-			ppsc->support_aspm = true;
+		if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) {
+			bool support_aspm = true;
+			ppsc->support_aspm = support_aspm;
+		}
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 ("switch case not process\n"));
 		break;
 	}
+
+	/* toshiba aspm issue, toshiba will set aspm selfly
+	 * so we should not set aspm in driver */
+	pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm);
+	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE &&
+		init_aspm == 0x43)
+		ppsc->support_aspm = false;
 }
 
 static bool _rtl_pci_platform_switch_device_pci_aspm(
@@ -139,8 +186,11 @@ static bool _rtl_pci_platform_switch_device_pci_aspm(
 			u8 value)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)
+		value |= 0x40;
 
-	value |= 0x40;
 	pci_write_config_byte(rtlpci->pdev, 0x80, value);
 
 	return false;
@@ -150,11 +200,13 @@ static bool _rtl_pci_platform_switch_device_pci_aspm(
 static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	u8 buffer;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
-	buffer = value;
 	pci_write_config_byte(rtlpci->pdev, 0x81, value);
 
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+		udelay(100);
+
 	return true;
 }
 
@@ -175,6 +227,9 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
 	u16 aspmlevel = 0;
 	u8 tmp_u1b = 0;
 
+	if (!ppsc->support_aspm)
+		return;
+
 	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
 			 ("PCI(Bridge) UNKNOWN.\n"));
@@ -228,6 +283,9 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 	u8 u_pcibridge_aspmsetting;
 	u8 u_device_aspmsetting;
 
+	if (!ppsc->support_aspm)
+		return;
+
 	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
 			 ("PCI(Bridge) UNKNOWN.\n"));
@@ -272,7 +330,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 					     RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0);
 		RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
 	}
-	udelay(200);
+	udelay(100);
 }
 
 static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
@@ -309,13 +367,13 @@ static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
 	u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
 	u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
 	u8 linkctrl_reg;
-	u8 num4bBytes;
+	u8 num4bbytes;
 
-	num4bBytes = (capabilityoffset + 0x10) / 4;
+	num4bbytes = (capabilityoffset + 0x10) / 4;
 
 	/*Read  Link Control Register */
 	rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-				     pcicfg_addrport + (num4bBytes << 2));
+				     pcicfg_addrport + (num4bbytes << 2));
 	rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg);
 
 	pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
@@ -348,7 +406,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev,
 	pci_write_config_byte(pdev, 0x70f, tmp);
 }
 
-static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw)
+static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
 {
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 
@@ -362,52 +420,6 @@ static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw)
 
 }
 
-static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
-{
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-
-	/*close ASPM for AMD defaultly */
-	rtlpci->const_amdpci_aspm = 0;
-
-	/*
-	 * ASPM PS mode.
-	 * 0 - Disable ASPM,
-	 * 1 - Enable ASPM without Clock Req,
-	 * 2 - Enable ASPM with Clock Req,
-	 * 3 - Always Enable ASPM with Clock Req,
-	 * 4 - Always Enable ASPM without Clock Req.
-	 * set defult to RTL8192CE:3 RTL8192E:2
-	 * */
-	rtlpci->const_pci_aspm = 3;
-
-	/*Setting for PCI-E device */
-	rtlpci->const_devicepci_aspm_setting = 0x03;
-
-	/*Setting for PCI-E bridge */
-	rtlpci->const_hostpci_aspm_setting = 0x02;
-
-	/*
-	 * In Hw/Sw Radio Off situation.
-	 * 0 - Default,
-	 * 1 - From ASPM setting without low Mac Pwr,
-	 * 2 - From ASPM setting with low Mac Pwr,
-	 * 3 - Bus D3
-	 * set default to RTL8192CE:0 RTL8192SE:2
-	 */
-	rtlpci->const_hwsw_rfoff_d3 = 0;
-
-	/*
-	 * This setting works for those device with
-	 * backdoor ASPM setting such as EPHY setting.
-	 * 0 - Not support ASPM,
-	 * 1 - Support ASPM,
-	 * 2 - According to chipset.
-	 */
-	rtlpci->const_support_pciaspm = 1;
-
-	_rtl_pci_initialize_adapter_common(hw);
-}
-
 static void _rtl_pci_io_handler_init(struct device *dev,
 				     struct ieee80211_hw *hw)
 {
@@ -429,6 +441,90 @@ static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
 {
 }
 
+static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
+		struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	u8 additionlen = FCS_LEN;
+	struct sk_buff *next_skb;
+
+	/* here open is 4, wep/tkip is 8, aes is 12*/
+	if (info->control.hw_key)
+		additionlen += info->control.hw_key->icv_len;
+
+	/* The most skb num is 6 */
+	tcb_desc->empkt_num = 0;
+	spin_lock_bh(&rtlpriv->locks.waitq_lock);
+	skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) {
+		struct ieee80211_tx_info *next_info;
+
+		next_info = IEEE80211_SKB_CB(next_skb);
+		if (next_info->flags & IEEE80211_TX_CTL_AMPDU) {
+			tcb_desc->empkt_len[tcb_desc->empkt_num] =
+				next_skb->len + additionlen;
+			tcb_desc->empkt_num++;
+		} else {
+			break;
+		}
+
+		if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid],
+				      next_skb))
+			break;
+
+		if (tcb_desc->empkt_num >= 5)
+			break;
+	}
+	spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+	return true;
+}
+
+/* just for early mode now */
+static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct sk_buff *skb = NULL;
+	struct ieee80211_tx_info *info = NULL;
+	int tid; /* should be int */
+
+	if (!rtlpriv->rtlhal.earlymode_enable)
+		return;
+
+	/* we juse use em for BE/BK/VI/VO */
+	for (tid = 7; tid >= 0; tid--) {
+		u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)];
+		struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+		while (!mac->act_scanning &&
+		       rtlpriv->psc.rfpwr_state == ERFON) {
+			struct rtl_tcb_desc tcb_desc;
+			memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+			spin_lock_bh(&rtlpriv->locks.waitq_lock);
+			if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
+			   (ring->entries - skb_queue_len(&ring->queue) > 5)) {
+				skb = skb_dequeue(&mac->skb_waitq[tid]);
+			} else {
+				spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+				break;
+			}
+			spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+			/* Some macaddr can't do early mode. like
+			 * multicast/broadcast/no_qos data */
+			info = IEEE80211_SKB_CB(skb);
+			if (info->flags & IEEE80211_TX_CTL_AMPDU)
+				_rtl_update_earlymode_info(hw, skb,
+							   &tcb_desc, tid);
+
+			rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+		}
+	}
+}
+
+
 static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -440,6 +536,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
 		struct sk_buff *skb;
 		struct ieee80211_tx_info *info;
+		__le16 fc;
+		u8 tid;
 
 		u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
 							  HW_DESC_OWN);
@@ -460,6 +558,10 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 						      HW_DESC_TXBUFF_ADDR),
 				 skb->len, PCI_DMA_TODEVICE);
 
+		/* remove early mode header */
+		if (rtlpriv->rtlhal.earlymode_enable)
+			skb_pull(skb, EM_HDR_LEN);
+
 		RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE,
 			 ("new ring->idx:%d, "
 			  "free: skb_queue_len:%d, free: seq:%x\n",
@@ -467,6 +569,30 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 			  skb_queue_len(&ring->queue),
 			  *(u16 *) (skb->data + 22)));
 
+		if (prio == TXCMD_QUEUE) {
+			dev_kfree_skb(skb);
+			goto tx_status_ok;
+
+		}
+
+		/* for sw LPS, just after NULL skb send out, we can
+		 * sure AP kown we are sleeped, our we should not let
+		 * rf to sleep*/
+		fc = rtl_get_fc(skb);
+		if (ieee80211_is_nullfunc(fc)) {
+			if (ieee80211_has_pm(fc)) {
+				rtlpriv->mac80211.offchan_deley = true;
+				rtlpriv->psc.state_inap = 1;
+			} else {
+				rtlpriv->psc.state_inap = 0;
+			}
+		}
+
+		/* update tid tx pkt num */
+		tid = rtl_get_tid(skb);
+		if (tid <= 7)
+			rtlpriv->link_info.tidtx_inperiod[tid]++;
+
 		info = IEEE80211_SKB_CB(skb);
 		ieee80211_tx_info_clear_status(info);
 
@@ -489,7 +615,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 					skb_get_queue_mapping
 					(skb));
 		}
-
+tx_status_ok:
 		skb = NULL;
 	}
 
@@ -561,23 +687,21 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 			 *skb_trim(skb, skb->len - 4);
 			 */
 
-			hdr = (struct ieee80211_hdr *)(skb->data);
-			fc = hdr->frame_control;
+			hdr = rtl_get_hdr(skb);
+			fc = rtl_get_fc(skb);
 
-			if (!stats.crc) {
+			if (!stats.crc || !stats.hwerror) {
 				memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
 				       sizeof(rx_status));
 
-				if (is_broadcast_ether_addr(hdr->addr1))
+				if (is_broadcast_ether_addr(hdr->addr1)) {
 					;/*TODO*/
-				else {
-					if (is_multicast_ether_addr(hdr->addr1))
-						;/*TODO*/
-					else {
-						unicast = true;
-						rtlpriv->stats.rxbytesunicast +=
-						    skb->len;
-					}
+				} else if (is_multicast_ether_addr(hdr->addr1)) {
+					;/*TODO*/
+				} else {
+					unicast = true;
+					rtlpriv->stats.rxbytesunicast +=
+					    skb->len;
 				}
 
 				rtl_is_special_data(hw, skb, false);
@@ -591,28 +715,38 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 						    num_rx_inperiod++;
 				}
 
-				if (unlikely(!rtl_action_proc(hw, skb,
-				    false))) {
+				/* for sw lps */
+				rtl_swlps_beacon(hw, (void *)skb->data,
+						 skb->len);
+				rtl_recognize_peer(hw, (void *)skb->data,
+						   skb->len);
+				if ((rtlpriv->mac80211.opmode ==
+				     NL80211_IFTYPE_AP) &&
+				    (rtlpriv->rtlhal.current_bandtype ==
+				     BAND_ON_2_4G) &&
+				     (ieee80211_is_beacon(fc) ||
+				     ieee80211_is_probe_resp(fc))) {
 					dev_kfree_skb_any(skb);
 				} else {
-					struct sk_buff *uskb = NULL;
-					u8 *pdata;
-					uskb = dev_alloc_skb(skb->len + 128);
-					if (!uskb) {
-						RT_TRACE(rtlpriv,
-							(COMP_INTR | COMP_RECV),
-							DBG_EMERG,
-							("can't alloc rx skb\n"));
-						goto done;
+					if (unlikely(!rtl_action_proc(hw, skb,
+					    false))) {
+						dev_kfree_skb_any(skb);
+					} else {
+						struct sk_buff *uskb = NULL;
+						u8 *pdata;
+						uskb = dev_alloc_skb(skb->len
+								     + 128);
+						memcpy(IEEE80211_SKB_RXCB(uskb),
+						       &rx_status,
+						       sizeof(rx_status));
+						pdata = (u8 *)skb_put(uskb,
+							skb->len);
+						memcpy(pdata, skb->data,
+						       skb->len);
+						dev_kfree_skb_any(skb);
+
+						ieee80211_rx_irqsafe(hw, uskb);
 					}
-					memcpy(IEEE80211_SKB_RXCB(uskb),
-							&rx_status,
-							sizeof(rx_status));
-					pdata = (u8 *)skb_put(uskb, skb->len);
-					memcpy(pdata, skb->data, skb->len);
-					dev_kfree_skb_any(skb);
-
-					ieee80211_rx_irqsafe(hw, uskb);
 				}
 			} else {
 				dev_kfree_skb_any(skb);
@@ -627,7 +761,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 			new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
 			if (unlikely(!new_skb)) {
 				RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
-					 DBG_EMERG,
+					 DBG_DMESG,
 					 ("can't alloc skb for rx\n"));
 				goto done;
 			}
@@ -645,7 +779,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 
 		}
 done:
-		bufferaddress = (u32)(*((dma_addr_t *) skb->cb));
+		bufferaddress = (*((dma_addr_t *)skb->cb));
 		tmp_one = 1;
 		rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
 					    HW_DESC_RXBUFF_ADDR,
@@ -674,6 +808,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
 	struct ieee80211_hw *hw = dev_id;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	unsigned long flags;
 	u32 inta = 0;
 	u32 intb = 0;
@@ -760,23 +895,36 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
 		_rtl_pci_tx_isr(hw, VO_QUEUE);
 	}
 
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+		if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) {
+			rtlpriv->link_info.num_tx_inperiod++;
+
+			RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+					("CMD TX OK interrupt!\n"));
+			_rtl_pci_tx_isr(hw, TXCMD_QUEUE);
+		}
+	}
+
 	/*<2> Rx related */
 	if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) {
 		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n"));
-		tasklet_schedule(&rtlpriv->works.irq_tasklet);
+		_rtl_pci_rx_interrupt(hw);
 	}
 
 	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 ("rx descriptor unavailable!\n"));
-		tasklet_schedule(&rtlpriv->works.irq_tasklet);
+		_rtl_pci_rx_interrupt(hw);
 	}
 
 	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n"));
-		tasklet_schedule(&rtlpriv->works.irq_tasklet);
+		_rtl_pci_rx_interrupt(hw);
 	}
 
+	if (rtlpriv->rtlhal.earlymode_enable)
+		tasklet_schedule(&rtlpriv->works.irq_tasklet);
+
 	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 	return IRQ_HANDLED;
 
@@ -787,7 +935,7 @@ done:
 
 static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
 {
-	_rtl_pci_rx_interrupt(hw);
+	_rtl_pci_tx_chk_waitq(hw);
 }
 
 static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
@@ -795,14 +943,15 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+	struct rtl8192_tx_ring *ring = NULL;
 	struct ieee80211_hdr *hdr = NULL;
 	struct ieee80211_tx_info *info = NULL;
 	struct sk_buff *pskb = NULL;
 	struct rtl_tx_desc *pdesc = NULL;
-	unsigned int queue_index;
+	struct rtl_tcb_desc tcb_desc;
 	u8 temp_one = 1;
 
+	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
 	ring = &rtlpci->tx_ring[BEACON_QUEUE];
 	pskb = __skb_dequeue(&ring->queue);
 	if (pskb)
@@ -812,14 +961,11 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
 	pskb = ieee80211_beacon_get(hw, mac->vif);
 	if (pskb == NULL)
 		return;
-	hdr = (struct ieee80211_hdr *)(pskb->data);
+	hdr = rtl_get_hdr(pskb);
 	info = IEEE80211_SKB_CB(pskb);
-
-	queue_index = BEACON_QUEUE;
-
 	pdesc = &ring->desc[0];
 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
-					info, pskb, queue_index);
+		info, pskb, BEACON_QUEUE, &tcb_desc);
 
 	__skb_queue_tail(&ring->queue, pskb);
 
@@ -861,7 +1007,6 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 
 	rtlpci->up_first_time = true;
 	rtlpci->being_init_adapter = false;
@@ -869,31 +1014,20 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
 	rtlhal->hw = hw;
 	rtlpci->pdev = pdev;
 
-	ppsc->inactiveps = false;
-	ppsc->leisure_ps = true;
-	ppsc->fwctrl_lps = true;
-	ppsc->reg_fwctrl_lps = 3;
-	ppsc->reg_max_lps_awakeintvl = 5;
-
-	if (ppsc->reg_fwctrl_lps == 1)
-		ppsc->fwctrl_psmode = FW_PS_MIN_MODE;
-	else if (ppsc->reg_fwctrl_lps == 2)
-		ppsc->fwctrl_psmode = FW_PS_MAX_MODE;
-	else if (ppsc->reg_fwctrl_lps == 3)
-		ppsc->fwctrl_psmode = FW_PS_DTIM_MODE;
-
 	/*Tx/Rx related var */
 	_rtl_pci_init_trx_var(hw);
 
-	 /*IBSS*/ mac->beacon_interval = 100;
+	/*IBSS*/ mac->beacon_interval = 100;
 
-	 /*AMPDU*/ mac->min_space_cfg = 0;
+	/*AMPDU*/
+	mac->min_space_cfg = 0;
 	mac->max_mss_density = 0;
 	/*set sane AMPDU defaults */
 	mac->current_ampdu_density = 7;
 	mac->current_ampdu_factor = 3;
 
-	 /*QOS*/ rtlpci->acm_method = eAcmWay2_SW;
+	/*QOS*/
+	rtlpci->acm_method = eAcmWay2_SW;
 
 	/*task */
 	tasklet_init(&rtlpriv->works.irq_tasklet,
@@ -934,7 +1068,8 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
 		 ("queue:%d, ring_addr:%p\n", prio, ring));
 
 	for (i = 0; i < entries; i++) {
-		nextdescaddress = (u32) dma + ((i + 1) % entries) *
+		nextdescaddress = (u32) dma +
+					      ((i + 1) % entries) *
 					      sizeof(*ring);
 
 		rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
@@ -999,7 +1134,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
 					   rtlpci->rxbuffersize,
 					   PCI_DMA_FROMDEVICE);
 
-			bufferaddress = (u32)(*((dma_addr_t *)skb->cb));
+			bufferaddress = (*((dma_addr_t *)skb->cb));
 			rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
 						    HW_DESC_RXBUFF_ADDR,
 						    (u8 *)&bufferaddress);
@@ -1182,72 +1317,73 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
 	return 0;
 }
 
-static unsigned int _rtl_mac_to_hwqueue(__le16 fc,
-		unsigned int mac80211_queue_index)
+static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+					struct sk_buff *skb)
 {
-	unsigned int hw_queue_index;
-
-	if (unlikely(ieee80211_is_beacon(fc))) {
-		hw_queue_index = BEACON_QUEUE;
-		goto out;
-	}
-
-	if (ieee80211_is_mgmt(fc)) {
-		hw_queue_index = MGNT_QUEUE;
-		goto out;
-	}
-
-	switch (mac80211_queue_index) {
-	case 0:
-		hw_queue_index = VO_QUEUE;
-		break;
-	case 1:
-		hw_queue_index = VI_QUEUE;
-		break;
-	case 2:
-		hw_queue_index = BE_QUEUE;;
-		break;
-	case 3:
-		hw_queue_index = BK_QUEUE;
-		break;
-	default:
-		hw_queue_index = BE_QUEUE;
-		RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n",
-				  mac80211_queue_index));
-		break;
-	}
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_sta *sta = info->control.sta;
+	struct rtl_sta_info *sta_entry = NULL;
+	u8 tid = rtl_get_tid(skb);
+
+	if (!sta)
+		return false;
+	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+
+	if (!rtlpriv->rtlhal.earlymode_enable)
+		return false;
+	if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL)
+		return false;
+	if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE)
+		return false;
+	if (tid > 7)
+		return false;
+
+	/* maybe every tid should be checked */
+	if (!rtlpriv->link_info.higher_busytxtraffic[tid])
+		return false;
+
+	spin_lock_bh(&rtlpriv->locks.waitq_lock);
+	skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb);
+	spin_unlock_bh(&rtlpriv->locks.waitq_lock);
 
-out:
-	return hw_queue_index;
+	return true;
 }
 
-static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		struct rtl_tcb_desc *ptcb_desc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry = NULL;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_sta *sta = info->control.sta;
 	struct rtl8192_tx_ring *ring;
 	struct rtl_tx_desc *pdesc;
 	u8 idx;
-	unsigned int queue_index, hw_queue;
+	u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
 	unsigned long flags;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
-	__le16 fc = hdr->frame_control;
+	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+	__le16 fc = rtl_get_fc(skb);
 	u8 *pda_addr = hdr->addr1;
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	/*ssn */
-	u8 *qc = NULL;
 	u8 tid = 0;
 	u16 seq_number = 0;
 	u8 own;
 	u8 temp_one = 1;
 
-	if (ieee80211_is_mgmt(fc))
-		rtl_tx_mgmt_proc(hw, skb);
-	rtl_action_proc(hw, skb, true);
+	if (ieee80211_is_auth(fc)) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+		rtl_ips_nic_on(hw);
+	}
+
+	if (rtlpriv->psc.sw_ps_enabled) {
+		if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
+			!ieee80211_has_pm(fc))
+			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+	}
 
-	queue_index = skb_get_queue_mapping(skb);
-	hw_queue = _rtl_mac_to_hwqueue(fc, queue_index);
+	rtl_action_proc(hw, skb, true);
 
 	if (is_multicast_ether_addr(pda_addr))
 		rtlpriv->stats.txbytesmulticast += skb->len;
@@ -1257,7 +1393,6 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		rtlpriv->stats.txbytesunicast += skb->len;
 
 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
 	ring = &rtlpci->tx_ring[hw_queue];
 	if (hw_queue != BEACON_QUEUE)
 		idx = (ring->idx + skb_queue_len(&ring->queue)) %
@@ -1280,43 +1415,30 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		return skb->len;
 	}
 
-	/*
-	 *if(ieee80211_is_nullfunc(fc)) {
-	 *      spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-	 *      return 1;
-	 *}
-	 */
-
 	if (ieee80211_is_data_qos(fc)) {
-		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-
-		seq_number = mac->tids[tid].seq_number;
-		seq_number &= IEEE80211_SCTL_SEQ;
-		/*
-		 *hdr->seq_ctrl = hdr->seq_ctrl &
-		 *cpu_to_le16(IEEE80211_SCTL_FRAG);
-		 *hdr->seq_ctrl |= cpu_to_le16(seq_number);
-		 */
-
-		seq_number += 1;
+		tid = rtl_get_tid(skb);
+		if (sta) {
+			sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+			seq_number = (le16_to_cpu(hdr->seq_ctrl) &
+				      IEEE80211_SCTL_SEQ) >> 4;
+			seq_number += 1;
+
+			if (!ieee80211_has_morefrags(hdr->frame_control))
+				sta_entry->tids[tid].seq_number = seq_number;
+		}
 	}
 
 	if (ieee80211_is_data(fc))
 		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
 
-	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
-					info, skb, hw_queue);
+	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
+			info, skb, hw_queue, ptcb_desc);
 
 	__skb_queue_tail(&ring->queue, skb);
 
-	rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true,
+	rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true,
 				    HW_DESC_OWN, (u8 *)&temp_one);
 
-	if (!ieee80211_has_morefrags(hdr->frame_control)) {
-		if (qc)
-			mac->tids[tid].seq_number = seq_number;
-	}
 
 	if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
 	    hw_queue != BEACON_QUEUE) {
@@ -1338,6 +1460,35 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	return 0;
 }
 
+static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u16 i = 0;
+	int queue_id;
+	struct rtl8192_tx_ring *ring;
+
+	for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
+		u32 queue_len;
+		ring = &pcipriv->dev.tx_ring[queue_id];
+		queue_len = skb_queue_len(&ring->queue);
+		if (queue_len == 0 || queue_id == BEACON_QUEUE ||
+			queue_id == TXCMD_QUEUE) {
+			queue_id--;
+			continue;
+		} else {
+			msleep(20);
+			i++;
+		}
+
+		/* we just wait 1s for all queues */
+		if (rtlpriv->psc.rfpwr_state == ERFOFF ||
+			is_hal_stop(rtlhal) || i >= 200)
+			return;
+	}
+}
+
 static void rtl_pci_deinit(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1456,11 +1607,13 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
 	struct pci_dev *bridge_pdev = pdev->bus->self;
 	u16 venderid;
 	u16 deviceid;
+	u8 revisionid;
 	u16 irqline;
 	u8 tmp;
 
 	venderid = pdev->vendor;
 	deviceid = pdev->device;
+	pci_read_config_byte(pdev, 0x8, &revisionid);
 	pci_read_config_word(pdev, 0x3C, &irqline);
 
 	if (deviceid == RTL_PCI_8192_DID ||
@@ -1471,7 +1624,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
 	    deviceid == RTL_PCI_8173_DID ||
 	    deviceid == RTL_PCI_8172_DID ||
 	    deviceid == RTL_PCI_8171_DID) {
-		switch (pdev->revision) {
+		switch (revisionid) {
 		case RTL_PCI_REVISION_ID_8192PCIE:
 			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 				 ("8192 PCI-E is found - "
@@ -1500,6 +1653,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 			 ("8192C PCI-E is found - "
 			  "vid/did=%x/%x\n", venderid, deviceid));
+	} else if (deviceid == RTL_PCI_8192DE_DID ||
+		   deviceid == RTL_PCI_8192DE_DID2) {
+		rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			 ("8192D PCI-E is found - "
+			  "vid/did=%x/%x\n", venderid, deviceid));
 	} else {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 ("Err: Unknown device -"
@@ -1508,6 +1667,25 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
 		rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE;
 	}
 
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) {
+		if (revisionid == 0 || revisionid == 1) {
+			if (revisionid == 0) {
+				RT_TRACE(rtlpriv, COMP_INIT,
+					 DBG_LOUD, ("Find 92DE MAC0.\n"));
+				rtlhal->interfaceindex = 0;
+			} else if (revisionid == 1) {
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+					("Find 92DE MAC1.\n"));
+				rtlhal->interfaceindex = 1;
+			}
+		} else {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				("Unknown device - "
+				"VendorID/DeviceID=%x/%x, Revision=%x\n",
+				venderid, deviceid, revisionid));
+			rtlhal->interfaceindex = 0;
+		}
+	}
 	/*find bus info */
 	pcipriv->ndis_adapter.busnumber = pdev->bus->number;
 	pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
@@ -1533,12 +1711,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
 		    PCI_SLOT(bridge_pdev->devfn);
 		pcipriv->ndis_adapter.pcibridge_funcnum =
 		    PCI_FUNC(bridge_pdev->devfn);
-		pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
-		    pci_pcie_cap(bridge_pdev);
 		pcipriv->ndis_adapter.pcicfg_addrport =
 		    (pcipriv->ndis_adapter.pcibridge_busnum << 16) |
 		    (pcipriv->ndis_adapter.pcibridge_devnum << 11) |
 		    (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31);
+		pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
+		    pci_pcie_cap(bridge_pdev);
 		pcipriv->ndis_adapter.num4bytes =
 		    (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4;
 
@@ -1621,6 +1799,11 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
 	pcipriv = (void *)rtlpriv->priv;
 	pcipriv->dev.pdev = pdev;
 
+	/* init cfg & intf_ops */
+	rtlpriv->rtlhal.interface = INTF_PCI;
+	rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
+	rtlpriv->intf_ops = &rtl_pci_ops;
+
 	/*
 	 *init dbgp flags before all
 	 *other functions, because we will
@@ -1638,13 +1821,14 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
 		return err;
 	}
 
-	pmem_start = pci_resource_start(pdev, 2);
-	pmem_len = pci_resource_len(pdev, 2);
-	pmem_flags = pci_resource_flags(pdev, 2);
+	pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
+	pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id);
+	pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id);
 
 	/*shared mem start */
 	rtlpriv->io.pci_mem_start =
-			(unsigned long)pci_iomap(pdev, 2, pmem_len);
+			(unsigned long)pci_iomap(pdev,
+			rtlpriv->cfg->bar_id, pmem_len);
 	if (rtlpriv->io.pci_mem_start == 0) {
 		RT_ASSERT(false, ("Can't map PCI mem\n"));
 		goto fail2;
@@ -1663,11 +1847,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
 	pci_write_config_byte(pdev, 0x04, 0x06);
 	pci_write_config_byte(pdev, 0x04, 0x07);
 
-	/* init cfg & intf_ops */
-	rtlpriv->rtlhal.interface = INTF_PCI;
-	rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
-	rtlpriv->intf_ops = &rtl_pci_ops;
-
 	/* find adapter */
 	_rtl_pci_find_adapter(pdev, hw);
 
@@ -1785,8 +1964,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
 
 	rtl_pci_deinit(hw);
 	rtl_deinit_core(hw);
-	if (rtlpriv->cfg->ops->deinit_sw_leds)
-		rtlpriv->cfg->ops->deinit_sw_leds(hw);
 	_rtl_pci_io_handler_release(hw);
 	rtlpriv->cfg->ops->deinit_sw_vars(hw);
 
@@ -1801,6 +1978,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
 	}
 
 	pci_disable_device(pdev);
+
+	rtl_pci_disable_aspm(hw);
+
 	pci_set_drvdata(pdev, NULL);
 
 	ieee80211_free_hw(hw);
@@ -1824,10 +2004,15 @@ no need to call hw_disable here.
 ****************************************/
 int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpriv->cfg->ops->hw_suspend(hw);
+	rtl_deinit_rfkill(hw);
+
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, PCI_D3hot);
-
 	return 0;
 }
 EXPORT_SYMBOL(rtl_pci_suspend);
@@ -1835,6 +2020,8 @@ EXPORT_SYMBOL(rtl_pci_suspend);
 int rtl_pci_resume(struct pci_dev *pdev)
 {
 	int ret;
+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	pci_set_power_state(pdev, PCI_D0);
 	ret = pci_enable_device(pdev);
@@ -1845,15 +2032,20 @@ int rtl_pci_resume(struct pci_dev *pdev)
 
 	pci_restore_state(pdev);
 
+	rtlpriv->cfg->ops->hw_resume(hw);
+	rtl_init_rfkill(hw);
 	return 0;
 }
 EXPORT_SYMBOL(rtl_pci_resume);
 
 struct rtl_intf_ops rtl_pci_ops = {
+	.read_efuse_byte = read_efuse_byte,
 	.adapter_start = rtl_pci_start,
 	.adapter_stop = rtl_pci_stop,
 	.adapter_tx = rtl_pci_tx,
+	.flush = rtl_pci_flush,
 	.reset_trx_ring = rtl_pci_reset_trx_ring,
+	.waitq_insert = rtl_pci_tx_chk_waitq_insert,
 
 	.disable_aspm = rtl_pci_disable_aspm,
 	.enable_aspm = rtl_pci_enable_aspm,
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 12747b9c71e1167ab5b07aa372ca706d62fabaeb..671b1f5aa0cff1d351dd04de85033db63dbc3857 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -102,8 +102,8 @@
 #define RTL_PCI_8191CE_DID	0x8177	/*8192ce */
 #define RTL_PCI_8188CE_DID	0x8176	/*8192ce */
 #define RTL_PCI_8192CU_DID	0x8191	/*8192ce */
-#define RTL_PCI_8192DE_DID	0x092D	/*8192ce */
-#define RTL_PCI_8192DU_DID	0x092D	/*8192ce */
+#define RTL_PCI_8192DE_DID	0x8193	/*8192de */
+#define RTL_PCI_8192DE_DID2	0x002B	/*92DE*/
 
 /*8192 support 16 pages of IO registers*/
 #define RTL_MEM_MAPPED_IO_RANGE_8190PCI		0x1000
@@ -129,6 +129,11 @@ enum pci_bridge_vendor {
 	PCI_BRIDGE_VENDOR_MAX,
 };
 
+struct rtl_pci_capabilities_header {
+	u8 capability_id;
+	u8 next;
+};
+
 struct rtl_rx_desc {
 	u32 dword[8];
 } __packed;
@@ -161,7 +166,9 @@ struct rtl_pci {
 
 	bool driver_is_goingto_unload;
 	bool up_first_time;
+	bool first_init;
 	bool being_init_adapter;
+	bool init_ready;
 	bool irq_enabled;
 
 	/*Tx */
@@ -197,6 +204,9 @@ struct rtl_pci {
 
 	/*QOS & EDCA */
 	enum acm_method acm_method;
+
+	u16 shortretry_limit;
+	u16 longretry_limit;
 };
 
 struct mp_adapter {
@@ -227,6 +237,7 @@ struct rtl_pci_priv {
 	struct rtl_pci dev;
 	struct mp_adapter ndis_adapter;
 	struct rtl_led_ctl ledctl;
+	struct bt_coexist_info bt_coexist;
 };
 
 #define rtl_pcipriv(hw)		(((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index c8395fb0c050cad8eba695a92632505c2c363101..2bb71195e97658c98a39494d6190e3ce745b6344 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -36,7 +36,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	bool init_status = true;
 
 	/*<1> reset trx ring */
 	if (rtlhal->interface == INTF_PCI)
@@ -49,7 +48,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
 	/*<2> Enable Adapter */
 	rtlpriv->cfg->ops->hw_init(hw);
 	RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
-	/*init_status = false; */
 
 	/*<3> Enable Interrupt */
 	rtlpriv->cfg->ops->enable_interrupt(hw);
@@ -57,7 +55,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
 	/*<enable timer> */
 	rtl_watch_dog_timer_callback((unsigned long)hw);
 
-	return init_status;
+	return true;
 }
 EXPORT_SYMBOL(rtl_ps_enable_nic);
 
@@ -192,12 +190,13 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
 
 	ppsc->swrf_processing = true;
 
-	if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
+	if (ppsc->inactive_pwrstate == ERFOFF &&
+	    rtlhal->interface == INTF_PCI) {
 		if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
-		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) &&
+		    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
 		    rtlhal->interface == INTF_PCI) {
 			rtlpriv->intf_ops->disable_aspm(hw);
-			RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+			RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 		}
 	}
 
@@ -206,9 +205,10 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
 
 	if (ppsc->inactive_pwrstate == ERFOFF &&
 	    rtlhal->interface == INTF_PCI) {
-		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
+		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
+			!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
 			rtlpriv->intf_ops->enable_aspm(hw);
-			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+			RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 		}
 	}
 
@@ -232,6 +232,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
 		return;
 	}
 
+	if (mac->link_state > MAC80211_NOLINK)
+		return;
+
 	if (is_hal_stop(rtlhal))
 		return;
 
@@ -283,10 +286,14 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw)
 void rtl_ips_nic_on(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	enum rf_pwrstate rtstate;
 	unsigned long flags;
 
+	if (mac->opmode != NL80211_IFTYPE_STATION)
+		return;
+
 	spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
 
 	if (ppsc->inactiveps) {
@@ -369,8 +376,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
 	 *   mode and set RPWM to turn RF on.
 	 */
 
-	if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) &&
-	     ppsc->report_linked) {
+	if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
 		bool fw_current_inps;
 		if (ppsc->dot11_psmode == EACTIVE) {
 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
@@ -424,7 +430,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	unsigned long flag;
 
-	if (!(ppsc->fwctrl_lps && ppsc->leisure_ps))
+	if (!ppsc->fwctrl_lps)
 		return;
 
 	if (rtlpriv->sec.being_setkey)
@@ -445,17 +451,16 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
 
 	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 
-	if (ppsc->leisure_ps) {
-		/* Idle for a while if we connect to AP a while ago. */
-		if (mac->cnt_after_linked >= 2) {
-			if (ppsc->dot11_psmode == EACTIVE) {
-				RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+	/* Idle for a while if we connect to AP a while ago. */
+	if (mac->cnt_after_linked >= 2) {
+		if (ppsc->dot11_psmode == EACTIVE) {
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 					("Enter 802.11 power save mode...\n"));
 
-				rtl_lps_set_psmode(hw, EAUTOPS);
-			}
+			rtl_lps_set_psmode(hw, EAUTOPS);
 		}
 	}
+
 	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 }
 
@@ -469,17 +474,17 @@ void rtl_lps_leave(struct ieee80211_hw *hw)
 
 	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 
-	if (ppsc->fwctrl_lps && ppsc->leisure_ps) {
+	if (ppsc->fwctrl_lps) {
 		if (ppsc->dot11_psmode != EACTIVE) {
 
 			/*FIX ME */
 			rtlpriv->cfg->ops->enable_interrupt(hw);
 
 			if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
-			    RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) &&
+			    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
 			    rtlhal->interface == INTF_PCI) {
 				rtlpriv->intf_ops->disable_aspm(hw);
-				RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM);
+				RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 			}
 
 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
@@ -490,3 +495,214 @@ void rtl_lps_leave(struct ieee80211_hw *hw)
 	}
 	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 }
+
+/* For sw LPS*/
+void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct ieee80211_hdr *hdr = (void *) data;
+	struct ieee80211_tim_ie *tim_ie;
+	u8 *tim;
+	u8 tim_len;
+	bool u_buffed;
+	bool m_buffed;
+
+	if (mac->opmode != NL80211_IFTYPE_STATION)
+		return;
+
+	if (!rtlpriv->psc.swctrl_lps)
+		return;
+
+	if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
+		return;
+
+	if (!rtlpriv->psc.sw_ps_enabled)
+		return;
+
+	if (rtlpriv->psc.fwctrl_lps)
+		return;
+
+	if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
+		return;
+
+	/* check if this really is a beacon */
+	if (!ieee80211_is_beacon(hdr->frame_control))
+		return;
+
+	/* min. beacon length + FCS_LEN */
+	if (len <= 40 + FCS_LEN)
+		return;
+
+	/* and only beacons from the associated BSSID, please */
+	if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+		return;
+
+	rtlpriv->psc.last_beacon = jiffies;
+
+	tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
+	if (!tim)
+		return;
+
+	if (tim[1] < sizeof(*tim_ie))
+		return;
+
+	tim_len = tim[1];
+	tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+	if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
+		rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
+
+	/* Check whenever the PHY can be turned off again. */
+
+	/* 1. What about buffered unicast traffic for our AID? */
+	u_buffed = ieee80211_check_tim(tim_ie, tim_len,
+				       rtlpriv->mac80211.assoc_id);
+
+	/* 2. Maybe the AP wants to send multicast/broadcast data? */
+	m_buffed = tim_ie->bitmap_ctrl & 0x01;
+	rtlpriv->psc.multi_buffered = m_buffed;
+
+	/* unicast will process by mac80211 through
+	 * set ~IEEE80211_CONF_PS, So we just check
+	 * multicast frames here */
+	if (!m_buffed) {
+		/* back to low-power land. and delay is
+		 * prevent null power save frame tx fail */
+		queue_delayed_work(rtlpriv->works.rtl_wq,
+				&rtlpriv->works.ps_work, MSECS(5));
+	} else {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, "
+				"m_buffered: %x\n", u_buffed, m_buffed));
+	}
+}
+
+void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	unsigned long flag;
+
+	if (!rtlpriv->psc.swctrl_lps)
+		return;
+	if (mac->link_state != MAC80211_LINKED)
+		return;
+
+	if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
+		RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+		rtlpriv->intf_ops->disable_aspm(hw);
+		RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+	}
+
+	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+	rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
+	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+}
+
+void rtl_swlps_rfon_wq_callback(void *data)
+{
+	struct rtl_works *rtlworks =
+	    container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
+	struct ieee80211_hw *hw = rtlworks->hw;
+
+	rtl_swlps_rf_awake(hw);
+}
+
+void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	unsigned long flag;
+	u8 sleep_intv;
+
+	if (!rtlpriv->psc.sw_ps_enabled)
+		return;
+
+	if ((rtlpriv->sec.being_setkey) ||
+	    (mac->opmode == NL80211_IFTYPE_ADHOC))
+		return;
+
+	/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
+	if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
+		return;
+
+	if (rtlpriv->link_info.busytraffic)
+		return;
+
+	spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+	if (rtlpriv->psc.rfchange_inprogress) {
+		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+		return;
+	}
+	spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+
+	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+	rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false);
+	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+
+	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
+		!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+		rtlpriv->intf_ops->enable_aspm(hw);
+		RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+	}
+
+	/* here is power save alg, when this beacon is DTIM
+	 * we will set sleep time to dtim_period * n;
+	 * when this beacon is not DTIM, we will set sleep
+	 * time to sleep_intv = rtlpriv->psc.dtim_counter or
+	 * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
+
+	if (rtlpriv->psc.dtim_counter == 0) {
+		if (hw->conf.ps_dtim_period == 1)
+			sleep_intv = hw->conf.ps_dtim_period * 2;
+		else
+			sleep_intv = hw->conf.ps_dtim_period;
+	} else {
+		sleep_intv = rtlpriv->psc.dtim_counter;
+	}
+
+	if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
+		sleep_intv = MAX_SW_LPS_SLEEP_INTV;
+
+	/* this print should always be dtim_conter = 0 &
+	 * sleep  = dtim_period, that meaons, we should
+	 * awake before every dtim */
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+		 ("dtim_counter:%x will sleep :%d"
+		 " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv));
+
+	/* we tested that 40ms is enough for sw & hw sw delay */
+	queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
+			MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
+}
+
+
+void rtl_swlps_wq_callback(void *data)
+{
+	struct rtl_works *rtlworks = container_of_dwork_rtl(data,
+				     struct rtl_works,
+				     ps_work);
+	struct ieee80211_hw *hw = rtlworks->hw;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	bool ps = false;
+
+	ps = (hw->conf.flags & IEEE80211_CONF_PS);
+
+	/* we can sleep after ps null send ok */
+	if (rtlpriv->psc.state_inap) {
+		rtl_swlps_rf_sleep(hw);
+
+		if (rtlpriv->psc.state && !ps) {
+			rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies -
+					rtlpriv->psc.last_action);
+		}
+
+		if (ps)
+			rtlpriv->psc.last_slept = jiffies;
+
+		rtlpriv->psc.last_action = jiffies;
+		rtlpriv->psc.state = ps;
+	}
+}
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
index ae56da801a239d5730795e40f9d8dac942f345df..e3bf89840370729ce743f6d282c0fd459cd5d8a6 100644
--- a/drivers/net/wireless/rtlwifi/ps.h
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -30,6 +30,8 @@
 #ifndef __REALTEK_RTL_PCI_PS_H__
 #define __REALTEK_RTL_PCI_PS_H__
 
+#define MAX_SW_LPS_SLEEP_INTV	5
+
 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
 			 enum rf_pwrstate state_toset, u32 changesource,
 			 bool protect_or_not);
@@ -40,4 +42,11 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw);
 void rtl_ips_nic_off_wq_callback(void *data);
 void rtl_lps_enter(struct ieee80211_hw *hw);
 void rtl_lps_leave(struct ieee80211_hw *hw);
+
+void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len);
+void rtl_swlps_wq_callback(void *data);
+void rtl_swlps_rfon_wq_callback(void *data);
+void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
+void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
+
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c
index 91634107434a66aba4bea88ee39b62cc839867fa..30da68a7778643676bd3a897173c7176ebbb2da1 100644
--- a/drivers/net/wireless/rtlwifi/rc.c
+++ b/drivers/net/wireless/rtlwifi/rc.c
@@ -38,17 +38,14 @@
  *CCK11M or OFDM_54M based on wireless mode.
  */
 static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
+				  struct ieee80211_sta *sta,
 				  struct sk_buff *skb, bool not_data)
 {
 	struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
-
-	/*
-	 *mgt use 1M, although we have check it
-	 *before this function use rate_control_send_low,
-	 *we still check it here
-	 */
-	if (not_data)
-		return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_sta_info *sta_entry = NULL;
+	u8 wireless_mode = 0;
 
 	/*
 	 *this rate is no use for true rate, firmware
@@ -57,35 +54,78 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
 	 *2.in rtl_get_tcb_desc when we check rate is
 	 *      1M we will not use FW rate but user rate.
 	 */
-	if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) {
-		return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+	if (rtlmac->opmode == NL80211_IFTYPE_AP ||
+		rtlmac->opmode == NL80211_IFTYPE_ADHOC) {
+		if (sta) {
+			sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+			wireless_mode = sta_entry->wireless_mode;
+		} else {
+			return 0;
+		}
+	} else {
+		wireless_mode = rtlmac->mode;
+	}
+
+	if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) ||
+			not_data) {
+		return 0;
 	} else {
-		if (rtlmac->mode == WIRELESS_MODE_B)
-			return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
-		else
-			return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
+		if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+			if (wireless_mode == WIRELESS_MODE_B) {
+				return B_MODE_MAX_RIX;
+			} else if (wireless_mode == WIRELESS_MODE_G) {
+				return G_MODE_MAX_RIX;
+			} else {
+				if (get_rf_type(rtlphy) != RF_2T2R)
+					return N_MODE_MCS7_RIX;
+				else
+					return N_MODE_MCS15_RIX;
+			}
+		} else {
+			if (wireless_mode == WIRELESS_MODE_A) {
+				return A_MODE_MAX_RIX;
+			} else {
+				if (get_rf_type(rtlphy) != RF_2T2R)
+					return N_MODE_MCS7_RIX;
+				else
+					return N_MODE_MCS15_RIX;
+			}
+		}
 	}
 }
 
 static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
+				    struct ieee80211_sta *sta,
 				    struct ieee80211_tx_rate *rate,
 				    struct ieee80211_tx_rate_control *txrc,
-				    u8 tries, u8 rix, int rtsctsenable,
+				    u8 tries, char rix, int rtsctsenable,
 				    bool not_data)
 {
 	struct rtl_mac *mac = rtl_mac(rtlpriv);
+	u8 sgi_20 = 0, sgi_40 = 0;
 
+	if (sta) {
+		sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+		sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+	}
 	rate->count = tries;
-	rate->idx = (rix > 0x2) ? rix : 0x2;
+	rate->idx = rix >= 0x00 ? rix : 0x00;
 
 	if (!not_data) {
 		if (txrc->short_preamble)
 			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
-		if (mac->bw_40)
-			rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-		if (mac->sgi_20 || mac->sgi_40)
+		if (mac->opmode == NL80211_IFTYPE_AP ||
+			mac->opmode == NL80211_IFTYPE_ADHOC) {
+			if (sta && (sta->ht_cap.cap &
+			    IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+		} else {
+			if (mac->bw_40)
+				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+		}
+		if (sgi_20 || sgi_40)
 			rate->flags |= IEEE80211_TX_RC_SHORT_GI;
-		if (mac->ht_enable)
+		if (sta && sta->ht_cap.ht_supported)
 			rate->flags |= IEEE80211_TX_RC_MCS;
 	}
 }
@@ -97,39 +137,39 @@ static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta,
 	struct sk_buff *skb = txrc->skb;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_rate *rates = tx_info->control.rates;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	__le16 fc = hdr->frame_control;
+	__le16 fc = rtl_get_fc(skb);
 	u8 try_per_rate, i, rix;
 	bool not_data = !ieee80211_is_data(fc);
 
 	if (rate_control_send_low(sta, priv_sta, txrc))
 		return;
 
-	rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data);
-
+	rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data);
 	try_per_rate = 1;
-	_rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc,
+	_rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc,
 				try_per_rate, rix, 1, not_data);
 
 	if (!not_data) {
 		for (i = 1; i < 4; i++)
-			_rtl_rc_rate_set_series(rtlpriv, &rates[i],
+			_rtl_rc_rate_set_series(rtlpriv, sta, &rates[i],
 						txrc, i, (rix - i), 1,
 						not_data);
 	}
 }
 
-static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid)
+static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv,
+		struct rtl_sta_info *sta_entry, u16 tid)
 {
 	struct rtl_mac *mac = rtl_mac(rtlpriv);
 
 	if (mac->act_scanning)
 		return false;
 
-	if (mac->cnt_after_linked < 3)
+	if (mac->opmode == NL80211_IFTYPE_STATION &&
+		mac->cnt_after_linked < 3)
 		return false;
 
-	if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF)
+	if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP)
 		return true;
 
 	return false;
@@ -143,11 +183,9 @@ static void rtl_tx_status(void *ppriv,
 {
 	struct rtl_priv *rtlpriv = ppriv;
 	struct rtl_mac *mac = rtl_mac(rtlpriv);
-	struct ieee80211_hdr *hdr;
-	__le16 fc;
-
-	hdr = (struct ieee80211_hdr *)skb->data;
-	fc = hdr->frame_control;
+	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+	__le16 fc = rtl_get_fc(skb);
+	struct rtl_sta_info *sta_entry;
 
 	if (!priv_sta || !ieee80211_is_data(fc))
 		return;
@@ -159,17 +197,21 @@ static void rtl_tx_status(void *ppriv,
 	    || is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
 		return;
 
-	/* Check if aggregation has to be enabled for this tid */
-	if (conf_is_ht(&mac->hw->conf) &&
-	    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
-		if (ieee80211_is_data_qos(fc)) {
-			u8 *qc, tid;
-
-			qc = ieee80211_get_qos_ctl(hdr);
-			tid = qc[0] & 0xf;
-
-			if (_rtl_tx_aggr_check(rtlpriv, tid))
-				ieee80211_start_tx_ba_session(sta, tid, 5000);
+	if (sta) {
+		/* Check if aggregation has to be enabled for this tid */
+		sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+		if ((sta->ht_cap.ht_supported == true) &&
+				!(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+			if (ieee80211_is_data_qos(fc)) {
+				u8 tid = rtl_get_tid(skb);
+				if (_rtl_tx_aggr_check(rtlpriv, sta_entry,
+				    tid)) {
+					sta_entry->tids[tid].agg.agg_state =
+							 RTL_AGG_PROGRESS;
+					ieee80211_start_tx_ba_session(sta,
+								 tid, 5000);
+				}
+			}
 		}
 	}
 }
@@ -178,43 +220,6 @@ static void rtl_rate_init(void *ppriv,
 			  struct ieee80211_supported_band *sband,
 			  struct ieee80211_sta *sta, void *priv_sta)
 {
-	struct rtl_priv *rtlpriv = ppriv;
-	struct rtl_mac *mac = rtl_mac(rtlpriv);
-	u8 is_ht = conf_is_ht(&mac->hw->conf);
-
-	if ((mac->opmode == NL80211_IFTYPE_STATION) ||
-	    (mac->opmode == NL80211_IFTYPE_MESH_POINT) ||
-	    (mac->opmode == NL80211_IFTYPE_ADHOC)) {
-
-		switch (sband->band) {
-		case IEEE80211_BAND_2GHZ:
-			rtlpriv->rate_priv->cur_ratetab_idx =
-			    RATR_INX_WIRELESS_G;
-			if (is_ht)
-				rtlpriv->rate_priv->cur_ratetab_idx =
-				    RATR_INX_WIRELESS_NGB;
-			break;
-		case IEEE80211_BAND_5GHZ:
-			rtlpriv->rate_priv->cur_ratetab_idx =
-			    RATR_INX_WIRELESS_A;
-			if (is_ht)
-				rtlpriv->rate_priv->cur_ratetab_idx =
-				    RATR_INX_WIRELESS_NGB;
-			break;
-		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-				 ("Invalid band\n"));
-			rtlpriv->rate_priv->cur_ratetab_idx =
-			    RATR_INX_WIRELESS_NGB;
-			break;
-		}
-
-		RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG,
-			 ("Choosing rate table index: %d\n",
-			  rtlpriv->rate_priv->cur_ratetab_idx));
-
-	}
-
 }
 
 static void rtl_rate_update(void *ppriv,
@@ -223,49 +228,6 @@ static void rtl_rate_update(void *ppriv,
 			    u32 changed,
 			    enum nl80211_channel_type oper_chan_type)
 {
-	struct rtl_priv *rtlpriv = ppriv;
-	struct rtl_mac *mac = rtl_mac(rtlpriv);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	bool oper_cw40 = false, oper_sgi40;
-	bool local_cw40 = mac->bw_40;
-	bool local_sgi40 = mac->sgi_40;
-	u8 is_ht = conf_is_ht(&mac->hw->conf);
-
-	if (changed & IEEE80211_RC_HT_CHANGED) {
-		if (mac->opmode != NL80211_IFTYPE_STATION)
-			return;
-
-		if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS ||
-		    rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS)
-			oper_cw40 = true;
-
-		oper_sgi40 = mac->sgi_40;
-
-		if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) {
-			switch (sband->band) {
-			case IEEE80211_BAND_2GHZ:
-				rtlpriv->rate_priv->cur_ratetab_idx =
-				    RATR_INX_WIRELESS_G;
-				if (is_ht)
-					rtlpriv->rate_priv->cur_ratetab_idx =
-					    RATR_INX_WIRELESS_NGB;
-				break;
-			case IEEE80211_BAND_5GHZ:
-				rtlpriv->rate_priv->cur_ratetab_idx =
-				    RATR_INX_WIRELESS_A;
-				if (is_ht)
-					rtlpriv->rate_priv->cur_ratetab_idx =
-					    RATR_INX_WIRELESS_NGB;
-				break;
-			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-					 ("Invalid band\n"));
-				rtlpriv->rate_priv->cur_ratetab_idx =
-				    RATR_INX_WIRELESS_NGB;
-				break;
-			}
-		}
-	}
 }
 
 static void *rtl_rate_alloc(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h
index b4667c035f0bff66c2af1dd45f3cf6645909f5a6..4afa2c20adcf29870b8d97718006f448eb3ea86e 100644
--- a/drivers/net/wireless/rtlwifi/rc.h
+++ b/drivers/net/wireless/rtlwifi/rc.h
@@ -30,8 +30,15 @@
 #ifndef __RTL_RC_H__
 #define __RTL_RC_H__
 
+#define B_MODE_MAX_RIX 3
+#define G_MODE_MAX_RIX 11
+#define A_MODE_MAX_RIX 7
+
+/* in mac80211 mcs0-mcs15 is idx0-idx15*/
+#define N_MODE_MCS7_RIX 7
+#define N_MODE_MCS15_RIX 15
+
 struct rtl_rate_priv {
-	u8 cur_ratetab_idx;
 	u8 ht_cap;
 };
 
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index d26f957981adf16a1b3cb566d6287abf25bb3fb4..8f6718f163e5a3d7c86ff5e87cc11264b96174fe 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -66,31 +66,83 @@ static struct country_code_to_enum_rd allCountries[] = {
 	NL80211_RRF_PASSIVE_SCAN | \
 	NL80211_RRF_NO_OFDM)
 
+/* 5G chan 36 - chan 64*/
+#define RTL819x_5GHZ_5150_5350	\
+	REG_RULE(5150-10, 5350+10, 40, 0, 30, \
+	NL80211_RRF_PASSIVE_SCAN | \
+	NL80211_RRF_NO_IBSS)
+
+/* 5G chan 100 - chan 165*/
+#define RTL819x_5GHZ_5470_5850	\
+	REG_RULE(5470-10, 5850+10, 40, 0, 30, \
+	NL80211_RRF_PASSIVE_SCAN | \
+	NL80211_RRF_NO_IBSS)
+
+/* 5G chan 149 - chan 165*/
+#define RTL819x_5GHZ_5725_5850	\
+	REG_RULE(5725-10, 5850+10, 40, 0, 30, \
+	NL80211_RRF_PASSIVE_SCAN | \
+	NL80211_RRF_NO_IBSS)
+
+#define RTL819x_5GHZ_ALL	\
+	(RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
+
 static const struct ieee80211_regdomain rtl_regdom_11 = {
 	.n_reg_rules = 1,
 	.alpha2 = "99",
 	.reg_rules = {
 		      RTL819x_2GHZ_CH01_11,
-	}
+		      }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_12_13 = {
+	.n_reg_rules = 2,
+	.alpha2 = "99",
+	.reg_rules = {
+		      RTL819x_2GHZ_CH01_11,
+			  RTL819x_2GHZ_CH12_13,
+		      }
 };
 
-static const struct ieee80211_regdomain rtl_regdom_global = {
+static const struct ieee80211_regdomain rtl_regdom_no_midband = {
 	.n_reg_rules = 3,
 	.alpha2 = "99",
 	.reg_rules = {
 		      RTL819x_2GHZ_CH01_11,
-		      RTL819x_2GHZ_CH12_13,
-		      RTL819x_2GHZ_CH14,
-	}
+			  RTL819x_5GHZ_5150_5350,
+			  RTL819x_5GHZ_5725_5850,
+		      }
 };
 
-static const struct ieee80211_regdomain rtl_regdom_world = {
-	.n_reg_rules = 2,
+static const struct ieee80211_regdomain rtl_regdom_60_64 = {
+	.n_reg_rules = 3,
 	.alpha2 = "99",
 	.reg_rules = {
 		      RTL819x_2GHZ_CH01_11,
-		      RTL819x_2GHZ_CH12_13,
-	}
+			  RTL819x_2GHZ_CH12_13,
+			  RTL819x_5GHZ_5725_5850,
+		      }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_14_60_64 = {
+	.n_reg_rules = 4,
+	.alpha2 = "99",
+	.reg_rules = {
+		      RTL819x_2GHZ_CH01_11,
+			  RTL819x_2GHZ_CH12_13,
+			  RTL819x_2GHZ_CH14,
+			  RTL819x_5GHZ_5725_5850,
+		      }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_14 = {
+	.n_reg_rules = 3,
+	.alpha2 = "99",
+	.reg_rules = {
+		      RTL819x_2GHZ_CH01_11,
+			  RTL819x_2GHZ_CH12_13,
+			  RTL819x_2GHZ_CH14,
+		      }
 };
 
 static bool _rtl_is_radar_freq(u16 center_freq)
@@ -162,6 +214,8 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
 	u32 bandwidth = 0;
 	int r;
 
+	if (!wiphy->bands[IEEE80211_BAND_2GHZ])
+		return;
 	sband = wiphy->bands[IEEE80211_BAND_2GHZ];
 
 	/*
@@ -292,25 +346,26 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
 {
 	switch (reg->country_code) {
 	case COUNTRY_CODE_FCC:
+		return &rtl_regdom_no_midband;
 	case COUNTRY_CODE_IC:
 		return &rtl_regdom_11;
 	case COUNTRY_CODE_ETSI:
+	case COUNTRY_CODE_TELEC_NETGEAR:
+		return &rtl_regdom_60_64;
 	case COUNTRY_CODE_SPAIN:
 	case COUNTRY_CODE_FRANCE:
 	case COUNTRY_CODE_ISRAEL:
-	case COUNTRY_CODE_TELEC_NETGEAR:
-		return &rtl_regdom_world;
+	case COUNTRY_CODE_WORLD_WIDE_13:
+		return &rtl_regdom_12_13;
 	case COUNTRY_CODE_MKK:
 	case COUNTRY_CODE_MKK1:
 	case COUNTRY_CODE_TELEC:
 	case COUNTRY_CODE_MIC:
-		return &rtl_regdom_global;
+		return &rtl_regdom_14_60_64;
 	case COUNTRY_CODE_GLOBAL_DOMAIN:
-		return &rtl_regdom_global;
-	case COUNTRY_CODE_WORLD_WIDE_13:
-		return &rtl_regdom_world;
+		return &rtl_regdom_14;
 	default:
-		return &rtl_regdom_world;
+		return &rtl_regdom_no_midband;
 	}
 }
 
@@ -323,9 +378,11 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
 	const struct ieee80211_regdomain *regd;
 
 	wiphy->reg_notifier = reg_notifier;
+
 	wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 	wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
 	wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
+
 	regd = _rtl_regdomain_select(reg);
 	wiphy_apply_custom_regulatory(wiphy, regd);
 	_rtl_reg_apply_radar_flags(wiphy);
@@ -355,8 +412,8 @@ int rtl_regd_init(struct ieee80211_hw *hw,
 	if (wiphy == NULL || &rtlpriv->regd == NULL)
 		return -EINVAL;
 
-	/* force the channel plan to world wide 13 */
-	rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
+	/* init country_code from efuse channel plan */
+	rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan;
 
 	RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
 		 (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n",
@@ -373,8 +430,8 @@ int rtl_regd_init(struct ieee80211_hw *hw,
 	country = _rtl_regd_find_country(rtlpriv->regd.country_code);
 
 	if (country) {
-		rtlpriv->regd.alpha2[0] = country->isoName[0];
-		rtlpriv->regd.alpha2[1] = country->isoName[1];
+		rtlpriv->regd.alpha2[0] = country->iso_name[0];
+		rtlpriv->regd.alpha2[1] = country->iso_name[1];
 	} else {
 		rtlpriv->regd.alpha2[0] = '0';
 		rtlpriv->regd.alpha2[1] = '0';
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
index 4cdbc4ae76d4a45326a45ac30a9b28883b312185..d23118938fac57035452331e4dbab04318e5aac8 100644
--- a/drivers/net/wireless/rtlwifi/regd.h
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -32,7 +32,7 @@
 
 struct country_code_to_enum_rd {
 	u16 countrycode;
-	const char *isoName;
+	const char *iso_name;
 };
 
 enum country_code_type_t {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index c228b9ee37113a1b0098e34c9d69132b4a67dd33..97183829b9be849fc96666ff0e106c5045e30414 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -28,10 +28,26 @@
  *****************************************************************************/
 
 #include "dm_common.h"
+#include "phy_common.h"
+#include "../pci.h"
+#include "../base.h"
 
 struct dig_t dm_digtable;
 static struct ps_t dm_pstable;
 
+#define BT_RSSI_STATE_NORMAL_POWER	BIT_OFFSET_LEN_MASK_32(0, 1)
+#define BT_RSSI_STATE_AMDPU_OFF		BIT_OFFSET_LEN_MASK_32(1, 1)
+#define BT_RSSI_STATE_SPECIAL_LOW	BIT_OFFSET_LEN_MASK_32(2, 1)
+#define BT_RSSI_STATE_BG_EDCA_LOW	BIT_OFFSET_LEN_MASK_32(3, 1)
+#define BT_RSSI_STATE_TXPOWER_LOW	BIT_OFFSET_LEN_MASK_32(4, 1)
+
+#define RTLPRIV			(struct rtl_priv *)
+#define GET_UNDECORATED_AVERAGE_RSSI(_priv)	\
+	((RTLPRIV(_priv))->mac80211.opmode == \
+			     NL80211_IFTYPE_ADHOC) ?	\
+	((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \
+	((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb)
+
 static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
 	0x7f8001fe,
 	0x788001e2,
@@ -304,7 +320,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
 
 static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
 {
-	static u8 binitialized; /* initialized to false */
+	static u8 initialized; /* initialized to false */
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
@@ -315,11 +331,11 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
 
 	if ((multi_sta == false) || (dm_digtable.cursta_connectctate !=
 				     DIG_STA_DISCONNECT)) {
-		binitialized = false;
+		initialized = false;
 		dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
 		return;
-	} else if (binitialized == false) {
-		binitialized = true;
+	} else if (initialized == false) {
+		initialized = true;
 		dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
 		dm_digtable.cur_igvalue = 0x20;
 		rtl92c_dm_write_dig(hw);
@@ -461,10 +477,7 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
 	if (mac->act_scanning == true)
 		return;
 
-	if ((mac->link_state > MAC80211_NOLINK) &&
-	    (mac->link_state < MAC80211_LINKED))
-		dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT;
-	else if (mac->link_state >= MAC80211_LINKED)
+	if (mac->link_state >= MAC80211_LINKED)
 		dm_digtable.cursta_connectctate = DIG_STA_CONNECT;
 	else
 		dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT;
@@ -562,23 +575,42 @@ EXPORT_SYMBOL(rtl92c_dm_init_edca_turbo);
 static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
 	static u64 last_txok_cnt;
 	static u64 last_rxok_cnt;
-	u64 cur_txok_cnt;
-	u64 cur_rxok_cnt;
+	static u32 last_bt_edca_ul;
+	static u32 last_bt_edca_dl;
+	u64 cur_txok_cnt = 0;
+	u64 cur_rxok_cnt = 0;
 	u32 edca_be_ul = 0x5ea42b;
 	u32 edca_be_dl = 0x5ea42b;
+	bool bt_change_edca = false;
 
-	if (mac->opmode == NL80211_IFTYPE_ADHOC)
-		goto dm_checkedcaturbo_exit;
+	if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
+	    (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+		rtlpriv->dm.current_turbo_edca = false;
+		last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+		last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+	}
+
+	if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
+		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+		bt_change_edca = true;
+	}
+
+	if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
+		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
+		bt_change_edca = true;
+	}
 
 	if (mac->link_state != MAC80211_LINKED) {
 		rtlpriv->dm.current_turbo_edca = false;
 		return;
 	}
 
-	if (!mac->ht_enable) {	/*FIX MERGE */
+	if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
 		if (!(edca_be_ul & 0xffff0000))
 			edca_be_ul |= 0x005e0000;
 
@@ -586,10 +618,12 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
 			edca_be_dl |= 0x005e0000;
 	}
 
-	if ((!rtlpriv->dm.is_any_nonbepkts) &&
-	    (!rtlpriv->dm.disable_framebursting)) {
+	if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
+	     (!rtlpriv->dm.disable_framebursting))) {
+
 		cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
 		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
 		if (cur_rxok_cnt > 4 * cur_txok_cnt) {
 			if (!rtlpriv->dm.is_cur_rdlstate ||
 			    !rtlpriv->dm.current_turbo_edca) {
@@ -618,7 +652,6 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
 		}
 	}
 
-dm_checkedcaturbo_exit:
 	rtlpriv->dm.is_any_nonbepkts = false;
 	last_txok_cnt = rtlpriv->stats.txbytesunicast;
 	last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
@@ -633,14 +666,14 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 thermalvalue, delta, delta_lck, delta_iqk;
 	long ele_a, ele_d, temp_cck, val_x, value32;
-	long val_y, ele_c;
+	long val_y, ele_c = 0;
 	u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0;
 	int i;
 	bool is2t = IS_92C_SERIAL(rtlhal->version);
 	u8 txpwr_level[2] = {0, 0};
 	u8 ofdm_min_index = 6, rf;
 
-	rtlpriv->dm.txpower_trackingInit = true;
+	rtlpriv->dm.txpower_trackinginit = true;
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 		 ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n"));
 
@@ -683,7 +716,6 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
 			for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
 				if (ele_d == (ofdmswing_table[i] &
 				    MASKOFDM_D)) {
-					ofdm_index_old[1] = (u8) i;
 
 					RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
 					   DBG_LOUD,
@@ -1062,7 +1094,7 @@ static void rtl92c_dm_initialize_txpower_tracking_thermalmeter(
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	rtlpriv->dm.txpower_tracking = true;
-	rtlpriv->dm.txpower_trackingInit = false;
+	rtlpriv->dm.txpower_trackinginit = false;
 
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 		 ("pMgntInfo->txpower_tracking = %d\n",
@@ -1132,6 +1164,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rate_adaptive *p_ra = &(rtlpriv->ra);
 	u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
+	struct ieee80211_sta *sta = NULL;
 
 	if (is_hal_stop(rtlhal)) {
 		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
@@ -1145,8 +1178,8 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
 		return;
 	}
 
-	if (mac->link_state == MAC80211_LINKED) {
-
+	if (mac->link_state == MAC80211_LINKED &&
+	    mac->opmode == NL80211_IFTYPE_STATION) {
 		switch (p_ra->pre_ratr_state) {
 		case DM_RATR_STA_HIGH:
 			high_rssithresh_for_ra = 50;
@@ -1185,10 +1218,13 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
 				 ("PreState = %d, CurState = %d\n",
 				  p_ra->pre_ratr_state, p_ra->ratr_state));
 
-			rtlpriv->cfg->ops->update_rate_mask(hw,
+			rcu_read_lock();
+			sta = ieee80211_find_sta(mac->vif, mac->bssid);
+			rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
 					p_ra->ratr_state);
 
 			p_ra->pre_ratr_state = p_ra->ratr_state;
+			rcu_read_unlock();
 		}
 	}
 }
@@ -1202,51 +1238,6 @@ static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
 	dm_pstable.rssi_val_min = 0;
 }
 
-static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
-	if (dm_pstable.rssi_val_min != 0) {
-		if (dm_pstable.pre_ccastate == CCA_2R) {
-			if (dm_pstable.rssi_val_min >= 35)
-				dm_pstable.cur_ccasate = CCA_1R;
-			else
-				dm_pstable.cur_ccasate = CCA_2R;
-		} else {
-			if (dm_pstable.rssi_val_min <= 30)
-				dm_pstable.cur_ccasate = CCA_2R;
-			else
-				dm_pstable.cur_ccasate = CCA_1R;
-		}
-	} else {
-		dm_pstable.cur_ccasate = CCA_MAX;
-	}
-
-	if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) {
-		if (dm_pstable.cur_ccasate == CCA_1R) {
-			if (get_rf_type(rtlphy) == RF_2T2R) {
-				rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
-					      MASKBYTE0, 0x13);
-				rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20);
-			} else {
-				rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
-					      MASKBYTE0, 0x23);
-				rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c);
-			}
-		} else {
-			rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0,
-				      0x33);
-			rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63);
-		}
-		dm_pstable.pre_ccastate = dm_pstable.cur_ccasate;
-	}
-
-	RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n",
-					       (dm_pstable.cur_ccasate ==
-						0) ? "1RCCA" : "2RCCA"));
-}
-
 void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
 {
 	static u8 initialize;
@@ -1352,7 +1343,9 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
 	}
 
 	if (IS_92C_SERIAL(rtlhal->version))
-		rtl92c_dm_1r_cca(hw);
+		;/* rtl92c_dm_1r_cca(hw); */
+	else
+		rtl92c_dm_rf_saving(hw, false);
 }
 
 void rtl92c_dm_init(struct ieee80211_hw *hw)
@@ -1369,6 +1362,84 @@ void rtl92c_dm_init(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(rtl92c_dm_init);
 
+void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	long undecorated_smoothed_pwdb;
+
+	if (!rtlpriv->dm.dynamic_txpower_enable)
+		return;
+
+	if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+		return;
+	}
+
+	if ((mac->link_state < MAC80211_LINKED) &&
+	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+			 ("Not connected to any\n"));
+
+		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+
+		rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+		return;
+	}
+
+	if (mac->link_state >= MAC80211_LINKED) {
+		if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+			undecorated_smoothed_pwdb =
+			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+				 ("AP Client PWDB = 0x%lx\n",
+				  undecorated_smoothed_pwdb));
+		} else {
+			undecorated_smoothed_pwdb =
+			    rtlpriv->dm.undecorated_smoothed_pwdb;
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+				 ("STA Default Port PWDB = 0x%lx\n",
+				  undecorated_smoothed_pwdb));
+		}
+	} else {
+		undecorated_smoothed_pwdb =
+		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 ("AP Ext Port PWDB = 0x%lx\n",
+			  undecorated_smoothed_pwdb));
+	}
+
+	if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"));
+	} else if ((undecorated_smoothed_pwdb <
+		    (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+		   (undecorated_smoothed_pwdb >=
+		    TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+
+		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"));
+	} else if (undecorated_smoothed_pwdb <
+		   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 ("TXHIGHPWRLEVEL_NORMAL\n"));
+	}
+
+	if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 ("PHY_SetTxPowerLevel8192S() Channel = %d\n",
+			  rtlphy->current_channel));
+		rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+	}
+
+	rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
 void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1388,11 +1459,321 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
 		rtl92c_dm_dig(hw);
 		rtl92c_dm_false_alarm_counter_statistics(hw);
 		rtl92c_dm_dynamic_bb_powersaving(hw);
-		rtlpriv->cfg->ops->dm_dynamic_txpower(hw);
+		rtl92c_dm_dynamic_txpower(hw);
 		rtl92c_dm_check_txpower_tracking(hw);
 		rtl92c_dm_refresh_rate_adaptive_mask(hw);
+		rtl92c_dm_bt_coexist(hw);
 		rtl92c_dm_check_edca_turbo(hw);
-
 	}
 }
 EXPORT_SYMBOL(rtl92c_dm_watchdog);
+
+u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+	long undecorated_smoothed_pwdb;
+	u8 curr_bt_rssi_state = 0x00;
+
+	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+		undecorated_smoothed_pwdb =
+				 GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
+	} else {
+		if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)
+			undecorated_smoothed_pwdb = 100;
+		else
+			undecorated_smoothed_pwdb =
+				rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+	}
+
+	/* Check RSSI to determine HighPower/NormalPower state for
+	 * BT coexistence. */
+	if (undecorated_smoothed_pwdb >= 67)
+		curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER);
+	else if (undecorated_smoothed_pwdb < 62)
+		curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER;
+
+	/* Check RSSI to determine AMPDU setting for BT coexistence. */
+	if (undecorated_smoothed_pwdb >= 40)
+		curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF);
+	else if (undecorated_smoothed_pwdb <= 32)
+		curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF;
+
+	/* Marked RSSI state. It will be used to determine BT coexistence
+	 * setting later. */
+	if (undecorated_smoothed_pwdb < 35)
+		curr_bt_rssi_state |=  BT_RSSI_STATE_SPECIAL_LOW;
+	else
+		curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW);
+
+	/* Set Tx Power according to BT status. */
+	if (undecorated_smoothed_pwdb >= 30)
+		curr_bt_rssi_state |=  BT_RSSI_STATE_TXPOWER_LOW;
+	else if (undecorated_smoothed_pwdb < 25)
+		curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW);
+
+	/* Check BT state related to BT_Idle in B/G mode. */
+	if (undecorated_smoothed_pwdb < 15)
+		curr_bt_rssi_state |=  BT_RSSI_STATE_BG_EDCA_LOW;
+	else
+		curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW);
+
+	if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) {
+		rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state;
+		return true;
+	} else {
+		return false;
+	}
+}
+EXPORT_SYMBOL(rtl92c_bt_rssi_state_change);
+
+static bool rtl92c_bt_state_change(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+	u32 polling, ratio_tx, ratio_pri;
+	u32 bt_tx, bt_pri;
+	u8 bt_state;
+	u8 cur_service_type;
+
+	if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
+		return false;
+
+	bt_state = rtl_read_byte(rtlpriv, 0x4fd);
+	bt_tx = rtl_read_dword(rtlpriv, 0x488);
+	bt_tx = bt_tx & 0x00ffffff;
+	bt_pri = rtl_read_dword(rtlpriv, 0x48c);
+	bt_pri = bt_pri & 0x00ffffff;
+	polling = rtl_read_dword(rtlpriv, 0x490);
+
+	if (bt_tx == 0xffffffff && bt_pri == 0xffffffff &&
+	    polling == 0xffffffff && bt_state == 0xff)
+		return false;
+
+	bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1);
+	if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) {
+		rtlpcipriv->bt_coexist.bt_cur_state = bt_state;
+
+		if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) {
+			rtlpcipriv->bt_coexist.bt_service = BT_IDLE;
+
+			bt_state = bt_state |
+			  ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+			  0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+			  BIT_OFFSET_LEN_MASK_32(2, 1);
+			rtl_write_byte(rtlpriv, 0x4fd, bt_state);
+		}
+		return true;
+	}
+
+	ratio_tx = bt_tx * 1000 / polling;
+	ratio_pri = bt_pri * 1000 / polling;
+	rtlpcipriv->bt_coexist.ratio_tx = ratio_tx;
+	rtlpcipriv->bt_coexist.ratio_pri = ratio_pri;
+
+	if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) {
+
+		if ((ratio_tx < 30)  && (ratio_pri < 30))
+			cur_service_type = BT_IDLE;
+		else if ((ratio_pri > 110) && (ratio_pri < 250))
+			cur_service_type = BT_SCO;
+		else if ((ratio_tx >= 200) && (ratio_pri >= 200))
+			cur_service_type = BT_BUSY;
+		else if ((ratio_tx >= 350) && (ratio_tx < 500))
+			cur_service_type = BT_OTHERBUSY;
+		else if (ratio_tx >= 500)
+			cur_service_type = BT_PAN;
+		else
+			cur_service_type = BT_OTHER_ACTION;
+
+		if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) {
+			rtlpcipriv->bt_coexist.bt_service = cur_service_type;
+			bt_state = bt_state |
+			   ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+			   0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+			   ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ?
+			   0 : BIT_OFFSET_LEN_MASK_32(2, 1));
+
+			/* Add interrupt migration when bt is not ini
+			 * idle state (no traffic). */
+			if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+				rtl_write_word(rtlpriv, 0x504, 0x0ccc);
+				rtl_write_byte(rtlpriv, 0x506, 0x54);
+				rtl_write_byte(rtlpriv, 0x507, 0x54);
+			} else {
+				rtl_write_byte(rtlpriv, 0x506, 0x00);
+				rtl_write_byte(rtlpriv, 0x507, 0x00);
+			}
+
+			rtl_write_byte(rtlpriv, 0x4fd, bt_state);
+			return true;
+		}
+	}
+
+	return false;
+
+}
+
+static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	static bool media_connect;
+
+	if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+		media_connect = false;
+	} else {
+		if (!media_connect) {
+			media_connect = true;
+			return true;
+		}
+		media_connect = true;
+	}
+
+	return false;
+}
+
+static void rtl92c_bt_set_normal(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+
+	if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) {
+		rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b;
+		rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b;
+	} else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) {
+		rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f;
+		rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f;
+	} else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) {
+		if (rtlpcipriv->bt_coexist.ratio_tx > 160) {
+			rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f;
+			rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f;
+		} else {
+			rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b;
+			rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b;
+		}
+	} else {
+		rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+		rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+	}
+
+	if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) &&
+	     (rtlpriv->mac80211.mode == WIRELESS_MODE_G ||
+	     (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) &&
+	     (rtlpcipriv->bt_coexist.bt_rssi_state &
+	     BT_RSSI_STATE_BG_EDCA_LOW)) {
+		rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b;
+		rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b;
+	}
+}
+
+static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+
+	/* Only enable HW BT coexist when BT in "Busy" state. */
+	if (rtlpriv->mac80211.vendor == PEER_CISCO &&
+	    rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) {
+		rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+	} else {
+		if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) &&
+		    (rtlpcipriv->bt_coexist.bt_rssi_state &
+		     BT_RSSI_STATE_NORMAL_POWER)) {
+			rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+		} else if ((rtlpcipriv->bt_coexist.bt_service ==
+			    BT_OTHER_ACTION) && (rtlpriv->mac80211.mode <
+			    WIRELESS_MODE_N_24G) &&
+			    (rtlpcipriv->bt_coexist.bt_rssi_state &
+			    BT_RSSI_STATE_SPECIAL_LOW)) {
+			rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+		} else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) {
+			rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+		} else {
+			rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+		}
+	}
+
+	if (rtlpcipriv->bt_coexist.bt_service == BT_PAN)
+		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100);
+	else
+		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0);
+
+	if (rtlpcipriv->bt_coexist.bt_rssi_state &
+	    BT_RSSI_STATE_NORMAL_POWER) {
+		rtl92c_bt_set_normal(hw);
+	} else {
+		rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+		rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+	}
+
+	if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+		rtlpriv->cfg->ops->set_rfreg(hw,
+				 RF90_PATH_A,
+				 0x1e,
+				 0xf0, 0xf);
+	} else {
+		rtlpriv->cfg->ops->set_rfreg(hw,
+		     RF90_PATH_A, 0x1e, 0xf0,
+		     rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+	}
+
+	if (!rtlpriv->dm.dynamic_txpower_enable) {
+		if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+			if (rtlpcipriv->bt_coexist.bt_rssi_state &
+				BT_RSSI_STATE_TXPOWER_LOW) {
+				rtlpriv->dm.dynamic_txhighpower_lvl =
+							TXHIGHPWRLEVEL_BT2;
+			} else {
+				rtlpriv->dm.dynamic_txhighpower_lvl =
+					TXHIGHPWRLEVEL_BT1;
+			}
+		} else {
+			rtlpriv->dm.dynamic_txhighpower_lvl =
+				TXHIGHPWRLEVEL_NORMAL;
+		}
+		rtl92c_phy_set_txpower_level(hw,
+			rtlpriv->phy.current_channel);
+	}
+}
+
+static void rtl92c_check_bt_change(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+	if (rtlpcipriv->bt_coexist.bt_cur_state) {
+		if (rtlpcipriv->bt_coexist.bt_ant_isolation)
+			rtl92c_bt_ant_isolation(hw);
+	} else {
+		rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+		rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0,
+				rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+
+		rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+		rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+	}
+}
+
+void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw)
+{
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+	bool wifi_connect_change;
+	bool bt_state_change;
+	bool rssi_state_change;
+
+	if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+	     (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) {
+
+		wifi_connect_change = rtl92c_bt_wifi_connect_change(hw);
+		bt_state_change = rtl92c_bt_state_change(hw);
+		rssi_state_change = rtl92c_bt_rssi_state_change(hw);
+
+		if (wifi_connect_change || bt_state_change || rssi_state_change)
+			rtl92c_check_bt_change(hw);
+	}
+}
+EXPORT_SYMBOL(rtl92c_dm_bt_coexist);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
index b9cbb0a3c03f5534caaba5d551d4e766ba55b257..b9736d3e9a397cad52a009df793449550cd1b490 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
@@ -200,5 +200,7 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
 void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
 void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
 void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery);
+void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw);
+void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index bc9d24134ac4d155d6db882eb250fec29562a2f3..50303e1adff109b6fc73676bf77b3c7632c565fa 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -223,29 +223,15 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
 	u8 *pfwdata;
 	u32 fwsize;
 	enum version_8192c version = rtlhal->version;
-	const struct firmware *firmware;
 
 	printk(KERN_INFO "rtl8192c: Loading firmware file %s\n",
 	       rtlpriv->cfg->fw_name);
-	if (request_firmware(&firmware, rtlpriv->cfg->fw_name,
-			    rtlpriv->io.dev)) {
-		printk(KERN_ERR "rtl8192c: Firmware loading failed\n");
+	if (!rtlhal->pfirmware)
 		return 1;
-	}
-
-	if (firmware->size > 0x4000) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 ("Firmware is too big!\n"));
-		release_firmware(firmware);
-		return 1;
-	}
-
-	memcpy(rtlhal->pfirmware, firmware->data, firmware->size);
-	fwsize = firmware->size;
-	release_firmware(firmware);
 
 	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
 	pfwdata = (u8 *) rtlhal->pfirmware;
+	fwsize = rtlhal->fwsize;
 
 	if (IS_FW_HEADER_EXIST(pfwheader)) {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
@@ -553,6 +539,39 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 }
 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
 
+static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
+				struct sk_buff *skb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring;
+	struct rtl_tx_desc *pdesc;
+	u8 own;
+	unsigned long flags;
+	struct sk_buff *pskb = NULL;
+
+	ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+	pskb = __skb_dequeue(&ring->queue);
+	if (pskb)
+		kfree_skb(pskb);
+
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+	pdesc = &ring->desc[0];
+	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
+
+	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
+
+	__skb_queue_tail(&ring->queue, skb);
+
+	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+	return true;
+}
+
 #define BEACON_PG		0 /*->1*/
 #define PSPOLL_PG		2
 #define NULL_PG			3
@@ -670,7 +689,7 @@ static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
+void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -679,12 +698,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 	u32 totalpacketlen;
 	bool rtstatus;
 	u8 u1RsvdPageLoc[3] = {0};
-	bool b_dlok = false;
+	bool dlok = false;
 
 	u8 *beacon;
-	u8 *p_pspoll;
+	u8 *pspoll;
 	u8 *nullfunc;
-	u8 *p_probersp;
+	u8 *probersp;
 	/*---------------------------------------------------------
 				(1) beacon
 	---------------------------------------------------------*/
@@ -695,10 +714,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 	/*-------------------------------------------------------
 				(2) ps-poll
 	--------------------------------------------------------*/
-	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
-	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
-	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
-	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+	pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+	SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
+	SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
+	SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
 
 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
 
@@ -715,10 +734,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 	/*---------------------------------------------------------
 				(4) probe response
 	----------------------------------------------------------*/
-	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
-	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
-	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
-	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
+	probersp = &reserved_page_packet[PROBERSP_PG * 128];
+	SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
+	SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
 
 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
 
@@ -736,12 +755,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 	memcpy((u8 *) skb_put(skb, totalpacketlen),
 	       &reserved_page_packet, totalpacketlen);
 
-	rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb);
+	rtstatus = _rtl92c_cmd_send_packet(hw, skb);
 
 	if (rtstatus)
-		b_dlok = true;
+		dlok = true;
 
-	if (b_dlok) {
+	if (dlok) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 ("Set RSVD page location to Fw.\n"));
 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
index 3db33bd14666ebeee9bb30ef1f546d5114ef8b89..3d5823c12621ef0e2da79d1c3d68616f7671a431 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
@@ -27,8 +27,8 @@
  *
  *****************************************************************************/
 
-#ifndef __RTL92C__FW__H__
-#define __RTL92C__FW__H__
+#ifndef __RTL92C__FW__COMMON__H__
+#define __RTL92C__FW__COMMON__H__
 
 #define FW_8192C_SIZE				0x3000
 #define FW_8192C_START_ADDRESS			0x1000
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
index a70228278398ab2c893391e963a7f520327d1026..c5424cad43cb578ea57d8d095dfba92a4b23c772 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
@@ -78,27 +78,29 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
 					       " data(%#x)\n", regaddr, bitmask,
 					       data));
+
 }
 EXPORT_SYMBOL(rtl92c_phy_set_bb_reg);
 
 u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw,
-					 enum radio_path rfpath, u32 offset)
+				  enum radio_path rfpath, u32 offset)
 {
 	RT_ASSERT(false, ("deprecated!\n"));
 	return 0;
+
 }
 EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read);
 
 void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
-					   enum radio_path rfpath, u32 offset,
-					   u32 data)
+				    enum radio_path rfpath, u32 offset,
+				    u32 data)
 {
 	RT_ASSERT(false, ("deprecated!\n"));
 }
 EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write);
 
 u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
-				      enum radio_path rfpath, u32 offset)
+			       enum radio_path rfpath, u32 offset)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -149,8 +151,8 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
 EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read);
 
 void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
-					enum radio_path rfpath, u32 offset,
-					u32 data)
+				 enum radio_path rfpath, u32 offset,
+				 u32 data)
 {
 	u32 data_and_addr;
 	u32 newoffset;
@@ -197,6 +199,7 @@ static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw)
 	rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2);
 	rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2);
 }
+
 bool rtl92c_phy_rf_config(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -241,13 +244,14 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
 	rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
 						RFPGA0_XA_HSSIPARAMETER2,
 						0x200));
+
 	return true;
 }
 EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile);
 
 void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
-						   u32 regaddr, u32 bitmask,
-						   u32 data)
+					    u32 regaddr, u32 bitmask,
+					    u32 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -317,61 +321,48 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
 	}
 	if (regaddr == RTXAGC_B_RATE54_24) {
 		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data;
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
 			  rtlphy->pwrgroup_cnt,
 			  rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9]));
 	}
-
 	if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
 		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data;
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
 			  rtlphy->pwrgroup_cnt,
 			  rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14]));
 	}
-
 	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
 		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data;
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
 			  rtlphy->pwrgroup_cnt,
 			  rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15]));
 	}
-
 	if (regaddr == RTXAGC_B_MCS03_MCS00) {
 		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data;
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
 			  rtlphy->pwrgroup_cnt,
 			  rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10]));
 	}
-
 	if (regaddr == RTXAGC_B_MCS07_MCS04) {
 		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data;
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
 			  rtlphy->pwrgroup_cnt,
 			  rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11]));
 	}
-
 	if (regaddr == RTXAGC_B_MCS11_MCS08) {
 		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data;
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
 			  rtlphy->pwrgroup_cnt,
 			  rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12]));
 	}
-
 	if (regaddr == RTXAGC_B_MCS15_MCS12) {
 		rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data;
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
 			  rtlphy->pwrgroup_cnt,
@@ -583,6 +574,7 @@ static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw,
 
 	rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
 	rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+
 }
 
 void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
@@ -611,7 +603,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 idx;
 	u8 rf_path;
-
 	u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw,
 						      WIRELESS_MODE_B,
 						      power_indbm);
@@ -639,11 +630,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
 }
 EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm);
 
-void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval)
-{
-}
-EXPORT_SYMBOL(rtl92c_phy_set_beacon_hw_reg);
-
 u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
 				enum wireless_mode wirelessmode,
 				long power_indbm)
@@ -741,9 +727,9 @@ void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
 	if (rtlphy->set_bwmode_inprogress)
 		return;
 	rtlphy->set_bwmode_inprogress = true;
-	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw)))
-		rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw);
-	else {
+	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+		rtlphy->set_bwmode_inprogress = false;
+	} else {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 ("FALSE driver sleep or unload\n"));
 		rtlphy->set_bwmode_inprogress = false;
@@ -773,8 +759,9 @@ void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw)
 				mdelay(delay);
 			else
 				continue;
-		} else
+		} else {
 			rtlphy->sw_chnl_inprogress = false;
+		}
 		break;
 	} while (true);
 	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
@@ -811,9 +798,32 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(rtl92c_phy_sw_chnl);
 
-static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
-					     u8 channel, u8 *stage, u8 *step,
-					     u32 *delay)
+static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+					     u32 cmdtableidx, u32 cmdtablesz,
+					     enum swchnlcmd_id cmdid,
+					     u32 para1, u32 para2, u32 msdelay)
+{
+	struct swchnlcmd *pcmd;
+
+	if (cmdtable == NULL) {
+		RT_ASSERT(false, ("cmdtable cannot be NULL.\n"));
+		return false;
+	}
+
+	if (cmdtableidx >= cmdtablesz)
+		return false;
+
+	pcmd = cmdtable + cmdtableidx;
+	pcmd->cmdid = cmdid;
+	pcmd->para1 = para1;
+	pcmd->para2 = para2;
+	pcmd->msdelay = msdelay;
+	return true;
+}
+
+bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+				      u8 channel, u8 *stage, u8 *step,
+				      u32 *delay)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -917,29 +927,6 @@ static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
 	return false;
 }
 
-static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
-					     u32 cmdtableidx, u32 cmdtablesz,
-					     enum swchnlcmd_id cmdid,
-					     u32 para1, u32 para2, u32 msdelay)
-{
-	struct swchnlcmd *pcmd;
-
-	if (cmdtable == NULL) {
-		RT_ASSERT(false, ("cmdtable cannot be NULL.\n"));
-		return false;
-	}
-
-	if (cmdtableidx >= cmdtablesz)
-		return false;
-
-	pcmd = cmdtable + cmdtableidx;
-	pcmd->cmdid = cmdid;
-	pcmd->para1 = para1;
-	pcmd->para2 = para2;
-	pcmd->msdelay = msdelay;
-	return true;
-}
-
 bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath)
 {
 	return true;
@@ -1002,13 +989,13 @@ static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw)
 	reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
 	reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
 	reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
+
 	if (!(reg_eac & BIT(31)) &&
 	    (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
 	    (((reg_ebc & 0x03FF0000) >> 16) != 0x42))
 		result |= 0x01;
 	else
 		return result;
-
 	if (!(reg_eac & BIT(30)) &&
 	    (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) &&
 	    (((reg_ecc & 0x03FF0000) >> 16) != 0x36))
@@ -1023,9 +1010,9 @@ static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
 	u32 oldval_0, x, tx0_a, reg;
 	long y, tx0_c;
 
-	if (final_candidate == 0xFF)
+	if (final_candidate == 0xFF) {
 		return;
-	else if (iqk_ok) {
+	} else if (iqk_ok) {
 		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
 					  MASKDWORD) >> 22) & 0x3FF;
 		x = result[final_candidate][0];
@@ -1063,9 +1050,9 @@ static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw,
 	u32 oldval_1, x, tx1_a, reg;
 	long y, tx1_c;
 
-	if (final_candidate == 0xFF)
+	if (final_candidate == 0xFF) {
 		return;
-	else if (iqk_ok) {
+	} else if (iqk_ok) {
 		oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
 					  MASKDWORD) >> 22) & 0x3FF;
 		x = result[final_candidate][4];
@@ -1282,6 +1269,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
 						   RFPGA0_XA_HSSIPARAMETER1,
 						   BIT(8));
 	}
+
 	if (!rtlphy->rfpi_enable)
 		_rtl92c_phy_pi_mode_switch(hw, true);
 	if (t == 0) {
@@ -1317,9 +1305,10 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
 					0x3FF0000) >> 16;
 			break;
 		} else if (i == (retrycount - 1) && patha_ok == 0x01)
+
 			result[t][0] = (rtl_get_bbreg(hw, 0xe94,
 						      MASKDWORD) & 0x3FF0000) >>
-						      16;
+			    16;
 		result[t][1] =
 		    (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16;
 
@@ -1375,8 +1364,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
 static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
 				     char delta, bool is2t)
 {
-	/* This routine is deliberately dummied out for later fixes */
-#if 0
+#if 0 /* This routine is deliberately dummied out for later fixes */
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -1434,7 +1422,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
 		0x04db25a4, 0x0b1b25a4
 	};
 
-	u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c };
+	const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c };
 
 	u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 };
 
@@ -1463,13 +1451,15 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
 		0x00050006
 	};
 
-	const u32 apk_result[PATH_NUM][APK_BB_REG_NUM];
+	u32 apk_result[PATH_NUM][APK_BB_REG_NUM];
 
 	long bb_offset, delta_v, delta_offset;
 
 	if (!is2t)
 		pathbound = 1;
 
+	return;
+
 	for (index = 0; index < PATH_NUM; index++) {
 		apk_offset[index] = apk_normal_offset[index];
 		apk_value[index] = apk_normal_value[index];
@@ -1730,8 +1720,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
 			       0x08));
 
 	}
-
-	rtlphy->apk_done = true;
+	rtlphy->b_apk_done = true;
 #endif
 }
 
@@ -1758,6 +1747,7 @@ static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw,
 			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1);
 
 	}
+
 }
 
 #undef IQK_ADDA_REG_NUM
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
index 53ffb098158636b7ee101da2db4efb0fab396a97..9a264c0d6127da662691d0a790997b5982d838b9 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
@@ -27,8 +27,8 @@
  *
  *****************************************************************************/
 
-#ifndef __RTL92C_PHY_H__
-#define __RTL92C_PHY_H__
+#ifndef __RTL92C_PHY_COMMON_H__
+#define __RTL92C_PHY_COMMON_H__
 
 #define MAX_PRECMD_CNT			16
 #define MAX_RFDEPENDCMD_CNT		16
@@ -39,6 +39,7 @@
 #define RT_CANNOT_IO(hw)		false
 #define HIGHPOWER_RADIOA_ARRAYLEN	22
 
+#define IQK_ADDA_REG_NUM		16
 #define MAX_TOLERANCE			5
 #define	IQK_DELAY_TIME			1
 
@@ -56,6 +57,7 @@
 #define IQK_ADDA_REG_NUM		16
 #define IQK_MAC_REG_NUM			4
 
+#define IQK_DELAY_TIME			1
 #define RF90_PATH_MAX			2
 
 #define CT_OFFSET_MAC_ADDR		0X16
@@ -77,6 +79,7 @@
 
 #define RTL92C_MAX_PATH_NUM		2
 #define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER	255
+
 enum swchnlcmd_id {
 	CMDID_END,
 	CMDID_SET_TXPOWEROWER_LEVEL,
@@ -184,45 +187,41 @@ struct tx_power_struct {
 	u32 mcs_original_offset[4][16];
 };
 
-extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
+u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
 				   u32 regaddr, u32 bitmask);
-extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
 				  u32 regaddr, u32 bitmask, u32 data);
-extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
+u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
 				   enum radio_path rfpath, u32 regaddr,
 				   u32 bitmask);
-extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw,
-				  enum radio_path rfpath, u32 regaddr,
-				  u32 bitmask, u32 data);
-extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
+bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
 						 enum radio_path rfpath);
-extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
-extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
+void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
 					 long *powerlevel);
-extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
-extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
+void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
 					  long power_indbm);
-extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
+void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
 					     u8 operation);
-extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
-extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
 				   enum nl80211_channel_type ch_type);
-extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
-extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
-extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
-extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
 					 u16 beaconinterval);
 void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
 void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
 void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
 bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 					  enum radio_path rfpath);
-extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
+bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
 					      u32 rfpath);
-extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
+bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
 					  enum rf_pwrstate rfpwr_state);
 void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw);
 void rtl92c_phy_set_io(struct ieee80211_hw *hw);
@@ -235,12 +234,25 @@ u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
 				enum wireless_mode wirelessmode,
 				long power_indbm);
 void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
-static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
-					     u32 cmdtableidx, u32 cmdtablesz,
-					     enum swchnlcmd_id cmdid, u32 para1,
-					     u32 para2, u32 msdelay);
-static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
-					     u8 channel, u8 *stage, u8 *step,
-					     u32 *delay);
+void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw);
+bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+				      u8 channel, u8 *stage, u8 *step,
+				      u32 *delay);
+u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw);
+u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw,
+				  enum radio_path rfpath, u32 offset);
+void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+				    enum radio_path rfpath, u32 offset,
+				    u32 data);
+u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
+			       enum radio_path rfpath, u32 offset);
+void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
+				 enum radio_path rfpath, u32 offset,
+				 u32 data);
+bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
+void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
+					    u32 regaddr, u32 bitmask,
+					    u32 data);
+bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
index 2f577c8828fc0fd2c45f9bfb28a34c04b142d806..35ff7df41a1d66b3e2243dd8ec164321a5217666 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -121,19 +121,6 @@
 #define CHIP_92C			0x01
 #define CHIP_88C			0x00
 
-/* Add vendor information into chip version definition.
- * Add UMC B-Cut and RTL8723 chip info definition.
- *
- * BIT 7	Reserved
- * BIT 6	UMC BCut
- * BIT 5	Manufacturer(TSMC/UMC)
- * BIT 4	TEST/NORMAL
- * BIT 3	8723 Version
- * BIT 2	8723?
- * BIT 1	1T2R?
- * BIT 0	88C/92C
-*/
-
 enum version_8192c {
 	VERSION_A_CHIP_92C = 0x01,
 	VERSION_A_CHIP_88C = 0x00,
@@ -280,20 +267,6 @@ struct h2c_cmd_8192c {
 	u8 *p_cmdbuffer;
 };
 
-static inline u8 _rtl92c_get_chnl_group(u8 chnl)
-{
-	u8 group = 0;
-
-	if (chnl < 3)
-		group = 0;
-	else if (chnl < 9)
-		group = 1;
-	else
-		group = 2;
-
-	return group;
-}
-
 /* NOTE: reference to rtl8192c_rates struct */
 static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT,
 				       u8 desc_rate, bool first_ampdu)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
index 7d76504df4d18ea4173ef8196d74a81e69ee961b..2df33e53e15a53ac9a5b68e9ef0524e376a52361 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
@@ -29,10 +29,12 @@
 
 #include "../wifi.h"
 #include "../base.h"
+#include "../pci.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
 #include "dm.h"
+#include "../rtl8192c/fw_common.h"
 
 void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)
 {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
index 36302ebae4a37544d67d83f47d0199dac2ec58f2..07dd9552e82f559344a239ce7b46a91c3d686708 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
@@ -192,6 +192,7 @@ void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw);
 void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw);
 void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
 void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
+void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw);
 void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index 05477f465a7531b6b499f1679c0c63a3edcfd9a6..4a56138eb33cf2e3cda5b180c9bc40d82ea4bc56 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -30,12 +30,14 @@
 #include "../wifi.h"
 #include "../efuse.h"
 #include "../base.h"
+#include "../regd.h"
 #include "../cam.h"
 #include "../ps.h"
 #include "../pci.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
+#include "../rtl8192c/fw_common.h"
 #include "dm.h"
 #include "led.h"
 #include "hw.h"
@@ -137,15 +139,6 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 
 		break;
 		}
-	case HW_VAR_MGT_FILTER:
-		*((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0);
-		break;
-	case HW_VAR_CTRL_FILTER:
-		*((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1);
-		break;
-	case HW_VAR_DATA_FILTER:
-		*((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2);
-		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 ("switch case not process\n"));
@@ -156,6 +149,7 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -178,7 +172,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			rate_cfg |= 0x01;
 			rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
 			rtl_write_byte(rtlpriv, REG_RRSR + 1,
-				       (rate_cfg >> 8)&0xff);
+				       (rate_cfg >> 8) & 0xff);
 			while (rate_cfg > 0x1) {
 				rate_cfg = (rate_cfg >> 1);
 				rate_index++;
@@ -276,13 +270,19 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 		}
 	case HW_VAR_AMPDU_FACTOR:{
-			u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+			u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9};
+			u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97};
 
 			u8 factor_toset;
 			u8 *p_regtoset = NULL;
 			u8 index = 0;
 
-			p_regtoset = regtoset_normal;
+			if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+			    (rtlpcipriv->bt_coexist.bt_coexist_type ==
+			    BT_CSR_BC4))
+				p_regtoset = regtoset_bt;
+			else
+				p_regtoset = regtoset_normal;
 
 			factor_toset = *((u8 *) val);
 			if (factor_toset <= 3) {
@@ -317,45 +317,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		}
 	case HW_VAR_AC_PARAM:{
 			u8 e_aci = *((u8 *) val);
-			u32 u4b_ac_param;
-			u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min);
-			u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max);
-			u16 tx_op = le16_to_cpu(mac->ac[e_aci].tx_op);
-
-			u4b_ac_param = (u32) mac->ac[e_aci].aifs;
-			u4b_ac_param |= ((u32)cw_min
-					 & 0xF) << AC_PARAM_ECW_MIN_OFFSET;
-			u4b_ac_param |= ((u32)cw_max &
-					 0xF) << AC_PARAM_ECW_MAX_OFFSET;
-			u4b_ac_param |= (u32)tx_op << AC_PARAM_TXOP_OFFSET;
-
-			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
-				 ("queue:%x, ac_param:%x\n", e_aci,
-				  u4b_ac_param));
-
-			switch (e_aci) {
-			case AC1_BK:
-				rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM,
-						u4b_ac_param);
-				break;
-			case AC0_BE:
-				rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM,
-						u4b_ac_param);
-				break;
-			case AC2_VI:
-				rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM,
-						u4b_ac_param);
-				break;
-			case AC3_VO:
-				rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM,
-						u4b_ac_param);
-				break;
-			default:
-				RT_ASSERT(false,
-				  ("SetHwReg8185(): invalid aci: %d !\n",
-				   e_aci));
-				break;
-			}
+			rtl92c_dm_init_edca_turbo(hw);
 
 			if (rtlpci->acm_method != eAcmWay2_SW)
 				rtlpriv->cfg->ops->set_hw_reg(hw,
@@ -526,9 +488,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HW_VAR_CORRECT_TSF:{
 			u8 btype_ibss = ((u8 *) (val))[0];
 
-			/*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ?
-					1 : 0;*/
-
 			if (btype_ibss == true)
 				_rtl92ce_stop_tx_beacon(hw);
 
@@ -537,7 +496,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			rtl_write_dword(rtlpriv, REG_TSFTR,
 					(u32) (mac->tsf & 0xffffffff));
 			rtl_write_dword(rtlpriv, REG_TSFTR + 4,
-					(u32) ((mac->tsf >> 32)&0xffffffff));
+					(u32) ((mac->tsf >> 32) & 0xffffffff));
 
 			_rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0);
 
@@ -547,15 +506,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 			break;
 
 		}
-	case HW_VAR_MGT_FILTER:
-		rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val);
-		break;
-	case HW_VAR_CTRL_FILTER:
-		rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val);
-		break;
-	case HW_VAR_DATA_FILTER:
-		rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val);
-		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case "
 							"not process\n"));
@@ -679,12 +629,12 @@ static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw)
 		rtl92ce_sw_led_on(hw, pLed0);
 	else
 		rtl92ce_sw_led_off(hw, pLed0);
-
 }
 
 static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
@@ -693,9 +643,22 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
 	u16 retry;
 
 	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+	if (rtlpcipriv->bt_coexist.bt_coexistence) {
+		u32 value32;
+		value32 = rtl_read_dword(rtlpriv, REG_APS_FSMCO);
+		value32 |= (SOP_ABG | SOP_AMB | XOP_BTCK);
+		rtl_write_dword(rtlpriv, REG_APS_FSMCO, value32);
+	}
 	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
 	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F);
 
+	if (rtlpcipriv->bt_coexist.bt_coexistence) {
+		u32 u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL);
+
+		u4b_tmp &= (~0x00024800);
+		rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp);
+	}
+
 	bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0);
 	udelay(2);
 
@@ -726,6 +689,11 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
 	rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82);
 	udelay(2);
 
+	if (rtlpcipriv->bt_coexist.bt_coexistence) {
+		bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2) & 0xfd;
+		rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, bytetmp);
+	}
+
 	rtl_write_word(rtlpriv, REG_CR, 0x2ff);
 
 	if (_rtl92ce_llt_table_init(hw) == false)
@@ -793,6 +761,7 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	u8 reg_bw_opmode;
 	u32 reg_ratr, reg_prsr;
 
@@ -824,7 +793,11 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
 	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
 	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
 
-	rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841);
+	if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+	    (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+		rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431);
+	else
+		rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841);
 
 	rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2);
 
@@ -840,11 +813,20 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
 	rtl_write_byte(rtlpriv, REG_PIFS, 0x1C);
 	rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16);
 
-	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
-
-	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+	if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+	    (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) {
+		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+		rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402);
+	} else {
+		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+	}
 
-	rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666);
+	if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+	     (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+		rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666);
+	else
+		rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666);
 
 	rtl_write_byte(rtlpriv, REG_ACKTO, 0x40);
 
@@ -948,8 +930,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
 	}
 
 	rtlhal->last_hmeboxnum = 0;
-	rtl92ce_phy_mac_config(hw);
-	rtl92ce_phy_bb_config(hw);
+	rtl92c_phy_mac_config(hw);
+	rtl92c_phy_bb_config(hw);
 	rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
 	rtl92c_phy_rf_config(hw);
 	rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
@@ -962,15 +944,20 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
 	_rtl92ce_hw_configure(hw);
 	rtl_cam_reset_all_entry(hw);
 	rtl92ce_enable_hw_security_config(hw);
+
 	ppsc->rfpwr_state = ERFON;
+
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
 	_rtl92ce_enable_aspm_back_door(hw);
 	rtlpriv->intf_ops->enable_aspm(hw);
+
+	rtl8192ce_bt_hw_init(hw);
+
 	if (ppsc->rfpwr_state == ERFON) {
 		rtl92c_phy_set_rfpath_switch(hw, 1);
-		if (iqk_initialized)
+		if (iqk_initialized) {
 			rtl92c_phy_iq_calibrate(hw, true);
-		else {
+		} else {
 			rtl92c_phy_iq_calibrate(hw, false);
 			iqk_initialized = true;
 		}
@@ -1128,75 +1115,62 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
 	return 0;
 }
 
-static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw,
-				     enum nl80211_iftype type)
+void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
-	u8 filterout_non_associated_bssid = false;
 
-	switch (type) {
-	case NL80211_IFTYPE_ADHOC:
-	case NL80211_IFTYPE_STATION:
-		filterout_non_associated_bssid = true;
-		break;
-	case NL80211_IFTYPE_UNSPECIFIED:
-	case NL80211_IFTYPE_AP:
-	default:
-		break;
-	}
+	if (rtlpriv->psc.rfpwr_state != ERFON)
+		return;
 
-	if (filterout_non_associated_bssid == true) {
+	if (check_bssid == true) {
 		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
 					      (u8 *) (&reg_rcr));
 		_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4));
-	} else if (filterout_non_associated_bssid == false) {
+	} else if (check_bssid == false) {
 		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
 		_rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0);
 		rtlpriv->cfg->ops->set_hw_reg(hw,
 					      HW_VAR_RCR, (u8 *) (&reg_rcr));
 	}
+
 }
 
 int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
 {
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
 	if (_rtl92ce_set_media_status(hw, type))
 		return -EOPNOTSUPP;
-	_rtl92ce_set_check_bssid(hw, type);
+
+	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+		if (type != NL80211_IFTYPE_AP)
+			rtl92ce_set_check_bssid(hw, true);
+	} else {
+		rtl92ce_set_check_bssid(hw, false);
+	}
+
 	return 0;
 }
 
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
 void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u32 u4b_ac_param;
-	u16 cw_min = le16_to_cpu(mac->ac[aci].cw_min);
-	u16 cw_max = le16_to_cpu(mac->ac[aci].cw_max);
-	u16 tx_op = le16_to_cpu(mac->ac[aci].tx_op);
-
 	rtl92c_dm_init_edca_turbo(hw);
-	u4b_ac_param = (u32) mac->ac[aci].aifs;
-	u4b_ac_param |= (u32) ((cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET);
-	u4b_ac_param |= (u32) ((cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET);
-	u4b_ac_param |= (u32) (tx_op << AC_PARAM_TXOP_OFFSET);
-	RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG,
-		 ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n",
-		  aci, u4b_ac_param, mac->ac[aci].aifs, cw_min,
-		  cw_max, tx_op));
 	switch (aci) {
 	case AC1_BK:
-		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param);
+		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
 		break;
 	case AC0_BE:
-		rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param);
+		/* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */
 		break;
 	case AC2_VI:
-		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param);
+		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
 		break;
 	case AC3_VO:
-		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param);
+		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
 		break;
 	default:
 		RT_ASSERT(false, ("invalid aci: %d !\n", aci));
@@ -1227,8 +1201,10 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
 static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 u1b_tmp;
+	u32 u4b_tmp;
 
 	rtlpriv->intf_ops->enable_aspm(hw);
 	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
@@ -1243,13 +1219,27 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
 	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
 	rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000);
 	u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL);
-	rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 |
-			(u1b_tmp << 8));
+	if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+	     ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) ||
+	     (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8))) {
+		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00F30000 |
+				(u1b_tmp << 8));
+	} else {
+		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 |
+				(u1b_tmp << 8));
+	}
 	rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790);
 	rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080);
 	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80);
 	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23);
-	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e);
+	if (rtlpcipriv->bt_coexist.bt_coexistence) {
+		u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL);
+		u4b_tmp |= 0x03824800;
+		rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp);
+	} else {
+		rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e);
+	}
+
 	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
 	rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10);
 }
@@ -1327,6 +1317,7 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
 
 	RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
 		 ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr));
+
 	if (add_msr)
 		rtlpci->irq_mask[0] |= add_msr;
 	if (rm_msr)
@@ -1582,7 +1573,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
 			 ("RTL819X Not boot from eeprom, check it !!"));
 	}
 
-	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"),
+	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
 		      hwinfo, HWSET_MAX_SIZE);
 
 	eeprom_id = *((u16 *)&hwinfo[0]);
@@ -1610,6 +1601,10 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
 					     rtlefuse->autoload_failflag,
 					     hwinfo);
 
+	rtl8192ce_read_bt_coexist_info_from_hwpg(hw,
+						 rtlefuse->autoload_failflag,
+						 hwinfo);
+
 	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
 	rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
 	rtlefuse->txpwr_fromeprom = true;
@@ -1618,6 +1613,9 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 		 ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid));
 
+	/* set channel paln to world wide 13 */
+	rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+
 	if (rtlhal->oem_id == RT_CID_DEFAULT) {
 		switch (rtlefuse->eeprom_oemid) {
 		case EEPROM_CID_DEFAULT:
@@ -1701,30 +1699,36 @@ void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw)
 	} else {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n"));
 	}
-
 	_rtl92ce_hal_customized_behavior(hw);
 }
 
-void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
+static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-
-	u32 ratr_value = (u32) mac->basic_rates;
-	u8 *mcsrate = mac->mcs;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 ratr_value;
 	u8 ratr_index = 0;
 	u8 nmode = mac->ht_enable;
-	u8 mimo_ps = 1;
+	u8 mimo_ps = IEEE80211_SMPS_OFF;
 	u16 shortgi_rate;
 	u32 tmp_ratr_value;
 	u8 curtxbw_40mhz = mac->bw_40;
-	u8 curshortgi_40mhz = mac->sgi_40;
-	u8 curshortgi_20mhz = mac->sgi_20;
+	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+			       1 : 0;
+	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+			       1 : 0;
 	enum wireless_mode wirelessmode = mac->mode;
 
-	ratr_value |= ((*(u16 *) (mcsrate))) << 12;
-
+	if (rtlhal->current_bandtype == BAND_ON_5G)
+		ratr_value = sta->supp_rates[1] << 4;
+	else
+		ratr_value = sta->supp_rates[0];
+	ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+			sta->ht_cap.mcs.rx_mask[0] << 12);
 	switch (wirelessmode) {
 	case WIRELESS_MODE_B:
 		if (ratr_value & 0x0000000c)
@@ -1738,7 +1742,7 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
 		nmode = 1;
-		if (mimo_ps == 0) {
+		if (mimo_ps == IEEE80211_SMPS_STATIC) {
 			ratr_value &= 0x0007F005;
 		} else {
 			u32 ratr_mask;
@@ -1761,10 +1765,19 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
 		break;
 	}
 
-	ratr_value &= 0x0FFFFFFF;
+	if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+	    (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) &&
+	    (rtlpcipriv->bt_coexist.bt_cur_state) &&
+	    (rtlpcipriv->bt_coexist.bt_ant_isolation) &&
+	    ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ||
+	    (rtlpcipriv->bt_coexist.bt_service == BT_BUSY)))
+		ratr_value &= 0x0fffcfc0;
+	else
+		ratr_value &= 0x0FFFFFFF;
 
-	if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || (!curtxbw_40mhz &&
-		       curshortgi_20mhz))) {
+	if (nmode && ((curtxbw_40mhz &&
+			 curshortgi_40mhz) || (!curtxbw_40mhz &&
+					       curshortgi_20mhz))) {
 
 		ratr_value |= 0x10000000;
 		tmp_ratr_value = (ratr_value >> 12);
@@ -1784,24 +1797,42 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
 		 ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0)));
 }
 
-void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
+static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u8 rssi_level)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u32 ratr_bitmap = (u32) mac->basic_rates;
-	u8 *p_mcsrate = mac->mcs;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry = NULL;
+	u32 ratr_bitmap;
 	u8 ratr_index;
-	u8 curtxbw_40mhz = mac->bw_40;
-	u8 curshortgi_40mhz = mac->sgi_40;
-	u8 curshortgi_20mhz = mac->sgi_20;
-	enum wireless_mode wirelessmode = mac->mode;
+	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+				? 1 : 0;
+	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				1 : 0;
+	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				1 : 0;
+	enum wireless_mode wirelessmode = 0;
 	bool shortgi = false;
 	u8 rate_mask[5];
 	u8 macid = 0;
-	u8 mimops = 1;
-
-	ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12);
+	u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+	sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+	wirelessmode = sta_entry->wireless_mode;
+	if (mac->opmode == NL80211_IFTYPE_STATION)
+		curtxbw_40mhz = mac->bw_40;
+	else if (mac->opmode == NL80211_IFTYPE_AP ||
+		mac->opmode == NL80211_IFTYPE_ADHOC)
+		macid = sta->aid + 1;
+
+	if (rtlhal->current_bandtype == BAND_ON_5G)
+		ratr_bitmap = sta->supp_rates[1] << 4;
+	else
+		ratr_bitmap = sta->supp_rates[0];
+	ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+			sta->ht_cap.mcs.rx_mask[0] << 12);
 	switch (wirelessmode) {
 	case WIRELESS_MODE_B:
 		ratr_index = RATR_INX_WIRELESS_B;
@@ -1828,7 +1859,7 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
 	case WIRELESS_MODE_N_5G:
 		ratr_index = RATR_INX_WIRELESS_NGB;
 
-		if (mimops == 0) {
+		if (mimo_ps == IEEE80211_SMPS_STATIC) {
 			if (rssi_level == 1)
 				ratr_bitmap &= 0x00070000;
 			else if (rssi_level == 2)
@@ -1892,8 +1923,8 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
 	}
 	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
 		 ("ratr_bitmap :%x\n", ratr_bitmap));
-	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
-				       (ratr_index << 28);
+	*(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) |
+				     (ratr_index << 28));
 	rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
 	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, "
 						 "ratr_val:%x, %x:%x:%x:%x:%x\n",
@@ -1902,6 +1933,20 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
 						 rate_mask[2], rate_mask[3],
 						 rate_mask[4]));
 	rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+
+	if (macid != 0)
+		sta_entry->ratr_index = ratr_index;
+}
+
+void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u8 rssi_level)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->dm.useramask)
+		rtl92ce_update_hal_rate_mask(hw, sta, rssi_level);
+	else
+		rtl92ce_update_hal_rate_table(hw, sta);
 }
 
 void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw)
@@ -1919,7 +1964,7 @@ void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw)
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
 }
 
-bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
+bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -1929,7 +1974,7 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
 	bool actuallyset = false;
 	unsigned long flag;
 
-	if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter))
+	if (rtlpci->being_init_adapter)
 		return false;
 
 	if (ppsc->swrf_processing)
@@ -1946,12 +1991,6 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
 
 	cur_rfstate = ppsc->rfpwr_state;
 
-	if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
-	    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) {
-		rtlpriv->intf_ops->disable_aspm(hw);
-		RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
-	}
-
 	rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv,
 		       REG_MAC_PINMUX_CFG)&~(BIT(3)));
 
@@ -1976,38 +2015,13 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
 	}
 
 	if (actuallyset) {
-		if (e_rfpowerstate_toset == ERFON) {
-			if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
-			    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) {
-				rtlpriv->intf_ops->disable_aspm(hw);
-				RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
-			}
-		}
-
 		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
 		ppsc->rfchange_inprogress = false;
 		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
-
-		if (e_rfpowerstate_toset == ERFOFF) {
-			if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
-				rtlpriv->intf_ops->enable_aspm(hw);
-				RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
-			}
-		}
-
-	} else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) {
+	} else {
 		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
 			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
 
-		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
-			rtlpriv->intf_ops->enable_aspm(hw);
-			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
-		}
-
-		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
-		ppsc->rfchange_inprogress = false;
-		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
-	} else {
 		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
 		ppsc->rfchange_inprogress = false;
 		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
@@ -2086,15 +2100,31 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
 				macaddr = cam_const_broad;
 				entry_id = key_index;
 			} else {
+				if (mac->opmode == NL80211_IFTYPE_AP) {
+					entry_id = rtl_cam_get_free_entry(hw,
+								 p_macaddr);
+					if (entry_id >=  TOTAL_CAM_ENTRY) {
+						RT_TRACE(rtlpriv, COMP_SEC,
+						     DBG_EMERG,
+						     ("Can not find free hw"
+						     " security cam entry\n"));
+						return;
+					}
+				} else {
+					entry_id = CAM_PAIRWISE_KEY_POSITION;
+				}
+
 				key_index = PAIRWISE_KEYIDX;
-				entry_id = CAM_PAIRWISE_KEY_POSITION;
 				is_pairwise = true;
 			}
 		}
 
 		if (rtlpriv->sec.key_len[key_index] == 0) {
 			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 ("delete one entry\n"));
+				 ("delete one entry, entry_id is %d\n",
+				 entry_id));
+			if (mac->opmode == NL80211_IFTYPE_AP)
+				rtl_cam_del_entry(hw, p_macaddr);
 			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
 		} else {
 			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
@@ -2146,3 +2176,132 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
 		}
 	}
 }
+
+static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw)
+{
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+	rtlpcipriv->bt_coexist.bt_coexistence =
+			rtlpcipriv->bt_coexist.eeprom_bt_coexist;
+	rtlpcipriv->bt_coexist.bt_ant_num =
+			rtlpcipriv->bt_coexist.eeprom_bt_ant_num;
+	rtlpcipriv->bt_coexist.bt_coexist_type =
+			rtlpcipriv->bt_coexist.eeprom_bt_type;
+
+	if (rtlpcipriv->bt_coexist.reg_bt_iso == 2)
+		rtlpcipriv->bt_coexist.bt_ant_isolation =
+			rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation;
+	else
+		rtlpcipriv->bt_coexist.bt_ant_isolation =
+			rtlpcipriv->bt_coexist.reg_bt_iso;
+
+	rtlpcipriv->bt_coexist.bt_radio_shared_type =
+			rtlpcipriv->bt_coexist.eeprom_bt_radio_shared;
+
+	if (rtlpcipriv->bt_coexist.bt_coexistence) {
+
+		if (rtlpcipriv->bt_coexist.reg_bt_sco == 1)
+			rtlpcipriv->bt_coexist.bt_service = BT_OTHER_ACTION;
+		else if (rtlpcipriv->bt_coexist.reg_bt_sco == 2)
+			rtlpcipriv->bt_coexist.bt_service = BT_SCO;
+		else if (rtlpcipriv->bt_coexist.reg_bt_sco == 4)
+			rtlpcipriv->bt_coexist.bt_service = BT_BUSY;
+		else if (rtlpcipriv->bt_coexist.reg_bt_sco == 5)
+			rtlpcipriv->bt_coexist.bt_service = BT_OTHERBUSY;
+		else
+			rtlpcipriv->bt_coexist.bt_service = BT_IDLE;
+
+		rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+		rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+		rtlpcipriv->bt_coexist.bt_rssi_state = 0xff;
+	}
+}
+
+void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+					      bool auto_load_fail, u8 *hwinfo)
+{
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+	u8 value;
+
+	if (!auto_load_fail) {
+		rtlpcipriv->bt_coexist.eeprom_bt_coexist =
+					((hwinfo[RF_OPTION1] & 0xe0) >> 5);
+		value = hwinfo[RF_OPTION4];
+		rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1);
+		rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1);
+		rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation =
+							 ((value & 0x10) >> 4);
+		rtlpcipriv->bt_coexist.eeprom_bt_radio_shared =
+							 ((value & 0x20) >> 5);
+	} else {
+		rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0;
+		rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE;
+		rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2;
+		rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0;
+		rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;
+	}
+
+	rtl8192ce_bt_var_init(hw);
+}
+
+void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw)
+{
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+	/* 0:Low, 1:High, 2:From Efuse. */
+	rtlpcipriv->bt_coexist.reg_bt_iso = 2;
+	/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+	rtlpcipriv->bt_coexist.reg_bt_sco = 3;
+	/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+	rtlpcipriv->bt_coexist.reg_bt_sco = 0;
+}
+
+
+void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+	u8 u1_tmp;
+
+	if (rtlpcipriv->bt_coexist.bt_coexistence &&
+	    ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) ||
+	      rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8)) {
+
+		if (rtlpcipriv->bt_coexist.bt_ant_isolation)
+			rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+
+		u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) &
+			 BIT_OFFSET_LEN_MASK_32(0, 1);
+		u1_tmp = u1_tmp |
+			 ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+			 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+			 ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ?
+			 0 : BIT_OFFSET_LEN_MASK_32(2, 1));
+		rtl_write_byte(rtlpriv, 0x4fd, u1_tmp);
+
+		rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa);
+		rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040);
+		rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010);
+
+		/* Config to 1T1R. */
+		if (rtlphy->rf_type == RF_1T1R) {
+			u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE);
+			u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+			rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp);
+
+			u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE);
+			u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+			rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp);
+		}
+	}
+}
+
+void rtl92ce_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl92ce_resume(struct ieee80211_hw *hw)
+{
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
index a3dfdb6351688c4fb3a4075e33fc96d040e36ecc..07dbe3e340a5579c4af1c55ca805eb69dc649372 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
@@ -30,7 +30,18 @@
 #ifndef __RTL92CE_HW_H__
 #define __RTL92CE_HW_H__
 
-#define H2C_RA_MASK	6
+static inline u8 _rtl92c_get_chnl_group(u8 chnl)
+{
+	u8 group;
+
+	if (chnl < 3)
+		group = 0;
+	else if (chnl < 9)
+		group = 1;
+	else
+		group = 2;
+	return group;
+}
 
 void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
 void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw);
@@ -41,28 +52,27 @@ void rtl92ce_card_disable(struct ieee80211_hw *hw);
 void rtl92ce_enable_interrupt(struct ieee80211_hw *hw);
 void rtl92ce_disable_interrupt(struct ieee80211_hw *hw);
 int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type);
+void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
 void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci);
 void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw);
 void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw);
 void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
 				   u32 add_msr, u32 rm_msr);
 void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw);
-void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
+void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				 struct ieee80211_sta *sta, u8 rssi_level);
 void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw);
 bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
 void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw);
 void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
 		     u8 *p_macaddr, bool is_group, u8 enc_algo,
 		     bool is_wepkey, bool clear_all);
-bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
-void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
-void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
-int rtl92c_download_fw(struct ieee80211_hw *hw);
-void rtl92c_firmware_selfreset(struct ieee80211_hw *hw);
-void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
-			 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer);
-bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw);
+
+void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+			bool autoload_fail, u8 *hwinfo);
+void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw);
+void rtl92ce_suspend(struct ieee80211_hw *hw);
+void rtl92ce_resume(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
index d21b934b5c3373a68ca97086b973b53e1cd5718e..9dd1ed7b64223301c1875491ed109250e1543abf 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
@@ -106,12 +106,11 @@ void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
 void rtl92ce_init_sw_leds(struct ieee80211_hw *hw)
 {
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
-
 	_rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
 	_rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
 }
 
-void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
+static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
 				    enum led_ctl_mode ledaction)
 {
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
@@ -146,7 +145,7 @@ void rtl92ce_led_control(struct ieee80211_hw *hw,
 	     ledaction == LED_CTL_POWER_ON)) {
 		return;
 	}
-	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n",
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d.\n",
 				ledaction));
 	_rtl92ce_sw_led_control(hw, ledaction);
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
index 94332b3af5b1e21cb951226a620432a833d01966..7dfccea2095b016705f60174c4f3ee7ad91ab49e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
@@ -34,7 +34,5 @@ void rtl92ce_init_sw_leds(struct ieee80211_hw *hw);
 void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
 void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
 void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
-void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
-				    enum led_ctl_mode ledaction);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
index d0541e8c6012eb80bf0ca046f9413610c2d105c3..73ae8a431848693818e55fcd76cceb6717031284 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
@@ -38,7 +38,9 @@
 #include "dm.h"
 #include "table.h"
 
-u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw,
+static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+
+u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
 			    enum radio_path rfpath, u32 regaddr, u32 bitmask)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -73,9 +75,47 @@ u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw,
 	return readback_value;
 }
 
+bool rtl92c_phy_mac_config(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool is92c = IS_92C_SERIAL(rtlhal->version);
+	bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw);
+
+	if (is92c)
+		rtl_write_byte(rtlpriv, 0x14, 0x71);
+	return rtstatus;
+}
+
+bool rtl92c_phy_bb_config(struct ieee80211_hw *hw)
+{
+	bool rtstatus = true;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u16 regval;
+	u32 regvaldw;
+	u8 reg_hwparafile = 1;
+
+	_rtl92c_phy_init_bb_rf_register_definition(hw);
+	regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+	rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+		       regval | BIT(13) | BIT(0) | BIT(1));
+	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83);
+	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb);
+	rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+		       FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+		       FEN_BB_GLB_RSTn | FEN_BBRSTB);
+	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
+	regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0);
+	rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23));
+	if (reg_hwparafile == 1)
+		rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
+	return rtstatus;
+}
+
 void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
-			   enum radio_path rfpath,
-			   u32 regaddr, u32 bitmask, u32 data)
+			    enum radio_path rfpath,
+			    u32 regaddr, u32 bitmask, u32 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -121,45 +161,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
 					       bitmask, data, rfpath));
 }
 
-bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	bool is92c = IS_92C_SERIAL(rtlhal->version);
-	bool rtstatus = _rtl92ce_phy_config_mac_with_headerfile(hw);
-
-	if (is92c)
-		rtl_write_byte(rtlpriv, 0x14, 0x71);
-	return rtstatus;
-}
-
-bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw)
-{
-	bool rtstatus = true;
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u16 regval;
-	u32 regvaldw;
-	u8 reg_hwparafile = 1;
-
-	_rtl92c_phy_init_bb_rf_register_definition(hw);
-	regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
-	rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
-		       regval | BIT(13) | BIT(0) | BIT(1));
-	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83);
-	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb);
-	rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
-	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
-		       FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
-		       FEN_BB_GLB_RSTn | FEN_BBRSTB);
-	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
-	regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0);
-	rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23));
-	if (reg_hwparafile == 1)
-		rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
-	return rtstatus;
-}
-
-bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 i;
@@ -177,7 +179,7 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
 }
 
 bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
-						  u8 configtype)
+					    u8 configtype)
 {
 	int i;
 	u32 *phy_regarray_table;
@@ -236,7 +238,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
 }
 
 bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
-						    u8 configtype)
+					      u8 configtype)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	int i;
@@ -274,7 +276,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
 	return true;
 }
 
-bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 					  enum radio_path rfpath)
 {
 
@@ -364,74 +366,6 @@ bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 	return true;
 }
 
-void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u8 reg_bw_opmode;
-	u8 reg_prsr_rsc;
-
-	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
-		 ("Switch to %s bandwidth\n",
-		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
-		  "20MHz" : "40MHz"))
-
-	    if (is_hal_stop(rtlhal))
-		return;
-
-	reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
-	reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
-
-	switch (rtlphy->current_chan_bw) {
-	case HT_CHANNEL_WIDTH_20:
-		reg_bw_opmode |= BW_OPMODE_20MHZ;
-		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
-		break;
-
-	case HT_CHANNEL_WIDTH_20_40:
-		reg_bw_opmode &= ~BW_OPMODE_20MHZ;
-		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
-
-		reg_prsr_rsc =
-		    (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
-		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
-		break;
-
-	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
-		break;
-	}
-
-	switch (rtlphy->current_chan_bw) {
-	case HT_CHANNEL_WIDTH_20:
-		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
-		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
-		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
-		break;
-	case HT_CHANNEL_WIDTH_20_40:
-		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
-		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
-		rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
-			      (mac->cur_40_prime_sc >> 1));
-		rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
-		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);
-		rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
-			      (mac->cur_40_prime_sc ==
-			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
-		break;
-	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
-		break;
-	}
-	rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
-	rtlphy->set_bwmode_inprogress = false;
-	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
-}
-
 void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 {
 	u8 tmpreg;
@@ -477,6 +411,36 @@ void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 	}
 }
 
+static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+	u32 u4b_tmp;
+	u8 delay = 5;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+	rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+	u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+	while (u4b_tmp != 0 && delay > 0) {
+		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0);
+		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+		u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+		delay--;
+	}
+	if (delay == 0) {
+		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);
+		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+			 ("Switch RF timeout !!!.\n"));
+		return;
+	}
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
 static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
 					    enum rf_pwrstate rfpwr_state)
 {
@@ -523,33 +487,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
 			break;
 		}
 	case ERFOFF:{
-			for (queue_id = 0, i = 0;
-			     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
-				ring = &pcipriv->dev.tx_ring[queue_id];
-				if (skb_queue_len(&ring->queue) == 0 ||
-				    queue_id == BEACON_QUEUE) {
-					queue_id++;
-					continue;
-				} else {
-					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-						 ("eRf Off/Sleep: %d times "
-						  "TcbBusyQueue[%d] "
-						  "=%d before doze!\n", (i + 1),
-						  queue_id,
-						  skb_queue_len(&ring->queue)));
-					udelay(10);
-					i++;
-				}
-				if (i >= MAX_DOZE_WAITING_TIMES_9x) {
-					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-						 ("\nERFOFF: %d times "
-						  "TcbBusyQueue[%d] = %d !\n",
-						  MAX_DOZE_WAITING_TIMES_9x,
-						  queue_id,
-						  skb_queue_len(&ring->queue)));
-					break;
-				}
-			}
 			if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
 				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 					 ("IPS Set eRf nic disable\n"));
@@ -581,6 +518,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
 						  "TcbBusyQueue[%d] =%d before "
 						  "doze!\n", (i + 1), queue_id,
 						  skb_queue_len(&ring->queue)));
+
 					udelay(10);
 					i++;
 				}
@@ -599,7 +537,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
 				  jiffies_to_msecs(jiffies -
 						   ppsc->last_awake_jiffies)));
 			ppsc->last_sleep_jiffies = jiffies;
-			_rtl92c_phy_set_rf_sleep(hw);
+			_rtl92ce_phy_set_rf_sleep(hw);
 			break;
 		}
 	default:
@@ -614,10 +552,11 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
 	return bresult;
 }
 
-bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
+bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
 				   enum rf_pwrstate rfpwr_state)
 {
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
 	bool bresult = false;
 
 	if (rfpwr_state == ppsc->rfpwr_state)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
index a37267e3fc22b2e825652e2e2991daf9d01235c9..ad580852cc76284f28c64d7fbea52c344deaf9fe 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
@@ -39,6 +39,7 @@
 #define RT_CANNOT_IO(hw)		false
 #define HIGHPOWER_RADIOA_ARRAYLEN	22
 
+#define IQK_ADDA_REG_NUM		16
 #define MAX_TOLERANCE			5
 #define	IQK_DELAY_TIME			1
 
@@ -56,6 +57,8 @@
 #define IQK_ADDA_REG_NUM		16
 #define IQK_MAC_REG_NUM			4
 
+#define IQK_DELAY_TIME			1
+
 #define RF90_PATH_MAX			2
 
 #define CT_OFFSET_MAC_ADDR		0X16
@@ -76,7 +79,7 @@
 #define CT_OFFSET_CUSTOMER_ID		0x7F
 
 #define RTL92C_MAX_PATH_NUM		2
-#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER	255
+
 enum swchnlcmd_id {
 	CMDID_END,
 	CMDID_SET_TXPOWEROWER_LEVEL,
@@ -184,43 +187,44 @@ struct tx_power_struct {
 	u32 mcs_original_offset[4][16];
 };
 
-extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
+bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
+u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
 				   u32 regaddr, u32 bitmask);
-extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
 				  u32 regaddr, u32 bitmask, u32 data);
-extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
+u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
 				   enum radio_path rfpath, u32 regaddr,
 				   u32 bitmask);
 extern void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
-				  enum radio_path rfpath, u32 regaddr,
-				  u32 bitmask, u32 data);
-extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
+				   enum radio_path rfpath, u32 regaddr,
+				   u32 bitmask, u32 data);
+bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
 bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
+bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
 						 enum radio_path rfpath);
-extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
-extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
+void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
 					 long *powerlevel);
-extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
-extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
+void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
 					  long power_indbm);
-extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
+void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
 					     u8 operation);
-extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
-extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
 				   enum nl80211_channel_type ch_type);
-extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
-extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
-extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
-extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
 					 u16 beaconinterval);
 void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
 void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
+void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
 void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
 bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 					  enum radio_path rfpath);
-extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
+bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
 					      u32 rfpath);
 bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
 bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
@@ -237,9 +241,6 @@ u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask);
 void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
 					enum radio_path rfpath, u32 offset,
 					u32 data);
-void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
-						   u32 regaddr, u32 bitmask,
-						   u32 data);
 void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
 					   enum radio_path rfpath, u32 offset,
 					   u32 data);
@@ -250,5 +251,11 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
 void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
 bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
 void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw);
+bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				   enum rf_pwrstate rfpwr_state);
+bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+					    u8 configtype);
+bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+					      u8 configtype);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
index b0868a613841f0f05e6cc316b3eea39b43f1bea8..598cecc63f41a554c362e218b2ab92e1e358bc64 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
@@ -72,6 +72,7 @@
 #define REG_GPIO_IO_SEL_2			0x0062
 /* RTL8723 WIFI/BT/GPS Multi-Function control source. */
 #define REG_MULTI_FUNC_CTRL			0x0068
+
 #define REG_MCUFWDL				0x0080
 
 #define REG_HMEBOX_EXT_0			0x0088
@@ -542,7 +543,7 @@
 #define	IMR_OCPINT				BIT(1)
 #define	IMR_WLANOFF				BIT(0)
 
-#define	HWSET_MAX_SIZE				128
+#define EFUSE_REAL_CONTENT_LEN			512
 
 #define	EEPROM_DEFAULT_TSSI			0x0
 #define EEPROM_DEFAULT_TXPOWERDIFF		0x0
@@ -656,6 +657,7 @@
 #define	STOPBE					BIT(1)
 #define	STOPBK					BIT(0)
 
+#define	RCR_APPFCS				BIT(31)
 #define	RCR_APP_FCS				BIT(31)
 #define	RCR_APP_MIC				BIT(30)
 #define	RCR_APP_ICV				BIT(29)
@@ -688,6 +690,7 @@
 
 #define REG_USB_INFO				0xFE17
 #define REG_USB_SPECIAL_OPTION			0xFE55
+
 #define REG_USB_DMA_AGG_TO			0xFE5B
 #define REG_USB_AGG_TO				0xFE5C
 #define REG_USB_AGG_TH				0xFE5D
@@ -775,7 +778,6 @@
 
 #define	BOOT_FROM_EEPROM			BIT(4)
 #define	EEPROM_EN				BIT(5)
-#define	EEPROMSEL				BOOT_FROM_EEPROM
 
 #define AFE_BGEN				BIT(0)
 #define AFE_MBEN				BIT(1)
@@ -901,28 +903,7 @@
 #define BD_PKG_SEL				BIT(25)
 #define BD_HCI_SEL				BIT(26)
 #define TYPE_ID					BIT(27)
-
-/* REG_GPIO_OUTSTS (For RTL8723 only) */
-#define	EFS_HCI_SEL				(BIT(0)|BIT(1))
-#define	PAD_HCI_SEL				(BIT(2)|BIT(3))
-#define	HCI_SEL					(BIT(4)|BIT(5))
-#define	PKG_SEL_HCI				BIT(6)
-#define	FEN_GPS					BIT(7)
-#define	FEN_BT					BIT(8)
-#define	FEN_WL					BIT(9)
-#define	FEN_PCI					BIT(10)
-#define	FEN_USB					BIT(11)
-#define	BTRF_HWPDN_N				BIT(12)
-#define	WLRF_HWPDN_N				BIT(13)
-#define	PDN_BT_N				BIT(14)
-#define	PDN_GPS_N				BIT(15)
-#define	BT_CTL_HWPDN				BIT(16)
-#define	GPS_CTL_HWPDN				BIT(17)
-#define	PPHY_SUSB				BIT(20)
-#define	UPHY_SUSB				BIT(21)
-#define	PCI_SUSEN				BIT(22)
-#define	USB_SUSEN				BIT(23)
-#define	RF_RL_ID			(BIT(31) | BIT(30) | BIT(29) | BIT(28))
+#define	RF_RL_ID		(BIT(31) | BIT(30) | BIT(29) | BIT(28))
 
 #define CHIP_VER_RTL_MASK			0xF000
 #define CHIP_VER_RTL_SHIFT			12
@@ -1077,6 +1058,7 @@
 #define _RARF_RC8(x)				(((x) & 0x1F) << 24)
 
 #define AC_PARAM_TXOP_OFFSET			16
+#define AC_PARAM_TXOP_LIMIT_OFFSET		16
 #define AC_PARAM_ECW_MAX_OFFSET			12
 #define AC_PARAM_ECW_MIN_OFFSET			8
 #define AC_PARAM_AIFS_OFFSET			0
@@ -1221,33 +1203,11 @@
 #define EPROM_CMD_CONFIG			0x3
 #define EPROM_CMD_LOAD				1
 
-#define	HWSET_MAX_SIZE_92S		HWSET_MAX_SIZE
+#define	HWSET_MAX_SIZE_92S			HWSET_MAX_SIZE
 
-#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2)
-
-/* REG_MULTI_FUNC_CTRL(For RTL8723 Only) */
-/* Enable GPIO[9] as WiFi HW PDn source */
 #define	WL_HWPDN_EN				BIT(0)
-/* WiFi HW PDn polarity control */
-#define	WL_HWPDN_SL				BIT(1)
-/* WiFi function enable */
-#define	WL_FUNC_EN				BIT(2)
-/* Enable GPIO[9] as WiFi RF HW PDn source */
-#define	WL_HWROF_EN				BIT(3)
-/* Enable GPIO[11] as BT HW PDn source */
-#define	BT_HWPDN_EN				BIT(16)
-/* BT HW PDn polarity control */
-#define	BT_HWPDN_SL				BIT(17)
-/* BT function enable */
-#define	BT_FUNC_EN				BIT(18)
-/* Enable GPIO[11] as BT/GPS RF HW PDn source */
-#define	BT_HWROF_EN				BIT(19)
-/* Enable GPIO[10] as GPS HW PDn source */
-#define	GPS_HWPDN_EN				BIT(20)
-/* GPS HW PDn polarity control */
-#define	GPS_HWPDN_SL				BIT(21)
-/* GPS function enable */
-#define	GPS_FUNC_EN				BIT(22)
+
+#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2)
 
 #define	RPMAC_RESET				0x100
 #define	RPMAC_TXSTART				0x104
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
index e301b12e281afa5505709f8e5f97a13deac8f8ec..90d0f2cf3b2746873e3af8e4539b3bf55e66be21 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
@@ -34,9 +34,9 @@
 #include "rf.h"
 #include "dm.h"
 
-static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
 
-void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -62,7 +62,7 @@ void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 }
 
 void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
-				       u8 *ppowerlevel)
+					u8 *ppowerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -128,8 +128,7 @@ void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
 
 	tmpval = tx_agc[RF90_PATH_A] >> 8;
 
-	if (mac->mode == WIRELESS_MODE_B)
-		tmpval = tmpval & 0xff00ffff;
+	tmpval = tmpval & 0xff00ffff;
 
 	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
 
@@ -440,16 +439,17 @@ bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw)
 	else
 		rtlphy->num_total_rfpath = 2;
 
-	return _rtl92c_phy_rf6052_config_parafile(hw);
+	return _rtl92ce_phy_rf6052_config_parafile(hw);
+
 }
 
-static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	u32 u4_regvalue = 0;
 	u8 rfpath;
-	bool rtstatus;
+	bool rtstatus = true;
 	struct bb_reg_def *pphyreg;
 
 	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
@@ -484,12 +484,12 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
 
 		switch (rfpath) {
 		case RF90_PATH_A:
-			rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw,
-					(enum radio_path) rfpath);
+			rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,
+						(enum radio_path)rfpath);
 			break;
 		case RF90_PATH_B:
-			rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw,
-					(enum radio_path) rfpath);
+			rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,
+						(enum radio_path)rfpath);
 			break;
 		case RF90_PATH_C:
 			break;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
index 3aa520c1c171de26bd2a096c5be9a816714fd4bc..39ff03685986a130b3304150bb0ab56a3ab42015 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
@@ -34,14 +34,11 @@
 #define RF6052_MAX_REG			0x3F
 #define RF6052_MAX_PATH			2
 
-extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
-					    u8 bandwidth);
-extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
-					      u8 *ppowerlevel);
-extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
-					       u8 *ppowerlevel, u8 channel);
-bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw);
-bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
-					  enum radio_path rfpath);
-
+extern void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+					     u8 bandwidth);
+extern void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+					       u8 *ppowerlevel);
+extern void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+						u8 *ppowerlevel, u8 channel);
+extern bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw);
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index f4e2f3dcccaeb0efc1d245edea2a856bafe9a2c6..390bbb5ee11d425a4da2672e4b0895288c9e2076 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -42,10 +42,58 @@
 #include "trx.h"
 #include "led.h"
 
+static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	/*close ASPM for AMD defaultly */
+	rtlpci->const_amdpci_aspm = 0;
+
+	/*
+	 * ASPM PS mode.
+	 * 0 - Disable ASPM,
+	 * 1 - Enable ASPM without Clock Req,
+	 * 2 - Enable ASPM with Clock Req,
+	 * 3 - Alwyas Enable ASPM with Clock Req,
+	 * 4 - Always Enable ASPM without Clock Req.
+	 * set defult to RTL8192CE:3 RTL8192E:2
+	 * */
+	rtlpci->const_pci_aspm = 3;
+
+	/*Setting for PCI-E device */
+	rtlpci->const_devicepci_aspm_setting = 0x03;
+
+	/*Setting for PCI-E bridge */
+	rtlpci->const_hostpci_aspm_setting = 0x02;
+
+	/*
+	 * In Hw/Sw Radio Off situation.
+	 * 0 - Default,
+	 * 1 - From ASPM setting without low Mac Pwr,
+	 * 2 - From ASPM setting with low Mac Pwr,
+	 * 3 - Bus D3
+	 * set default to RTL8192CE:0 RTL8192SE:2
+	 */
+	rtlpci->const_hwsw_rfoff_d3 = 0;
+
+	/*
+	 * This setting works for those device with
+	 * backdoor ASPM setting such as EPHY setting.
+	 * 0 - Not support ASPM,
+	 * 1 - Support ASPM,
+	 * 2 - According to chipset.
+	 */
+	rtlpci->const_support_pciaspm = 1;
+}
+
 int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
 {
+	int err;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	const struct firmware *firmware;
+
+	rtl8192ce_bt_reg_init(hw);
 
 	rtlpriv->dm.dm_initialgain_enable = 1;
 	rtlpriv->dm.dm_flag = 0;
@@ -53,7 +101,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
 	rtlpriv->dm.thermalvalue = 0;
 	rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13);
 
-	rtlpci->receive_config = (RCR_APP_FCS |
+	/* compatible 5G band 88ce just 2.4G band & smsp */
+	rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+	rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+	rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+	rtlpci->receive_config = (RCR_APPFCS |
 				  RCR_AMF |
 				  RCR_ADF |
 				  RCR_APP_MIC |
@@ -76,13 +129,49 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
 
 	rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0);
 
-	rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000);
+	/* for LPS & IPS */
+	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpriv->psc.reg_fwctrl_lps = 3;
+	rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+	/* for ASPM, you can close aspm through
+	 * set const_support_pciaspm = 0 */
+	rtl92c_init_aspm_vars(hw);
+
+	if (rtlpriv->psc.reg_fwctrl_lps == 1)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+	else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+	else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+	/* for firmware buf */
+	rtlpriv->rtlhal.pfirmware = vzalloc(0x4000);
 	if (!rtlpriv->rtlhal.pfirmware) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 ("Can't alloc buffer for fw.\n"));
 		return 1;
 	}
 
+	/* request fw */
+	err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
+			rtlpriv->io.dev);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 ("Failed to request firmware!\n"));
+		return 1;
+	}
+	if (firmware->size > 0x4000) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 ("Firmware is too big!\n"));
+		release_firmware(firmware);
+		return 1;
+	}
+	memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
+	rtlpriv->rtlhal.fwsize = firmware->size;
+	release_firmware(firmware);
+
 	return 0;
 }
 
@@ -103,17 +192,19 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
 	.interrupt_recognized = rtl92ce_interrupt_recognized,
 	.hw_init = rtl92ce_hw_init,
 	.hw_disable = rtl92ce_card_disable,
+	.hw_suspend = rtl92ce_suspend,
+	.hw_resume = rtl92ce_resume,
 	.enable_interrupt = rtl92ce_enable_interrupt,
 	.disable_interrupt = rtl92ce_disable_interrupt,
 	.set_network_type = rtl92ce_set_network_type,
+	.set_chk_bssid = rtl92ce_set_check_bssid,
 	.set_qos = rtl92ce_set_qos,
 	.set_bcn_reg = rtl92ce_set_beacon_related_registers,
 	.set_bcn_intv = rtl92ce_set_beacon_interval,
 	.update_interrupt_mask = rtl92ce_update_interrupt_mask,
 	.get_hw_reg = rtl92ce_get_hw_reg,
 	.set_hw_reg = rtl92ce_set_hw_reg,
-	.update_rate_table = rtl92ce_update_hal_rate_table,
-	.update_rate_mask = rtl92ce_update_hal_rate_mask,
+	.update_rate_tbl = rtl92ce_update_hal_rate_tbl,
 	.fill_tx_desc = rtl92ce_tx_fill_desc,
 	.fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc,
 	.query_rx_desc = rtl92ce_rx_query_desc,
@@ -123,7 +214,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
 	.switch_channel = rtl92c_phy_sw_chnl,
 	.dm_watchdog = rtl92c_dm_watchdog,
 	.scan_operation_backup = rtl92c_phy_scan_operation_backup,
-	.set_rf_power_state = rtl92ce_phy_set_rf_power_state,
+	.set_rf_power_state = rtl92c_phy_set_rf_power_state,
 	.led_control = rtl92ce_led_control,
 	.set_desc = rtl92ce_set_desc,
 	.get_desc = rtl92ce_get_desc,
@@ -133,24 +224,27 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
 	.init_sw_leds = rtl92ce_init_sw_leds,
 	.get_bbreg = rtl92c_phy_query_bb_reg,
 	.set_bbreg = rtl92c_phy_set_bb_reg,
-	.get_rfreg = rtl92ce_phy_query_rf_reg,
 	.set_rfreg = rtl92ce_phy_set_rf_reg,
-	.cmd_send_packet = _rtl92c_cmd_send_packet,
+	.get_rfreg = rtl92c_phy_query_rf_reg,
 	.phy_rf6052_config = rtl92ce_phy_rf6052_config,
 	.phy_rf6052_set_cck_txpower = rtl92ce_phy_rf6052_set_cck_txpower,
 	.phy_rf6052_set_ofdm_txpower = rtl92ce_phy_rf6052_set_ofdm_txpower,
 	.config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile,
 	.config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile,
 	.phy_lc_calibrate = _rtl92ce_phy_lc_calibrate,
-	.phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback,
 	.dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower,
 };
 
 static struct rtl_mod_params rtl92ce_mod_params = {
-	.sw_crypto = 0,
+	.sw_crypto = false,
+	.inactiveps = true,
+	.swctrl_lps = false,
+	.fwctrl_lps = true,
 };
 
 static struct rtl_hal_cfg rtl92ce_hal_cfg = {
+	.bar_id = 2,
+	.write_readback = true,
 	.name = "rtl92c_pci",
 	.fw_name = "rtlwifi/rtl8192cfw.bin",
 	.ops = &rtl8192ce_hal_ops,
@@ -174,6 +268,8 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
 	.maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
 	.maps[EFUSE_ANA8M] = EFUSE_ANA8M,
 	.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+	.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+	.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
 
 	.maps[RWCAM] = REG_CAMCMD,
 	.maps[WCAMI] = REG_CAMWRITE,
@@ -238,7 +334,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
 	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
 };
 
-static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = {
+DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = {
 	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)},
 	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)},
 	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)},
@@ -256,7 +352,13 @@ MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless");
 MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin");
 
 module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444);
+module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444);
 MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
+MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
+MODULE_PARM_DESC(fwlps, "using linked fw control power save "
+		 "(default 1 is open)\n");
 
 static struct pci_driver rtl92ce_driver = {
 	.name = KBUILD_MODNAME,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
index 36e657668c1e720d974a07c71a0473b2812eaa2c..b7dc3263e433171d8bc7687cca8af063630d7a9e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
@@ -33,19 +33,9 @@
 int rtl92c_init_sw_vars(struct ieee80211_hw *hw);
 void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw);
 void rtl92c_init_var_map(struct ieee80211_hw *hw);
-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
-			     struct sk_buff *skb);
-void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
-					u8 *ppowerlevel);
-void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
-					 u8 *ppowerlevel, u8 channel);
 bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
-						  u8 configtype);
+					    u8 configtype);
 bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
-						    u8 configtype);
-void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
-u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw,
-			    enum radio_path rfpath, u32 regaddr, u32 bitmask);
-void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+					      u8 configtype);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index aa2b5815600fa8a5db87f37f9fa1eb180bdd1941..54b2bd53d36a5d21dea008ec5af17521aeef275f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -36,42 +36,16 @@
 #include "trx.h"
 #include "led.h"
 
-static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(__le16 fc,
-							  unsigned int
-							  skb_queue)
+static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
 {
-	enum rtl_desc_qsel qsel;
+	__le16 fc = rtl_get_fc(skb);
 
-	if (unlikely(ieee80211_is_beacon(fc))) {
-		qsel = QSLT_BEACON;
-		return qsel;
-	}
-
-	if (ieee80211_is_mgmt(fc)) {
-		qsel = QSLT_MGNT;
-		return qsel;
-	}
+	if (unlikely(ieee80211_is_beacon(fc)))
+		return QSLT_BEACON;
+	if (ieee80211_is_mgmt(fc))
+		return QSLT_MGNT;
 
-	switch (skb_queue) {
-	case VO_QUEUE:
-		qsel = QSLT_VO;
-		break;
-	case VI_QUEUE:
-		qsel = QSLT_VI;
-		break;
-	case BE_QUEUE:
-		qsel = QSLT_BE;
-		break;
-	case BK_QUEUE:
-		qsel = QSLT_BK;
-		break;
-	default:
-		qsel = QSLT_BE;
-		RT_ASSERT(false, ("BE queue, skb_queue:%d,"
-				  " set qsel = 0x%X\n", skb_queue, QSLT_BE));
-		break;
-	}
-	return qsel;
+	return skb->priority;
 }
 
 static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
@@ -255,6 +229,7 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
 	u8 evm, pwdb_all, rf_rx_num = 0;
 	u8 i, max_spatial_stream;
 	u32 rssi, total_rssi = 0;
+	bool in_powersavemode = false;
 	bool is_cck_rate;
 
 	is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
@@ -270,9 +245,13 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
 		u8 report, cck_highpwr;
 		cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
 
-		cck_highpwr = (u8) rtl_get_bbreg(hw,
-					 RFPGA0_XA_HSSIPARAMETER2,
-					 BIT(9));
+		if (!in_powersavemode)
+			cck_highpwr = (u8) rtl_get_bbreg(hw,
+						 RFPGA0_XA_HSSIPARAMETER2,
+						 BIT(9));
+		else
+			cck_highpwr = false;
+
 		if (!cck_highpwr) {
 			u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
 			report = cck_buf->cck_agc_rpt & 0xc0;
@@ -398,6 +377,7 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw,
 
 		if (rtlpriv->stats.ui_rssi.total_num++ >=
 		    PHY_RSSI_SLID_WIN_MAX) {
+
 			rtlpriv->stats.ui_rssi.total_num =
 			    PHY_RSSI_SLID_WIN_MAX;
 			last_rssi =
@@ -424,10 +404,6 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw,
 	if (!pstats->is_cck && pstats->packet_toself) {
 		for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
 		     rfpath++) {
-
-			if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath))
-				continue;
-
 			if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
 				rtlpriv->stats.rx_rssi_percentage[rfpath] =
 				    pstats->rx_mimo_signalstrength[rfpath];
@@ -723,7 +699,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
 void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx,
 			  struct ieee80211_tx_info *info, struct sk_buff *skb,
-			  unsigned int queue_index)
+			  u8 hw_queue, struct rtl_tcb_desc *tcb_desc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -732,16 +708,9 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 	bool defaultadapter = true;
 	struct ieee80211_sta *sta;
 	u8 *pdesc = (u8 *) pdesc_tx;
-	struct rtl_tcb_desc tcb_desc;
-	u8 *qc = ieee80211_get_qos_ctl(hdr);
-	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 	u16 seq_number;
 	__le16 fc = hdr->frame_control;
-	u8 rate_flag = info->control.rates[0].flags;
-
-	enum rtl_desc_qsel fw_qsel =
-	    _rtl92ce_map_hwqueue_to_fwqueue(fc, queue_index);
-
+	u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue);
 	bool firstseg = ((hdr->seq_ctrl &
 			  cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
 
@@ -751,56 +720,68 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 	dma_addr_t mapping = pci_map_single(rtlpci->pdev,
 					    skb->data, skb->len,
 					    PCI_DMA_TODEVICE);
+	u8 bw_40 = 0;
+
+	rcu_read_lock();
+	sta = get_sta(hw, mac->vif, mac->bssid);
+	if (mac->opmode == NL80211_IFTYPE_STATION) {
+		bw_40 = mac->bw_40;
+	} else if (mac->opmode == NL80211_IFTYPE_AP ||
+		mac->opmode == NL80211_IFTYPE_ADHOC) {
+		if (sta)
+			bw_40 = sta->ht_cap.cap &
+				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+	}
 
 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 
-	rtl_get_tcb_desc(hw, info, skb, &tcb_desc);
+	rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc);
 
 	CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c));
 
+	if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+		firstseg = true;
+		lastseg = true;
+	}
 	if (firstseg) {
 		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
 
-		SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate);
+		SET_TX_DESC_TX_RATE(pdesc, tcb_desc->hw_rate);
 
-		if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble)
+		if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble)
 			SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
 
-		if (mac->tids[tid].agg.agg_state == RTL_AGG_ON &&
-		    info->flags & IEEE80211_TX_CTL_AMPDU) {
+		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
 			SET_TX_DESC_AGG_BREAK(pdesc, 1);
 			SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
 		}
 		SET_TX_DESC_SEQ(pdesc, seq_number);
 
-		SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.rts_enable &&
-						!tcb_desc.
+		SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc->rts_enable &&
+						!tcb_desc->
 						cts_enable) ? 1 : 0));
 		SET_TX_DESC_HW_RTS_ENABLE(pdesc,
-					  ((tcb_desc.rts_enable
-					    || tcb_desc.cts_enable) ? 1 : 0));
-		SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.cts_enable) ? 1 : 0));
-		SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.rts_stbc) ? 1 : 0));
+					  ((tcb_desc->rts_enable
+					    || tcb_desc->cts_enable) ? 1 : 0));
+		SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc->cts_enable) ? 1 : 0));
+		SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc->rts_stbc) ? 1 : 0));
 
-		SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate);
+		SET_TX_DESC_RTS_RATE(pdesc, tcb_desc->rts_rate);
 		SET_TX_DESC_RTS_BW(pdesc, 0);
-		SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc);
+		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_use_shortpreamble ? 1 : 0)
-				      : (tcb_desc.rts_use_shortgi ? 1 : 0)));
+				      ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+				       (tcb_desc->rts_use_shortpreamble ? 1 : 0)
+				       : (tcb_desc->rts_use_shortgi ? 1 : 0)));
 
-		if (mac->bw_40) {
-			if (tcb_desc.packet_bw) {
+		if (bw_40) {
+			if (tcb_desc->packet_bw) {
 				SET_TX_DESC_DATA_BW(pdesc, 1);
 				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
 			} else {
 				SET_TX_DESC_DATA_BW(pdesc, 0);
-
-				if (rate_flag & IEEE80211_TX_RC_DUP_DATA) {
-					SET_TX_DESC_TX_SUB_CARRIER(pdesc,
-							mac->cur_40_prime_sc);
-				}
+				SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+						 mac->cur_40_prime_sc);
 			}
 		} else {
 			SET_TX_DESC_DATA_BW(pdesc, 0);
@@ -810,13 +791,10 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 		SET_TX_DESC_LINIP(pdesc, 0);
 		SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len);
 
-		rcu_read_lock();
-		sta = ieee80211_find_sta(mac->vif, mac->bssid);
 		if (sta) {
 			u8 ampdu_density = sta->ht_cap.ampdu_density;
 			SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
 		}
-		rcu_read_unlock();
 
 		if (info->control.hw_key) {
 			struct ieee80211_key_conf *keyconf =
@@ -844,7 +822,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
 		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
 		SET_TX_DESC_DISABLE_FB(pdesc, 0);
-		SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0);
+		SET_TX_DESC_USE_RATE(pdesc, tcb_desc->use_driver_rate ? 1 : 0);
 
 		if (ieee80211_is_data_qos(fc)) {
 			if (mac->rdg_en) {
@@ -855,24 +833,24 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 			}
 		}
 	}
+	rcu_read_unlock();
 
 	SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
 	SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
 
 	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len);
 
-	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
 
 	if (rtlpriv->dm.useramask) {
-		SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index);
-		SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id);
+		SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, tcb_desc->mac_id);
 	} else {
-		SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index);
-		SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index);
+		SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, tcb_desc->ratr_index);
 	}
 
-	if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps &&
-	    ppsc->fwctrl_lps) {
+	if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) {
 		SET_TX_DESC_HWSEQ_EN(pdesc, 1);
 		SET_TX_DESC_PKT_ID(pdesc, 8);
 
@@ -923,7 +901,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
 
 	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len));
 
-	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
 
 	SET_TX_DESC_RATE_ID(pdesc, 7);
 	SET_TX_DESC_MACID(pdesc, 0);
@@ -1021,7 +999,7 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name)
 	return ret;
 }
 
-void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue)
+void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	if (hw_queue == BEACON_QUEUE) {
@@ -1032,35 +1010,3 @@ void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue)
 	}
 }
 
-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
-			     struct sk_buff *skb)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	struct rtl8192_tx_ring *ring;
-	struct rtl_tx_desc *pdesc;
-	u8 own;
-	unsigned long flags;
-	struct sk_buff *pskb = NULL;
-
-	ring = &rtlpci->tx_ring[BEACON_QUEUE];
-
-	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
-	pskb = __skb_dequeue(&ring->queue);
-	if (pskb)
-		kfree_skb(pskb);
-
-	pdesc = &ring->desc[0];
-	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
-
-	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
-
-	__skb_queue_tail(&ring->queue, skb);
-
-	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
-	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
-
-	return true;
-}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
index b0b0b13dd0aebf1065acdba0c2d5784a28dcbb7c..0f117713750126acd76f00353ba2e44fba2691f5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -724,17 +724,16 @@ struct rx_desc_92c {
 void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
 			  struct ieee80211_hdr *hdr,
 			  u8 *pdesc, struct ieee80211_tx_info *info,
-			  struct sk_buff *skb, unsigned int qsel);
+			  struct sk_buff *skb, u8 hw_queue,
+			  struct rtl_tcb_desc *ptcb_desc);
 bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
 			   struct rtl_stats *stats,
 			   struct ieee80211_rx_status *rx_status,
 			   u8 *pdesc, struct sk_buff *skb);
 void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
 u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name);
-void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue);
+void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
 			     bool b_firstseg, bool b_lastseg,
 			     struct sk_buff *skb);
-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb);
-
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index e43be254782787e57b13fcabb9e77b13929baaf4..52e2af58c1ed983ad0a5547995e7d137657813ce 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -39,6 +39,7 @@
 #include "mac.h"
 #include "dm.h"
 #include "hw.h"
+#include "../rtl8192ce/hw.h"
 #include "trx.h"
 #include "led.h"
 #include "table.h"
@@ -605,10 +606,10 @@ void rtl92cu_read_eeprom_info(struct ieee80211_hw *hw)
 	if (!IS_NORMAL_CHIP(rtlhal->version))
 		return;
 	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
-	rtlefuse->epromtype = (tmp_u1b & EEPROMSEL) ?
+	rtlefuse->epromtype = (tmp_u1b & BOOT_FROM_EEPROM) ?
 			       EEPROM_93C46 : EEPROM_BOOT_EFUSE;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from %s\n",
-		 (tmp_u1b & EEPROMSEL) ? "EERROM" : "EFUSE"));
+		 (tmp_u1b & BOOT_FROM_EEPROM) ? "EERROM" : "EFUSE"));
 	rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload %s\n",
 		 (tmp_u1b & EEPROM_EN) ? "OK!!" : "ERR!!"));
@@ -977,7 +978,7 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
-	mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APP_FCS |
+	mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS |
 		      RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL |
 		      RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32);
 	rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf);
@@ -2182,7 +2183,9 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	}
 }
 
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw)
+void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
+				   struct ieee80211_sta *sta,
+				   u8 rssi_level)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
index 62af555bb61c91999731492bc16f913224bd6853..32f85cba106ae7f2491e84a5caebf208208a0c53 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
@@ -98,13 +98,14 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw,
 				   u32 add_msr, u32 rm_msr);
 void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
 void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw);
+void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
+				   struct ieee80211_sta *sta,
+				   u8 rssi_level);
 void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
 
 void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw);
 bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid);
 void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
-u8 _rtl92c_get_chnl_group(u8 chnl);
 int rtl92c_download_fw(struct ieee80211_hw *hw);
 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
index 4e020e654e6b95e82df9c3a968567801acb141c5..9a3d0239e27e6ae7aa8b1c8665bba3afcabc3279 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
@@ -38,7 +38,7 @@
 #include "table.h"
 
 u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
-			    enum radio_path rfpath, u32 regaddr, u32 bitmask)
+			     enum radio_path rfpath, u32 regaddr, u32 bitmask)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 original_value, readback_value, bitshift;
@@ -64,8 +64,8 @@ u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
 }
 
 void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
-			   enum radio_path rfpath,
-			   u32 regaddr, u32 bitmask, u32 data)
+			    enum radio_path rfpath,
+			    u32 regaddr, u32 bitmask, u32 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -163,7 +163,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
 }
 
 bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
-						  u8 configtype)
+					    u8 configtype)
 {
 	int i;
 	u32 *phy_regarray_table;
@@ -223,7 +223,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
 }
 
 bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
-						    u8 configtype)
+					      u8 configtype)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -459,7 +459,7 @@ void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 	}
 }
 
-bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
+static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
 					    enum rf_pwrstate rfpwr_state)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -595,7 +595,7 @@ bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
 }
 
 bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
-				   enum rf_pwrstate rfpwr_state)
+				    enum rf_pwrstate rfpwr_state)
 {
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	bool bresult = false;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h
index 06299559ab685e8369a8822093678d7a91f389b8..ff81a61729d7bb1a353c9d05556363e205a21bf4 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h
@@ -34,3 +34,17 @@ bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath);
 void rtl92c_phy_set_io(struct ieee80211_hw *hw);
 bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
 bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw);
+u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
+			     enum radio_path rfpath, u32 regaddr, u32 bitmask);
+void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
+			    enum radio_path rfpath,
+			    u32 regaddr, u32 bitmask, u32 data);
+bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw);
+bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+					      u8 configtype);
+void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
+bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+					    u8 configtype);
+void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				    enum rf_pwrstate rfpwr_state);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 1c79c226f14522aeacf63f6705712310e36b4caf..c7576ec4744ecb6155e1518fb75828c9292cb6b6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -62,7 +62,7 @@ void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 }
 
 void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
-				       u8 *ppowerlevel)
+					u8 *ppowerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -389,7 +389,7 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
 }
 
 void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
-					u8 *ppowerlevel, u8 channel)
+					 u8 *ppowerlevel, u8 channel)
 {
 	u32 writeVal[2], powerBase0[2], powerBase1[2];
 	u8 index = 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h
index 86c2728cfa00ecbc4562410a86e563b5609f67b7..500a2094b6bbe496078b6c73c2ca9164b26a3390 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h
@@ -43,5 +43,9 @@ extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
 bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw);
 bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 					  enum radio_path rfpath);
+void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+					u8 *ppowerlevel);
+void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+					 u8 *ppowerlevel, u8 channel);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 71244a38d49e73a74b86912a712a129b3a8dad5c..bee7c1480f63c6c43e4fa87efb82d77eb63503c1 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -94,7 +94,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
 	.update_interrupt_mask = rtl92cu_update_interrupt_mask,
 	.get_hw_reg = rtl92cu_get_hw_reg,
 	.set_hw_reg = rtl92cu_set_hw_reg,
-	.update_rate_table = rtl92cu_update_hal_rate_table,
+	.update_rate_tbl = rtl92cu_update_hal_rate_table,
 	.update_rate_mask = rtl92cu_update_hal_rate_mask,
 	.fill_tx_desc = rtl92cu_tx_fill_desc,
 	.fill_fake_txdesc = rtl92cu_fill_fake_txdesc,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 3f0cb81c424f0e4bf8206723e3b9a1807940f10d..79c98f62175fc514ba39ba4937039fbed0a5a829 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -498,14 +498,14 @@ static void _rtl_tx_desc_checksum(u8 *txdesc)
 void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx,
 			  struct ieee80211_tx_info *info, struct sk_buff *skb,
-			  unsigned int queue_index)
+			  u8 queue_index,
+			  struct rtl_tcb_desc *tcb_desc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	bool defaultadapter = true;
-	struct ieee80211_sta *sta;
-	struct rtl_tcb_desc tcb_desc;
+	struct ieee80211_sta *sta = info->control.sta = info->control.sta;
 	u8 *qc = ieee80211_get_qos_ctl(hdr);
 	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 	u16 seq_number;
@@ -517,15 +517,15 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
 	u8 *txdesc;
 
 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
-	rtl_get_tcb_desc(hw, info, skb, &tcb_desc);
+	rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc);
 	txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE);
 	memset(txdesc, 0, RTL_TX_HEADER_SIZE);
 	SET_TX_DESC_PKT_SIZE(txdesc, pktlen);
 	SET_TX_DESC_LINIP(txdesc, 0);
 	SET_TX_DESC_PKT_OFFSET(txdesc, RTL_DUMMY_OFFSET);
 	SET_TX_DESC_OFFSET(txdesc, RTL_TX_HEADER_SIZE);
-	SET_TX_DESC_TX_RATE(txdesc, tcb_desc.hw_rate);
-	if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble)
+	SET_TX_DESC_TX_RATE(txdesc, tcb_desc->hw_rate);
+	if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble)
 		SET_TX_DESC_DATA_SHORTGI(txdesc, 1);
 	if (mac->tids[tid].agg.agg_state == RTL_AGG_ON &&
 		    info->flags & IEEE80211_TX_CTL_AMPDU) {
@@ -535,21 +535,21 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
 		SET_TX_DESC_AGG_BREAK(txdesc, 1);
 	}
 	SET_TX_DESC_SEQ(txdesc, seq_number);
-	SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable &&
-			       !tcb_desc.cts_enable) ? 1 : 0));
-	SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable ||
-				  tcb_desc.cts_enable) ? 1 : 0));
-	SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc.cts_enable) ? 1 : 0));
-	SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc.rts_stbc) ? 1 : 0));
-	SET_TX_DESC_RTS_RATE(txdesc, tcb_desc.rts_rate);
+	SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable &&
+			       !tcb_desc->cts_enable) ? 1 : 0));
+	SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable ||
+				  tcb_desc->cts_enable) ? 1 : 0));
+	SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc->cts_enable) ? 1 : 0));
+	SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc->rts_stbc) ? 1 : 0));
+	SET_TX_DESC_RTS_RATE(txdesc, tcb_desc->rts_rate);
 	SET_TX_DESC_RTS_BW(txdesc, 0);
-	SET_TX_DESC_RTS_SC(txdesc, tcb_desc.rts_sc);
+	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_use_shortpreamble ? 1 : 0)
-			       : (tcb_desc.rts_use_shortgi ? 1 : 0)));
+			      ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+			       (tcb_desc->rts_use_shortpreamble ? 1 : 0)
+			       : (tcb_desc->rts_use_shortgi ? 1 : 0)));
 	if (mac->bw_40) {
-		if (tcb_desc.packet_bw) {
+		if (tcb_desc->packet_bw) {
 			SET_TX_DESC_DATA_BW(txdesc, 1);
 			SET_TX_DESC_DATA_SC(txdesc, 3);
 		} else {
@@ -590,7 +590,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
 	SET_TX_DESC_DATA_RATE_FB_LIMIT(txdesc, 0x1F);
 	SET_TX_DESC_RTS_RATE_FB_LIMIT(txdesc, 0xF);
 	SET_TX_DESC_DISABLE_FB(txdesc, 0);
-	SET_TX_DESC_USE_RATE(txdesc, tcb_desc.use_driver_rate ? 1 : 0);
+	SET_TX_DESC_USE_RATE(txdesc, tcb_desc->use_driver_rate ? 1 : 0);
 	if (ieee80211_is_data_qos(fc)) {
 		if (mac->rdg_en) {
 			RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
@@ -600,11 +600,11 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
 		}
 	}
 	if (rtlpriv->dm.useramask) {
-		SET_TX_DESC_RATE_ID(txdesc, tcb_desc.ratr_index);
-		SET_TX_DESC_MACID(txdesc, tcb_desc.mac_id);
+		SET_TX_DESC_RATE_ID(txdesc, tcb_desc->ratr_index);
+		SET_TX_DESC_MACID(txdesc, tcb_desc->mac_id);
 	} else {
-		SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc.ratr_index);
-		SET_TX_DESC_MACID(txdesc, tcb_desc.ratr_index);
+		SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc->ratr_index);
+		SET_TX_DESC_MACID(txdesc, tcb_desc->ratr_index);
 	}
 	if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps &&
 	      ppsc->fwctrl_lps) {
@@ -656,7 +656,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw,
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
 	__le16 fc = hdr->frame_control;
 
-	memset(pdesc, 0, RTL_TX_HEADER_SIZE);
+	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);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
index b396d46edbb7a615d5f95762c2f065bc46e6f6d3..53de5f66e2424803a6d9424fb4d301439a8d7155 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
@@ -37,6 +37,8 @@
 #define RTL92C_SIZE_MAX_RX_BUFFER		15360   /* 8192 */
 #define RX_DRV_INFO_SIZE_UNIT			8
 
+#define RTL_AGG_ON				1
+
 enum usb_rx_agg_mode {
 	USB_RX_AGG_DISABLE,
 	USB_RX_AGG_DMA,
@@ -419,7 +421,8 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *,
 void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx,
 			  struct ieee80211_tx_info *info, struct sk_buff *skb,
-			  unsigned int queue_index);
+			  u8 queue_index,
+			  struct rtl_tcb_desc *tcb_desc);
 void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc,
 			      u32 buffer_len, bool bIsPsPoll);
 void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index f5d85735d6420d350b1e3376b506bbdad5b95a75..a9367eba1ea7502d60787c6850859305779ac0be 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -852,6 +852,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct rtl_tx_desc *pdesc = NULL;
+	struct rtl_tcb_desc tcb_desc;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
 	__le16 fc = hdr->frame_control;
 	u8 *pda_addr = hdr->addr1;
@@ -860,8 +861,17 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
 	u8 tid = 0;
 	u16 seq_number = 0;
 
-	if (ieee80211_is_mgmt(fc))
-		rtl_tx_mgmt_proc(hw, skb);
+	if (ieee80211_is_auth(fc)) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+		rtl_ips_nic_on(hw);
+	}
+
+	if (rtlpriv->psc.sw_ps_enabled) {
+		if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
+		    !ieee80211_has_pm(fc))
+			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+	}
+
 	rtl_action_proc(hw, skb, true);
 	if (is_multicast_ether_addr(pda_addr))
 		rtlpriv->stats.txbytesmulticast += skb->len;
@@ -878,7 +888,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
 		seq_number <<= 4;
 	}
 	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb,
-					hw_queue);
+					hw_queue, &tcb_desc);
 	if (!ieee80211_has_morefrags(hdr->frame_control)) {
 		if (qc)
 			mac->tids[tid].seq_number = seq_number;
@@ -887,7 +897,8 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
 		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
 }
 
-static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		      struct rtl_tcb_desc *dummy)
 {
 	struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h
index abadfe918d30f2a30ec592d159785ac76222f302..d2a63fb3e1e60ca61598dfdf73aea13b4da3f002 100644
--- a/drivers/net/wireless/rtlwifi/usb.h
+++ b/drivers/net/wireless/rtlwifi/usb.h
@@ -31,6 +31,8 @@
 #include <linux/usb.h>
 #include <linux/skbuff.h>
 
+#define RTL_RX_DESC_SIZE		24
+
 #define RTL_USB_DEVICE(vend, prod, cfg) \
 	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
 	.idVendor = (vend), \
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 2713efe07ce525c628131d8b91615fe1ed0586d2..693395ee98f9d75c1687afb8594c7716878d7907 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -68,6 +68,8 @@
 #define QBSS_LOAD_SIZE				5
 #define MAX_WMMELE_LENGTH			64
 
+#define TOTAL_CAM_ENTRY				32
+
 /*slot time for 11g. */
 #define RTL_SLOT_TIME_9				9
 #define RTL_SLOT_TIME_20			20
@@ -94,8 +96,10 @@
 #define	CHANNEL_GROUP_MAX_5G		9
 #define CHANNEL_MAX_NUMBER_2G		14
 #define AVG_THERMAL_NUM			8
+#define MAX_TID_COUNT			9
 
 /* for early mode */
+#define FCS_LEN				4
 #define EM_HDR_LEN			8
 enum intf_type {
 	INTF_PCI = 0,
@@ -159,6 +163,8 @@ enum hardware_type {
 (IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal))
 #define	IS_HARDWARE_TYPE_8723(rtlhal)			\
 (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal))
+#define IS_HARDWARE_TYPE_8723U(rtlhal)			\
+	(rtlhal->hw_type == HARDWARE_TYPE_RTL8723U)
 
 enum scan_operation_backup_opt {
 	SCAN_OPT_BACKUP = 0,
@@ -297,6 +303,9 @@ enum hw_variables {
 	HW_VAR_DATA_FILTER,
 };
 
+#define HWSET_MAX_SIZE				128
+#define EFUSE_MAX_SECTION			16
+
 enum _RT_MEDIA_STATUS {
 	RT_MEDIA_DISCONNECT = 0,
 	RT_MEDIA_CONNECT = 1
@@ -843,6 +852,7 @@ struct rtl_phy {
 	bool apk_done;
 	u32 reg_rf3c[2];	/* pathA / pathB  */
 
+	/* bfsync */
 	u8 framesync;
 	u32 framesync_c34;
 
@@ -852,6 +862,10 @@ struct rtl_phy {
 };
 
 #define MAX_TID_COUNT				9
+#define RTL_AGG_STOP				0
+#define RTL_AGG_PROGRESS			1
+#define RTL_AGG_START				2
+#define RTL_AGG_OPERATIONAL			3
 #define RTL_AGG_OFF				0
 #define RTL_AGG_ON				1
 #define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA		2
@@ -871,6 +885,13 @@ struct rtl_tid_data {
 	struct rtl_ht_agg agg;
 };
 
+struct rtl_sta_info {
+	u8 ratr_index;
+	u8 wireless_mode;
+	u8 mimo_ps;
+	struct rtl_tid_data tids[MAX_TID_COUNT];
+} __packed;
+
 struct rtl_priv;
 struct rtl_io {
 	struct device *dev;
@@ -894,6 +915,7 @@ struct rtl_io {
 	u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr);
 	int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
 			    u8 *pdata);
+
 };
 
 struct rtl_mac {
@@ -916,6 +938,8 @@ struct rtl_mac {
 	int n_channels;
 	int n_bitrates;
 
+	bool offchan_deley;
+
 	/*filters */
 	u32 rx_conf;
 	u16 rx_mgt_filter;
@@ -1032,7 +1056,9 @@ struct rtl_security {
 	enum rt_enc_alg pairwise_enc_algorithm;
 	/*Encryption Algorithm for Brocast/Multicast */
 	enum rt_enc_alg group_enc_algorithm;
-
+	/*Cam Entry Bitmap */
+	u32 hwsec_cam_bitmap;
+	u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN];
 	/*local Key buffer, indx 0 is for
 	   pairwise key 1-4 is for agoup key. */
 	u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN];
@@ -1053,7 +1079,7 @@ struct rtl_dm {
 	bool current_turbo_edca;
 	bool is_any_nonbepkts;	/*out dm */
 	bool is_cur_rdlstate;
-	bool txpower_trackingInit;
+	bool txpower_trackinginit;
 	bool disable_framebursting;
 	bool cck_inch14;
 	bool txpower_tracking;
@@ -1079,7 +1105,6 @@ struct rtl_dm {
 	bool disable_tx_int;
 	char ofdm_index[2];
 	char cck_index;
-	u8 power_index_backup[6];
 };
 
 #define	EFUSE_MAX_LOGICAL_SIZE			256
@@ -1175,6 +1200,7 @@ struct rtl_ps_ctl {
 	 * otherwise Offset[560h] = 0x00.
 	 * */
 	bool support_aspm;
+
 	bool support_backdoor;
 
 	/*for LPS */
@@ -1201,7 +1227,6 @@ struct rtl_ps_ctl {
 
 	/*just for PCIE ASPM */
 	u8 const_amdpci_aspm;
-
 	bool pwrdown_mode;
 
 	enum rf_pwrstate inactive_pwrstate;
@@ -1282,6 +1307,10 @@ struct rt_link_detect {
 	bool busytraffic;
 	bool higher_busytraffic;
 	bool higher_busyrxtraffic;
+
+	u32 tidtx_in4period[MAX_TID_COUNT][4];
+	u32 tidtx_inperiod[MAX_TID_COUNT];
+	bool higher_busytxtraffic[MAX_TID_COUNT];
 };
 
 struct rtl_tcb_desc {
@@ -1344,13 +1373,15 @@ struct rtl_hal_ops {
 				       u32 add_msr, u32 rm_msr);
 	void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
 	void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
-	void (*update_rate_table) (struct ieee80211_hw *hw);
+	void (*update_rate_tbl) (struct ieee80211_hw *hw,
+			      struct ieee80211_sta *sta, u8 rssi_level);
 	void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level);
 	void (*fill_tx_desc) (struct ieee80211_hw *hw,
 			      struct ieee80211_hdr *hdr, u8 *pdesc_tx,
 			      struct ieee80211_tx_info *info,
-			      struct sk_buff *skb, unsigned int queue_index);
-	void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 * pDesc,
+			      struct sk_buff *skb, u8 hw_queue,
+			      struct rtl_tcb_desc *ptcb_desc);
+	void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc,
 				  u32 buffer_len, bool bIsPsPoll);
 	void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc,
 				 bool firstseg, bool lastseg,
@@ -1370,10 +1401,10 @@ struct rtl_hal_ops {
 			     enum led_ctl_mode ledaction);
 	void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val);
 	u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name);
-	void (*tx_polling) (struct ieee80211_hw *hw, unsigned int hw_queue);
+	void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue);
 	void (*enable_hw_sec) (struct ieee80211_hw *hw);
 	void (*set_key) (struct ieee80211_hw *hw, u32 key_index,
-			 u8 *p_macaddr, bool is_group, u8 enc_algo,
+			 u8 *macaddr, bool is_group, u8 enc_algo,
 			 bool is_wepkey, bool clear_all);
 	void (*init_sw_leds) (struct ieee80211_hw *hw);
 	void (*deinit_sw_leds) (struct ieee80211_hw *hw);
@@ -1384,6 +1415,7 @@ struct rtl_hal_ops {
 			  u32 regaddr, u32 bitmask);
 	void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath,
 			   u32 regaddr, u32 bitmask, u32 data);
+	void (*linked_set_reg) (struct ieee80211_hw *hw);
 	bool (*phy_rf6052_config) (struct ieee80211_hw *hw);
 	void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw,
 					    u8 *powerlevel);
@@ -1404,7 +1436,9 @@ struct rtl_intf_ops {
 	int (*adapter_start) (struct ieee80211_hw *hw);
 	void (*adapter_stop) (struct ieee80211_hw *hw);
 
-	int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb);
+	int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb,
+			struct rtl_tcb_desc *ptcb_desc);
+	void (*flush)(struct ieee80211_hw *hw, bool drop);
 	int (*reset_trx_ring) (struct ieee80211_hw *hw);
 	bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb);
 
@@ -1418,6 +1452,15 @@ struct rtl_intf_ops {
 struct rtl_mod_params {
 	/* default: 0 = using hardware encryption */
 	int sw_crypto;
+
+	/* default: 1 = using no linked power save */
+	bool inactiveps;
+
+	/* default: 1 = using linked sw power save */
+	bool swctrl_lps;
+
+	/* default: 1 = using linked fw power save */
+	bool fwctrl_lps;
 };
 
 struct rtl_hal_usbint_cfg {
@@ -1445,6 +1488,7 @@ struct rtl_hal_usbint_cfg {
 
 struct rtl_hal_cfg {
 	u8 bar_id;
+	bool write_readback;
 	char *name;
 	char *fw_name;
 	struct rtl_hal_ops *ops;
@@ -1469,7 +1513,6 @@ struct rtl_locks {
 	spinlock_t rf_lock;
 	spinlock_t lps_lock;
 	spinlock_t waitq_lock;
-	spinlock_t tx_urb_lock;
 
 	/*Dual mac*/
 	spinlock_t cck_and_rw_pagea_lock;
@@ -1653,13 +1696,23 @@ struct bt_coexist_info {
 #define EF4BYTE(_val)		\
 	(le32_to_cpu(_val))
 
+/* Read data from memory */
+#define READEF1BYTE(_ptr)	\
+	EF1BYTE(*((u8 *)(_ptr)))
 /* Read le16 data from memory and convert to host ordering */
 #define READEF2BYTE(_ptr)	\
 	EF2BYTE(*((u16 *)(_ptr)))
+#define READEF4BYTE(_ptr)	\
+	EF4BYTE(*((u32 *)(_ptr)))
 
+/* Write data to memory */
+#define WRITEEF1BYTE(_ptr, _val)	\
+	(*((u8 *)(_ptr))) = EF1BYTE(_val)
 /* Write le16 data to memory in host ordering */
 #define WRITEEF2BYTE(_ptr, _val)	\
 	(*((u16 *)(_ptr))) = EF2BYTE(_val)
+#define WRITEEF4BYTE(_ptr, _val)	\
+	(*((u16 *)(_ptr))) = EF2BYTE(_val)
 
 /* Create a bit mask
  * Examples:
@@ -1698,6 +1751,25 @@ struct bt_coexist_info {
 #define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \
 	(EF1BYTE(*((u8 *)(__pstart))))
 
+/*Description:
+Translate subfield (continuous bits in little-endian) of 4-byte
+value to host byte ordering.*/
+#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		(LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset))  & \
+		BIT_LEN_MASK_32(__bitlen) \
+	)
+#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		(LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \
+		BIT_LEN_MASK_16(__bitlen) \
+	)
+#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		(LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \
+		BIT_LEN_MASK_8(__bitlen) \
+	)
+
 /* Description:
  * Mask subfield (continuous bits in little-endian) of 4-byte value
  * and return the result in 4-byte value in host byte ordering.
@@ -1721,6 +1793,18 @@ struct bt_coexist_info {
 /* Description:
  * Set subfield of little-endian 4-byte value to specified value.
  */
+#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \
+	*((u32 *)(__pstart)) = EF4BYTE \
+	( \
+		LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
+		((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \
+	);
+#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
+	*((u16 *)(__pstart)) = EF2BYTE \
+	( \
+		LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
+		((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \
+	);
 #define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \
 	*((u8 *)(__pstart)) = EF1BYTE \
 	( \
@@ -1728,12 +1812,16 @@ struct bt_coexist_info {
 		((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \
 	);
 
+#define	N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \
+	(__value) : (((__value + __aligment - 1) / __aligment) * __aligment))
+
 /****************************************
 	mem access macro define end
 ****************************************/
 
 #define byte(x, n) ((x >> (8 * n)) & 0xff)
 
+#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC)
 #define RTL_WATCH_DOG_TIME	2000
 #define MSECS(t)		msecs_to_jiffies(t)
 #define WLAN_FC_GET_VERS(fc)	(le16_to_cpu(fc) & IEEE80211_FCTL_VERS)
@@ -1768,6 +1856,15 @@ struct bt_coexist_info {
 #define container_of_dwork_rtl(x, y, z) \
 	container_of(container_of(x, struct delayed_work, work), y, z)
 
+#define FILL_OCTET_STRING(_os, _octet, _len)	\
+		(_os).octet = (u8 *)(_octet);		\
+		(_os).length = (_len);
+
+#define CP_MACADDR(des, src)	\
+	((des)[0] = (src)[0], (des)[1] = (src)[1],\
+	(des)[2] = (src)[2], (des)[3] = (src)[3],\
+	(des)[4] = (src)[4], (des)[5] = (src)[5])
+
 static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr)
 {
 	return rtlpriv->io.read8_sync(rtlpriv, addr);
@@ -1786,17 +1883,26 @@ static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr)
 static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8)
 {
 	rtlpriv->io.write8_async(rtlpriv, addr, val8);
+
+	if (rtlpriv->cfg->write_readback)
+		rtlpriv->io.read8_sync(rtlpriv, addr);
 }
 
 static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16)
 {
 	rtlpriv->io.write16_async(rtlpriv, addr, val16);
+
+	if (rtlpriv->cfg->write_readback)
+		rtlpriv->io.read16_sync(rtlpriv, addr);
 }
 
 static inline void rtl_write_dword(struct rtl_priv *rtlpriv,
 				   u32 addr, u32 val32)
 {
 	rtlpriv->io.write32_async(rtlpriv, addr, val32);
+
+	if (rtlpriv->cfg->write_readback)
+		rtlpriv->io.read32_sync(rtlpriv, addr);
 }
 
 static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw,
@@ -1855,4 +1961,31 @@ static inline u8 get_rf_type(struct rtl_phy *rtlphy)
 	return rtlphy->rf_type;
 }
 
+static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb)
+{
+	return (struct ieee80211_hdr *)(skb->data);
+}
+
+static inline __le16 rtl_get_fc(struct sk_buff *skb)
+{
+	return rtl_get_hdr(skb)->frame_control;
+}
+
+static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr)
+{
+	return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+static inline u16 rtl_get_tid(struct sk_buff *skb)
+{
+	return rtl_get_tid_h(rtl_get_hdr(skb));
+}
+
+static inline struct ieee80211_sta *get_sta(struct ieee80211_hw *hw,
+					    struct ieee80211_vif *vif,
+					    u8 *bssid)
+{
+	return ieee80211_find_sta(vif, bssid);
+}
+
 #endif
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 692ebff38fc89ceb67e342a2f08c20f8f0284532..35ce7b0f4a609ad5eff9151bf37b4bf0979b5374 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -3,7 +3,7 @@ menuconfig WL12XX_MENU
 	depends on MAC80211 && EXPERIMENTAL
 	---help---
 	  This will enable TI wl12xx driver support for the following chips:
-	  wl1271 and wl1273.
+	  wl1271, wl1273, wl1281 and wl1283.
 	  The drivers make use of the mac80211 stack.
 
 config WL12XX
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index a3db755ceedace20d394e95175d461fd0e32d685..a5c9c0aff83ffecad6211099a7f4caed2760c398 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -965,10 +965,13 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
 	}
 
 	/* memory config */
-	mem_conf->num_stations = wl->conf.mem.num_stations;
-	mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num;
-	mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num;
-	mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles;
+	/* FIXME: for now we always use mem_wl127x for AP, because it
+	 * doesn't support dynamic memory and we don't have the
+	 * optimal values for wl128x without dynamic memory yet */
+	mem_conf->num_stations = wl->conf.mem_wl127x.num_stations;
+	mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num;
+	mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num;
+	mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles;
 	mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
 
 	ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
@@ -986,6 +989,7 @@ out:
 int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
 {
 	struct wl1271_acx_sta_config_memory *mem_conf;
+	struct conf_memory_settings *mem;
 	int ret;
 
 	wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
@@ -996,16 +1000,21 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
 		goto out;
 	}
 
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		mem = &wl->conf.mem_wl128x;
+	else
+		mem = &wl->conf.mem_wl127x;
+
 	/* memory config */
-	mem_conf->num_stations = wl->conf.mem.num_stations;
-	mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num;
-	mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num;
-	mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles;
+	mem_conf->num_stations = mem->num_stations;
+	mem_conf->rx_mem_block_num = mem->rx_block_num;
+	mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
+	mem_conf->num_ssid_profiles = mem->ssid_profiles;
 	mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
-	mem_conf->dyn_mem_enable = wl->conf.mem.dynamic_memory;
-	mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks;
-	mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks;
-	mem_conf->tx_min = wl->conf.mem.tx_min;
+	mem_conf->dyn_mem_enable = mem->dynamic_memory;
+	mem_conf->tx_free_req = mem->min_req_tx_blocks;
+	mem_conf->rx_free_req = mem->min_req_rx_blocks;
+	mem_conf->tx_min = mem->tx_min;
 
 	ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
 				   sizeof(*mem_conf));
@@ -1019,6 +1028,32 @@ out:
 	return ret;
 }
 
+int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap)
+{
+	struct wl1271_acx_host_config_bitmap *bitmap_conf;
+	int ret;
+
+	bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
+	if (!bitmap_conf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
+
+	ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
+				   bitmap_conf, sizeof(*bitmap_conf));
+	if (ret < 0) {
+		wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(bitmap_conf);
+
+	return ret;
+}
+
 int wl1271_acx_init_mem_config(struct wl1271 *wl)
 {
 	int ret;
@@ -1489,22 +1524,46 @@ out:
 	return ret;
 }
 
-int wl1271_acx_max_tx_retry(struct wl1271 *wl)
+int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
 {
-	struct wl1271_acx_max_tx_retry *acx = NULL;
+	struct wl1271_acx_ap_max_tx_retry *acx = NULL;
 	int ret;
 
-	wl1271_debug(DEBUG_ACX, "acx max tx retry");
+	wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
 
 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
 	if (!acx)
 		return -ENOMEM;
 
-	acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries);
+	acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
 
 	ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
 	if (ret < 0) {
-		wl1271_warning("acx max tx retry failed: %d", ret);
+		wl1271_warning("acx ap max tx retry failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+}
+
+int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl)
+{
+	struct wl1271_acx_sta_max_tx_retry *acx = NULL;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx sta max tx retry");
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx)
+		return -ENOMEM;
+
+	acx->max_tx_retry = wl->conf.tx.max_tx_retries;
+
+	ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx));
+	if (ret < 0) {
+		wl1271_warning("acx sta max tx retry failed: %d", ret);
 		goto out;
 	}
 
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index dd19b01d807b021233cc02dca6d9224ab6f6c4c7..942908cd53a3edd34ac7ec1852b09dc4e80f8521 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -939,6 +939,16 @@ struct wl1271_acx_keep_alive_config {
 	u8 padding;
 } __packed;
 
+#define HOST_IF_CFG_RX_FIFO_ENABLE     BIT(0)
+#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
+#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
+
+struct wl1271_acx_host_config_bitmap {
+	struct acx_header header;
+
+	__le32 host_cfg_bitmap;
+} __packed;
+
 enum {
 	WL1271_ACX_TRIG_TYPE_LEVEL = 0,
 	WL1271_ACX_TRIG_TYPE_EDGE,
@@ -1135,7 +1145,7 @@ struct wl1271_acx_fw_tsf_information {
 	u8 padding[3];
 } __packed;
 
-struct wl1271_acx_max_tx_retry {
+struct wl1271_acx_ap_max_tx_retry {
 	struct acx_header header;
 
 	/*
@@ -1146,6 +1156,13 @@ struct wl1271_acx_max_tx_retry {
 	u8 padding_1[2];
 } __packed;
 
+struct wl1271_acx_sta_max_tx_retry {
+	struct acx_header header;
+
+	u8 max_tx_retry;
+	u8 padding_1[3];
+} __packed;
+
 struct wl1271_acx_config_ps {
 	struct acx_header header;
 
@@ -1275,6 +1292,7 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl);
 int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
 int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
 int wl1271_acx_init_mem_config(struct wl1271 *wl);
+int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
 int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
 int wl1271_acx_smart_reflex(struct wl1271 *wl);
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
@@ -1296,7 +1314,8 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
 int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
 				       bool enable);
 int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
-int wl1271_acx_max_tx_retry(struct wl1271 *wl);
+int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
+int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl);
 int wl1271_acx_config_ps(struct wl1271 *wl);
 int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
 
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 6934dffd5174f93465d4e2f4f9d29126d49e527a..d263ebb6f9742a3ffbe456f1bf5ce1a83a4a868c 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -22,6 +22,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/wl12xx.h>
 
 #include "acx.h"
 #include "reg.h"
@@ -243,33 +244,57 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
 	if (wl->nvs == NULL)
 		return -ENODEV;
 
-	/*
-	 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
-	 * configurations) can be removed when those NVS files stop floating
-	 * around.
-	 */
-	if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
-	    wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
-		/* for now 11a is unsupported in AP mode */
-		if (wl->bss_type != BSS_TYPE_AP_BSS &&
-		    wl->nvs->general_params.dual_mode_select)
-			wl->enable_11a = true;
-	}
+	if (wl->chip.id == CHIP_ID_1283_PG20) {
+		struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
+
+		if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) {
+			if (nvs->general_params.dual_mode_select)
+				wl->enable_11a = true;
+		} else {
+			wl1271_error("nvs size is not as expected: %zu != %zu",
+				     wl->nvs_len,
+				     sizeof(struct wl128x_nvs_file));
+			kfree(wl->nvs);
+			wl->nvs = NULL;
+			wl->nvs_len = 0;
+			return -EILSEQ;
+		}
 
-	if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
-	    (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
-	     wl->enable_11a)) {
-		wl1271_error("nvs size is not as expected: %zu != %zu",
-			     wl->nvs_len, sizeof(struct wl1271_nvs_file));
-		kfree(wl->nvs);
-		wl->nvs = NULL;
-		wl->nvs_len = 0;
-		return -EILSEQ;
-	}
+		/* only the first part of the NVS needs to be uploaded */
+		nvs_len = sizeof(nvs->nvs);
+		nvs_ptr = (u8 *)nvs->nvs;
+
+	} else {
+		struct wl1271_nvs_file *nvs =
+			(struct wl1271_nvs_file *)wl->nvs;
+		/*
+		 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz
+		 * band configurations) can be removed when those NVS files stop
+		 * floating around.
+		 */
+		if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
+		    wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
+			/* for now 11a is unsupported in AP mode */
+			if (wl->bss_type != BSS_TYPE_AP_BSS &&
+			    nvs->general_params.dual_mode_select)
+				wl->enable_11a = true;
+		}
 
-	/* only the first part of the NVS needs to be uploaded */
-	nvs_len = sizeof(wl->nvs->nvs);
-	nvs_ptr = (u8 *)wl->nvs->nvs;
+		if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
+		    (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+		     wl->enable_11a)) {
+			wl1271_error("nvs size is not as expected: %zu != %zu",
+				wl->nvs_len, sizeof(struct wl1271_nvs_file));
+			kfree(wl->nvs);
+			wl->nvs = NULL;
+			wl->nvs_len = 0;
+			return -EILSEQ;
+		}
+
+		/* only the first part of the NVS needs to be uploaded */
+		nvs_len = sizeof(nvs->nvs);
+		nvs_ptr = (u8 *) nvs->nvs;
+	}
 
 	/* update current MAC address to NVS */
 	nvs_ptr[11] = wl->mac_addr[0];
@@ -319,10 +344,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
 	/*
 	 * We've reached the first zero length, the first NVS table
 	 * is located at an aligned offset which is at least 7 bytes further.
+	 * NOTE: The wl->nvs->nvs element must be first, in order to
+	 * simplify the casting, we assume it is at the beginning of
+	 * the wl->nvs structure.
 	 */
-	nvs_ptr = (u8 *)wl->nvs->nvs +
-			ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4);
-	nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
+	nvs_ptr = (u8 *)wl->nvs +
+			ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
+	nvs_len -= nvs_ptr - (u8 *)wl->nvs;
 
 	/* Now we must set the partition correctly */
 	wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -450,10 +478,14 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
 		DISCONNECT_EVENT_COMPLETE_ID |
 		RSSI_SNR_TRIGGER_0_EVENT_ID |
 		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
-		SOFT_GEMINI_SENSE_EVENT_ID;
+		SOFT_GEMINI_SENSE_EVENT_ID |
+		MAX_TX_RETRY_EVENT_ID;
 
 	if (wl->bss_type == BSS_TYPE_AP_BSS)
-		wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
+		wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
+				  INACTIVE_STA_EVENT_ID;
+	else
+		wl->event_mask |= DUMMY_PACKET_EVENT_ID;
 
 	ret = wl1271_event_unmask(wl);
 	if (ret < 0) {
@@ -493,24 +525,159 @@ static void wl1271_boot_hw_version(struct wl1271 *wl)
 		wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
 }
 
-/* uploads NVS and firmware */
-int wl1271_load_firmware(struct wl1271 *wl)
+static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
 {
-	int ret = 0;
-	u32 tmp, clk, pause;
+	u16 spare_reg;
+
+	/* Mask bits [2] & [8:4] in the sys_clk_cfg register */
+	spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG);
+	if (spare_reg == 0xFFFF)
+		return -EFAULT;
+	spare_reg |= (BIT(3) | BIT(5) | BIT(6));
+	wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+
+	/* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */
+	wl1271_top_reg_write(wl, SYS_CLK_CFG_REG,
+			     WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
+
+	/* Delay execution for 15msec, to let the HW settle */
+	mdelay(15);
+
+	return 0;
+}
+
+static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
+{
+	u16 tcxo_detection;
+
+	tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG);
+	if (tcxo_detection & TCXO_DET_FAILED)
+		return false;
+
+	return true;
+}
+
+static bool wl128x_is_fref_valid(struct wl1271 *wl)
+{
+	u16 fref_detection;
+
+	fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG);
+	if (fref_detection & FREF_CLK_DETECT_FAIL)
+		return false;
+
+	return true;
+}
+
+static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl)
+{
+	wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
+	wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
+	wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL);
+
+	return 0;
+}
+
+static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
+{
+	u16 spare_reg;
+	u16 pll_config;
+	u8 input_freq;
+
+	/* Mask bits [3:1] in the sys_clk_cfg register */
+	spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG);
+	if (spare_reg == 0xFFFF)
+		return -EFAULT;
+	spare_reg |= BIT(2);
+	wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+
+	/* Handle special cases of the TCXO clock */
+	if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
+	    wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
+		return wl128x_manually_configure_mcs_pll(wl);
+
+	/* Set the input frequency according to the selected clock source */
+	input_freq = (clk & 1) + 1;
+
+	pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG);
+	if (pll_config == 0xFFFF)
+		return -EFAULT;
+	pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
+	pll_config |= MCS_PLL_ENABLE_HP;
+	wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
+
+	return 0;
+}
+
+/*
+ * WL128x has two clocks input - TCXO and FREF.
+ * TCXO is the main clock of the device, while FREF is used to sync
+ * between the GPS and the cellular modem.
+ * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used
+ * as the WLAN/BT main clock.
+ */
+static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
+{
+	u16 sys_clk_cfg;
+
+	/* For XTAL-only modes, FREF will be used after switching from TCXO */
+	if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
+	    wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
+		if (!wl128x_switch_tcxo_to_fref(wl))
+			return -EINVAL;
+		goto fref_clk;
+	}
+
+	/* Query the HW, to determine which clock source we should use */
+	sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG);
+	if (sys_clk_cfg == 0xFFFF)
+		return -EINVAL;
+	if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF)
+		goto fref_clk;
+
+	/* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
+	if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
+	    wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
+		if (!wl128x_switch_tcxo_to_fref(wl))
+			return -EINVAL;
+		goto fref_clk;
+	}
+
+	/* TCXO clock is selected */
+	if (!wl128x_is_tcxo_valid(wl))
+		return -EINVAL;
+	*selected_clock = wl->tcxo_clock;
+	goto config_mcs_pll;
+
+fref_clk:
+	/* FREF clock is selected */
+	if (!wl128x_is_fref_valid(wl))
+		return -EINVAL;
+	*selected_clock = wl->ref_clock;
+
+config_mcs_pll:
+	return wl128x_configure_mcs_pll(wl, *selected_clock);
+}
+
+static int wl127x_boot_clk(struct wl1271 *wl)
+{
+	u32 pause;
+	u32 clk;
 
 	wl1271_boot_hw_version(wl);
 
-	if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4)
+	if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
+	    wl->ref_clock == CONF_REF_CLK_38_4_E ||
+	    wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
 		/* ref clk: 19.2/38.4/38.4-XTAL */
 		clk = 0x3;
-	else if (wl->ref_clock == 1 || wl->ref_clock == 3)
+	else if (wl->ref_clock == CONF_REF_CLK_26_E ||
+		 wl->ref_clock == CONF_REF_CLK_52_E)
 		/* ref clk: 26/52 */
 		clk = 0x5;
 	else
 		return -EINVAL;
 
-	if (wl->ref_clock != 0) {
+	if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
 		u16 val;
 		/* Set clock type (open drain) */
 		val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
@@ -540,6 +707,26 @@ int wl1271_load_firmware(struct wl1271 *wl)
 	pause |= WU_COUNTER_PAUSE_VAL;
 	wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
 
+	return 0;
+}
+
+/* uploads NVS and firmware */
+int wl1271_load_firmware(struct wl1271 *wl)
+{
+	int ret = 0;
+	u32 tmp, clk;
+	int selected_clock = -1;
+
+	if (wl->chip.id == CHIP_ID_1283_PG20) {
+		ret = wl128x_boot_clk(wl, &selected_clock);
+		if (ret < 0)
+			goto out;
+	} else {
+		ret = wl127x_boot_clk(wl);
+		if (ret < 0)
+			goto out;
+	}
+
 	/* Continue the ELP wake up sequence */
 	wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
 	udelay(500);
@@ -555,7 +742,12 @@ int wl1271_load_firmware(struct wl1271 *wl)
 
 	wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
 
-	clk |= (wl->ref_clock << 1) << 4;
+	if (wl->chip.id == CHIP_ID_1283_PG20) {
+		clk |= ((selected_clock & 0x3) << 1) << 4;
+	} else {
+		clk |= (wl->ref_clock << 1) << 4;
+	}
+
 	wl1271_write32(wl, DRPW_SCRATCH_START, clk);
 
 	wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -585,16 +777,12 @@ int wl1271_load_firmware(struct wl1271 *wl)
 	/* 6. read the EEPROM parameters */
 	tmp = wl1271_read32(wl, SCR_PAD2);
 
-	ret = wl1271_boot_write_irq_polarity(wl);
-	if (ret < 0)
-		goto out;
-
-	wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
-		       WL1271_ACX_ALL_EVENTS_VECTOR);
-
 	/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
 	 * to upload_fw) */
 
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds);
+
 	ret = wl1271_boot_upload_firmware(wl);
 	if (ret < 0)
 		goto out;
@@ -618,6 +806,13 @@ int wl1271_boot(struct wl1271 *wl)
 	if (ret < 0)
 		goto out;
 
+	ret = wl1271_boot_write_irq_polarity(wl);
+	if (ret < 0)
+		goto out;
+
+	wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
+		       WL1271_ACX_ALL_EVENTS_VECTOR);
+
 	/* Enable firmware interrupts now */
 	wl1271_boot_enable_interrupts(wl);
 
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h
index 17229b86fc71018ef22d93043f62c56d6d71716b..e8f8255bbabeb45641a465d8602b6e4fb1871a7d 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/boot.h
@@ -74,4 +74,56 @@ struct wl1271_static_data {
 #define FREF_CLK_POLARITY_BITS 0xfffff8ff
 #define CLK_REQ_OUTN_SEL       0x700
 
+/* PLL configuration algorithm for wl128x */
+#define SYS_CLK_CFG_REG              0x2200
+/* Bit[0]   -  0-TCXO,  1-FREF */
+#define MCS_PLL_CLK_SEL_FREF         BIT(0)
+/* Bit[3:2] - 01-TCXO, 10-FREF */
+#define WL_CLK_REQ_TYPE_FREF         BIT(3)
+#define WL_CLK_REQ_TYPE_PG2          (BIT(3) | BIT(2))
+/* Bit[4]   -  0-TCXO,  1-FREF */
+#define PRCM_CM_EN_MUX_WLAN_FREF     BIT(4)
+
+#define TCXO_ILOAD_INT_REG           0x2264
+#define TCXO_CLK_DETECT_REG          0x2266
+
+#define TCXO_DET_FAILED              BIT(4)
+
+#define FREF_ILOAD_INT_REG           0x2084
+#define FREF_CLK_DETECT_REG          0x2086
+#define FREF_CLK_DETECT_FAIL         BIT(4)
+
+/* Use this reg for masking during driver access */
+#define WL_SPARE_REG                 0x2320
+#define WL_SPARE_VAL                 BIT(2)
+/* Bit[6:5:3] -  mask wl write SYS_CLK_CFG[8:5:2:4] */
+#define WL_SPARE_MASK_8526           (BIT(6) | BIT(5) | BIT(3))
+
+#define PLL_LOCK_COUNTERS_REG        0xD8C
+#define PLL_LOCK_COUNTERS_COEX       0x0F
+#define PLL_LOCK_COUNTERS_MCS        0xF0
+#define MCS_PLL_OVERRIDE_REG         0xD90
+#define MCS_PLL_CONFIG_REG           0xD92
+#define MCS_SEL_IN_FREQ_MASK         0x0070
+#define MCS_SEL_IN_FREQ_SHIFT        4
+#define MCS_PLL_CONFIG_REG_VAL       0x73
+#define MCS_PLL_ENABLE_HP            (BIT(0) | BIT(1))
+
+#define MCS_PLL_M_REG                0xD94
+#define MCS_PLL_N_REG                0xD96
+#define MCS_PLL_M_REG_VAL            0xC8
+#define MCS_PLL_N_REG_VAL            0x07
+
+#define SDIO_IO_DS                   0xd14
+
+/* SDIO/wSPI DS configuration values */
+enum {
+	HCI_IO_DS_8MA = 0,
+	HCI_IO_DS_4MA = 1, /* default */
+	HCI_IO_DS_6MA = 2,
+	HCI_IO_DS_2MA = 3,
+};
+
+/* end PLL configuration algorithm for wl128x */
+
 #endif
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 96324336f936bcdd047062bca63b041c5694db46..69d24f35cd9a2848fdee1a261dedab2e2059650f 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -110,7 +110,47 @@ out:
 int wl1271_cmd_general_parms(struct wl1271 *wl)
 {
 	struct wl1271_general_parms_cmd *gen_parms;
-	struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
+	struct wl1271_ini_general_params *gp =
+		&((struct wl1271_nvs_file *)wl->nvs)->general_params;
+	bool answer = false;
+	int ret;
+
+	if (!wl->nvs)
+		return -ENODEV;
+
+	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
+	if (!gen_parms)
+		return -ENOMEM;
+
+	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
+
+	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
+
+	if (gp->tx_bip_fem_auto_detect)
+		answer = true;
+
+	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
+	if (ret < 0) {
+		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
+		goto out;
+	}
+
+	gp->tx_bip_fem_manufacturer =
+		gen_parms->general_params.tx_bip_fem_manufacturer;
+
+	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
+		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
+
+out:
+	kfree(gen_parms);
+	return ret;
+}
+
+int wl128x_cmd_general_parms(struct wl1271 *wl)
+{
+	struct wl128x_general_parms_cmd *gen_parms;
+	struct wl128x_ini_general_params *gp =
+		&((struct wl128x_nvs_file *)wl->nvs)->general_params;
 	bool answer = false;
 	int ret;
 
@@ -147,8 +187,9 @@ out:
 
 int wl1271_cmd_radio_parms(struct wl1271 *wl)
 {
+	struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
 	struct wl1271_radio_parms_cmd *radio_parms;
-	struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
+	struct wl1271_ini_general_params *gp = &nvs->general_params;
 	int ret;
 
 	if (!wl->nvs)
@@ -161,18 +202,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
 
 	/* 2.4GHz parameters */
-	memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
+	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
 	       sizeof(struct wl1271_ini_band_params_2));
 	memcpy(&radio_parms->dyn_params_2,
-	       &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
 	       sizeof(struct wl1271_ini_fem_params_2));
 
 	/* 5GHz parameters */
 	memcpy(&radio_parms->static_params_5,
-	       &wl->nvs->stat_radio_params_5,
+	       &nvs->stat_radio_params_5,
 	       sizeof(struct wl1271_ini_band_params_5));
 	memcpy(&radio_parms->dyn_params_5,
-	       &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
 	       sizeof(struct wl1271_ini_fem_params_5));
 
 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
@@ -186,6 +227,50 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	return ret;
 }
 
+int wl128x_cmd_radio_parms(struct wl1271 *wl)
+{
+	struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
+	struct wl128x_radio_parms_cmd *radio_parms;
+	struct wl128x_ini_general_params *gp = &nvs->general_params;
+	int ret;
+
+	if (!wl->nvs)
+		return -ENODEV;
+
+	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
+	if (!radio_parms)
+		return -ENOMEM;
+
+	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
+
+	/* 2.4GHz parameters */
+	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
+	       sizeof(struct wl128x_ini_band_params_2));
+	memcpy(&radio_parms->dyn_params_2,
+	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+	       sizeof(struct wl128x_ini_fem_params_2));
+
+	/* 5GHz parameters */
+	memcpy(&radio_parms->static_params_5,
+	       &nvs->stat_radio_params_5,
+	       sizeof(struct wl128x_ini_band_params_5));
+	memcpy(&radio_parms->dyn_params_5,
+	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+	       sizeof(struct wl128x_ini_fem_params_5));
+
+	radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
+
+	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
+		    radio_parms, sizeof(*radio_parms));
+
+	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
+	if (ret < 0)
+		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
+
+	kfree(radio_parms);
+	return ret;
+}
+
 int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
 {
 	struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
@@ -985,7 +1070,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
 
 	memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
 
-	cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
+	cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
 	cmd->bss_index = WL1271_AP_BSS_INDEX;
 	cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
 	cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 54c12e71417e9ce50f60c6213bae219784371de6..5cac95d9480c33b92f313b9b83be0e9ec0e172aa 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -32,7 +32,9 @@ struct acx_header;
 int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
 		    size_t res_len);
 int wl1271_cmd_general_parms(struct wl1271 *wl);
+int wl128x_cmd_general_parms(struct wl1271 *wl);
 int wl1271_cmd_radio_parms(struct wl1271 *wl);
+int wl128x_cmd_radio_parms(struct wl1271 *wl);
 int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
 int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
 int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
@@ -415,6 +417,21 @@ struct wl1271_general_parms_cmd {
 	u8 padding[3];
 } __packed;
 
+struct wl128x_general_parms_cmd {
+	struct wl1271_cmd_header header;
+
+	struct wl1271_cmd_test_header test;
+
+	struct wl128x_ini_general_params general_params;
+
+	u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+	u8 sr_sen_n_p;
+	u8 sr_sen_n_p_gain;
+	u8 sr_sen_nrn;
+	u8 sr_sen_prn;
+	u8 padding[3];
+} __packed;
+
 struct wl1271_radio_parms_cmd {
 	struct wl1271_cmd_header header;
 
@@ -431,6 +448,23 @@ struct wl1271_radio_parms_cmd {
 	u8 padding3[2];
 } __packed;
 
+struct wl128x_radio_parms_cmd {
+	struct wl1271_cmd_header header;
+
+	struct wl1271_cmd_test_header test;
+
+	/* Static radio parameters */
+	struct wl128x_ini_band_params_2 static_params_2;
+	struct wl128x_ini_band_params_5 static_params_5;
+
+	u8 fem_vendor_and_options;
+
+	/* Dynamic radio parameters */
+	struct wl128x_ini_fem_params_2 dyn_params_2;
+	u8 padding2;
+	struct wl128x_ini_fem_params_5 dyn_params_5;
+} __packed;
+
 struct wl1271_ext_radio_parms_cmd {
 	struct wl1271_cmd_header header;
 
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 8a8323896eecf265536384988d714417b0f28ea2..e3de91528de8947dfda54f95343b7fbe2bc9ef6c 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -683,10 +683,18 @@ struct conf_tx_settings {
 	struct conf_tx_rate_class ap_bcst_conf;
 
 	/*
-	 * AP-mode - allow this number of TX retries to a station before an
+	 * Allow this number of TX retries to a connected station/AP before an
 	 * event is triggered from FW.
+	 * In AP-mode the hlids of unreachable stations are given in the
+	 * "sta_tx_retry_exceeded" member in the event mailbox.
 	 */
-	u16 ap_max_tx_retries;
+	u8 max_tx_retries;
+
+	/*
+	 * AP-mode - after this number of seconds a connected station is
+	 * considered inactive.
+	 */
+	u16 ap_aging_period;
 
 	/*
 	 * Configuration for TID parameters.
@@ -1004,7 +1012,9 @@ enum {
 	CONF_REF_CLK_19_2_E,
 	CONF_REF_CLK_26_E,
 	CONF_REF_CLK_38_4_E,
-	CONF_REF_CLK_52_E
+	CONF_REF_CLK_52_E,
+	CONF_REF_CLK_38_4_M_XTAL,
+	CONF_REF_CLK_26_M_XTAL,
 };
 
 enum single_dual_band_enum {
@@ -1018,15 +1028,6 @@ enum single_dual_band_enum {
 #define CONF_NUMBER_OF_CHANNELS_2_4 14
 #define CONF_NUMBER_OF_CHANNELS_5   35
 
-struct conf_radio_parms {
-	/*
-	 * FEM parameter set to use
-	 *
-	 * Range: 0 or 1
-	 */
-	u8 fem;
-};
-
 struct conf_itrim_settings {
 	/* enable dco itrim */
 	u8 enable;
@@ -1202,7 +1203,9 @@ struct conf_drv_settings {
 	struct conf_scan_settings scan;
 	struct conf_rf_settings rf;
 	struct conf_ht_setting ht;
-	struct conf_memory_settings mem;
+	struct conf_memory_settings mem_wl127x;
+	struct conf_memory_settings mem_wl128x;
+	u8 hci_io_ds;
 };
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 8e75b09723b9578eb9ec0768b257191fe0981432..70ab1986788e221bc3cb7bed5e35d23508493bea 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -267,7 +267,7 @@ static ssize_t gpio_power_write(struct file *file,
 	}
 	buf[len] = '\0';
 
-	ret = strict_strtoul(buf, 0, &value);
+	ret = kstrtoul(buf, 0, &value);
 	if (ret < 0) {
 		wl1271_warning("illegal value in gpio_power");
 		return -EINVAL;
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 1b170c5cc595f22dde0b1c494b7276059e278960..d7be3aec6fc38cdb2feb83335a150deef07200e6 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -33,6 +33,7 @@ void wl1271_pspoll_work(struct work_struct *work)
 {
 	struct delayed_work *dwork;
 	struct wl1271 *wl;
+	int ret;
 
 	dwork = container_of(work, struct delayed_work, work);
 	wl = container_of(dwork, struct wl1271, pspoll_work);
@@ -55,8 +56,13 @@ void wl1271_pspoll_work(struct work_struct *work)
 	 * delivery failure occurred, and no-one changed state since, so
 	 * we should go back to powersave.
 	 */
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
 	wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
 
+	wl1271_ps_elp_sleep(wl);
 out:
 	mutex_unlock(&wl->mutex);
 };
@@ -129,11 +135,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 
 		/* enable beacon early termination */
 		ret = wl1271_acx_bet_enable(wl, true);
-		if (ret < 0)
-			break;
-
-		/* go to extremely low power mode */
-		wl1271_ps_elp_sleep(wl);
 		break;
 	default:
 		break;
@@ -173,6 +174,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 	u32 vector;
 	bool beacon_loss = false;
 	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
+	bool disconnect_sta = false;
+	unsigned long sta_bitmap = 0;
 
 	wl1271_event_mbox_dump(mbox);
 
@@ -228,9 +231,60 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 			wl1271_event_rssi_trigger(wl, mbox);
 	}
 
+	if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
+		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
+		if (wl->vif)
+			wl1271_tx_dummy_packet(wl);
+	}
+
+	/*
+	 * "TX retries exceeded" has a different meaning according to mode.
+	 * In AP mode the offending station is disconnected. In STA mode we
+	 * report connection loss.
+	 */
+	if (vector & MAX_TX_RETRY_EVENT_ID) {
+		wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
+		if (is_ap) {
+			sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
+			disconnect_sta = true;
+		} else {
+			beacon_loss = true;
+		}
+	}
+
+	if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
+		wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
+		sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
+		disconnect_sta = true;
+	}
+
 	if (wl->vif && beacon_loss)
 		ieee80211_connection_loss(wl->vif);
 
+	if (is_ap && disconnect_sta) {
+		u32 num_packets = wl->conf.tx.max_tx_retries;
+		struct ieee80211_sta *sta;
+		const u8 *addr;
+		int h;
+
+		for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
+		     h < AP_MAX_LINKS;
+		     h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
+			if (!wl1271_is_active_sta(wl, h))
+				continue;
+
+			addr = wl->links[h].addr;
+
+			rcu_read_lock();
+			sta = ieee80211_find_sta(wl->vif, addr);
+			if (sta) {
+				wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
+				ieee80211_report_low_ack(sta, num_packets);
+			}
+			rcu_read_unlock();
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index 0e80886f3031fe740fa74b1ff4faaa4294f4e387..7ae5a0821241f0c2a1762cf3a5f8ecd7274ab862 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -58,10 +58,16 @@ enum {
 	CHANNEL_SWITCH_COMPLETE_EVENT_ID	 = BIT(17),
 	BSS_LOSE_EVENT_ID			 = BIT(18),
 	REGAINED_BSS_EVENT_ID			 = BIT(19),
-	ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID	 = BIT(20),
-	STA_REMOVE_COMPLETE_EVENT_ID		 = BIT(21), /* AP */
+	MAX_TX_RETRY_EVENT_ID			 = BIT(20),
+	/* STA: dummy paket for dynamic mem blocks */
+	DUMMY_PACKET_EVENT_ID                    = BIT(21),
+	/* AP: STA remove complete */
+	STA_REMOVE_COMPLETE_EVENT_ID             = BIT(21),
 	SOFT_GEMINI_SENSE_EVENT_ID		 = BIT(22),
+	/* STA: SG prediction */
 	SOFT_GEMINI_PREDICTION_EVENT_ID		 = BIT(23),
+	/* AP: Inactive STA */
+	INACTIVE_STA_EVENT_ID			 = BIT(23),
 	SOFT_GEMINI_AVALANCHE_EVENT_ID		 = BIT(24),
 	PLT_RX_CALIBRATION_COMPLETE_EVENT_ID	 = BIT(25),
 	DBG_EVENT_ID				 = BIT(26),
@@ -116,7 +122,11 @@ struct event_mailbox {
 
 	/* AP FW only */
 	u8 hlid_removed;
+
+	/* a bitmap of hlids for stations that have been inactive too long */
 	__le16 sta_aging_status;
+
+	/* a bitmap of hlids for stations which didn't respond to TX */
 	__le16 sta_tx_retry_exceeded;
 
 	u8 reserved_5[24];
@@ -127,4 +137,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
 int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
 void wl1271_pspoll_work(struct work_struct *work);
 
+/* Functions from main.c */
+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
+
 #endif
diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h
index c330a2583dfd0c8f62f516020e79073d154278ca..1420c842b8f1585ac0146071fa88cb63d263cf09 100644
--- a/drivers/net/wireless/wl12xx/ini.h
+++ b/drivers/net/wireless/wl12xx/ini.h
@@ -41,6 +41,28 @@ struct wl1271_ini_general_params {
 	u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
 } __packed;
 
+#define WL128X_INI_MAX_SETTINGS_PARAM 4
+
+struct wl128x_ini_general_params {
+	u8 ref_clock;
+	u8 settling_time;
+	u8 clk_valid_on_wakeup;
+	u8 tcxo_ref_clock;
+	u8 tcxo_settling_time;
+	u8 tcxo_valid_on_wakeup;
+	u8 tcxo_ldo_voltage;
+	u8 xtal_itrim_val;
+	u8 platform_conf;
+	u8 dual_mode_select;
+	u8 tx_bip_fem_auto_detect;
+	u8 tx_bip_fem_manufacturer;
+	u8 general_settings[WL128X_INI_MAX_SETTINGS_PARAM];
+	u8 sr_state;
+	u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+	u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+	u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+} __packed;
+
 #define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15
 
 struct wl1271_ini_band_params_2 {
@@ -49,9 +71,16 @@ struct wl1271_ini_band_params_2 {
 	u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
 } __packed;
 
-#define WL1271_INI_RATE_GROUP_COUNT 6
 #define WL1271_INI_CHANNEL_COUNT_2 14
 
+struct wl128x_ini_band_params_2 {
+	u8 rx_trace_insertion_loss;
+	u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2];
+	u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __packed;
+
+#define WL1271_INI_RATE_GROUP_COUNT 6
+
 struct wl1271_ini_fem_params_2 {
 	__le16 tx_bip_ref_pd_voltage;
 	u8 tx_bip_ref_power;
@@ -68,6 +97,28 @@ struct wl1271_ini_fem_params_2 {
 	u8 normal_to_degraded_high_thr;
 } __packed;
 
+#define WL128X_INI_RATE_GROUP_COUNT 7
+/* low and high temperatures */
+#define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2
+
+struct wl128x_ini_fem_params_2 {
+	__le16 tx_bip_ref_pd_voltage;
+	u8 tx_bip_ref_power;
+	u8 tx_bip_ref_offset;
+	u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2];
+	u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2];
+	u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1];
+	u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2];
+	u8 tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES];
+	u8 rx_fem_insertion_loss;
+	u8 degraded_low_to_normal_thr;
+	u8 normal_to_degraded_high_thr;
+} __packed;
+
 #define WL1271_INI_CHANNEL_COUNT_5 35
 #define WL1271_INI_SUB_BAND_COUNT_5 7
 
@@ -77,6 +128,12 @@ struct wl1271_ini_band_params_5 {
 	u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
 } __packed;
 
+struct wl128x_ini_band_params_5 {
+	u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_5];
+	u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __packed;
+
 struct wl1271_ini_fem_params_5 {
 	__le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
 	u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
@@ -92,6 +149,23 @@ struct wl1271_ini_fem_params_5 {
 	u8 normal_to_degraded_high_thr;
 } __packed;
 
+struct wl128x_ini_fem_params_5 {
+	__le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
+	u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT];
+	u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5];
+	u8 tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 *
+		WL128X_INI_PD_VS_TEMPERATURE_RANGES];
+	u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+	u8 degraded_low_to_normal_thr;
+	u8 normal_to_degraded_high_thr;
+} __packed;
 
 /* NVS data structure */
 #define WL1271_INI_NVS_SECTION_SIZE		     468
@@ -100,7 +174,7 @@ struct wl1271_ini_fem_params_5 {
 #define WL1271_INI_LEGACY_NVS_FILE_SIZE              800
 
 struct wl1271_nvs_file {
-	/* NVS section */
+	/* NVS section - must be first! */
 	u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
 
 	/* INI section */
@@ -120,4 +194,24 @@ struct wl1271_nvs_file {
 	} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
 } __packed;
 
+struct wl128x_nvs_file {
+	/* NVS section - must be first! */
+	u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
+
+	/* INI section */
+	struct wl128x_ini_general_params general_params;
+	u8 fem_vendor_and_options;
+	struct wl128x_ini_band_params_2 stat_radio_params_2;
+	u8 padding2;
+	struct {
+		struct wl128x_ini_fem_params_2 params;
+		u8 padding;
+	} dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+	struct wl128x_ini_band_params_5 stat_radio_params_5;
+	u8 padding3;
+	struct {
+		struct wl128x_ini_fem_params_5 params;
+		u8 padding;
+	} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+} __packed;
 #endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 6072fe457135ab4a4e4b2715d8ddf499491fe73b..ab3b1e21de2991c41d91fe2ad91f5e76d097f3da 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -31,6 +31,7 @@
 #include "cmd.h"
 #include "reg.h"
 #include "tx.h"
+#include "io.h"
 
 int wl1271_sta_init_templates_config(struct wl1271 *wl)
 {
@@ -321,9 +322,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
 {
 	int ret;
 
-	ret = wl1271_cmd_ext_radio_parms(wl);
-	if (ret < 0)
-		return ret;
+	if (wl->chip.id != CHIP_ID_1283_PG20) {
+		ret = wl1271_cmd_ext_radio_parms(wl);
+		if (ret < 0)
+			return ret;
+	}
 
 	/* PS config */
 	ret = wl1271_acx_config_ps(wl);
@@ -372,6 +375,10 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
 	if (ret < 0)
 		return ret;
 
+	ret = wl1271_acx_sta_max_tx_retry(wl);
+	if (ret < 0)
+		return ret;
+
 	ret = wl1271_acx_sta_mem_cfg(wl);
 	if (ret < 0)
 		return ret;
@@ -438,7 +445,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_acx_max_tx_retry(wl);
+	ret = wl1271_acx_ap_max_tx_retry(wl);
 	if (ret < 0)
 		return ret;
 
@@ -504,6 +511,27 @@ static int wl1271_set_ba_policies(struct wl1271 *wl)
 	return ret;
 }
 
+int wl1271_chip_specific_init(struct wl1271 *wl)
+{
+	int ret = 0;
+
+	if (wl->chip.id == CHIP_ID_1283_PG20) {
+		u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
+
+		if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
+			/* Enable SDIO padding */
+			host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
+
+		/* Must be before wl1271_acx_init_mem_config() */
+		ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
+		if (ret < 0)
+			goto out;
+	}
+out:
+	return ret;
+}
+
+
 int wl1271_hw_init(struct wl1271 *wl)
 {
 	struct conf_tx_ac_category *conf_ac;
@@ -511,11 +539,22 @@ int wl1271_hw_init(struct wl1271 *wl)
 	int ret, i;
 	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
 
-	ret = wl1271_cmd_general_parms(wl);
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		ret = wl128x_cmd_general_parms(wl);
+	else
+		ret = wl1271_cmd_general_parms(wl);
+	if (ret < 0)
+		return ret;
+
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		ret = wl128x_cmd_radio_parms(wl);
+	else
+		ret = wl1271_cmd_radio_parms(wl);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_radio_parms(wl);
+	/* Chip-specific init */
+	ret = wl1271_chip_specific_init(wl);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h
index 3a8bd3f426d287f0749cfcb68706c4b9eab5fbd6..4975270a91ab8948d316a4d957b3e76f5b4cc4cc 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/init.h
@@ -31,6 +31,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl);
 int wl1271_init_phy_config(struct wl1271 *wl);
 int wl1271_init_pta(struct wl1271 *wl);
 int wl1271_init_energy_detection(struct wl1271 *wl);
+int wl1271_chip_specific_init(struct wl1271 *wl);
 int wl1271_hw_init(struct wl1271 *wl);
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
index d557f73e7c191ef48ea612e0e1a858bb7f0f8f28..da5c1ad942a45d81c08de332f1c0a7871e9c546b 100644
--- a/drivers/net/wireless/wl12xx/io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -29,6 +29,7 @@
 #include "wl12xx.h"
 #include "wl12xx_80211.h"
 #include "io.h"
+#include "tx.h"
 
 #define OCP_CMD_LOOP  32
 
@@ -43,6 +44,16 @@
 #define OCP_STATUS_REQ_FAILED 0x20000
 #define OCP_STATUS_RESP_ERROR 0x30000
 
+bool wl1271_set_block_size(struct wl1271 *wl)
+{
+	if (wl->if_ops->set_block_size) {
+		wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE);
+		return true;
+	}
+
+	return false;
+}
+
 void wl1271_disable_interrupts(struct wl1271 *wl)
 {
 	wl->if_ops->disable_irq(wl);
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index 00c771ea70bf99a67105b688567ba48ba0a96ac9..beed621a8ae0cb5110e01517e54e968841026a14 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -169,5 +169,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl);
 struct ieee80211_hw *wl1271_alloc_hw(void);
 int wl1271_free_hw(struct wl1271 *wl);
 irqreturn_t wl1271_irq(int irq, void *data);
+bool wl1271_set_block_size(struct wl1271 *wl);
+int wl1271_tx_dummy_packet(struct wl1271 *wl);
+void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters);
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 8b3c8d196b03310bc7760340411414b0bbf7e82c..0c69e959d0dee5c9341b9698a76c509383c66192 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -30,6 +30,7 @@
 #include <linux/vmalloc.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/wl12xx.h>
 
 #include "wl12xx.h"
 #include "wl12xx_80211.h"
@@ -54,7 +55,7 @@ static struct conf_drv_settings default_conf = {
 			[CONF_SG_BT_PER_THRESHOLD]                  = 7500,
 			[CONF_SG_HV3_MAX_OVERRIDE]                  = 0,
 			[CONF_SG_BT_NFS_SAMPLE_INTERVAL]            = 400,
-			[CONF_SG_BT_LOAD_RATIO]                     = 50,
+			[CONF_SG_BT_LOAD_RATIO]                     = 200,
 			[CONF_SG_AUTO_PS_MODE]                      = 1,
 			[CONF_SG_AUTO_SCAN_PROBE_REQ]               = 170,
 			[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3]   = 50,
@@ -191,7 +192,8 @@ static struct conf_drv_settings default_conf = {
 			.long_retry_limit    = 10,
 			.aflags              = 0,
 		},
-		.ap_max_tx_retries = 100,
+		.max_tx_retries = 100,
+		.ap_aging_period = 300,
 		.tid_conf_count = 4,
 		.tid_conf = {
 			[CONF_TX_AC_BE] = {
@@ -254,7 +256,7 @@ static struct conf_drv_settings default_conf = {
 		.ps_poll_threshold           = 10,
 		.ps_poll_recovery_period     = 700,
 		.bet_enable                  = CONF_BET_MODE_ENABLE,
-		.bet_max_consecutive         = 10,
+		.bet_max_consecutive         = 50,
 		.psm_entry_retries           = 5,
 		.psm_exit_retries            = 255,
 		.psm_entry_nullfunc_retries  = 3,
@@ -298,7 +300,7 @@ static struct conf_drv_settings default_conf = {
 		.tx_ba_win_size = 64,
 		.inactivity_timeout = 10000,
 	},
-	.mem = {
+	.mem_wl127x = {
 		.num_stations                 = 1,
 		.ssid_profiles                = 1,
 		.rx_block_num                 = 70,
@@ -307,7 +309,18 @@ static struct conf_drv_settings default_conf = {
 		.min_req_tx_blocks            = 100,
 		.min_req_rx_blocks            = 22,
 		.tx_min                       = 27,
-	}
+	},
+	.mem_wl128x = {
+		.num_stations                 = 1,
+		.ssid_profiles                = 1,
+		.rx_block_num                 = 40,
+		.tx_min_block_num             = 40,
+		.dynamic_memory               = 1,
+		.min_req_tx_blocks            = 45,
+		.min_req_rx_blocks            = 22,
+		.tx_min                       = 27,
+	},
+	.hci_io_ds = HCI_IO_DS_6MA,
 };
 
 static void __wl1271_op_remove_interface(struct wl1271 *wl);
@@ -329,6 +342,7 @@ static struct platform_device wl1271_device = {
 	},
 };
 
+static DEFINE_MUTEX(wl_list_mutex);
 static LIST_HEAD(wl_list);
 
 static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
@@ -359,10 +373,12 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
 		return NOTIFY_DONE;
 
 	wl_temp = hw->priv;
+	mutex_lock(&wl_list_mutex);
 	list_for_each_entry(wl, &wl_list, list) {
 		if (wl == wl_temp)
 			break;
 	}
+	mutex_unlock(&wl_list_mutex);
 	if (wl != wl_temp)
 		return NOTIFY_DONE;
 
@@ -438,15 +454,30 @@ static int wl1271_plt_init(struct wl1271 *wl)
 	struct conf_tx_tid *conf_tid;
 	int ret, i;
 
-	ret = wl1271_cmd_general_parms(wl);
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		ret = wl128x_cmd_general_parms(wl);
+	else
+		ret = wl1271_cmd_general_parms(wl);
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_radio_parms(wl);
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		ret = wl128x_cmd_radio_parms(wl);
+	else
+		ret = wl1271_cmd_radio_parms(wl);
+	if (ret < 0)
+		return ret;
+
+	if (wl->chip.id != CHIP_ID_1283_PG20) {
+		ret = wl1271_cmd_ext_radio_parms(wl);
+		if (ret < 0)
+			return ret;
+	}
 	if (ret < 0)
 		return ret;
 
-	ret = wl1271_cmd_ext_radio_parms(wl);
+	/* Chip-specific initializations */
+	ret = wl1271_chip_specific_init(wl);
 	if (ret < 0)
 		return ret;
 
@@ -593,15 +624,17 @@ static void wl1271_fw_status(struct wl1271 *wl,
 {
 	struct wl1271_fw_common_status *status = &full_status->common;
 	struct timespec ts;
-	u32 total = 0;
+	u32 old_tx_blk_count = wl->tx_blocks_available;
+	u32 freed_blocks = 0;
 	int i;
 
-	if (wl->bss_type == BSS_TYPE_AP_BSS)
+	if (wl->bss_type == BSS_TYPE_AP_BSS) {
 		wl1271_raw_read(wl, FW_STATUS_ADDR, status,
 				sizeof(struct wl1271_fw_ap_status), false);
-	else
+	} else {
 		wl1271_raw_read(wl, FW_STATUS_ADDR, status,
 				sizeof(struct wl1271_fw_sta_status), false);
+	}
 
 	wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
 		     "drv_rx_counter = %d, tx_results_counter = %d)",
@@ -612,22 +645,37 @@ static void wl1271_fw_status(struct wl1271 *wl,
 
 	/* update number of available TX blocks */
 	for (i = 0; i < NUM_TX_QUEUES; i++) {
-		u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
-			wl->tx_blocks_freed[i];
+		freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
+				wl->tx_blocks_freed[i];
 
 		wl->tx_blocks_freed[i] =
 			le32_to_cpu(status->tx_released_blks[i]);
-		wl->tx_blocks_available += cnt;
-		total += cnt;
 	}
 
-	/* if more blocks are available now, tx work can be scheduled */
-	if (total)
-		clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
+	wl->tx_allocated_blocks -= freed_blocks;
 
-	/* for AP update num of allocated TX blocks per link and ps status */
-	if (wl->bss_type == BSS_TYPE_AP_BSS)
+	if (wl->bss_type == BSS_TYPE_AP_BSS) {
+		/* Update num of allocated TX blocks per link and ps status */
 		wl1271_irq_update_links_status(wl, &full_status->ap);
+		wl->tx_blocks_available += freed_blocks;
+	} else {
+		int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
+
+		/*
+		 * The FW might change the total number of TX memblocks before
+		 * we get a notification about blocks being released. Thus, the
+		 * available blocks calculation might yield a temporary result
+		 * which is lower than the actual available blocks. Keeping in
+		 * mind that only blocks that were allocated can be moved from
+		 * TX to RX, tx_blocks_available should never decrease here.
+		 */
+		wl->tx_blocks_available = max((int)wl->tx_blocks_available,
+					      avail);
+	}
+
+	/* if more blocks are available now, tx work can be scheduled */
+	if (wl->tx_blocks_available > old_tx_blk_count)
+		clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
 
 	/* update the host-chipset time offset */
 	getnstimeofday(&ts);
@@ -674,6 +722,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
 	set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
 	cancel_work_sync(&wl->tx_work);
 
+	/*
+	 * In case edge triggered interrupt must be used, we cannot iterate
+	 * more than once without introducing race conditions with the hardirq.
+	 */
+	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
+		loopcount = 1;
+
 	mutex_lock(&wl->mutex);
 
 	wl1271_debug(DEBUG_IRQ, "IRQ work");
@@ -785,11 +840,17 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
 
 	switch (wl->bss_type) {
 	case BSS_TYPE_AP_BSS:
-		fw_name = WL1271_AP_FW_NAME;
+		if (wl->chip.id == CHIP_ID_1283_PG20)
+			fw_name = WL128X_AP_FW_NAME;
+		else
+			fw_name = WL127X_AP_FW_NAME;
 		break;
 	case BSS_TYPE_IBSS:
 	case BSS_TYPE_STA_BSS:
-		fw_name = WL1271_FW_NAME;
+		if (wl->chip.id == CHIP_ID_1283_PG20)
+			fw_name = WL128X_FW_NAME;
+		else
+			fw_name	= WL1271_FW_NAME;
 		break;
 	default:
 		wl1271_error("no compatible firmware for bss_type %d",
@@ -838,14 +899,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
 	const struct firmware *fw;
 	int ret;
 
-	ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
+	ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
 
 	if (ret < 0) {
 		wl1271_error("could not get nvs file: %d", ret);
 		return ret;
 	}
 
-	wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+	wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
 
 	if (!wl->nvs) {
 		wl1271_error("could not allocate memory for the nvs file");
@@ -954,6 +1015,17 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 		if (ret < 0)
 			goto out;
 		break;
+	case CHIP_ID_1283_PG20:
+		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
+			     wl->chip.id);
+
+		ret = wl1271_setup(wl);
+		if (ret < 0)
+			goto out;
+		if (wl1271_set_block_size(wl))
+			wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
+		break;
+	case CHIP_ID_1283_PG10:
 	default:
 		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
 		ret = -ENODEV;
@@ -978,6 +1050,24 @@ out:
 	return ret;
 }
 
+static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
+{
+	unsigned int quirks = 0;
+	unsigned int *fw_ver = wl->chip.fw_ver;
+
+	/* Only for wl127x */
+	if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
+	    /* Check STA version */
+	    (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
+	      (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
+	     /* Check AP version */
+	     ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
+	      (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
+		quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
+
+	return quirks;
+}
+
 int wl1271_plt_start(struct wl1271 *wl)
 {
 	int retries = WL1271_BOOT_RETRIES;
@@ -1013,6 +1103,9 @@ int wl1271_plt_start(struct wl1271 *wl)
 		wl->state = WL1271_STATE_PLT;
 		wl1271_notice("firmware booted in PLT mode (%s)",
 			      wl->chip.fw_ver_str);
+
+		/* Check if any quirks are needed with older fw versions */
+		wl->quirks |= wl1271_get_fw_ver_quirks(wl);
 		goto out;
 
 irq_disable:
@@ -1040,7 +1133,7 @@ out:
 	return ret;
 }
 
-int __wl1271_plt_stop(struct wl1271 *wl)
+static int __wl1271_plt_stop(struct wl1271 *wl)
 {
 	int ret = 0;
 
@@ -1124,6 +1217,69 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 
+int wl1271_tx_dummy_packet(struct wl1271 *wl)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->wl_lock, flags);
+	set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
+	wl->tx_queue_count++;
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+	/* The FW is low on RX memory blocks, so send the dummy packet asap */
+	if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
+		wl1271_tx_work_locked(wl);
+
+	/*
+	 * If the FW TX is busy, TX work will be scheduled by the threaded
+	 * interrupt handler function
+	 */
+	return 0;
+}
+
+/*
+ * The size of the dummy packet should be at least 1400 bytes. However, in
+ * order to minimize the number of bus transactions, aligning it to 512 bytes
+ * boundaries could be beneficial, performance wise
+ */
+#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
+
+static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
+{
+	struct sk_buff *skb;
+	struct ieee80211_hdr_3addr *hdr;
+	unsigned int dummy_packet_size;
+
+	dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
+			    sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
+
+	skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
+	if (!skb) {
+		wl1271_warning("Failed to allocate a dummy packet skb");
+		return NULL;
+	}
+
+	skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
+
+	hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
+	memset(hdr, 0, sizeof(*hdr));
+	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+					 IEEE80211_STYPE_NULLFUNC |
+					 IEEE80211_FCTL_TODS);
+
+	memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
+
+	/* Dummy packets require the TID to be management */
+	skb->priority = WL1271_TID_MGMT;
+
+	/* Initialize all fields that might be used */
+	skb->queue_mapping = 0;
+	memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
+
+	return skb;
+}
+
+
 static struct notifier_block wl1271_dev_notifier = {
 	.notifier_call = wl1271_dev_notify,
 };
@@ -1174,6 +1330,16 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 		goto out;
 	}
 
+	/*
+	 * in some very corner case HW recovery scenarios its possible to
+	 * get here before __wl1271_op_remove_interface is complete, so
+	 * opt out if that is the case.
+	 */
+	if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
 	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 		wl->bss_type = BSS_TYPE_STA_BSS;
@@ -1242,6 +1408,7 @@ power_off:
 
 	wl->vif = vif;
 	wl->state = WL1271_STATE_ON;
+	set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
 	wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
 
 	/* update hw/fw version info in wiphy struct */
@@ -1249,6 +1416,9 @@ power_off:
 	strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
 		sizeof(wiphy->fw_version));
 
+	/* Check if any quirks are needed with older fw versions */
+	wl->quirks |= wl1271_get_fw_ver_quirks(wl);
+
 	/*
 	 * Now we know if 11a is supported (info from the NVS), so disable
 	 * 11a channels if not supported
@@ -1262,8 +1432,10 @@ power_off:
 out:
 	mutex_unlock(&wl->mutex);
 
+	mutex_lock(&wl_list_mutex);
 	if (!ret)
 		list_add(&wl->list, &wl_list);
+	mutex_unlock(&wl_list_mutex);
 
 	return ret;
 }
@@ -1274,11 +1446,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
 
+	/* because of hardware recovery, we may get here twice */
+	if (wl->state != WL1271_STATE_ON)
+		return;
+
 	wl1271_info("down");
 
+	mutex_lock(&wl_list_mutex);
 	list_del(&wl->list);
-
-	WARN_ON(wl->state != WL1271_STATE_ON);
+	mutex_unlock(&wl_list_mutex);
 
 	/* enable dyn ps just in case (if left on due to fw crash etc) */
 	if (wl->bss_type == BSS_TYPE_STA_BSS)
@@ -1286,12 +1462,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
 
 	if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
 		wl->scan.state = WL1271_SCAN_STATE_IDLE;
-		kfree(wl->scan.scanned_ch);
-		wl->scan.scanned_ch = NULL;
+		memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
 		wl->scan.req = NULL;
 		ieee80211_scan_completed(wl->hw, true);
 	}
 
+	/*
+	 * this must be before the cancel_work calls below, so that the work
+	 * functions don't perform further work.
+	 */
 	wl->state = WL1271_STATE_OFF;
 
 	mutex_unlock(&wl->mutex);
@@ -1321,6 +1500,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
 	wl->psm_entry_retry = 0;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
 	wl->tx_blocks_available = 0;
+	wl->tx_allocated_blocks = 0;
 	wl->tx_results_count = 0;
 	wl->tx_packets_count = 0;
 	wl->tx_security_last_seq = 0;
@@ -1328,7 +1508,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
 	wl->time_offset = 0;
 	wl->session_counter = 0;
 	wl->rate_set = CONF_TX_RATE_MASK_BASIC;
-	wl->flags = 0;
 	wl->vif = NULL;
 	wl->filters = 0;
 	wl1271_free_ap_keys(wl);
@@ -1336,6 +1515,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
 	wl->ap_fw_ps_map = 0;
 	wl->ap_ps_map = 0;
 
+	/*
+	 * this is performed after the cancel_work calls and the associated
+	 * mutex_lock, so that wl1271_op_add_interface does not accidentally
+	 * get executed before all these vars have been reset.
+	 */
+	wl->flags = 0;
+
 	for (i = 0; i < NUM_TX_QUEUES; i++)
 		wl->tx_blocks_freed[i] = 0;
 
@@ -1368,7 +1554,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
 	cancel_work_sync(&wl->recovery_work);
 }
 
-static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
+void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
 {
 	wl1271_set_default_filters(wl);
 
@@ -1431,10 +1617,10 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
 	 * One of the side effects of the JOIN command is that is clears
 	 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
 	 * to a WPA/WPA2 access point will therefore kill the data-path.
-	 * Currently there is no supported scenario for JOIN during
-	 * association - if it becomes a supported scenario, the WPA/WPA2 keys
-	 * must be handled somehow.
-	 *
+	 * Currently the only valid scenario for JOIN during association
+	 * is on roaming, in which case we will also be given new keys.
+	 * Keep the below message for now, unless it starts bothering
+	 * users who really like to roam a lot :)
 	 */
 	if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
 		wl1271_info("JOIN while associated.");
@@ -1490,7 +1676,7 @@ static int wl1271_unjoin(struct wl1271 *wl)
 	clear_bit(WL1271_FLAG_JOINED, &wl->flags);
 	memset(wl->bssid, 0, ETH_ALEN);
 
-	/* stop filterting packets based on bssid */
+	/* stop filtering packets based on bssid */
 	wl1271_configure_filters(wl, FIF_OTHER_BSS);
 
 out:
@@ -1569,7 +1755,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 	mutex_lock(&wl->mutex);
 
 	if (unlikely(wl->state == WL1271_STATE_OFF)) {
-		ret = -EAGAIN;
+		/* we support configuring the channel and band while off */
+		if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+			wl->band = conf->channel->band;
+			wl->channel = channel;
+		}
+
 		goto out;
 	}
 
@@ -2650,32 +2841,31 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
 		conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
 		conf_tid->apsd_conf[0] = 0;
 		conf_tid->apsd_conf[1] = 0;
-	} else {
-		ret = wl1271_ps_elp_wakeup(wl);
-		if (ret < 0)
-			goto out;
+		goto out;
+	}
 
-		/*
-		 * the txop is confed in units of 32us by the mac80211,
-		 * we need us
-		 */
-		ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
-					params->cw_min, params->cw_max,
-					params->aifs, params->txop << 5);
-		if (ret < 0)
-			goto out_sleep;
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
 
-		ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
-					 CONF_CHANNEL_TYPE_EDCF,
-					 wl1271_tx_get_queue(queue),
-					 ps_scheme, CONF_ACK_POLICY_LEGACY,
-					 0, 0);
-		if (ret < 0)
-			goto out_sleep;
+	/*
+	 * the txop is confed in units of 32us by the mac80211,
+	 * we need us
+	 */
+	ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
+				params->cw_min, params->cw_max,
+				params->aifs, params->txop << 5);
+	if (ret < 0)
+		goto out_sleep;
+
+	ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
+				 CONF_CHANNEL_TYPE_EDCF,
+				 wl1271_tx_get_queue(queue),
+				 ps_scheme, CONF_ACK_POLICY_LEGACY,
+				 0, 0);
 
 out_sleep:
-		wl1271_ps_elp_sleep(wl);
-	}
+	wl1271_ps_elp_sleep(wl);
 
 out:
 	mutex_unlock(&wl->mutex);
@@ -2764,6 +2954,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
 	__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
 }
 
+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
+{
+	int id = hlid - WL1271_AP_STA_HLID_START;
+	return test_bit(id, wl->ap_hlid_map);
+}
+
 static int wl1271_op_sta_add(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif,
 			     struct ieee80211_sta *sta)
@@ -2847,10 +3043,11 @@ out:
 	return ret;
 }
 
-int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-			   enum ieee80211_ampdu_mlme_action action,
-			   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-			   u8 buf_size)
+static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif,
+				  enum ieee80211_ampdu_mlme_action action,
+				  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+				  u8 buf_size)
 {
 	struct wl1271 *wl = hw->priv;
 	int ret;
@@ -3003,7 +3200,8 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
 
 #ifdef CONFIG_WL12XX_HT
 #define WL12XX_HT_CAP { \
-	.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
+	.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
+	       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
 	.ht_supported = true, \
 	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
@@ -3207,8 +3405,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
 	unsigned long res;
 	int ret;
 
-	ret = strict_strtoul(buf, 10, &res);
-
+	ret = kstrtoul(buf, 10, &res);
 	if (ret < 0) {
 		wl1271_warning("incorrect value written to bt_coex_mode");
 		return count;
@@ -3273,7 +3470,11 @@ int wl1271_register_hw(struct wl1271 *wl)
 
 	ret = wl1271_fetch_nvs(wl);
 	if (ret == 0) {
-		u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
+		/* NOTE: The wl->nvs->nvs element must be first, in
+		 * order to simplify the casting, we assume it is at
+		 * the beginning of the wl->nvs structure.
+		 */
+		u8 *nvs_ptr = (u8 *)wl->nvs;
 
 		wl->mac_addr[0] = nvs_ptr[11];
 		wl->mac_addr[1] = nvs_ptr[10];
@@ -3341,7 +3542,6 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
 		IEEE80211_HW_HAS_RATE_CONTROL |
 		IEEE80211_HW_CONNECTION_MONITOR |
 		IEEE80211_HW_SUPPORTS_CQM_RSSI |
-		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		IEEE80211_HW_AP_LINK_PS;
 
 	wl->hw->wiphy->cipher_suites = cipher_suites;
@@ -3358,6 +3558,10 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
 	wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
 			sizeof(struct ieee80211_header);
 
+	/* make sure all our channels fit in the scanned_ch bitmask */
+	BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
+		     ARRAY_SIZE(wl1271_channels_5ghz) >
+		     WL1271_MAX_CHANNELS);
 	/*
 	 * We keep local copies of the band structs because we need to
 	 * modify them on a per-device basis.
@@ -3458,6 +3662,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 	wl->ap_ps_map = 0;
 	wl->ap_fw_ps_map = 0;
 	wl->quirks = 0;
+	wl->platform_quirks = 0;
 
 	memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
@@ -3478,11 +3683,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 		goto err_hw;
 	}
 
+	wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
+	if (!wl->dummy_packet) {
+		ret = -ENOMEM;
+		goto err_aggr;
+	}
+
 	/* Register platform device */
 	ret = platform_device_register(wl->plat_dev);
 	if (ret) {
 		wl1271_error("couldn't register platform device");
-		goto err_aggr;
+		goto err_dummy_packet;
 	}
 	dev_set_drvdata(&wl->plat_dev->dev, wl);
 
@@ -3508,6 +3719,9 @@ err_bt_coex_state:
 err_platform:
 	platform_device_unregister(wl->plat_dev);
 
+err_dummy_packet:
+	dev_kfree_skb(wl->dummy_packet);
+
 err_aggr:
 	free_pages((unsigned long)wl->aggr_buf, order);
 
@@ -3527,6 +3741,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
 int wl1271_free_hw(struct wl1271 *wl)
 {
 	platform_device_unregister(wl->plat_dev);
+	dev_kfree_skb(wl->dummy_packet);
 	free_pages((unsigned long)wl->aggr_buf,
 			get_order(WL1271_AGGR_BUFFER_SIZE));
 	kfree(wl->plat_dev);
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 971f13e792da0bf304c15f877ecdcb7d3c8bdf6a..b8deada5d0206203a3d8462253dcb185662d1927 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -149,9 +149,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
 	case STATION_ACTIVE_MODE:
 	default:
 		wl1271_debug(DEBUG_PSM, "leaving psm");
-		ret = wl1271_ps_elp_wakeup(wl);
-		if (ret < 0)
-			return ret;
 
 		/* disable beacon early termination */
 		ret = wl1271_acx_bet_enable(wl, false);
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index 990960771528e423773a03f6c31d1a9b1caa6a4d..440a4ee9cb4203196471d1f2e3fca3c8f6a663cd 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -207,6 +207,8 @@
 
 #define CHIP_ID_1271_PG10              (0x4030101)
 #define CHIP_ID_1271_PG20              (0x4030111)
+#define CHIP_ID_1283_PG10              (0x05030101)
+#define CHIP_ID_1283_PG20              (0x05030111)
 
 #define ENABLE                         (REGISTERS_BASE + 0x5450)
 
@@ -452,24 +454,11 @@
 #define HI_CFG_UART_TX_OUT_GPIO_14  0x00000200
 #define HI_CFG_UART_TX_OUT_GPIO_7   0x00000400
 
-/*
- * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile
- *       for platforms using active high interrupt level
- */
-#ifdef USE_ACTIVE_HIGH
 #define HI_CFG_DEF_VAL              \
 	(HI_CFG_UART_ENABLE |        \
 	HI_CFG_RST232_ENABLE |      \
 	HI_CFG_CLOCK_REQ_SELECT |   \
 	HI_CFG_HOST_INT_ENABLE)
-#else
-#define HI_CFG_DEF_VAL              \
-	(HI_CFG_UART_ENABLE |        \
-	HI_CFG_RST232_ENABLE |      \
-	HI_CFG_CLOCK_REQ_SELECT |   \
-	HI_CFG_HOST_INT_ENABLE)
-
-#endif
 
 #define REF_FREQ_19_2                       0
 #define REF_FREQ_26_0                       1
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 919b59f00301bd8133babbf2538e749c9dddd51b..2a581495d5c94f95b414ef165cb6bda1a183fb61 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -48,18 +48,14 @@ static void wl1271_rx_status(struct wl1271 *wl,
 			     struct ieee80211_rx_status *status,
 			     u8 beacon)
 {
-	enum ieee80211_band desc_band;
-
 	memset(status, 0, sizeof(struct ieee80211_rx_status));
 
-	status->band = wl->band;
-
 	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
-		desc_band = IEEE80211_BAND_2GHZ;
+		status->band = IEEE80211_BAND_2GHZ;
 	else
-		desc_band = IEEE80211_BAND_5GHZ;
+		status->band = IEEE80211_BAND_5GHZ;
 
-	status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band);
+	status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);
 
 #ifdef CONFIG_WL12XX_HT
 	/* 11n support */
@@ -76,7 +72,8 @@ static void wl1271_rx_status(struct wl1271 *wl,
 	 */
 	wl->noise = desc->rssi - (desc->snr >> 1);
 
-	status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band);
+	status->freq = ieee80211_channel_to_frequency(desc->channel,
+						      status->band);
 
 	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
 		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
@@ -163,18 +160,25 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 			break;
 		}
 
-		/*
-		 * Choose the block we want to read
-		 * For aggregated packets, only the first memory block should
-		 * be retrieved. The FW takes care of the rest.
-		 */
-		mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
-		wl->rx_mem_pool_addr.addr = (mem_block << 8) +
-			le32_to_cpu(wl_mem_map->packet_memory_pool_start);
-		wl->rx_mem_pool_addr.addr_extra =
-			wl->rx_mem_pool_addr.addr + 4;
-		wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
-				sizeof(wl->rx_mem_pool_addr), false);
+		if (wl->chip.id != CHIP_ID_1283_PG20) {
+			/*
+			 * Choose the block we want to read
+			 * For aggregated packets, only the first memory block
+			 * should be retrieved. The FW takes care of the rest.
+			 */
+			mem_block = wl1271_rx_get_mem_block(status,
+							    drv_rx_counter);
+
+			wl->rx_mem_pool_addr.addr = (mem_block << 8) +
+			   le32_to_cpu(wl_mem_map->packet_memory_pool_start);
+
+			wl->rx_mem_pool_addr.addr_extra =
+				wl->rx_mem_pool_addr.addr + 4;
+
+			wl1271_write(wl, WL1271_SLV_REG_DATA,
+				     &wl->rx_mem_pool_addr,
+				     sizeof(wl->rx_mem_pool_addr), false);
+		}
 
 		/* Read all available packets at once */
 		wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 420653a2859ce68c40ba8be0b93b80d624f48598..5d0544c8f3f584a052a4b3d957b3fecfe1ffc4dc 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -48,8 +48,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
 		goto out;
 
 	wl->scan.state = WL1271_SCAN_STATE_IDLE;
-	kfree(wl->scan.scanned_ch);
-	wl->scan.scanned_ch = NULL;
+	memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
 	wl->scan.req = NULL;
 	ieee80211_scan_completed(wl->hw, false);
 
@@ -87,7 +86,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
 
 		flags = req->channels[i]->flags;
 
-		if (!wl->scan.scanned_ch[i] &&
+		if (!test_bit(i, wl->scan.scanned_ch) &&
 		    !(flags & IEEE80211_CHAN_DISABLED) &&
 		    ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
 		    (req->channels[i]->band == band)) {
@@ -124,7 +123,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
 			memset(&channels[j].bssid_msb, 0xff, 2);
 
 			/* Mark the channels we already used */
-			wl->scan.scanned_ch[i] = true;
+			set_bit(i, wl->scan.scanned_ch);
 
 			j++;
 		}
@@ -291,6 +290,12 @@ void wl1271_scan_stm(struct wl1271 *wl)
 int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
 		struct cfg80211_scan_request *req)
 {
+	/*
+	 * cfg80211 should guarantee that we don't get more channels
+	 * than what we have registered.
+	 */
+	BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
+
 	if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
 		return -EBUSY;
 
@@ -304,10 +309,8 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
 	}
 
 	wl->scan.req = req;
+	memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
 
-	wl->scan.scanned_ch = kcalloc(req->n_channels,
-				      sizeof(*wl->scan.scanned_ch),
-				      GFP_KERNEL);
 	/* we assume failure so that timeout scenarios are handled correctly */
 	wl->scan.failed = true;
 	ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index b1c7d031c39163686050d624246190e22ee2e348..bcd4ad7ba90df55f7c9416e63ca56903695f27dd 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -51,6 +51,13 @@ static const struct sdio_device_id wl1271_devices[] = {
 };
 MODULE_DEVICE_TABLE(sdio, wl1271_devices);
 
+static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz)
+{
+	sdio_claim_host(wl->if_priv);
+	sdio_set_block_size(wl->if_priv, blksz);
+	sdio_release_host(wl->if_priv);
+}
+
 static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
 {
 	return wl->if_priv;
@@ -203,7 +210,8 @@ static struct wl1271_if_operations sdio_ops = {
 	.power		= wl1271_sdio_set_power,
 	.dev		= wl1271_sdio_wl_to_dev,
 	.enable_irq	= wl1271_sdio_enable_interrupts,
-	.disable_irq	= wl1271_sdio_disable_interrupts
+	.disable_irq	= wl1271_sdio_disable_interrupts,
+	.set_block_size = wl1271_sdio_set_block_size,
 };
 
 static int __devinit wl1271_probe(struct sdio_func *func,
@@ -212,6 +220,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	struct ieee80211_hw *hw;
 	const struct wl12xx_platform_data *wlan_data;
 	struct wl1271 *wl;
+	unsigned long irqflags;
 	int ret;
 
 	/* We are only able to handle the wlan function */
@@ -230,6 +239,9 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	/* Grab access to FN0 for ELP reg. */
 	func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
 
+	/* Use block mode for transferring over one block size of data */
+	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
 	wlan_data = wl12xx_get_platform_data();
 	if (IS_ERR(wlan_data)) {
 		ret = PTR_ERR(wlan_data);
@@ -239,9 +251,16 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 
 	wl->irq = wlan_data->irq;
 	wl->ref_clock = wlan_data->board_ref_clock;
+	wl->tcxo_clock = wlan_data->board_tcxo_clock;
+	wl->platform_quirks = wlan_data->platform_quirks;
+
+	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
+		irqflags = IRQF_TRIGGER_RISING;
+	else
+		irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
 
 	ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
-				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   irqflags,
 				   DRIVER_NAME, wl);
 	if (ret < 0) {
 		wl1271_error("request_irq() failed: %d", ret);
@@ -343,4 +362,6 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
 MODULE_FIRMWARE(WL1271_FW_NAME);
-MODULE_FIRMWARE(WL1271_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_AP_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c
index 9fcbd3dd8490fd18b1c71fd736e73b7a7c260087..f2891539287733c6354a5322460c4e4e159b8765 100644
--- a/drivers/net/wireless/wl12xx/sdio_test.c
+++ b/drivers/net/wireless/wl12xx/sdio_test.c
@@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
 	const struct firmware *fw;
 	int ret;
 
-	ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
+	if (wl->chip.id == CHIP_ID_1283_PG20)
+		ret = request_firmware(&fw, WL128X_FW_NAME,
+				       wl1271_wl_to_dev(wl));
+	else
+		ret = request_firmware(&fw, WL1271_FW_NAME,
+				       wl1271_wl_to_dev(wl));
 
 	if (ret < 0) {
 		wl1271_error("could not get firmware: %d", ret);
@@ -227,14 +232,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
 	const struct firmware *fw;
 	int ret;
 
-	ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
+	ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
 
 	if (ret < 0) {
 		wl1271_error("could not get nvs file: %d", ret);
 		return ret;
 	}
 
-	wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+	wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
 
 	if (!wl->nvs) {
 		wl1271_error("could not allocate memory for the nvs file");
@@ -288,6 +293,11 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 		wl1271_notice("chip id 0x%x (1271 PG20)",
 				wl->chip.id);
 		break;
+	case CHIP_ID_1283_PG20:
+		wl1271_notice("chip id 0x%x (1283 PG20)",
+				wl->chip.id);
+		break;
+	case CHIP_ID_1283_PG10:
 	default:
 		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
 		return -ENODEV;
@@ -407,6 +417,9 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	/* Grab access to FN0 for ELP reg. */
 	func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
 
+	/* Use block mode for transferring over one block size of data */
+	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
 	wlan_data = wl12xx_get_platform_data();
 	if (IS_ERR(wlan_data)) {
 		ret = PTR_ERR(wlan_data);
@@ -416,6 +429,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 
 	wl->irq = wlan_data->irq;
 	wl->ref_clock = wlan_data->board_ref_clock;
+	wl->tcxo_clock = wlan_data->board_tcxo_clock;
 
 	sdio_set_drvdata(func, wl_test);
 
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index ffc745b17f4d631f88a98d3531e2f69b6776e6a4..51662bb680197a5585335f231364718ce9b2d3e8 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -355,7 +355,8 @@ static struct wl1271_if_operations spi_ops = {
 	.power		= wl1271_spi_set_power,
 	.dev		= wl1271_spi_wl_to_dev,
 	.enable_irq	= wl1271_spi_enable_interrupts,
-	.disable_irq	= wl1271_spi_disable_interrupts
+	.disable_irq	= wl1271_spi_disable_interrupts,
+	.set_block_size = NULL,
 };
 
 static int __devinit wl1271_probe(struct spi_device *spi)
@@ -363,6 +364,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 	struct wl12xx_platform_data *pdata;
 	struct ieee80211_hw *hw;
 	struct wl1271 *wl;
+	unsigned long irqflags;
 	int ret;
 
 	pdata = spi->dev.platform_data;
@@ -400,6 +402,13 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 	}
 
 	wl->ref_clock = pdata->board_ref_clock;
+	wl->tcxo_clock = pdata->board_tcxo_clock;
+	wl->platform_quirks = pdata->platform_quirks;
+
+	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
+		irqflags = IRQF_TRIGGER_RISING;
+	else
+		irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
 
 	wl->irq = spi->irq;
 	if (wl->irq < 0) {
@@ -409,7 +418,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 	}
 
 	ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
-				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   irqflags,
 				   DRIVER_NAME, wl);
 	if (ret < 0) {
 		wl1271_error("request_irq() failed: %d", ret);
@@ -490,5 +499,7 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
 MODULE_FIRMWARE(WL1271_FW_NAME);
-MODULE_FIRMWARE(WL1271_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_AP_FW_NAME);
 MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c
index 6ec06a4a4c6dfdbe220f39bc4f910445901fbb22..da351d7cd1f29ff3772f53ac27c2faad561e560d 100644
--- a/drivers/net/wireless/wl12xx/testmode.c
+++ b/drivers/net/wireless/wl12xx/testmode.c
@@ -27,6 +27,7 @@
 
 #include "wl12xx.h"
 #include "acx.h"
+#include "reg.h"
 
 #define WL1271_TM_MAX_DATA_LENGTH 1024
 
@@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
 
 	kfree(wl->nvs);
 
-	if (len != sizeof(struct wl1271_nvs_file))
+	if ((wl->chip.id == CHIP_ID_1283_PG20) &&
+	    (len != sizeof(struct wl128x_nvs_file)))
+		return -EINVAL;
+	else if (len != sizeof(struct wl1271_nvs_file))
 		return -EINVAL;
 
 	wl->nvs = kzalloc(len, GFP_KERNEL);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 5e9ef7d53e7eeb5958aafc63467228ef6a0368cb..7a3339fd34158a8ebad55906ba9a03ff43ead2b1 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -70,6 +70,28 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
 	}
 }
 
+static int wl1271_tx_update_filters(struct wl1271 *wl,
+						 struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr;
+
+	hdr = (struct ieee80211_hdr *)(skb->data +
+				       sizeof(struct wl1271_tx_hw_descr));
+
+	/*
+	 * stop bssid-based filtering before transmitting authentication
+	 * requests. this way the hw will never drop authentication
+	 * responses coming from BSSIDs it isn't familiar with (e.g. on
+	 * roaming)
+	 */
+	if (!ieee80211_is_auth(hdr->frame_control))
+		return 0;
+
+	wl1271_configure_filters(wl, FIF_OTHER_BSS);
+
+	return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+}
+
 static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
 						 struct sk_buff *skb)
 {
@@ -127,13 +149,29 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb)
 	}
 }
 
+static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
+						unsigned int packet_length)
+{
+	if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
+		return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
+	else
+		return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
+}
+
 static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
 				u32 buf_offset, u8 hlid)
 {
 	struct wl1271_tx_hw_descr *desc;
 	u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
+	u32 len;
 	u32 total_blocks;
 	int id, ret = -EBUSY;
+	u32 spare_blocks;
+
+	if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
+		spare_blocks = 2;
+	else
+		spare_blocks = 1;
 
 	if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
 		return -EAGAIN;
@@ -145,17 +183,27 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
 
 	/* approximate the number of blocks required for this packet
 	   in the firmware */
-	total_blocks = total_len + TX_HW_BLOCK_SIZE - 1;
-	total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE;
+	len = wl12xx_calc_packet_alignment(wl, total_len);
+
+	total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
+		spare_blocks;
+
 	if (total_blocks <= wl->tx_blocks_available) {
 		desc = (struct wl1271_tx_hw_descr *)skb_push(
 			skb, total_len - skb->len);
 
-		desc->extra_mem_blocks = TX_HW_BLOCK_SPARE;
-		desc->total_mem_blocks = total_blocks;
+		/* HW descriptor fields change between wl127x and wl128x */
+		if (wl->chip.id == CHIP_ID_1283_PG20) {
+			desc->wl128x_mem.total_mem_blocks = total_blocks;
+		} else {
+			desc->wl127x_mem.extra_blocks = spare_blocks;
+			desc->wl127x_mem.total_mem_blocks = total_blocks;
+		}
+
 		desc->id = id;
 
 		wl->tx_blocks_available -= total_blocks;
+		wl->tx_allocated_blocks += total_blocks;
 
 		if (wl->bss_type == BSS_TYPE_AP_BSS)
 			wl->links[hlid].allocated_blks += total_blocks;
@@ -172,13 +220,18 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
 	return ret;
 }
 
+static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
+{
+	return wl->dummy_packet == skb;
+}
+
 static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
 			      u32 extra, struct ieee80211_tx_info *control,
 			      u8 hlid)
 {
 	struct timespec ts;
 	struct wl1271_tx_hw_descr *desc;
-	int pad, ac, rate_idx;
+	int aligned_len, ac, rate_idx;
 	s64 hosttime;
 	u16 tx_attr;
 
@@ -202,12 +255,25 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
 	else
 		desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
 
-	/* configure the tx attributes */
-	tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
-
-	/* queue (we use same identifiers for tid's and ac's */
+	/* queue */
 	ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
-	desc->tid = ac;
+	desc->tid = skb->priority;
+
+	if (wl12xx_is_dummy_packet(wl, skb)) {
+		/*
+		 * FW expects the dummy packet to have an invalid session id -
+		 * any session id that is different than the one set in the join
+		 */
+		tx_attr = ((~wl->session_counter) <<
+			   TX_HW_ATTR_OFST_SESSION_COUNTER) &
+			   TX_HW_ATTR_SESSION_COUNTER;
+
+		tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
+	} else {
+		/* configure the tx attributes */
+		tx_attr =
+			wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+	}
 
 	if (wl->bss_type != BSS_TYPE_AP_BSS) {
 		desc->aid = hlid;
@@ -237,20 +303,37 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
 	tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
 	desc->reserved = 0;
 
-	/* align the length (and store in terms of words) */
-	pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO);
-	desc->length = cpu_to_le16(pad >> 2);
+	aligned_len = wl12xx_calc_packet_alignment(wl, skb->len);
 
-	/* calculate number of padding bytes */
-	pad = pad - skb->len;
-	tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+	if (wl->chip.id == CHIP_ID_1283_PG20) {
+		desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
+		desc->length = cpu_to_le16(aligned_len >> 2);
 
-	desc->tx_attr = cpu_to_le16(tx_attr);
+		wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
+			     "tx_attr: 0x%x len: %d life: %d mem: %d",
+			     desc->hlid, tx_attr,
+			     le16_to_cpu(desc->length),
+			     le16_to_cpu(desc->life_time),
+			     desc->wl128x_mem.total_mem_blocks);
+	} else {
+		int pad;
+
+		/* Store the aligned length in terms of words */
+		desc->length = cpu_to_le16(aligned_len >> 2);
+
+		/* calculate number of padding bytes */
+		pad = aligned_len - skb->len;
+		tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
 
-	wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
-		"tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid,
-		le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length),
-		le16_to_cpu(desc->life_time), desc->total_mem_blocks);
+		wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
+			     "tx_attr: 0x%x len: %d life: %d mem: %d", pad,
+			     desc->hlid, tx_attr,
+			     le16_to_cpu(desc->length),
+			     le16_to_cpu(desc->life_time),
+			     desc->wl127x_mem.total_mem_blocks);
+	}
+
+	desc->tx_attr = cpu_to_le16(tx_attr);
 }
 
 /* caller must hold wl->mutex */
@@ -300,19 +383,29 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
 	if (wl->bss_type == BSS_TYPE_AP_BSS) {
 		wl1271_tx_ap_update_inconnection_sta(wl, skb);
 		wl1271_tx_regulate_link(wl, hlid);
+	} else {
+		wl1271_tx_update_filters(wl, skb);
 	}
 
 	wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
 
 	/*
-	 * The length of each packet is stored in terms of words. Thus, we must
-	 * pad the skb data to make sure its length is aligned.
-	 * The number of padding bytes is computed and set in wl1271_tx_fill_hdr
+	 * The length of each packet is stored in terms of
+	 * words. Thus, we must pad the skb data to make sure its
+	 * length is aligned.  The number of padding bytes is computed
+	 * and set in wl1271_tx_fill_hdr.
+	 * In special cases, we want to align to a specific block size
+	 * (eg. for wl128x with SDIO we align to 256).
 	 */
-	total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO);
+	total_len = wl12xx_calc_packet_alignment(wl, skb->len);
+
 	memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
 	memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
 
+	/* Revert side effects in the dummy packet skb, so it can be reused */
+	if (wl12xx_is_dummy_packet(wl, skb))
+		skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+
 	return total_len;
 }
 
@@ -425,10 +518,23 @@ out:
 
 static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
 {
+	unsigned long flags;
+	struct sk_buff *skb = NULL;
+
 	if (wl->bss_type == BSS_TYPE_AP_BSS)
-		return wl1271_ap_skb_dequeue(wl);
+		skb = wl1271_ap_skb_dequeue(wl);
+	else
+		skb = wl1271_sta_skb_dequeue(wl);
+
+	if (!skb &&
+	    test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
+		skb = wl->dummy_packet;
+		spin_lock_irqsave(&wl->wl_lock, flags);
+		wl->tx_queue_count--;
+		spin_unlock_irqrestore(&wl->wl_lock, flags);
+	}
 
-	return wl1271_sta_skb_dequeue(wl);
+	return skb;
 }
 
 static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
@@ -436,7 +542,9 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
 	unsigned long flags;
 	int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
 
-	if (wl->bss_type == BSS_TYPE_AP_BSS) {
+	if (wl12xx_is_dummy_packet(wl, skb)) {
+		set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
+	} else if (wl->bss_type == BSS_TYPE_AP_BSS) {
 		u8 hlid = wl1271_tx_get_hlid(skb);
 		skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
 
@@ -454,22 +562,14 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
 void wl1271_tx_work_locked(struct wl1271 *wl)
 {
 	struct sk_buff *skb;
-	bool woken_up = false;
 	u32 buf_offset = 0;
 	bool sent_packets = false;
 	int ret;
 
 	if (unlikely(wl->state == WL1271_STATE_OFF))
-		goto out;
+		return;
 
 	while ((skb = wl1271_skb_dequeue(wl))) {
-		if (!woken_up) {
-			ret = wl1271_ps_elp_wakeup(wl);
-			if (ret < 0)
-				goto out_ack;
-			woken_up = true;
-		}
-
 		ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
 		if (ret == -EAGAIN) {
 			/*
@@ -516,18 +616,22 @@ out_ack:
 
 		wl1271_handle_tx_low_watermark(wl);
 	}
-
-out:
-	if (woken_up)
-		wl1271_ps_elp_sleep(wl);
 }
 
 void wl1271_tx_work(struct work_struct *work)
 {
 	struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
+	int ret;
 
 	mutex_lock(&wl->mutex);
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
 	wl1271_tx_work_locked(wl);
+
+	wl1271_ps_elp_wakeup(wl);
+out:
 	mutex_unlock(&wl->mutex);
 }
 
@@ -549,6 +653,11 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 	skb = wl->tx_frames[id];
 	info = IEEE80211_SKB_CB(skb);
 
+	if (wl12xx_is_dummy_packet(wl, skb)) {
+		wl1271_free_tx_id(wl, id);
+		return;
+	}
+
 	/* update the TX status info */
 	if (result->status == TX_SUCCESS) {
 		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
@@ -678,10 +787,13 @@ void wl1271_tx_reset(struct wl1271 *wl)
 			while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
 				wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
 					     skb);
-				info = IEEE80211_SKB_CB(skb);
-				info->status.rates[0].idx = -1;
-				info->status.rates[0].count = 0;
-				ieee80211_tx_status(wl->hw, skb);
+
+				if (!wl12xx_is_dummy_packet(wl, skb)) {
+					info = IEEE80211_SKB_CB(skb);
+					info->status.rates[0].idx = -1;
+					info->status.rates[0].count = 0;
+					ieee80211_tx_status(wl->hw, skb);
+				}
 			}
 		}
 	}
@@ -702,21 +814,27 @@ void wl1271_tx_reset(struct wl1271 *wl)
 		wl1271_free_tx_id(wl, i);
 		wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
 
-		/* Remove private headers before passing the skb to mac80211 */
-		info = IEEE80211_SKB_CB(skb);
-		skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
-		if (info->control.hw_key &&
-		    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-			int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-			memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data,
-				hdrlen);
-			skb_pull(skb, WL1271_TKIP_IV_SPACE);
-		}
+		if (!wl12xx_is_dummy_packet(wl, skb)) {
+			/*
+			 * Remove private headers before passing the skb to
+			 * mac80211
+			 */
+			info = IEEE80211_SKB_CB(skb);
+			skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+			if (info->control.hw_key &&
+			    info->control.hw_key->cipher ==
+			    WLAN_CIPHER_SUITE_TKIP) {
+				int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+				memmove(skb->data + WL1271_TKIP_IV_SPACE,
+					skb->data, hdrlen);
+				skb_pull(skb, WL1271_TKIP_IV_SPACE);
+			}
 
-		info->status.rates[0].idx = -1;
-		info->status.rates[0].count = 0;
+			info->status.rates[0].idx = -1;
+			info->status.rates[0].count = 0;
 
-		ieee80211_tx_status(wl->hw, skb);
+			ieee80211_tx_status(wl->hw, skb);
+		}
 	}
 }
 
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 02f07fa66e820f12c0c8790f7ee34f42a2b10a71..fc7835c4cf6398bfb55be0ae01a0662aaf07111d 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -25,7 +25,6 @@
 #ifndef __TX_H__
 #define __TX_H__
 
-#define TX_HW_BLOCK_SPARE                2
 #define TX_HW_BLOCK_SIZE                 252
 
 #define TX_HW_MGMT_PKT_LIFETIME_TU       2000
@@ -41,6 +40,7 @@
 					  BIT(8) | BIT(9))
 #define TX_HW_ATTR_LAST_WORD_PAD         (BIT(10) | BIT(11))
 #define TX_HW_ATTR_TX_CMPLT_REQ          BIT(12)
+#define TX_HW_ATTR_TX_DUMMY_REQ          BIT(13)
 
 #define TX_HW_ATTR_OFST_SAVE_RETRIES     0
 #define TX_HW_ATTR_OFST_HEADER_PAD       1
@@ -55,20 +55,60 @@
 #define WL1271_TX_ALIGN_TO 4
 #define WL1271_TKIP_IV_SPACE 4
 
+/* Used for management frames and dummy packets */
+#define WL1271_TID_MGMT 7
+
+struct wl127x_tx_mem {
+	/*
+	 * Number of extra memory blocks to allocate for this packet
+	 * in addition to the number of blocks derived from the packet
+	 * length.
+	 */
+	u8 extra_blocks;
+	/*
+	 * Total number of memory blocks allocated by the host for
+	 * this packet. Must be equal or greater than the actual
+	 * blocks number allocated by HW.
+	 */
+	u8 total_mem_blocks;
+} __packed;
+
+struct wl128x_tx_mem {
+	/*
+	 * Total number of memory blocks allocated by the host for
+	 * this packet.
+	 */
+	u8 total_mem_blocks;
+	/*
+	 * Number of extra bytes, at the end of the frame. the host
+	 * uses this padding to complete each frame to integer number
+	 * of SDIO blocks.
+	 */
+	u8 extra_bytes;
+} __packed;
+
+/*
+ * On wl128x based devices, when TX packets are aggregated, each packet
+ * size must be aligned to the SDIO block size. The maximum block size
+ * is bounded by the type of the padded bytes field that is sent to the
+ * FW. Currently the type is u8, so the maximum block size is 256 bytes.
+ */
+#define WL12XX_BUS_BLOCK_SIZE min(512u,	\
+	    (1u << (8 * sizeof(((struct wl128x_tx_mem *) 0)->extra_bytes))))
+
 struct wl1271_tx_hw_descr {
 	/* Length of packet in words, including descriptor+header+data */
 	__le16 length;
-	/* Number of extra memory blocks to allocate for this packet in
-	   addition to the number of blocks derived from the packet length */
-	u8 extra_mem_blocks;
-	/* Total number of memory blocks allocated by the host for this packet.
-	   Must be equal or greater than the actual blocks number allocated by
-	   HW!! */
-	u8 total_mem_blocks;
+	union {
+		struct wl127x_tx_mem wl127x_mem;
+		struct wl128x_tx_mem wl128x_mem;
+	} __packed;
 	/* Device time (in us) when the packet arrived to the driver */
 	__le32 start_time;
-	/* Max delay in TUs until transmission. The last device time the
-	   packet can be transmitted is: startTime+(1024*LifeTime) */
+	/*
+	 * Max delay in TUs until transmission. The last device time the
+	 * packet can be transmitted is: start_time + (1024 * life_time)
+	 */
 	__le16 life_time;
 	/* Bitwise fields - see TX_ATTR... definitions above. */
 	__le16 tx_attr;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 86be83e25ec556c0a8304250e7e4d70fcd990e8b..7c521af58e7d477787e86f712b9e1b5bb9d2578e 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -131,9 +131,16 @@ extern u32 wl12xx_debug_level;
 
 
 #define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin"
-#define WL1271_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
+#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin"
+#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
+#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin"
 
-#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
+/*
+ * wl127x and wl128x are using the same NVS file name. However, the
+ * ini parameters between them are different.  The driver validates
+ * the correct NVS size in wl1271_boot_upload_nvs().
+ */
+#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
 
 #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
 #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
@@ -165,7 +172,6 @@ extern u32 wl12xx_debug_level;
 #define WL1271_PS_STA_MAX_BLOCKS  (2 * 9)
 
 #define WL1271_AP_BSS_INDEX        0
-#define WL1271_AP_DEF_INACTIV_SEC  300
 #define WL1271_AP_DEF_BEACON_EXP   20
 
 #define ACX_TX_DESCRIPTORS         32
@@ -200,13 +206,29 @@ struct wl1271_partition_set {
 
 struct wl1271;
 
-#define WL12XX_NUM_FW_VER 5
+enum {
+	FW_VER_CHIP,
+	FW_VER_IF_TYPE,
+	FW_VER_MAJOR,
+	FW_VER_SUBTYPE,
+	FW_VER_MINOR,
+
+	NUM_FW_VER
+};
+
+#define FW_VER_CHIP_WL127X 6
+#define FW_VER_CHIP_WL128X 7
+
+#define FW_VER_IF_TYPE_STA 1
+#define FW_VER_IF_TYPE_AP  2
+
+#define FW_VER_MINOR_1_SPARE_STA_MIN 58
+#define FW_VER_MINOR_1_SPARE_AP_MIN  47
 
-/* FIXME: I'm not sure about this structure name */
 struct wl1271_chip {
 	u32 id;
 	char fw_ver_str[ETHTOOL_BUSINFO_LEN];
-	unsigned int fw_ver[WL12XX_NUM_FW_VER];
+	unsigned int fw_ver[NUM_FW_VER];
 };
 
 struct wl1271_stats {
@@ -261,6 +283,8 @@ struct wl1271_fw_sta_status {
 	u8  tx_total;
 	u8  reserved1;
 	__le16 reserved2;
+	/* Total structure size is 68 bytes */
+	u32 padding;
 } __packed;
 
 struct wl1271_fw_full_status {
@@ -277,9 +301,10 @@ struct wl1271_rx_mem_pool_addr {
 	u32 addr_extra;
 };
 
+#define WL1271_MAX_CHANNELS 64
 struct wl1271_scan {
 	struct cfg80211_scan_request *req;
-	bool *scanned_ch;
+	unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
 	bool failed;
 	u8 state;
 	u8 ssid[IW_ESSID_MAX_SIZE+1];
@@ -297,6 +322,7 @@ struct wl1271_if_operations {
 	struct device* (*dev)(struct wl1271 *wl);
 	void (*enable_irq)(struct wl1271 *wl);
 	void (*disable_irq)(struct wl1271 *wl);
+	void (*set_block_size) (struct wl1271 *wl, unsigned int blksz);
 };
 
 #define MAX_NUM_KEYS 14
@@ -327,7 +353,9 @@ enum wl12xx_flags {
 	WL1271_FLAG_PSPOLL_FAILURE,
 	WL1271_FLAG_STA_STATE_SENT,
 	WL1271_FLAG_FW_TX_BUSY,
-	WL1271_FLAG_AP_STARTED
+	WL1271_FLAG_AP_STARTED,
+	WL1271_FLAG_IF_INITIALIZED,
+	WL1271_FLAG_DUMMY_PACKET_PENDING,
 };
 
 struct wl1271_link {
@@ -371,7 +399,7 @@ struct wl1271 {
 	u8 *fw;
 	size_t fw_len;
 	u8 fw_bss_type;
-	struct wl1271_nvs_file *nvs;
+	void *nvs;
 	size_t nvs_len;
 
 	s8 hw_pg_ver;
@@ -389,6 +417,7 @@ struct wl1271 {
 	/* Accounting for allocated / available TX blocks on HW */
 	u32 tx_blocks_freed[NUM_TX_QUEUES];
 	u32 tx_blocks_available;
+	u32 tx_allocated_blocks;
 	u32 tx_results_count;
 
 	/* Transmitted TX packets counter for chipset interface */
@@ -430,6 +459,9 @@ struct wl1271 {
 	/* Intermediate buffer, used for packet aggregation */
 	u8 *aggr_buf;
 
+	/* Reusable dummy packet template */
+	struct sk_buff *dummy_packet;
+
 	/* Network stack work  */
 	struct work_struct netstack_work;
 
@@ -527,6 +559,8 @@ struct wl1271 {
 	bool ba_support;
 	u8 ba_rx_bitmap;
 
+	int tcxo_clock;
+
 	/*
 	 * AP-mode - links indexed by HLID. The global and broadcast links
 	 * are always active.
@@ -544,6 +578,9 @@ struct wl1271 {
 
 	/* Quirks of specific hardware revisions */
 	unsigned int quirks;
+
+	/* Platform limitations */
+	unsigned int platform_quirks;
 };
 
 struct wl1271_station {
@@ -576,6 +613,15 @@ int wl1271_plt_stop(struct wl1271 *wl);
 /* Quirks */
 
 /* Each RX/TX transaction requires an end-of-transaction transfer */
-#define WL12XX_QUIRK_END_OF_TRANSACTION	BIT(0)
+#define WL12XX_QUIRK_END_OF_TRANSACTION		BIT(0)
+
+/*
+ * Older firmwares use 2 spare TX blocks
+ * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47)
+ */
+#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS		BIT(1)
+
+/* WL128X requires aggregated packets to be aligned to the SDIO block size */
+#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT	BIT(2)
 
 #endif
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 7c031fdc8205eff8475ecbd11dc098f3beb0c584..06d15b6f2215694b1c380c3891c4bedbf726858e 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
 	if (!ccdev)
 		return;
 	bus = ccdev->bus;
+
+	/* We support SLOW only on 6..9 */
+	if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW)
+		mode = SSB_CLKMODE_DYNAMIC;
+
+	if (cc->capabilities & SSB_CHIPCO_CAP_PMU)
+		return; /* PMU controls clockmode, separated function needed */
+	SSB_WARN_ON(ccdev->id.revision >= 20);
+
 	/* chipcommon cores prior to rev6 don't support dynamic clock control */
 	if (ccdev->id.revision < 6)
 		return;
-	/* chipcommon cores rev10 are a whole new ball game */
+
+	/* ChipCommon cores rev10+ need testing */
 	if (ccdev->id.revision >= 10)
 		return;
+
 	if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
 		return;
 
 	switch (mode) {
-	case SSB_CLKMODE_SLOW:
+	case SSB_CLKMODE_SLOW: /* For revs 6..9 only */
 		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
 		tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW;
 		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
 		break;
 	case SSB_CLKMODE_FAST:
-		ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
-		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
-		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
-		tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
-		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+		if (ccdev->id.revision < 10) {
+			ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
+			tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+			tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
+			chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+		} else {
+			chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
+				(chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) |
+				 SSB_CHIPCO_SYSCLKCTL_FORCEHT));
+			/* udelay(150); TODO: not available in early init */
+		}
 		break;
 	case SSB_CLKMODE_DYNAMIC:
-		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
-		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
-		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
-		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
-		if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
-			tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
-		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
-
-		/* for dynamic control, we have to release our xtal_pu "force on" */
-		if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
-			ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
+		if (ccdev->id.revision < 10) {
+			tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
+			tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+			if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) !=
+			    SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
+				tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+			chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+
+			/* For dynamic control, we have to release our xtal_pu
+			 * "force on" */
+			if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
+				ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
+		} else {
+			chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
+				(chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
+				 ~SSB_CHIPCO_SYSCLKCTL_FORCEHT));
+		}
 		break;
 	default:
 		SSB_WARN_ON(1);
@@ -260,6 +286,12 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
 	if (cc->dev->id.revision >= 11)
 		cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
 	ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
+
+	if (cc->dev->id.revision >= 20) {
+		chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0);
+		chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0);
+	}
+
 	ssb_pmu_init(cc);
 	chipco_powercontrol_init(cc);
 	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 5732bb2c35787b5093d6b12a1d3fb7029bf59990..305ade7825f7e027ad706442face76f6ec91e0fc 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -423,6 +423,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
 
 	switch (bus->chip_id) {
 	case 0x4312:
+		 min_msk = 0xCBB;
+		 break;
 	case 0x4322:
 		/* We keep the default settings:
 		 * min_msk = 0xCBB
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 1ba9f0ee6f94978a1935e498d5e5d87ee6b1dafb..8fde1220bc89e1c11528ad9b8f5d68196f38c72e 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -21,6 +21,8 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address);
 static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
 				u8 address, u16 data);
 
+static void ssb_commit_settings(struct ssb_bus *bus);
+
 static inline
 u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
 {
@@ -412,6 +414,16 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
  * Workarounds.
  **************************************************/
 
+static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
+{
+	u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
+	if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
+		tmp &= ~0xF000;
+		tmp |= (pc->dev->core_index << 12);
+		pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp);
+	}
+}
+
 static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc)
 {
 	return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
@@ -430,6 +442,76 @@ static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc)
 		ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
 }
 
+static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc)
+{
+	struct ssb_device *pdev = pc->dev;
+	struct ssb_bus *bus = pdev->bus;
+	u32 tmp;
+
+	tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+	tmp |= SSB_PCICORE_SBTOPCI_PREF;
+	tmp |= SSB_PCICORE_SBTOPCI_BURST;
+	pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+
+	if (pdev->id.revision < 5) {
+		tmp = ssb_read32(pdev, SSB_IMCFGLO);
+		tmp &= ~SSB_IMCFGLO_SERTO;
+		tmp |= 2;
+		tmp &= ~SSB_IMCFGLO_REQTO;
+		tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
+		ssb_write32(pdev, SSB_IMCFGLO, tmp);
+		ssb_commit_settings(bus);
+	} else if (pdev->id.revision >= 11) {
+		tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+		tmp |= SSB_PCICORE_SBTOPCI_MRM;
+		pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+	}
+}
+
+static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc)
+{
+	u32 tmp;
+	u8 rev = pc->dev->id.revision;
+
+	if (rev == 0 || rev == 1) {
+		/* TLP Workaround register. */
+		tmp = ssb_pcie_read(pc, 0x4);
+		tmp |= 0x8;
+		ssb_pcie_write(pc, 0x4, tmp);
+	}
+	if (rev == 1) {
+		/* DLLP Link Control register. */
+		tmp = ssb_pcie_read(pc, 0x100);
+		tmp |= 0x40;
+		ssb_pcie_write(pc, 0x100, tmp);
+	}
+
+	if (rev == 0) {
+		const u8 serdes_rx_device = 0x1F;
+
+		ssb_pcie_mdio_write(pc, serdes_rx_device,
+					2 /* Timer */, 0x8128);
+		ssb_pcie_mdio_write(pc, serdes_rx_device,
+					6 /* CDR */, 0x0100);
+		ssb_pcie_mdio_write(pc, serdes_rx_device,
+					7 /* CDR BW */, 0x1466);
+	} else if (rev == 3 || rev == 4 || rev == 5) {
+		/* TODO: DLLP Power Management Threshold */
+		ssb_pcicore_serdes_workaround(pc);
+		/* TODO: ASPM */
+	} else if (rev == 7) {
+		/* TODO: No PLL down */
+	}
+
+	if (rev >= 6) {
+		/* Miscellaneous Configuration Fixup */
+		tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5));
+		if (!(tmp & 0x8000))
+			pcicore_write16(pc, SSB_PCICORE_SPROM(5),
+					tmp | 0x8000);
+	}
+}
+
 /**************************************************
  * Generic and Clientmode operation code.
  **************************************************/
@@ -449,6 +531,8 @@ void ssb_pcicore_init(struct ssb_pcicore *pc)
 	if (!ssb_device_is_enabled(dev))
 		ssb_device_enable(dev, 0);
 
+	ssb_pcicore_fix_sprom_core_index(pc);
+
 #ifdef CONFIG_SSB_PCICORE_HOSTMODE
 	pc->hostmode = pcicore_is_in_hostmode(pc);
 	if (pc->hostmode)
@@ -457,7 +541,10 @@ void ssb_pcicore_init(struct ssb_pcicore *pc)
 	if (!pc->hostmode)
 		ssb_pcicore_init_clientmode(pc);
 
+	/* Additional always once-executed workarounds */
 	ssb_pcicore_serdes_workaround(pc);
+	/* TODO: ASPM */
+	/* TODO: Clock Request Update */
 }
 
 static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
@@ -522,7 +609,7 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address)
 	pcicore_write32(pc, mdio_data, v);
 	/* Wait for the device to complete the transaction */
 	udelay(10);
-	for (i = 0; i < 200; i++) {
+	for (i = 0; i < max_retries; i++) {
 		v = pcicore_read32(pc, mdio_control);
 		if (v & 0x100 /* Trans complete */) {
 			udelay(10);
@@ -646,48 +733,10 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
 	if (pc->setup_done)
 		goto out;
 	if (pdev->id.coreid == SSB_DEV_PCI) {
-		tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
-		tmp |= SSB_PCICORE_SBTOPCI_PREF;
-		tmp |= SSB_PCICORE_SBTOPCI_BURST;
-		pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
-
-		if (pdev->id.revision < 5) {
-			tmp = ssb_read32(pdev, SSB_IMCFGLO);
-			tmp &= ~SSB_IMCFGLO_SERTO;
-			tmp |= 2;
-			tmp &= ~SSB_IMCFGLO_REQTO;
-			tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
-			ssb_write32(pdev, SSB_IMCFGLO, tmp);
-			ssb_commit_settings(bus);
-		} else if (pdev->id.revision >= 11) {
-			tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
-			tmp |= SSB_PCICORE_SBTOPCI_MRM;
-			pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
-		}
+		ssb_pcicore_pci_setup_workarounds(pc);
 	} else {
 		WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
-		//TODO: Better make defines for all these magic PCIE values.
-		if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
-			/* TLP Workaround register. */
-			tmp = ssb_pcie_read(pc, 0x4);
-			tmp |= 0x8;
-			ssb_pcie_write(pc, 0x4, tmp);
-		}
-		if (pdev->id.revision == 0) {
-			const u8 serdes_rx_device = 0x1F;
-
-			ssb_pcie_mdio_write(pc, serdes_rx_device,
-					    2 /* Timer */, 0x8128);
-			ssb_pcie_mdio_write(pc, serdes_rx_device,
-					    6 /* CDR */, 0x0100);
-			ssb_pcie_mdio_write(pc, serdes_rx_device,
-					    7 /* CDR BW */, 0x1466);
-		} else if (pdev->id.revision == 1) {
-			/* DLLP Link Control register. */
-			tmp = ssb_pcie_read(pc, 0x100);
-			tmp |= 0x40;
-			ssb_pcie_write(pc, 0x100, tmp);
-		}
+		ssb_pcicore_pcie_setup_workarounds(pc);
 	}
 	pc->setup_done = 1;
 out:
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index e05ba6eefc7e7d148fe94db458e2055bf342b9dc..ad3da93a428ca92cdc6c158c47e6fa8c3d7f9844 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -1117,23 +1117,22 @@ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
 {
 	u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
 
-	/* The REJECT bit changed position in TMSLOW between
-	 * Backplane revisions. */
+	/* The REJECT bit seems to be different for Backplane rev 2.3 */
 	switch (rev) {
 	case SSB_IDLOW_SSBREV_22:
-		return SSB_TMSLOW_REJECT_22;
+	case SSB_IDLOW_SSBREV_24:
+	case SSB_IDLOW_SSBREV_26:
+		return SSB_TMSLOW_REJECT;
 	case SSB_IDLOW_SSBREV_23:
 		return SSB_TMSLOW_REJECT_23;
-	case SSB_IDLOW_SSBREV_24:     /* TODO - find the proper REJECT bits */
-	case SSB_IDLOW_SSBREV_25:     /* same here */
-	case SSB_IDLOW_SSBREV_26:     /* same here */
+	case SSB_IDLOW_SSBREV_25:     /* TODO - find the proper REJECT bit */
 	case SSB_IDLOW_SSBREV_27:     /* same here */
-		return SSB_TMSLOW_REJECT_23;	/* this is a guess */
+		return SSB_TMSLOW_REJECT;	/* this is a guess */
 	default:
 		printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
 		WARN_ON(1);
 	}
-	return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
+	return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
 }
 
 int ssb_device_is_enabled(struct ssb_device *dev)
@@ -1309,20 +1308,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
 
 int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
 {
-	struct ssb_chipcommon *cc;
 	int err;
 	enum ssb_clkmode mode;
 
 	err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
 	if (err)
 		goto error;
-	cc = &bus->chipco;
-	mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
-	ssb_chipco_set_clockmode(cc, mode);
 
 #ifdef CONFIG_SSB_DEBUG
 	bus->powered_up = 1;
 #endif
+
+	mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
+	ssb_chipco_set_clockmode(&bus->chipco, mode);
+
 	return 0;
 error:
 	ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h
index 020387a114e34b738ae519c1391c1e7276ee24e8..60a7c49dcb49f8f3b526a2234e109b1c5d822edb 100644
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
@@ -28,6 +28,8 @@ struct ath9k_platform_data {
 	int led_pin;
 	u32 gpio_mask;
 	u32 gpio_val;
+
+	bool is_clk_25mhz;
 };
 
 #endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index 2cdf249b4e5f0627980e4140bf96170cb8546ad0..a08d693d832461fe84805e372776dc98bf8cbb9b 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -123,6 +123,8 @@
 #define SSB_CHIPCO_FLASHDATA		0x0048
 #define SSB_CHIPCO_BCAST_ADDR		0x0050
 #define SSB_CHIPCO_BCAST_DATA		0x0054
+#define SSB_CHIPCO_GPIOPULLUP		0x0058		/* Rev >= 20 only */
+#define SSB_CHIPCO_GPIOPULLDOWN		0x005C		/* Rev >= 20 only */
 #define SSB_CHIPCO_GPIOIN		0x0060
 #define SSB_CHIPCO_GPIOOUT		0x0064
 #define SSB_CHIPCO_GPIOOUTEN		0x0068
@@ -131,6 +133,9 @@
 #define SSB_CHIPCO_GPIOIRQ		0x0074
 #define SSB_CHIPCO_WATCHDOG		0x0080
 #define SSB_CHIPCO_GPIOTIMER		0x0088		/* LED powersave (corerev >= 16) */
+#define  SSB_CHIPCO_GPIOTIMER_OFFTIME	0x0000FFFF
+#define  SSB_CHIPCO_GPIOTIMER_OFFTIME_SHIFT	0
+#define  SSB_CHIPCO_GPIOTIMER_ONTIME	0xFFFF0000
 #define  SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT	16
 #define SSB_CHIPCO_GPIOTOUTM		0x008C		/* LED powersave (corerev >= 16) */
 #define SSB_CHIPCO_CLOCK_N		0x0090
@@ -189,8 +194,10 @@
 #define  SSB_CHIPCO_CLKCTLST_HAVEALPREQ	0x00000008 /* ALP available request */
 #define  SSB_CHIPCO_CLKCTLST_HAVEHTREQ	0x00000010 /* HT available request */
 #define  SSB_CHIPCO_CLKCTLST_HWCROFF	0x00000020 /* Force HW clock request off */
-#define  SSB_CHIPCO_CLKCTLST_HAVEHT	0x00010000 /* HT available */
-#define  SSB_CHIPCO_CLKCTLST_HAVEALP	0x00020000 /* APL available */
+#define  SSB_CHIPCO_CLKCTLST_HAVEALP	0x00010000 /* ALP available */
+#define  SSB_CHIPCO_CLKCTLST_HAVEHT	0x00020000 /* HT available */
+#define  SSB_CHIPCO_CLKCTLST_4328A0_HAVEHT	0x00010000 /* 4328a0 has reversed bits */
+#define  SSB_CHIPCO_CLKCTLST_4328A0_HAVEALP	0x00020000 /* 4328a0 has reversed bits */
 #define SSB_CHIPCO_HW_WORKAROUND	0x01E4 /* Hardware workaround (rev >= 20) */
 #define SSB_CHIPCO_UART0_DATA		0x0300
 #define SSB_CHIPCO_UART0_IMR		0x0304
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index 402955ae48ceac9c118833bed28ca093407e4638..efbf459d571c03eed928edd5f2fda9fc6f835019 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -97,7 +97,7 @@
 #define  SSB_INTVEC_ENET1	0x00000040 /* Enable interrupts for enet 1 */
 #define SSB_TMSLOW		0x0F98     /* SB Target State Low */
 #define  SSB_TMSLOW_RESET	0x00000001 /* Reset */
-#define  SSB_TMSLOW_REJECT_22	0x00000002 /* Reject (Backplane rev 2.2) */
+#define  SSB_TMSLOW_REJECT	0x00000002 /* Reject (Standard Backplane) */
 #define  SSB_TMSLOW_REJECT_23	0x00000004 /* Reject (Backplane rev 2.3) */
 #define  SSB_TMSLOW_CLOCK	0x00010000 /* Clock Enable */
 #define  SSB_TMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h
index bebb8efea0a66fd67bd19600bc08d1ad8d235d8a..4b697395326eb4e660a099faf352a91c0c8df915 100644
--- a/include/linux/wl12xx.h
+++ b/include/linux/wl12xx.h
@@ -24,12 +24,26 @@
 #ifndef _LINUX_WL12XX_H
 #define _LINUX_WL12XX_H
 
-/* The board reference clock values */
+/* Reference clock values */
 enum {
-	WL12XX_REFCLOCK_19 = 0,	/* 19.2 MHz */
-	WL12XX_REFCLOCK_26 = 1,	/* 26 MHz */
-	WL12XX_REFCLOCK_38 = 2,	/* 38.4 MHz */
-	WL12XX_REFCLOCK_54 = 3,	/* 54 MHz */
+	WL12XX_REFCLOCK_19	= 0, /* 19.2 MHz */
+	WL12XX_REFCLOCK_26	= 1, /* 26 MHz */
+	WL12XX_REFCLOCK_38	= 2, /* 38.4 MHz */
+	WL12XX_REFCLOCK_52	= 3, /* 52 MHz */
+	WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */
+	WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */
+};
+
+/* TCXO clock values */
+enum {
+	WL12XX_TCXOCLOCK_19_2	= 0, /* 19.2MHz */
+	WL12XX_TCXOCLOCK_26	= 1, /* 26 MHz */
+	WL12XX_TCXOCLOCK_38_4	= 2, /* 38.4MHz */
+	WL12XX_TCXOCLOCK_52	= 3, /* 52 MHz */
+	WL12XX_TCXOCLOCK_16_368	= 4, /* 16.368 MHz */
+	WL12XX_TCXOCLOCK_32_736	= 5, /* 32.736 MHz */
+	WL12XX_TCXOCLOCK_16_8	= 6, /* 16.8 MHz */
+	WL12XX_TCXOCLOCK_33_6	= 7, /* 33.6 MHz */
 };
 
 struct wl12xx_platform_data {
@@ -38,8 +52,13 @@ struct wl12xx_platform_data {
 	int irq;
 	bool use_eeprom;
 	int board_ref_clock;
+	int board_tcxo_clock;
+	unsigned long platform_quirks;
 };
 
+/* Platform does not support level trigger interrupts */
+#define WL12XX_PLATFORM_QUIRK_EDGE_IRQ	BIT(0)
+
 #ifdef CONFIG_WL12XX_PLATFORM_DATA
 
 int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 499b7b7c7c9a22aee553126120c03762e3ff16c2..0c20227e57f60af002eaa54c58ef6cd9dc9a8775 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -246,6 +246,15 @@ enum {
 #define HCI_AT_GENERAL_BONDING		0x04
 #define HCI_AT_GENERAL_BONDING_MITM	0x05
 
+/* Link Key types */
+#define HCI_LK_COMBINATION		0x00
+#define HCI_LK_LOCAL_UNIT		0x01
+#define HCI_LK_REMOTE_UNIT		0x02
+#define HCI_LK_DEBUG_COMBINATION	0x03
+#define HCI_LK_UNAUTH_COMBINATION	0x04
+#define HCI_LK_AUTH_COMBINATION		0x05
+#define HCI_LK_CHANGED_COMBINATION	0x06
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP			0x0000
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4093133c1283f28285559fd674773ae9336620ce..14cc3249c1eb04725f7820c32a5dae0c2565b317 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -126,6 +126,8 @@ struct hci_dev {
 	__u16		sniff_min_interval;
 	__u16		sniff_max_interval;
 
+	unsigned int	auto_accept_delay;
+
 	unsigned long	quirks;
 
 	atomic_t	cmd_cnt;
@@ -226,6 +228,7 @@ struct hci_conn {
 	__u16		pkt_type;
 	__u16		link_policy;
 	__u32		link_mode;
+	__u8		key_type;
 	__u8		auth_type;
 	__u8		sec_level;
 	__u8		pending_sec_level;
@@ -245,6 +248,7 @@ struct hci_conn {
 
 	struct timer_list disc_timer;
 	struct timer_list idle_timer;
+	struct timer_list auto_accept_timer;
 
 	struct work_struct work_add;
 	struct work_struct work_del;
@@ -511,8 +515,8 @@ int hci_uuids_clear(struct hci_dev *hdev);
 
 int hci_link_keys_clear(struct hci_dev *hdev);
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
-						u8 *key, u8 type, u8 pin_len);
+int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
+			bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 int hci_remote_oob_data_clear(struct hci_dev *hdev);
@@ -771,15 +775,16 @@ int mgmt_index_removed(u16 index);
 int mgmt_powered(u16 index, u8 powered);
 int mgmt_discoverable(u16 index, u8 discoverable);
 int mgmt_connectable(u16 index, u8 connectable);
-int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type);
+int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
 int mgmt_connected(u16 index, bdaddr_t *bdaddr);
 int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
 int mgmt_disconnect_failed(u16 index);
 int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
+int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
 int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
 int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value);
+int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
+							u8 confirm_hint);
 int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
 int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
 								u8 status);
@@ -790,6 +795,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
 int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
 								u8 *eir);
 int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
+int mgmt_discovering(u16 index, u8 discovering);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 7a215a7f9e391c3d9ef72651d3bb76a4c2f08309..c34b1c126363cc4c1ae4f88e32ec634f015d13ec 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -284,6 +284,25 @@ struct srej_list {
 
 struct l2cap_chan {
 	struct sock *sk;
+
+	struct l2cap_conn	*conn;
+
+	__le16		psm;
+	__u16		dcid;
+	__u16		scid;
+
+	__u16		imtu;
+	__u16		omtu;
+	__u16		flush_to;
+	__u8		mode;
+
+	__le16		sport;
+
+	__u8		sec_level;
+	__u8		role_switch;
+	__u8		force_reliable;
+	__u8		flushable;
+
 	__u8		ident;
 
 	__u8		conf_req[64];
@@ -291,6 +310,15 @@ struct l2cap_chan {
 	__u8		num_conf_req;
 	__u8		num_conf_rsp;
 
+	__u8		fcs;
+
+	__u8		tx_win;
+	__u8		max_tx;
+	__u16		retrans_timeout;
+	__u16		monitor_timeout;
+	__u16		mps;
+
+	__u8		conf_state;
 	__u16		conn_state;
 
 	__u8		next_tx_seq;
@@ -360,32 +388,6 @@ struct l2cap_conn {
 
 struct l2cap_pinfo {
 	struct bt_sock	bt;
-	__le16		psm;
-	__u16		dcid;
-	__u16		scid;
-
-	__u16		imtu;
-	__u16		omtu;
-	__u16		flush_to;
-	__u8		mode;
-
-	__u8		fcs;
-	__u8		sec_level;
-	__u8		role_switch;
-	__u8		force_reliable;
-	__u8		flushable;
-
-	__u8		conf_state;
-
-	__u8		tx_win;
-	__u8		max_tx;
-	__u16		retrans_timeout;
-	__u16		monitor_timeout;
-	__u16		mps;
-
-	__le16		sport;
-
-	struct l2cap_conn	*conn;
 	struct l2cap_chan	*chan;
 };
 
@@ -439,21 +441,20 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 #define __is_sar_start(ctrl)	(((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
 
 extern int disable_ertm;
-extern const struct proto_ops l2cap_sock_ops;
 extern struct bt_sock_list l2cap_sk_list;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
 
 void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
-void __l2cap_connect_rsp_defer(struct sock *sk);
+void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
 int __l2cap_wait_ack(struct sock *sk);
 
-struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len);
-struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len);
-struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
+struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
 int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
-void l2cap_do_send(struct sock *sk, struct sk_buff *skb);
+void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb);
 void l2cap_streaming_send(struct l2cap_chan *chan);
 int l2cap_ertm_send(struct l2cap_chan *chan);
 
@@ -465,7 +466,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent);
 struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
 							int proto, gfp_t prio);
 void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
+struct l2cap_chan *l2cap_chan_alloc(struct sock *sk);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
-int l2cap_do_connect(struct sock *sk);
+void l2cap_chan_free(struct l2cap_chan *chan);
+int l2cap_chan_connect(struct l2cap_chan *chan);
 
 #endif /* __L2CAP_H */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 6b6ff92ab499d9656283b0f8cb993d22eec9c158..4899286ed4e4a4ff9e20180675d618de8e0f7d62 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data {
 	bdaddr_t bdaddr;
 } __packed;
 
+#define MGMT_OP_START_DISCOVERY		0x001B
+
+#define MGMT_OP_STOP_DISCOVERY		0x001C
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
@@ -226,8 +230,8 @@ struct mgmt_ev_controller_error {
 
 #define MGMT_EV_NEW_KEY			0x000A
 struct mgmt_ev_new_key {
+	__u8 store_hint;
 	struct mgmt_key_info key;
-	__u8 old_key_type;
 } __packed;
 
 #define MGMT_EV_CONNECTED		0x000B
@@ -249,11 +253,13 @@ struct mgmt_ev_connect_failed {
 #define MGMT_EV_PIN_CODE_REQUEST	0x000E
 struct mgmt_ev_pin_code_request {
 	bdaddr_t bdaddr;
+	__u8 secure;
 } __packed;
 
 #define MGMT_EV_USER_CONFIRM_REQUEST	0x000F
 struct mgmt_ev_user_confirm_request {
 	bdaddr_t bdaddr;
+	__u8 confirm_hint;
 	__le32 value;
 } __packed;
 
@@ -281,3 +287,5 @@ struct mgmt_ev_remote_name {
 	bdaddr_t bdaddr;
 	__u8 name[MGMT_MAX_NAME_LENGTH];
 } __packed;
+
+#define MGMT_EV_DISCOVERING		0x0014
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d23dd6c1329cf463d5eb5126a97aae94f207bd15..db4b6b9f397703083038968d5eec9b18a0689390 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1822,6 +1822,10 @@ enum ieee80211_ampdu_mlme_action {
  *
  * @tx_frames_pending: Check if there is any pending frame in the hardware
  *	queues before entering power save.
+ *
+ * @set_bitrate_mask: Set a mask of rates to be used for rate control selection
+ *	when transmitting a frame. Currently only legacy rates are handled.
+ *	The callback can sleep.
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1910,6 +1914,8 @@ struct ieee80211_ops {
 	void (*get_ringparam)(struct ieee80211_hw *hw,
 			      u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
 	bool (*tx_frames_pending)(struct ieee80211_hw *hw);
+	int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+				const struct cfg80211_bitrate_mask *mask);
 };
 
 /**
@@ -2291,6 +2297,17 @@ static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw,
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
 				 struct sk_buff *skb);
 
+/**
+ * ieee80211_report_low_ack - report non-responding station
+ *
+ * When operating in AP-mode, call this function to report a non-responding
+ * connected STA.
+ *
+ * @sta: the non-responding connected sta
+ * @num_packets: number of packets sent to @sta without a response
+ */
+void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets);
+
 /**
  * ieee80211_beacon_get_tim - beacon generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index cce99b0919f50ec39b1a0029dc21fdb57ba29d09..c5b11af908be4fc3ab6c7a0cebb9639900feb162 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
 
 	bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
 
-	session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
+	session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu,
+					l2cap_pi(sock->sk)->chan->imtu);
 
 	BT_DBG("mtu %d", session->mtu);
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 7a6f56b2f49dfe5904f7f78f6ad46353e9ab1011..7f5ad8a2b22d03c2c3eea300cba7dec3b977d20d 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg)
 	hci_conn_enter_sniff_mode(conn);
 }
 
+static void hci_conn_auto_accept(unsigned long arg)
+{
+	struct hci_conn *conn = (void *) arg;
+	struct hci_dev *hdev = conn->hdev;
+
+	hci_dev_lock(hdev);
+
+	hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
+								&conn->dst);
+
+	hci_dev_unlock(hdev);
+}
+
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 {
 	struct hci_conn *conn;
@@ -287,6 +300,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 	conn->auth_type = HCI_AT_GENERAL_BONDING;
 	conn->io_capability = hdev->io_capability;
 	conn->remote_auth = 0xff;
+	conn->key_type = 0xff;
 
 	conn->power_save = 1;
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
@@ -311,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
 	setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
 	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
+	setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
+							(unsigned long) conn);
 
 	atomic_set(&conn->refcnt, 0);
 
@@ -341,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn)
 
 	del_timer(&conn->disc_timer);
 
+	del_timer(&conn->auto_accept_timer);
+
 	if (conn->type == ACL_LINK) {
 		struct hci_conn *sco = conn->link;
 		if (sco)
@@ -535,32 +553,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	return 0;
 }
 
+/* Encrypt the the link */
+static void hci_conn_encrypt(struct hci_conn *conn)
+{
+	BT_DBG("conn %p", conn);
+
+	if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+		struct hci_cp_set_conn_encrypt cp;
+		cp.handle  = cpu_to_le16(conn->handle);
+		cp.encrypt = 0x01;
+		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
+									&cp);
+	}
+}
+
 /* Enable security */
 int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 {
 	BT_DBG("conn %p", conn);
 
+	/* For sdp we don't need the link key. */
 	if (sec_level == BT_SECURITY_SDP)
 		return 1;
 
+	/* For non 2.1 devices and low security level we don't need the link
+	   key. */
 	if (sec_level == BT_SECURITY_LOW &&
 				(!conn->ssp_mode || !conn->hdev->ssp_mode))
 		return 1;
 
-	if (conn->link_mode & HCI_LM_ENCRYPT)
-		return hci_conn_auth(conn, sec_level, auth_type);
-
+	/* For other security levels we need the link key. */
+	if (!(conn->link_mode & HCI_LM_AUTH))
+		goto auth;
+
+	/* An authenticated combination key has sufficient security for any
+	   security level. */
+	if (conn->key_type == HCI_LK_AUTH_COMBINATION)
+		goto encrypt;
+
+	/* An unauthenticated combination key has sufficient security for
+	   security level 1 and 2. */
+	if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
+			(sec_level == BT_SECURITY_MEDIUM ||
+			sec_level == BT_SECURITY_LOW))
+		goto encrypt;
+
+	/* A combination key has always sufficient security for the security
+	   levels 1 or 2. High security level requires the combination key
+	   is generated using maximum PIN code length (16).
+	   For pre 2.1 units. */
+	if (conn->key_type == HCI_LK_COMBINATION &&
+			(sec_level != BT_SECURITY_HIGH ||
+			conn->pin_length == 16))
+		goto encrypt;
+
+auth:
 	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
 		return 0;
 
-	if (hci_conn_auth(conn, sec_level, auth_type)) {
-		struct hci_cp_set_conn_encrypt cp;
-		cp.handle  = cpu_to_le16(conn->handle);
-		cp.encrypt = 1;
-		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
-							sizeof(cp), &cp);
-	}
+	hci_conn_auth(conn, sec_level, auth_type);
+	return 0;
+
+encrypt:
+	if (conn->link_mode & HCI_LM_ENCRYPT)
+		return 1;
 
+	hci_conn_encrypt(conn);
 	return 0;
 }
 EXPORT_SYMBOL(hci_conn_security);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e057d123599636dc74d003f3b581e9dfd040aa2f..815269b07f20694c7f2968a096c5f3738fb81467 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1020,18 +1020,54 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 	return NULL;
 }
 
-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
-						u8 *val, u8 type, u8 pin_len)
+static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
+						u8 key_type, u8 old_key_type)
+{
+	/* Legacy key */
+	if (key_type < 0x03)
+		return 1;
+
+	/* Debug keys are insecure so don't store them persistently */
+	if (key_type == HCI_LK_DEBUG_COMBINATION)
+		return 0;
+
+	/* Changed combination key and there's no previous one */
+	if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff)
+		return 0;
+
+	/* Security mode 3 case */
+	if (!conn)
+		return 1;
+
+	/* Neither local nor remote side had no-bonding as requirement */
+	if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
+		return 1;
+
+	/* Local side had dedicated bonding as requirement */
+	if (conn->auth_type == 0x02 || conn->auth_type == 0x03)
+		return 1;
+
+	/* Remote side had dedicated bonding as requirement */
+	if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03)
+		return 1;
+
+	/* If none of the above criteria match, then don't store the key
+	 * persistently */
+	return 0;
+}
+
+int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
+				bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
 {
 	struct link_key *key, *old_key;
-	u8 old_key_type;
+	u8 old_key_type, persistent;
 
 	old_key = hci_find_link_key(hdev, bdaddr);
 	if (old_key) {
 		old_key_type = old_key->type;
 		key = old_key;
 	} else {
-		old_key_type = 0xff;
+		old_key_type = conn ? conn->key_type : 0xff;
 		key = kzalloc(sizeof(*key), GFP_ATOMIC);
 		if (!key)
 			return -ENOMEM;
@@ -1040,16 +1076,37 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
 
 	BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
 
+	/* Some buggy controller combinations generate a changed
+	 * combination key for legacy pairing even when there's no
+	 * previous key */
+	if (type == HCI_LK_CHANGED_COMBINATION &&
+					(!conn || conn->remote_auth == 0xff) &&
+					old_key_type == 0xff) {
+		type = HCI_LK_COMBINATION;
+		if (conn)
+			conn->key_type = type;
+	}
+
 	bacpy(&key->bdaddr, bdaddr);
 	memcpy(key->val, val, 16);
-	key->type = type;
 	key->pin_len = pin_len;
 
-	if (new_key)
-		mgmt_new_key(hdev->id, key, old_key_type);
-
-	if (type == 0x06)
+	if (type == HCI_LK_CHANGED_COMBINATION)
 		key->type = old_key_type;
+	else
+		key->type = type;
+
+	if (!new_key)
+		return 0;
+
+	persistent = hci_persistent_key(hdev, conn, type, old_key_type);
+
+	mgmt_new_key(hdev->id, key, persistent);
+
+	if (!persistent) {
+		list_del(&key->list);
+		kfree(key);
+	}
 
 	return 0;
 }
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cb25628c0583fc35e55fb351143724b8354cb462..d5aa97ee6ffae4ef03e4abce779470d963a957b3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 	if (status)
 		return;
 
-	clear_bit(HCI_INQUIRY, &hdev->flags);
+	if (test_bit(HCI_MGMT, &hdev->flags) &&
+				test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+		mgmt_discovering(hdev->id, 0);
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 
@@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
 	if (status)
 		return;
 
-	clear_bit(HCI_INQUIRY, &hdev->flags);
+	if (test_bit(HCI_MGMT, &hdev->flags) &&
+				test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+		mgmt_discovering(hdev->id, 0);
 
 	hci_conn_check_pending(hdev);
 }
@@ -841,10 +845,14 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 
 	if (status) {
 		hci_req_complete(hdev, HCI_OP_INQUIRY, status);
-
 		hci_conn_check_pending(hdev);
-	} else
-		set_bit(HCI_INQUIRY, &hdev->flags);
+		return;
+	}
+
+	if (test_bit(HCI_MGMT, &hdev->flags) &&
+					!test_and_set_bit(HCI_INQUIRY,
+							&hdev->flags))
+		mgmt_discovering(hdev->id, 1);
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1013,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-	if (conn && hci_outgoing_auth_needed(hdev, conn)) {
+	if (!conn)
+		goto unlock;
+
+	if (!hci_outgoing_auth_needed(hdev, conn))
+		goto unlock;
+
+	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 		struct hci_cp_auth_requested cp;
 		cp.handle = __cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
 	}
 
+unlock:
 	hci_dev_unlock(hdev);
 }
 
@@ -1208,7 +1223,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
 	BT_DBG("%s status %d", hdev->name, status);
 
-	clear_bit(HCI_INQUIRY, &hdev->flags);
+	if (test_bit(HCI_MGMT, &hdev->flags) &&
+				test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+		mgmt_discovering(hdev->id, 0);
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
@@ -1228,6 +1245,12 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 
 	hci_dev_lock(hdev);
 
+	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
+
+		if (test_bit(HCI_MGMT, &hdev->flags))
+			mgmt_discovering(hdev->id, 1);
+	}
+
 	for (; num_rsp; num_rsp--, info++) {
 		bacpy(&data.bdaddr, &info->bdaddr);
 		data.pscan_rep_mode	= info->pscan_rep_mode;
@@ -1443,7 +1466,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 			conn->sec_level = conn->pending_sec_level;
 		} else {
 			mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
-			conn->sec_level = BT_SECURITY_LOW;
 		}
 
 		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
@@ -1501,12 +1523,19 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
 		mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-	if (conn && hci_outgoing_auth_needed(hdev, conn)) {
+	if (!conn)
+		goto unlock;
+
+	if (!hci_outgoing_auth_needed(hdev, conn))
+		goto unlock;
+
+	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 		struct hci_cp_auth_requested cp;
 		cp.handle = __cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
 	}
 
+unlock:
 	hci_dev_unlock(hdev);
 }
 
@@ -2006,9 +2035,16 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
 	if (!test_bit(HCI_PAIRABLE, &hdev->flags))
 		hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
 					sizeof(ev->bdaddr), &ev->bdaddr);
+	else if (test_bit(HCI_MGMT, &hdev->flags)) {
+		u8 secure;
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_pin_code_request(hdev->id, &ev->bdaddr);
+		if (conn->pending_sec_level == BT_SECURITY_HIGH)
+			secure = 1;
+		else
+			secure = 0;
+
+		mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
+	}
 
 	hci_dev_unlock(hdev);
 }
@@ -2037,17 +2073,30 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 	BT_DBG("%s found key type %u for %s", hdev->name, key->type,
 							batostr(&ev->bdaddr));
 
-	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) {
+	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) &&
+				key->type == HCI_LK_DEBUG_COMBINATION) {
 		BT_DBG("%s ignoring debug key", hdev->name);
 		goto not_found;
 	}
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (conn) {
+		if (key->type == HCI_LK_UNAUTH_COMBINATION &&
+				conn->auth_type != 0xff &&
+				(conn->auth_type & 0x01)) {
+			BT_DBG("%s ignoring unauthenticated key", hdev->name);
+			goto not_found;
+		}
 
-	if (key->type == 0x04 && conn && conn->auth_type != 0xff &&
-						(conn->auth_type & 0x01)) {
-		BT_DBG("%s ignoring unauthenticated key", hdev->name);
-		goto not_found;
+		if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
+				conn->pending_sec_level == BT_SECURITY_HIGH) {
+			BT_DBG("%s ignoring key unauthenticated for high \
+							security", hdev->name);
+			goto not_found;
+		}
+
+		conn->key_type = key->type;
+		conn->pin_length = key->pin_len;
 	}
 
 	bacpy(&cp.bdaddr, &ev->bdaddr);
@@ -2079,11 +2128,15 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
 		hci_conn_hold(conn);
 		conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 		pin_len = conn->pin_length;
+
+		if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
+			conn->key_type = ev->key_type;
+
 		hci_conn_put(conn);
 	}
 
 	if (test_bit(HCI_LINK_KEYS, &hdev->flags))
-		hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key,
+		hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
 							ev->key_type, pin_len);
 
 	hci_dev_unlock(hdev);
@@ -2158,6 +2211,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 
 	hci_dev_lock(hdev);
 
+	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
+
+		if (test_bit(HCI_MGMT, &hdev->flags))
+			mgmt_discovering(hdev->id, 1);
+	}
+
 	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
 		struct inquiry_info_with_rssi_and_pscan_mode *info;
 		info = (void *) (skb->data + 1);
@@ -2320,6 +2379,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 	if (!num_rsp)
 		return;
 
+	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
+
+		if (test_bit(HCI_MGMT, &hdev->flags))
+			mgmt_discovering(hdev->id, 1);
+	}
+
 	hci_dev_lock(hdev);
 
 	for (; num_rsp; num_rsp--, info++) {
@@ -2353,7 +2418,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
 
 	/* If remote requests no-bonding follow that lead */
 	if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
-		return 0x00;
+		return conn->remote_auth | (conn->auth_type & 0x01);
 
 	return conn->auth_type;
 }
@@ -2382,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
 		cp.capability = conn->io_capability;
-		cp.authentication = hci_get_auth_req(conn);
+		conn->auth_type = hci_get_auth_req(conn);
+		cp.authentication = conn->auth_type;
 
 		if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
 				hci_find_remote_oob_data(hdev, &conn->dst))
@@ -2396,7 +2462,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 		struct hci_cp_io_capability_neg_reply cp;
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
-		cp.reason = 0x16; /* Pairing not allowed */
+		cp.reason = 0x18; /* Pairing not allowed */
 
 		hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
 							sizeof(cp), &cp);
@@ -2431,14 +2497,67 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 							struct sk_buff *skb)
 {
 	struct hci_ev_user_confirm_req *ev = (void *) skb->data;
+	int loc_mitm, rem_mitm, confirm_hint = 0;
+	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
 	hci_dev_lock(hdev);
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey);
+	if (!test_bit(HCI_MGMT, &hdev->flags))
+		goto unlock;
+
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (!conn)
+		goto unlock;
+
+	loc_mitm = (conn->auth_type & 0x01);
+	rem_mitm = (conn->remote_auth & 0x01);
+
+	/* If we require MITM but the remote device can't provide that
+	 * (it has NoInputNoOutput) then reject the confirmation
+	 * request. The only exception is when we're dedicated bonding
+	 * initiators (connect_cfm_cb set) since then we always have the MITM
+	 * bit set. */
+	if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
+		BT_DBG("Rejecting request: remote device can't provide MITM");
+		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
+					sizeof(ev->bdaddr), &ev->bdaddr);
+		goto unlock;
+	}
+
+	/* If no side requires MITM protection; auto-accept */
+	if ((!loc_mitm || conn->remote_cap == 0x03) &&
+				(!rem_mitm || conn->io_capability == 0x03)) {
 
+		/* If we're not the initiators request authorization to
+		 * proceed from user space (mgmt_user_confirm with
+		 * confirm_hint set to 1). */
+		if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+			BT_DBG("Confirming auto-accept as acceptor");
+			confirm_hint = 1;
+			goto confirm;
+		}
+
+		BT_DBG("Auto-accept of user confirmation with %ums delay",
+						hdev->auto_accept_delay);
+
+		if (hdev->auto_accept_delay > 0) {
+			int delay = msecs_to_jiffies(hdev->auto_accept_delay);
+			mod_timer(&conn->auto_accept_timer, jiffies + delay);
+			goto unlock;
+		}
+
+		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
+						sizeof(ev->bdaddr), &ev->bdaddr);
+		goto unlock;
+	}
+
+confirm:
+	mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
+								confirm_hint);
+
+unlock:
 	hci_dev_unlock(hdev);
 }
 
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 8775933ea837f4c2d7cf624b3861faf0d04e73e7..a6c3aa8be1f79796dbfa051af03b3503f23fbe4e 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -511,6 +511,35 @@ static const struct file_operations uuids_fops = {
 	.release	= single_release,
 };
 
+static int auto_accept_delay_set(void *data, u64 val)
+{
+	struct hci_dev *hdev = data;
+
+	hci_dev_lock_bh(hdev);
+
+	hdev->auto_accept_delay = val;
+
+	hci_dev_unlock_bh(hdev);
+
+	return 0;
+}
+
+static int auto_accept_delay_get(void *data, u64 *val)
+{
+	struct hci_dev *hdev = data;
+
+	hci_dev_lock_bh(hdev);
+
+	*val = hdev->auto_accept_delay;
+
+	hci_dev_unlock_bh(hdev);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
+					auto_accept_delay_set, "%llu\n");
+
 int hci_register_sysfs(struct hci_dev *hdev)
 {
 	struct device *dev = &hdev->dev;
@@ -545,6 +574,8 @@ int hci_register_sysfs(struct hci_dev *hdev)
 
 	debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
 
+	debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev,
+						&auto_accept_delay_fops);
 	return 0;
 }
 
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index ae6ebc6c3481e24bd9d8edf1cd9c6a08f46abfe9..c405a954a603341b52b51a98592ecccd618398e9 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -979,8 +979,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
 
 	bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
 
-	session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
-	session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
+	session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
+					l2cap_pi(ctrl_sock->sk)->chan->imtu);
+	session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
+					l2cap_pi(intr_sock->sk)->chan->imtu);
 
 	BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fd3c1f35aa009c5cbfb6d7dff609887c1e69f3f5..a378acc491ec687a009a5c59ca4d254d62f47e2b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -80,8 +80,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16
 	struct l2cap_chan *c;
 
 	list_for_each_entry(c, &conn->chan_l, list) {
-		struct sock *s = c->sk;
-		if (l2cap_pi(s)->dcid == cid)
+		if (c->dcid == cid)
 			return c;
 	}
 	return NULL;
@@ -93,8 +92,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16
 	struct l2cap_chan *c;
 
 	list_for_each_entry(c, &conn->chan_l, list) {
-		struct sock *s = c->sk;
-		if (l2cap_pi(s)->scid == cid)
+		if (c->scid == cid)
 			return c;
 	}
 	return NULL;
@@ -149,7 +147,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 	return 0;
 }
 
-static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
+struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
 {
 	struct l2cap_chan *chan;
 
@@ -162,38 +160,43 @@ static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
 	return chan;
 }
 
+void l2cap_chan_free(struct l2cap_chan *chan)
+{
+	kfree(chan);
+}
+
 static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
 	struct sock *sk = chan->sk;
 
 	BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
-			l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+			chan->psm, chan->dcid);
 
 	conn->disc_reason = 0x13;
 
-	l2cap_pi(sk)->conn = conn;
+	chan->conn = conn;
 
 	if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
 		if (conn->hcon->type == LE_LINK) {
 			/* LE connection */
-			l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU;
-			l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA;
-			l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
+			chan->omtu = L2CAP_LE_DEFAULT_MTU;
+			chan->scid = L2CAP_CID_LE_DATA;
+			chan->dcid = L2CAP_CID_LE_DATA;
 		} else {
 			/* Alloc CID for connection-oriented socket */
-			l2cap_pi(sk)->scid = l2cap_alloc_cid(conn);
-			l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+			chan->scid = l2cap_alloc_cid(conn);
+			chan->omtu = L2CAP_DEFAULT_MTU;
 		}
 	} else if (sk->sk_type == SOCK_DGRAM) {
 		/* Connectionless socket */
-		l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
-		l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS;
-		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+		chan->scid = L2CAP_CID_CONN_LESS;
+		chan->dcid = L2CAP_CID_CONN_LESS;
+		chan->omtu = L2CAP_DEFAULT_MTU;
 	} else {
 		/* Raw socket can send/recv signalling messages only */
-		l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING;
-		l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING;
-		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+		chan->scid = L2CAP_CID_SIGNALING;
+		chan->dcid = L2CAP_CID_SIGNALING;
+		chan->omtu = L2CAP_DEFAULT_MTU;
 	}
 
 	sock_hold(sk);
@@ -206,7 +209,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
 	struct sock *sk = chan->sk;
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct l2cap_conn *conn = chan->conn;
 	struct sock *parent = bt_sk(sk)->parent;
 
 	l2cap_sock_clear_timer(sk);
@@ -220,7 +223,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 		write_unlock_bh(&conn->chan_lock);
 		__sock_put(sk);
 
-		l2cap_pi(sk)->conn = NULL;
+		chan->conn = NULL;
 		hci_conn_put(conn->hcon);
 	}
 
@@ -236,13 +239,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 	} else
 		sk->sk_state_change(sk);
 
-	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE &&
-			l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE))
-		goto free;
+	if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
+			chan->conf_state & L2CAP_CONF_INPUT_DONE))
+		return;
 
 	skb_queue_purge(&chan->tx_q);
 
-	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
+	if (chan->mode == L2CAP_MODE_ERTM) {
 		struct srej_list *l, *tmp;
 
 		del_timer(&chan->retrans_timer);
@@ -257,15 +260,14 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 			kfree(l);
 		}
 	}
-
-free:
-	kfree(chan);
 }
 
-static inline u8 l2cap_get_auth_type(struct sock *sk)
+static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 {
+	struct sock *sk = chan->sk;
+
 	if (sk->sk_type == SOCK_RAW) {
-		switch (l2cap_pi(sk)->sec_level) {
+		switch (chan->sec_level) {
 		case BT_SECURITY_HIGH:
 			return HCI_AT_DEDICATED_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
@@ -273,16 +275,16 @@ static inline u8 l2cap_get_auth_type(struct sock *sk)
 		default:
 			return HCI_AT_NO_BONDING;
 		}
-	} else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
-		if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
-			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+	} else if (chan->psm == cpu_to_le16(0x0001)) {
+		if (chan->sec_level == BT_SECURITY_LOW)
+			chan->sec_level = BT_SECURITY_SDP;
 
-		if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+		if (chan->sec_level == BT_SECURITY_HIGH)
 			return HCI_AT_NO_BONDING_MITM;
 		else
 			return HCI_AT_NO_BONDING;
 	} else {
-		switch (l2cap_pi(sk)->sec_level) {
+		switch (chan->sec_level) {
 		case BT_SECURITY_HIGH:
 			return HCI_AT_GENERAL_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
@@ -294,15 +296,14 @@ static inline u8 l2cap_get_auth_type(struct sock *sk)
 }
 
 /* Service level security */
-static inline int l2cap_check_security(struct sock *sk)
+static inline int l2cap_check_security(struct l2cap_chan *chan)
 {
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct l2cap_conn *conn = chan->conn;
 	__u8 auth_type;
 
-	auth_type = l2cap_get_auth_type(sk);
+	auth_type = l2cap_get_auth_type(chan);
 
-	return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
-								auth_type);
+	return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
 }
 
 u8 l2cap_get_ident(struct l2cap_conn *conn)
@@ -350,7 +351,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
 	struct sk_buff *skb;
 	struct l2cap_hdr *lh;
 	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
-	struct l2cap_conn *conn = pi->conn;
+	struct l2cap_conn *conn = chan->conn;
 	struct sock *sk = (struct sock *)pi;
 	int count, hlen = L2CAP_HDR_SIZE + 2;
 	u8 flags;
@@ -358,7 +359,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
 	if (sk->sk_state != BT_CONNECTED)
 		return;
 
-	if (pi->fcs == L2CAP_FCS_CRC16)
+	if (chan->fcs == L2CAP_FCS_CRC16)
 		hlen += 2;
 
 	BT_DBG("chan %p, control 0x%2.2x", chan, control);
@@ -382,10 +383,10 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
 
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
 	lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
-	lh->cid = cpu_to_le16(pi->dcid);
+	lh->cid = cpu_to_le16(chan->dcid);
 	put_unaligned_le16(control, skb_put(skb, 2));
 
-	if (pi->fcs == L2CAP_FCS_CRC16) {
+	if (chan->fcs == L2CAP_FCS_CRC16) {
 		u16 fcs = crc16(0, (u8 *)lh, count - 2);
 		put_unaligned_le16(fcs, skb_put(skb, 2));
 	}
@@ -395,7 +396,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
 	else
 		flags = ACL_START;
 
-	hci_send_acl(pi->conn->hcon, skb, flags);
+	hci_send_acl(chan->conn->hcon, skb, flags);
 }
 
 static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
@@ -411,27 +412,27 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
 	l2cap_send_sframe(chan, control);
 }
 
-static inline int __l2cap_no_conn_pending(struct sock *sk)
+static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
 {
-	return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND);
+	return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
-	struct sock *sk = chan->sk;
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct l2cap_conn *conn = chan->conn;
 
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
 		if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
 			return;
 
-		if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) {
+		if (l2cap_check_security(chan) &&
+				__l2cap_no_conn_pending(chan)) {
 			struct l2cap_conn_req req;
-			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-			req.psm  = l2cap_pi(sk)->psm;
+			req.scid = cpu_to_le16(chan->scid);
+			req.psm  = chan->psm;
 
 			chan->ident = l2cap_get_ident(conn);
-			l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+			chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
 							sizeof(req), &req);
@@ -477,14 +478,14 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in
 
 	sk = chan->sk;
 
-	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
+	if (chan->mode == L2CAP_MODE_ERTM) {
 		del_timer(&chan->retrans_timer);
 		del_timer(&chan->monitor_timer);
 		del_timer(&chan->ack_timer);
 	}
 
-	req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
-	req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+	req.dcid = cpu_to_le16(chan->dcid);
+	req.scid = cpu_to_le16(chan->scid);
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
 			L2CAP_DISCONN_REQ, sizeof(req), &req);
 
@@ -515,15 +516,15 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 		if (sk->sk_state == BT_CONNECT) {
 			struct l2cap_conn_req req;
 
-			if (!l2cap_check_security(sk) ||
-					!__l2cap_no_conn_pending(sk)) {
+			if (!l2cap_check_security(chan) ||
+					!__l2cap_no_conn_pending(chan)) {
 				bh_unlock_sock(sk);
 				continue;
 			}
 
-			if (!l2cap_mode_supported(l2cap_pi(sk)->mode,
+			if (!l2cap_mode_supported(chan->mode,
 					conn->feat_mask)
-					&& l2cap_pi(sk)->conf_state &
+					&& chan->conf_state &
 					L2CAP_CONF_STATE2_DEVICE) {
 				/* __l2cap_sock_close() calls list_del(chan)
 				 * so release the lock */
@@ -534,11 +535,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 				continue;
 			}
 
-			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-			req.psm  = l2cap_pi(sk)->psm;
+			req.scid = cpu_to_le16(chan->scid);
+			req.psm  = chan->psm;
 
 			chan->ident = l2cap_get_ident(conn);
-			l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+			chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
 							sizeof(req), &req);
@@ -546,10 +547,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 		} else if (sk->sk_state == BT_CONNECT2) {
 			struct l2cap_conn_rsp rsp;
 			char buf[128];
-			rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
-			rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
+			rsp.scid = cpu_to_le16(chan->dcid);
+			rsp.dcid = cpu_to_le16(chan->scid);
 
-			if (l2cap_check_security(sk)) {
+			if (l2cap_check_security(chan)) {
 				if (bt_sk(sk)->defer_setup) {
 					struct sock *parent = bt_sk(sk)->parent;
 					rsp.result = cpu_to_le16(L2CAP_CR_PEND);
@@ -569,13 +570,13 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
 							sizeof(rsp), &rsp);
 
-			if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT ||
+			if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
 					rsp.result != L2CAP_CR_SUCCESS) {
 				bh_unlock_sock(sk);
 				continue;
 			}
 
-			l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+			chan->conf_state |= L2CAP_CONF_REQ_SENT;
 			l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 						l2cap_build_conf_req(chan, buf), buf);
 			chan->num_conf_req++;
@@ -598,10 +599,12 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
 	read_lock(&l2cap_sk_list.lock);
 
 	sk_for_each(sk, node, &l2cap_sk_list.head) {
+		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
 		if (state && sk->sk_state != state)
 			continue;
 
-		if (l2cap_pi(sk)->scid == cid) {
+		if (chan->scid == cid) {
 			/* Exact match. */
 			if (!bacmp(&bt_sk(sk)->src, src))
 				break;
@@ -648,6 +651,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 		goto clean;
 	}
 
+	l2cap_pi(sk)->chan = chan;
+
 	write_lock_bh(&conn->chan_lock);
 
 	hci_conn_hold(conn->hcon);
@@ -661,8 +666,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
 	__l2cap_chan_add(conn, chan);
 
-	l2cap_pi(sk)->chan = chan;
-
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
 	sk->sk_state = BT_CONNECTED;
@@ -722,7 +725,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 	list_for_each_entry(chan, &conn->chan_l, list) {
 		struct sock *sk = chan->sk;
 
-		if (l2cap_pi(sk)->force_reliable)
+		if (chan->force_reliable)
 			sk->sk_err = err;
 	}
 
@@ -828,10 +831,12 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
 	read_lock(&l2cap_sk_list.lock);
 
 	sk_for_each(sk, node, &l2cap_sk_list.head) {
+		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
 		if (state && sk->sk_state != state)
 			continue;
 
-		if (l2cap_pi(sk)->psm == psm) {
+		if (chan->psm == psm) {
 			/* Exact match. */
 			if (!bacmp(&bt_sk(sk)->src, src))
 				break;
@@ -847,19 +852,19 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
 	return node ? sk : sk1;
 }
 
-int l2cap_do_connect(struct sock *sk)
+int l2cap_chan_connect(struct l2cap_chan *chan)
 {
+	struct sock *sk = chan->sk;
 	bdaddr_t *src = &bt_sk(sk)->src;
 	bdaddr_t *dst = &bt_sk(sk)->dst;
 	struct l2cap_conn *conn;
-	struct l2cap_chan *chan;
 	struct hci_conn *hcon;
 	struct hci_dev *hdev;
 	__u8 auth_type;
 	int err;
 
 	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
-							l2cap_pi(sk)->psm);
+							chan->psm);
 
 	hdev = hci_get_route(dst, src);
 	if (!hdev)
@@ -867,14 +872,14 @@ int l2cap_do_connect(struct sock *sk)
 
 	hci_dev_lock_bh(hdev);
 
-	auth_type = l2cap_get_auth_type(sk);
+	auth_type = l2cap_get_auth_type(chan);
 
-	if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
+	if (chan->dcid == L2CAP_CID_LE_DATA)
 		hcon = hci_connect(hdev, LE_LINK, dst,
-					l2cap_pi(sk)->sec_level, auth_type);
+					chan->sec_level, auth_type);
 	else
 		hcon = hci_connect(hdev, ACL_LINK, dst,
-					l2cap_pi(sk)->sec_level, auth_type);
+					chan->sec_level, auth_type);
 
 	if (IS_ERR(hcon)) {
 		err = PTR_ERR(hcon);
@@ -888,20 +893,11 @@ int l2cap_do_connect(struct sock *sk)
 		goto done;
 	}
 
-	chan = l2cap_chan_alloc(sk);
-	if (!chan) {
-		hci_conn_put(hcon);
-		err = -ENOMEM;
-		goto done;
-	}
-
 	/* Update source addr of the socket */
 	bacpy(src, conn->src);
 
 	l2cap_chan_add(conn, chan);
 
-	l2cap_pi(sk)->chan = chan;
-
 	sk->sk_state = BT_CONNECT;
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
@@ -909,7 +905,7 @@ int l2cap_do_connect(struct sock *sk)
 		if (sk->sk_type != SOCK_SEQPACKET &&
 				sk->sk_type != SOCK_STREAM) {
 			l2cap_sock_clear_timer(sk);
-			if (l2cap_check_security(sk))
+			if (l2cap_check_security(chan))
 				sk->sk_state = BT_CONNECTED;
 		} else
 			l2cap_do_start(chan);
@@ -925,12 +921,13 @@ done:
 
 int __l2cap_wait_ack(struct sock *sk)
 {
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	DECLARE_WAITQUEUE(wait, current);
 	int err = 0;
 	int timeo = HZ/5;
 
 	add_wait_queue(sk_sleep(sk), &wait);
-	while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
+	while ((chan->unacked_frames > 0 && chan->conn)) {
 		set_current_state(TASK_INTERRUPTIBLE);
 
 		if (!timeo)
@@ -963,7 +960,7 @@ static void l2cap_monitor_timeout(unsigned long arg)
 
 	bh_lock_sock(sk);
 	if (chan->retry_count >= chan->remote_max_tx) {
-		l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 		bh_unlock_sock(sk);
 		return;
 	}
@@ -1011,15 +1008,14 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
 		del_timer(&chan->retrans_timer);
 }
 
-void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
+void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
-	struct hci_conn *hcon = pi->conn->hcon;
+	struct hci_conn *hcon = chan->conn->hcon;
 	u16 flags;
 
-	BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len);
+	BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
 
-	if (!pi->flushable && lmp_no_flush_capable(hcon->hdev))
+	if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
 		flags = ACL_START_NO_FLUSH;
 	else
 		flags = ACL_START;
@@ -1029,9 +1025,7 @@ void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
 
 void l2cap_streaming_send(struct l2cap_chan *chan)
 {
-	struct sock *sk = chan->sk;
 	struct sk_buff *skb;
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u16 control, fcs;
 
 	while ((skb = skb_dequeue(&chan->tx_q))) {
@@ -1039,12 +1033,12 @@ void l2cap_streaming_send(struct l2cap_chan *chan)
 		control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
 		put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
 
-		if (pi->fcs == L2CAP_FCS_CRC16) {
+		if (chan->fcs == L2CAP_FCS_CRC16) {
 			fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
 			put_unaligned_le16(fcs, skb->data + skb->len - 2);
 		}
 
-		l2cap_do_send(sk, skb);
+		l2cap_do_send(chan, skb);
 
 		chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
 	}
@@ -1052,8 +1046,6 @@ void l2cap_streaming_send(struct l2cap_chan *chan)
 
 static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 {
-	struct sock *sk = chan->sk;
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct sk_buff *skb, *tx_skb;
 	u16 control, fcs;
 
@@ -1072,7 +1064,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 
 	if (chan->remote_max_tx &&
 			bt_cb(skb)->retries == chan->remote_max_tx) {
-		l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 		return;
 	}
 
@@ -1091,19 +1083,18 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 
 	put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
-	if (pi->fcs == L2CAP_FCS_CRC16) {
+	if (chan->fcs == L2CAP_FCS_CRC16) {
 		fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
 		put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
 	}
 
-	l2cap_do_send(sk, tx_skb);
+	l2cap_do_send(chan, tx_skb);
 }
 
 int l2cap_ertm_send(struct l2cap_chan *chan)
 {
 	struct sk_buff *skb, *tx_skb;
 	struct sock *sk = chan->sk;
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u16 control, fcs;
 	int nsent = 0;
 
@@ -1114,7 +1105,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan)
 
 		if (chan->remote_max_tx &&
 				bt_cb(skb)->retries == chan->remote_max_tx) {
-			l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
+			l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 			break;
 		}
 
@@ -1134,12 +1125,12 @@ int l2cap_ertm_send(struct l2cap_chan *chan)
 		put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
 
-		if (pi->fcs == L2CAP_FCS_CRC16) {
+		if (chan->fcs == L2CAP_FCS_CRC16) {
 			fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
 			put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
 		}
 
-		l2cap_do_send(sk, tx_skb);
+		l2cap_do_send(chan, tx_skb);
 
 		__mod_retrans_timer();
 
@@ -1210,7 +1201,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan)
 
 static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
 {
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
 	struct sk_buff **frag;
 	int err, sent = 0;
 
@@ -1240,9 +1231,10 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
 	return sent;
 }
 
-struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len)
+struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
 {
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct sock *sk = chan->sk;
+	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff *skb;
 	int err, count, hlen = L2CAP_HDR_SIZE + 2;
 	struct l2cap_hdr *lh;
@@ -1257,9 +1249,9 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s
 
 	/* Create L2CAP header */
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+	lh->cid = cpu_to_le16(chan->dcid);
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-	put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2));
+	put_unaligned_le16(chan->psm, skb_put(skb, 2));
 
 	err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
 	if (unlikely(err < 0)) {
@@ -1269,9 +1261,10 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s
 	return skb;
 }
 
-struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len)
+struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
 {
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct sock *sk = chan->sk;
+	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff *skb;
 	int err, count, hlen = L2CAP_HDR_SIZE;
 	struct l2cap_hdr *lh;
@@ -1286,7 +1279,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size
 
 	/* Create L2CAP header */
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+	lh->cid = cpu_to_le16(chan->dcid);
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
 	err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
@@ -1297,9 +1290,10 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size
 	return skb;
 }
 
-struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
 {
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct sock *sk = chan->sk;
+	struct l2cap_conn *conn = chan->conn;
 	struct sk_buff *skb;
 	int err, count, hlen = L2CAP_HDR_SIZE + 2;
 	struct l2cap_hdr *lh;
@@ -1312,7 +1306,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz
 	if (sdulen)
 		hlen += 2;
 
-	if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16)
+	if (chan->fcs == L2CAP_FCS_CRC16)
 		hlen += 2;
 
 	count = min_t(unsigned int, (conn->mtu - hlen), len);
@@ -1323,7 +1317,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz
 
 	/* Create L2CAP header */
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+	lh->cid = cpu_to_le16(chan->dcid);
 	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 	put_unaligned_le16(control, skb_put(skb, 2));
 	if (sdulen)
@@ -1335,7 +1329,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz
 		return ERR_PTR(err);
 	}
 
-	if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16)
+	if (chan->fcs == L2CAP_FCS_CRC16)
 		put_unaligned_le16(0, skb_put(skb, 2));
 
 	bt_cb(skb)->retries = 0;
@@ -1344,7 +1338,6 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz
 
 int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
 {
-	struct sock *sk = chan->sk;
 	struct sk_buff *skb;
 	struct sk_buff_head sar_queue;
 	u16 control;
@@ -1352,7 +1345,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le
 
 	skb_queue_head_init(&sar_queue);
 	control = L2CAP_SDU_START;
-	skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len);
+	skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
 
@@ -1371,7 +1364,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le
 			buflen = len;
 		}
 
-		skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0);
+		skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
 		if (IS_ERR(skb)) {
 			skb_queue_purge(&sar_queue);
 			return PTR_ERR(skb);
@@ -1391,10 +1384,11 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le
 static void l2cap_chan_ready(struct sock *sk)
 {
 	struct sock *parent = bt_sk(sk)->parent;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 
 	BT_DBG("sk %p, parent %p", sk, parent);
 
-	l2cap_pi(sk)->conf_state = 0;
+	chan->conf_state = 0;
 	l2cap_sock_clear_timer(sk);
 
 	if (!parent) {
@@ -1615,9 +1609,8 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
 
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct l2cap_conf_req *req = data;
-	struct l2cap_conf_rfc rfc = { .mode = pi->mode };
+	struct l2cap_conf_rfc rfc = { .mode = chan->mode };
 	void *ptr = req->data;
 
 	BT_DBG("chan %p", chan);
@@ -1625,26 +1618,26 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 	if (chan->num_conf_req || chan->num_conf_rsp)
 		goto done;
 
-	switch (pi->mode) {
+	switch (chan->mode) {
 	case L2CAP_MODE_STREAMING:
 	case L2CAP_MODE_ERTM:
-		if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE)
+		if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
 			break;
 
 		/* fall through */
 	default:
-		pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
+		chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
 		break;
 	}
 
 done:
-	if (pi->imtu != L2CAP_DEFAULT_MTU)
-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+	if (chan->imtu != L2CAP_DEFAULT_MTU)
+		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
 
-	switch (pi->mode) {
+	switch (chan->mode) {
 	case L2CAP_MODE_BASIC:
-		if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) &&
-				!(pi->conn->feat_mask & L2CAP_FEAT_STREAMING))
+		if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
+				!(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
 			break;
 
 		rfc.mode            = L2CAP_MODE_BASIC;
@@ -1660,24 +1653,24 @@ done:
 
 	case L2CAP_MODE_ERTM:
 		rfc.mode            = L2CAP_MODE_ERTM;
-		rfc.txwin_size      = pi->tx_win;
-		rfc.max_transmit    = pi->max_tx;
+		rfc.txwin_size      = chan->tx_win;
+		rfc.max_transmit    = chan->max_tx;
 		rfc.retrans_timeout = 0;
 		rfc.monitor_timeout = 0;
 		rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-		if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
-			rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
+		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
+			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
 
 		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
 							(unsigned long) &rfc);
 
-		if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
+		if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
 			break;
 
-		if (pi->fcs == L2CAP_FCS_NONE ||
-				pi->conf_state & L2CAP_CONF_NO_FCS_RECV) {
-			pi->fcs = L2CAP_FCS_NONE;
-			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs);
+		if (chan->fcs == L2CAP_FCS_NONE ||
+				chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
+			chan->fcs = L2CAP_FCS_NONE;
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
 		}
 		break;
 
@@ -1688,24 +1681,24 @@ done:
 		rfc.retrans_timeout = 0;
 		rfc.monitor_timeout = 0;
 		rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-		if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
-			rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
+		if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
+			rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
 
 		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
 							(unsigned long) &rfc);
 
-		if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
+		if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
 			break;
 
-		if (pi->fcs == L2CAP_FCS_NONE ||
-				pi->conf_state & L2CAP_CONF_NO_FCS_RECV) {
-			pi->fcs = L2CAP_FCS_NONE;
-			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs);
+		if (chan->fcs == L2CAP_FCS_NONE ||
+				chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
+			chan->fcs = L2CAP_FCS_NONE;
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
 		}
 		break;
 	}
 
-	req->dcid  = cpu_to_le16(pi->dcid);
+	req->dcid  = cpu_to_le16(chan->dcid);
 	req->flags = cpu_to_le16(0);
 
 	return ptr - data;
@@ -1713,7 +1706,6 @@ done:
 
 static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct l2cap_conf_rsp *rsp = data;
 	void *ptr = rsp->data;
 	void *req = chan->conf_req;
@@ -1738,7 +1730,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 			break;
 
 		case L2CAP_CONF_FLUSH_TO:
-			pi->flush_to = val;
+			chan->flush_to = val;
 			break;
 
 		case L2CAP_CONF_QOS:
@@ -1751,7 +1743,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 
 		case L2CAP_CONF_FCS:
 			if (val == L2CAP_FCS_NONE)
-				pi->conf_state |= L2CAP_CONF_NO_FCS_RECV;
+				chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
 
 			break;
 
@@ -1768,25 +1760,25 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
 	if (chan->num_conf_rsp || chan->num_conf_req > 1)
 		goto done;
 
-	switch (pi->mode) {
+	switch (chan->mode) {
 	case L2CAP_MODE_STREAMING:
 	case L2CAP_MODE_ERTM:
-		if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
-			pi->mode = l2cap_select_mode(rfc.mode,
-					pi->conn->feat_mask);
+		if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
+			chan->mode = l2cap_select_mode(rfc.mode,
+					chan->conn->feat_mask);
 			break;
 		}
 
-		if (pi->mode != rfc.mode)
+		if (chan->mode != rfc.mode)
 			return -ECONNREFUSED;
 
 		break;
 	}
 
 done:
-	if (pi->mode != rfc.mode) {
+	if (chan->mode != rfc.mode) {
 		result = L2CAP_CONF_UNACCEPT;
-		rfc.mode = pi->mode;
+		rfc.mode = chan->mode;
 
 		if (chan->num_conf_rsp == 1)
 			return -ECONNREFUSED;
@@ -1803,23 +1795,23 @@ done:
 		if (mtu < L2CAP_DEFAULT_MIN_MTU)
 			result = L2CAP_CONF_UNACCEPT;
 		else {
-			pi->omtu = mtu;
-			pi->conf_state |= L2CAP_CONF_MTU_DONE;
+			chan->omtu = mtu;
+			chan->conf_state |= L2CAP_CONF_MTU_DONE;
 		}
-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
 
 		switch (rfc.mode) {
 		case L2CAP_MODE_BASIC:
-			pi->fcs = L2CAP_FCS_NONE;
-			pi->conf_state |= L2CAP_CONF_MODE_DONE;
+			chan->fcs = L2CAP_FCS_NONE;
+			chan->conf_state |= L2CAP_CONF_MODE_DONE;
 			break;
 
 		case L2CAP_MODE_ERTM:
 			chan->remote_tx_win = rfc.txwin_size;
 			chan->remote_max_tx = rfc.max_transmit;
 
-			if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
-				rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
+			if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
+				rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
 
 			chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
@@ -1828,7 +1820,7 @@ done:
 			rfc.monitor_timeout =
 				le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
 
-			pi->conf_state |= L2CAP_CONF_MODE_DONE;
+			chan->conf_state |= L2CAP_CONF_MODE_DONE;
 
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
 					sizeof(rfc), (unsigned long) &rfc);
@@ -1836,12 +1828,12 @@ done:
 			break;
 
 		case L2CAP_MODE_STREAMING:
-			if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
-				rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
+			if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
+				rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
 
 			chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
-			pi->conf_state |= L2CAP_CONF_MODE_DONE;
+			chan->conf_state |= L2CAP_CONF_MODE_DONE;
 
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
 					sizeof(rfc), (unsigned long) &rfc);
@@ -1852,29 +1844,28 @@ done:
 			result = L2CAP_CONF_UNACCEPT;
 
 			memset(&rfc, 0, sizeof(rfc));
-			rfc.mode = pi->mode;
+			rfc.mode = chan->mode;
 		}
 
 		if (result == L2CAP_CONF_SUCCESS)
-			pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
+			chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
 	}
-	rsp->scid   = cpu_to_le16(pi->dcid);
+	rsp->scid   = cpu_to_le16(chan->dcid);
 	rsp->result = cpu_to_le16(result);
 	rsp->flags  = cpu_to_le16(0x0000);
 
 	return ptr - data;
 }
 
-static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, u16 *result)
+static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct l2cap_conf_req *req = data;
 	void *ptr = req->data;
 	int type, olen;
 	unsigned long val;
 	struct l2cap_conf_rfc rfc;
 
-	BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data);
+	BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
 
 	while (len >= L2CAP_CONF_OPT_SIZE) {
 		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
@@ -1883,27 +1874,27 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
 		case L2CAP_CONF_MTU:
 			if (val < L2CAP_DEFAULT_MIN_MTU) {
 				*result = L2CAP_CONF_UNACCEPT;
-				pi->imtu = L2CAP_DEFAULT_MIN_MTU;
+				chan->imtu = L2CAP_DEFAULT_MIN_MTU;
 			} else
-				pi->imtu = val;
-			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+				chan->imtu = val;
+			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
 			break;
 
 		case L2CAP_CONF_FLUSH_TO:
-			pi->flush_to = val;
+			chan->flush_to = val;
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
-							2, pi->flush_to);
+							2, chan->flush_to);
 			break;
 
 		case L2CAP_CONF_RFC:
 			if (olen == sizeof(rfc))
 				memcpy(&rfc, (void *)val, olen);
 
-			if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
-							rfc.mode != pi->mode)
+			if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
+							rfc.mode != chan->mode)
 				return -ECONNREFUSED;
 
-			pi->fcs = 0;
+			chan->fcs = 0;
 
 			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
 					sizeof(rfc), (unsigned long) &rfc);
@@ -1911,78 +1902,74 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
 		}
 	}
 
-	if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode)
+	if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
 		return -ECONNREFUSED;
 
-	pi->mode = rfc.mode;
+	chan->mode = rfc.mode;
 
 	if (*result == L2CAP_CONF_SUCCESS) {
 		switch (rfc.mode) {
 		case L2CAP_MODE_ERTM:
-			pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
-			pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
-			pi->mps    = le16_to_cpu(rfc.max_pdu_size);
+			chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
+			chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
+			chan->mps    = le16_to_cpu(rfc.max_pdu_size);
 			break;
 		case L2CAP_MODE_STREAMING:
-			pi->mps    = le16_to_cpu(rfc.max_pdu_size);
+			chan->mps    = le16_to_cpu(rfc.max_pdu_size);
 		}
 	}
 
-	req->dcid   = cpu_to_le16(pi->dcid);
+	req->dcid   = cpu_to_le16(chan->dcid);
 	req->flags  = cpu_to_le16(0x0000);
 
 	return ptr - data;
 }
 
-static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags)
+static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
 {
 	struct l2cap_conf_rsp *rsp = data;
 	void *ptr = rsp->data;
 
-	BT_DBG("sk %p", sk);
+	BT_DBG("chan %p", chan);
 
-	rsp->scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp->scid   = cpu_to_le16(chan->dcid);
 	rsp->result = cpu_to_le16(result);
 	rsp->flags  = cpu_to_le16(flags);
 
 	return ptr - data;
 }
 
-void __l2cap_connect_rsp_defer(struct sock *sk)
+void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
 {
 	struct l2cap_conn_rsp rsp;
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	struct l2cap_conn *conn = chan->conn;
 	u8 buf[128];
 
-	sk->sk_state = BT_CONFIG;
-
-	rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
-	rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+	rsp.scid   = cpu_to_le16(chan->dcid);
+	rsp.dcid   = cpu_to_le16(chan->scid);
 	rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
 	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 	l2cap_send_cmd(conn, chan->ident,
 				L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
-	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
+	if (chan->conf_state & L2CAP_CONF_REQ_SENT)
 		return;
 
-	l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+	chan->conf_state |= L2CAP_CONF_REQ_SENT;
 	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 			l2cap_build_conf_req(chan, buf), buf);
 	chan->num_conf_req++;
 }
 
-static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
+static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	int type, olen;
 	unsigned long val;
 	struct l2cap_conf_rfc rfc;
 
-	BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len);
+	BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
 
-	if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING))
+	if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
 		return;
 
 	while (len >= L2CAP_CONF_OPT_SIZE) {
@@ -1999,12 +1986,12 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
 done:
 	switch (rfc.mode) {
 	case L2CAP_MODE_ERTM:
-		pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
-		pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
-		pi->mps    = le16_to_cpu(rfc.max_pdu_size);
+		chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
+		chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
+		chan->mps    = le16_to_cpu(rfc.max_pdu_size);
 		break;
 	case L2CAP_MODE_STREAMING:
-		pi->mps    = le16_to_cpu(rfc.max_pdu_size);
+		chan->mps    = le16_to_cpu(rfc.max_pdu_size);
 	}
 }
 
@@ -2076,6 +2063,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 		goto response;
 	}
 
+	l2cap_pi(sk)->chan = chan;
+
 	write_lock_bh(&conn->chan_lock);
 
 	/* Check if we already have channel with that dcid */
@@ -2091,23 +2080,21 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 	l2cap_sock_init(sk, parent);
 	bacpy(&bt_sk(sk)->src, conn->src);
 	bacpy(&bt_sk(sk)->dst, conn->dst);
-	l2cap_pi(sk)->psm  = psm;
-	l2cap_pi(sk)->dcid = scid;
+	chan->psm  = psm;
+	chan->dcid = scid;
 
 	bt_accept_enqueue(parent, sk);
 
 	__l2cap_chan_add(conn, chan);
 
-	l2cap_pi(sk)->chan = chan;
-
-	dcid = l2cap_pi(sk)->scid;
+	dcid = chan->scid;
 
 	l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
 	chan->ident = cmd->ident;
 
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
-		if (l2cap_check_security(sk)) {
+		if (l2cap_check_security(chan)) {
 			if (bt_sk(sk)->defer_setup) {
 				sk->sk_state = BT_CONNECT2;
 				result = L2CAP_CR_PEND;
@@ -2155,10 +2142,10 @@ sendresp:
 					L2CAP_INFO_REQ, sizeof(info), &info);
 	}
 
-	if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
+	if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
 				result == L2CAP_CR_SUCCESS) {
 		u8 buf[128];
-		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+		chan->conf_state |= L2CAP_CONF_REQ_SENT;
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 					l2cap_build_conf_req(chan, buf), buf);
 		chan->num_conf_req++;
@@ -2198,13 +2185,13 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
 	case L2CAP_CR_SUCCESS:
 		sk->sk_state = BT_CONFIG;
 		chan->ident = 0;
-		l2cap_pi(sk)->dcid = dcid;
-		l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
+		chan->dcid = dcid;
+		chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
 
-		if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
+		if (chan->conf_state & L2CAP_CONF_REQ_SENT)
 			break;
 
-		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+		chan->conf_state |= L2CAP_CONF_REQ_SENT;
 
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 					l2cap_build_conf_req(chan, req), req);
@@ -2212,7 +2199,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
 		break;
 
 	case L2CAP_CR_PEND:
-		l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+		chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 		break;
 
 	default:
@@ -2232,15 +2219,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
 	return 0;
 }
 
-static inline void set_default_fcs(struct l2cap_pinfo *pi)
+static inline void set_default_fcs(struct l2cap_chan *chan)
 {
+	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
+
 	/* FCS is enabled only in ERTM or streaming mode, if one or both
 	 * sides request it.
 	 */
-	if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING)
-		pi->fcs = L2CAP_FCS_NONE;
-	else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV))
-		pi->fcs = L2CAP_FCS_CRC16;
+	if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
+		chan->fcs = L2CAP_FCS_NONE;
+	else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
+		chan->fcs = L2CAP_FCS_CRC16;
 }
 
 static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
@@ -2276,7 +2265,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	len = cmd_len - sizeof(*req);
 	if (chan->conf_len + len > sizeof(chan->conf_req)) {
 		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-				l2cap_build_conf_rsp(sk, rsp,
+				l2cap_build_conf_rsp(chan, rsp,
 					L2CAP_CONF_REJECT, flags), rsp);
 		goto unlock;
 	}
@@ -2288,7 +2277,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (flags & 0x0001) {
 		/* Incomplete config. Send empty response. */
 		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-				l2cap_build_conf_rsp(sk, rsp,
+				l2cap_build_conf_rsp(chan, rsp,
 					L2CAP_CONF_SUCCESS, 0x0001), rsp);
 		goto unlock;
 	}
@@ -2306,27 +2295,27 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	/* Reset config buffer. */
 	chan->conf_len = 0;
 
-	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
+	if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
 		goto unlock;
 
-	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
-		set_default_fcs(l2cap_pi(sk));
+	if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
+		set_default_fcs(chan);
 
 		sk->sk_state = BT_CONNECTED;
 
 		chan->next_tx_seq = 0;
 		chan->expected_tx_seq = 0;
 		skb_queue_head_init(&chan->tx_q);
-		if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
+		if (chan->mode == L2CAP_MODE_ERTM)
 			l2cap_ertm_init(chan);
 
 		l2cap_chan_ready(sk);
 		goto unlock;
 	}
 
-	if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
+	if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
 		u8 buf[64];
-		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+		chan->conf_state |= L2CAP_CONF_REQ_SENT;
 		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 					l2cap_build_conf_req(chan, buf), buf);
 		chan->num_conf_req++;
@@ -2360,7 +2349,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
 	switch (result) {
 	case L2CAP_CONF_SUCCESS:
-		l2cap_conf_rfc_get(sk, rsp->data, len);
+		l2cap_conf_rfc_get(chan, rsp->data, len);
 		break;
 
 	case L2CAP_CONF_UNACCEPT:
@@ -2374,8 +2363,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
 			/* throw out any old stored conf requests */
 			result = L2CAP_CONF_SUCCESS;
-			len = l2cap_parse_conf_rsp(sk, rsp->data,
-							len, req, &result);
+			len = l2cap_parse_conf_rsp(chan, rsp->data, len,
+								req, &result);
 			if (len < 0) {
 				l2cap_send_disconn_req(conn, chan, ECONNRESET);
 				goto done;
@@ -2399,16 +2388,16 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 	if (flags & 0x01)
 		goto done;
 
-	l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
+	chan->conf_state |= L2CAP_CONF_INPUT_DONE;
 
-	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
-		set_default_fcs(l2cap_pi(sk));
+	if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
+		set_default_fcs(chan);
 
 		sk->sk_state = BT_CONNECTED;
 		chan->next_tx_seq = 0;
 		chan->expected_tx_seq = 0;
 		skb_queue_head_init(&chan->tx_q);
-		if (l2cap_pi(sk)->mode ==  L2CAP_MODE_ERTM)
+		if (chan->mode ==  L2CAP_MODE_ERTM)
 			l2cap_ertm_init(chan);
 
 		l2cap_chan_ready(sk);
@@ -2438,8 +2427,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
 	sk = chan->sk;
 
-	rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
-	rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp.dcid = cpu_to_le16(chan->scid);
+	rsp.scid = cpu_to_le16(chan->dcid);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
 
 	sk->sk_shutdown = SHUTDOWN_MASK;
@@ -2774,12 +2763,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 	kfree_skb(skb);
 }
 
-static int l2cap_check_fcs(struct l2cap_pinfo *pi,  struct sk_buff *skb)
+static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 {
 	u16 our_fcs, rcv_fcs;
 	int hdr_size = L2CAP_HDR_SIZE + 2;
 
-	if (pi->fcs == L2CAP_FCS_CRC16) {
+	if (chan->fcs == L2CAP_FCS_CRC16) {
 		skb_trim(skb, skb->len - 2);
 		rcv_fcs = get_unaligned_le16(skb->data + skb->len);
 		our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
@@ -2860,7 +2849,6 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
 
 static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct sk_buff *_skb;
 	int err;
 
@@ -2881,7 +2869,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
 
 		chan->sdu_len = get_unaligned_le16(skb->data);
 
-		if (chan->sdu_len > pi->imtu)
+		if (chan->sdu_len > chan->imtu)
 			goto disconnect;
 
 		chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
@@ -2924,7 +2912,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
 		if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
 			chan->partial_sdu_len += skb->len;
 
-			if (chan->partial_sdu_len > pi->imtu)
+			if (chan->partial_sdu_len > chan->imtu)
 				goto drop;
 
 			if (chan->partial_sdu_len != chan->sdu_len)
@@ -2961,7 +2949,7 @@ drop:
 	chan->sdu = NULL;
 
 disconnect:
-	l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+	l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 	kfree_skb(skb);
 	return 0;
 }
@@ -3022,7 +3010,7 @@ static void l2cap_busy_work(struct work_struct *work)
 
 		if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
 			err = -EBUSY;
-			l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY);
+			l2cap_send_disconn_req(chan->conn, chan, EBUSY);
 			break;
 		}
 
@@ -3092,7 +3080,6 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
 
 static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	struct sk_buff *_skb;
 	int err = -EINVAL;
 
@@ -3123,7 +3110,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
 		chan->sdu_len = get_unaligned_le16(skb->data);
 		skb_pull(skb, 2);
 
-		if (chan->sdu_len > pi->imtu) {
+		if (chan->sdu_len > chan->imtu) {
 			err = -EMSGSIZE;
 			break;
 		}
@@ -3164,7 +3151,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
 		chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
 		chan->partial_sdu_len += skb->len;
 
-		if (chan->partial_sdu_len > pi->imtu)
+		if (chan->partial_sdu_len > chan->imtu)
 			goto drop;
 
 		if (chan->partial_sdu_len == chan->sdu_len) {
@@ -3241,12 +3228,11 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
 
 static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
 {
-	struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 	u8 tx_seq = __get_txseq(rx_control);
 	u8 req_seq = __get_reqseq(rx_control);
 	u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
 	int tx_seq_offset, expected_tx_seq_offset;
-	int num_to_ack = (pi->tx_win/6) + 1;
+	int num_to_ack = (chan->tx_win/6) + 1;
 	int err = 0;
 
 	BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
@@ -3271,8 +3257,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
 		tx_seq_offset += 64;
 
 	/* invalid tx_seq */
-	if (tx_seq_offset >= pi->tx_win) {
-		l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+	if (tx_seq_offset >= chan->tx_win) {
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 		goto drop;
 	}
 
@@ -3539,7 +3525,6 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	u16 control;
 	u8 req_seq;
 	int len, next_tx_seq_offset, req_seq_offset;
@@ -3553,17 +3538,17 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 	 * Receiver will miss it and start proper recovery
 	 * procedures and ask retransmission.
 	 */
-	if (l2cap_check_fcs(pi, skb))
+	if (l2cap_check_fcs(chan, skb))
 		goto drop;
 
 	if (__is_sar_start(control) && __is_iframe(control))
 		len -= 2;
 
-	if (pi->fcs == L2CAP_FCS_CRC16)
+	if (chan->fcs == L2CAP_FCS_CRC16)
 		len -= 2;
 
-	if (len > pi->mps) {
-		l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+	if (len > chan->mps) {
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 		goto drop;
 	}
 
@@ -3579,13 +3564,13 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 
 	/* check for invalid req-seq */
 	if (req_seq_offset > next_tx_seq_offset) {
-		l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 		goto drop;
 	}
 
 	if (__is_iframe(control)) {
 		if (len < 0) {
-			l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 			goto drop;
 		}
 
@@ -3593,7 +3578,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 	} else {
 		if (len != 0) {
 			BT_ERR("%d", len);
-			l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+			l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 			goto drop;
 		}
 
@@ -3630,14 +3615,14 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 	if (sk->sk_state != BT_CONNECTED)
 		goto drop;
 
-	switch (pi->mode) {
+	switch (chan->mode) {
 	case L2CAP_MODE_BASIC:
 		/* If socket recv buffers overflows we drop data here
 		 * which is *bad* because L2CAP has to be reliable.
 		 * But we don't have any other choice. L2CAP doesn't
 		 * provide flow control mechanism. */
 
-		if (pi->imtu < skb->len)
+		if (chan->imtu < skb->len)
 			goto drop;
 
 		if (!sock_queue_rcv_skb(sk, skb))
@@ -3659,16 +3644,16 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 		skb_pull(skb, 2);
 		len = skb->len;
 
-		if (l2cap_check_fcs(pi, skb))
+		if (l2cap_check_fcs(chan, skb))
 			goto drop;
 
 		if (__is_sar_start(control))
 			len -= 2;
 
-		if (pi->fcs == L2CAP_FCS_CRC16)
+		if (chan->fcs == L2CAP_FCS_CRC16)
 			len -= 2;
 
-		if (len > pi->mps || len < 0 || __is_sframe(control))
+		if (len > chan->mps || len < 0 || __is_sframe(control))
 			goto drop;
 
 		tx_seq = __get_txseq(control);
@@ -3683,7 +3668,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 		goto done;
 
 	default:
-		BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode);
+		BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
 		break;
 	}
 
@@ -3712,7 +3697,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
 	if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
 		goto drop;
 
-	if (l2cap_pi(sk)->imtu < skb->len)
+	if (l2cap_pi(sk)->chan->imtu < skb->len)
 		goto drop;
 
 	if (!sock_queue_rcv_skb(sk, skb))
@@ -3742,7 +3727,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
 	if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
 		goto drop;
 
-	if (l2cap_pi(sk)->imtu < skb->len)
+	if (l2cap_pi(sk)->chan->imtu < skb->len)
 		goto drop;
 
 	if (!sock_queue_rcv_skb(sk, skb))
@@ -3812,17 +3797,19 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 	/* Find listening sockets and check their link_mode */
 	read_lock(&l2cap_sk_list.lock);
 	sk_for_each(sk, node, &l2cap_sk_list.head) {
+		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
 		if (sk->sk_state != BT_LISTEN)
 			continue;
 
 		if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
 			lm1 |= HCI_LM_ACCEPT;
-			if (l2cap_pi(sk)->role_switch)
+			if (chan->role_switch)
 				lm1 |= HCI_LM_MASTER;
 			exact++;
 		} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
 			lm2 |= HCI_LM_ACCEPT;
-			if (l2cap_pi(sk)->role_switch)
+			if (chan->role_switch)
 				lm2 |= HCI_LM_MASTER;
 		}
 	}
@@ -3874,19 +3861,21 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 	return 0;
 }
 
-static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
+static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
 {
+	struct sock *sk = chan->sk;
+
 	if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM)
 		return;
 
 	if (encrypt == 0x00) {
-		if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
+		if (chan->sec_level == BT_SECURITY_MEDIUM) {
 			l2cap_sock_clear_timer(sk);
 			l2cap_sock_set_timer(sk, HZ * 5);
-		} else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+		} else if (chan->sec_level == BT_SECURITY_HIGH)
 			__l2cap_sock_close(sk, ECONNREFUSED);
 	} else {
-		if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
+		if (chan->sec_level == BT_SECURITY_MEDIUM)
 			l2cap_sock_clear_timer(sk);
 	}
 }
@@ -3908,14 +3897,14 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
 		bh_lock_sock(sk);
 
-		if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
+		if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
 			bh_unlock_sock(sk);
 			continue;
 		}
 
 		if (!status && (sk->sk_state == BT_CONNECTED ||
 						sk->sk_state == BT_CONFIG)) {
-			l2cap_check_encryption(sk, encrypt);
+			l2cap_check_encryption(chan, encrypt);
 			bh_unlock_sock(sk);
 			continue;
 		}
@@ -3923,11 +3912,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 		if (sk->sk_state == BT_CONNECT) {
 			if (!status) {
 				struct l2cap_conn_req req;
-				req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-				req.psm  = l2cap_pi(sk)->psm;
+				req.scid = cpu_to_le16(chan->scid);
+				req.psm  = chan->psm;
 
 				chan->ident = l2cap_get_ident(conn);
-				l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+				chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 
 				l2cap_send_cmd(conn, chan->ident,
 					L2CAP_CONN_REQ, sizeof(req), &req);
@@ -3948,8 +3937,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 				result = L2CAP_CR_SEC_BLOCK;
 			}
 
-			rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
-			rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+			rsp.scid   = cpu_to_le16(chan->dcid);
+			rsp.dcid   = cpu_to_le16(chan->scid);
 			rsp.result = cpu_to_le16(result);
 			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
@@ -4021,10 +4010,10 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
 		if (chan && chan->sk) {
 			struct sock *sk = chan->sk;
 
-			if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
+			if (chan->imtu < len - L2CAP_HDR_SIZE) {
 				BT_ERR("Frame exceeding recv MTU (len %d, "
 							"MTU %d)", len,
-							l2cap_pi(sk)->imtu);
+							chan->imtu);
 				bh_unlock_sock(sk);
 				l2cap_conn_unreliable(conn, ECOMM);
 				goto drop;
@@ -4084,14 +4073,15 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
 
 	sk_for_each(sk, node, &l2cap_sk_list.head) {
 		struct l2cap_pinfo *pi = l2cap_pi(sk);
+		struct l2cap_chan *chan = pi->chan;
 
 		seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
 					batostr(&bt_sk(sk)->src),
 					batostr(&bt_sk(sk)->dst),
-					sk->sk_state, __le16_to_cpu(pi->psm),
-					pi->scid, pi->dcid,
-					pi->imtu, pi->omtu, pi->sec_level,
-					pi->mode);
+					sk->sk_state, __le16_to_cpu(chan->psm),
+					chan->scid, chan->dcid,
+					chan->imtu, chan->omtu, chan->sec_level,
+					chan->mode);
 	}
 
 	read_unlock_bh(&l2cap_sk_list.lock);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 47394a178bd5e0198a815e1e310dae7c88305ea6..7c4a9ae9b3ce96cf602c92918039171c6c8fc9e0 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -30,6 +30,8 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
+static const struct proto_ops l2cap_sock_ops;
+
 /* ---- L2CAP timers ---- */
 static void l2cap_sock_timeout(unsigned long arg)
 {
@@ -51,7 +53,7 @@ static void l2cap_sock_timeout(unsigned long arg)
 	if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
 		reason = ECONNREFUSED;
 	else if (sk->sk_state == BT_CONNECT &&
-				l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
+			l2cap_pi(sk)->chan->sec_level != BT_SECURITY_SDP)
 		reason = ECONNREFUSED;
 	else
 		reason = ETIMEDOUT;
@@ -80,9 +82,13 @@ static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
 	struct sock *sk;
 	struct hlist_node *node;
-	sk_for_each(sk, node, &l2cap_sk_list.head)
-		if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
+	sk_for_each(sk, node, &l2cap_sk_list.head) {
+		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+		if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src))
 			goto found;
+	}
+
 	sk = NULL;
 found:
 	return sk;
@@ -91,6 +97,7 @@ found:
 static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct sockaddr_l2 la;
 	int len, err = 0;
 
@@ -136,17 +143,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	} else {
 		/* Save source address */
 		bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
-		l2cap_pi(sk)->psm   = la.l2_psm;
-		l2cap_pi(sk)->sport = la.l2_psm;
+		chan->psm   = la.l2_psm;
+		chan->sport = la.l2_psm;
 		sk->sk_state = BT_BOUND;
 
 		if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
 					__le16_to_cpu(la.l2_psm) == 0x0003)
-			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+			chan->sec_level = BT_SECURITY_SDP;
 	}
 
 	if (la.l2_cid)
-		l2cap_pi(sk)->scid = la.l2_cid;
+		chan->scid = la.l2_cid;
 
 	write_unlock_bh(&l2cap_sk_list.lock);
 
@@ -158,6 +165,7 @@ done:
 static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct sockaddr_l2 la;
 	int len, err = 0;
 
@@ -182,7 +190,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 		goto done;
 	}
 
-	switch (l2cap_pi(sk)->mode) {
+	switch (chan->mode) {
 	case L2CAP_MODE_BASIC:
 		break;
 	case L2CAP_MODE_ERTM:
@@ -226,10 +234,10 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 
 	/* Set destination address and psm */
 	bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
-	l2cap_pi(sk)->psm = la.l2_psm;
-	l2cap_pi(sk)->dcid = la.l2_cid;
+	chan->psm = la.l2_psm;
+	chan->dcid = la.l2_cid;
 
-	err = l2cap_do_connect(sk);
+	err = l2cap_chan_connect(l2cap_pi(sk)->chan);
 	if (err)
 		goto done;
 
@@ -244,6 +252,7 @@ done:
 static int l2cap_sock_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	int err = 0;
 
 	BT_DBG("sk %p backlog %d", sk, backlog);
@@ -256,7 +265,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 		goto done;
 	}
 
-	switch (l2cap_pi(sk)->mode) {
+	switch (chan->mode) {
 	case L2CAP_MODE_BASIC:
 		break;
 	case L2CAP_MODE_ERTM:
@@ -269,7 +278,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 		goto done;
 	}
 
-	if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) {
+	if (!chan->psm && !chan->scid) {
 		bdaddr_t *src = &bt_sk(sk)->src;
 		u16 psm;
 
@@ -279,8 +288,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 
 		for (psm = 0x1001; psm < 0x1100; psm += 2)
 			if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
-				l2cap_pi(sk)->psm   = cpu_to_le16(psm);
-				l2cap_pi(sk)->sport = cpu_to_le16(psm);
+				chan->psm   = cpu_to_le16(psm);
+				chan->sport = cpu_to_le16(psm);
 				err = 0;
 				break;
 			}
@@ -360,6 +369,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
 {
 	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 
 	BT_DBG("sock %p, sk %p", sock, sk);
 
@@ -367,13 +377,13 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
 	*len = sizeof(struct sockaddr_l2);
 
 	if (peer) {
-		la->l2_psm = l2cap_pi(sk)->psm;
+		la->l2_psm = chan->psm;
 		bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
-		la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+		la->l2_cid = cpu_to_le16(chan->dcid);
 	} else {
-		la->l2_psm = l2cap_pi(sk)->sport;
+		la->l2_psm = chan->sport;
 		bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
-		la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid);
+		la->l2_cid = cpu_to_le16(chan->scid);
 	}
 
 	return 0;
@@ -382,6 +392,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
 static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct l2cap_options opts;
 	struct l2cap_conninfo cinfo;
 	int len, err = 0;
@@ -397,13 +408,13 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
 	switch (optname) {
 	case L2CAP_OPTIONS:
 		memset(&opts, 0, sizeof(opts));
-		opts.imtu     = l2cap_pi(sk)->imtu;
-		opts.omtu     = l2cap_pi(sk)->omtu;
-		opts.flush_to = l2cap_pi(sk)->flush_to;
-		opts.mode     = l2cap_pi(sk)->mode;
-		opts.fcs      = l2cap_pi(sk)->fcs;
-		opts.max_tx   = l2cap_pi(sk)->max_tx;
-		opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
+		opts.imtu     = chan->imtu;
+		opts.omtu     = chan->omtu;
+		opts.flush_to = chan->flush_to;
+		opts.mode     = chan->mode;
+		opts.fcs      = chan->fcs;
+		opts.max_tx   = chan->max_tx;
+		opts.txwin_size = (__u16)chan->tx_win;
 
 		len = min_t(unsigned int, len, sizeof(opts));
 		if (copy_to_user(optval, (char *) &opts, len))
@@ -412,7 +423,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
 		break;
 
 	case L2CAP_LM:
-		switch (l2cap_pi(sk)->sec_level) {
+		switch (chan->sec_level) {
 		case BT_SECURITY_LOW:
 			opt = L2CAP_LM_AUTH;
 			break;
@@ -428,10 +439,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
 			break;
 		}
 
-		if (l2cap_pi(sk)->role_switch)
+		if (chan->role_switch)
 			opt |= L2CAP_LM_MASTER;
 
-		if (l2cap_pi(sk)->force_reliable)
+		if (chan->force_reliable)
 			opt |= L2CAP_LM_RELIABLE;
 
 		if (put_user(opt, (u32 __user *) optval))
@@ -446,8 +457,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
 			break;
 		}
 
-		cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
-		memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3);
+		cinfo.hci_handle = chan->conn->hcon->handle;
+		memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
 
 		len = min_t(unsigned int, len, sizeof(cinfo));
 		if (copy_to_user(optval, (char *) &cinfo, len))
@@ -467,6 +478,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
 static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct bt_security sec;
 	int len, err = 0;
 
@@ -491,7 +503,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 			break;
 		}
 
-		sec.level = l2cap_pi(sk)->sec_level;
+		sec.level = chan->sec_level;
 
 		len = min_t(unsigned int, len, sizeof(sec));
 		if (copy_to_user(optval, (char *) &sec, len))
@@ -511,7 +523,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 		break;
 
 	case BT_FLUSHABLE:
-		if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval))
+		if (put_user(chan->flushable, (u32 __user *) optval))
 			err = -EFAULT;
 
 		break;
@@ -528,6 +540,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct l2cap_options opts;
 	int len, err = 0;
 	u32 opt;
@@ -543,13 +556,13 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 			break;
 		}
 
-		opts.imtu     = l2cap_pi(sk)->imtu;
-		opts.omtu     = l2cap_pi(sk)->omtu;
-		opts.flush_to = l2cap_pi(sk)->flush_to;
-		opts.mode     = l2cap_pi(sk)->mode;
-		opts.fcs      = l2cap_pi(sk)->fcs;
-		opts.max_tx   = l2cap_pi(sk)->max_tx;
-		opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
+		opts.imtu     = chan->imtu;
+		opts.omtu     = chan->omtu;
+		opts.flush_to = chan->flush_to;
+		opts.mode     = chan->mode;
+		opts.fcs      = chan->fcs;
+		opts.max_tx   = chan->max_tx;
+		opts.txwin_size = (__u16)chan->tx_win;
 
 		len = min_t(unsigned int, sizeof(opts), optlen);
 		if (copy_from_user((char *) &opts, optval, len)) {
@@ -562,10 +575,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 			break;
 		}
 
-		l2cap_pi(sk)->mode = opts.mode;
-		switch (l2cap_pi(sk)->mode) {
+		chan->mode = opts.mode;
+		switch (chan->mode) {
 		case L2CAP_MODE_BASIC:
-			l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
+			chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
 			break;
 		case L2CAP_MODE_ERTM:
 		case L2CAP_MODE_STREAMING:
@@ -577,11 +590,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 			break;
 		}
 
-		l2cap_pi(sk)->imtu = opts.imtu;
-		l2cap_pi(sk)->omtu = opts.omtu;
-		l2cap_pi(sk)->fcs  = opts.fcs;
-		l2cap_pi(sk)->max_tx = opts.max_tx;
-		l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
+		chan->imtu = opts.imtu;
+		chan->omtu = opts.omtu;
+		chan->fcs  = opts.fcs;
+		chan->max_tx = opts.max_tx;
+		chan->tx_win = (__u8)opts.txwin_size;
 		break;
 
 	case L2CAP_LM:
@@ -591,14 +604,14 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 		}
 
 		if (opt & L2CAP_LM_AUTH)
-			l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
+			chan->sec_level = BT_SECURITY_LOW;
 		if (opt & L2CAP_LM_ENCRYPT)
-			l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
+			chan->sec_level = BT_SECURITY_MEDIUM;
 		if (opt & L2CAP_LM_SECURE)
-			l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
+			chan->sec_level = BT_SECURITY_HIGH;
 
-		l2cap_pi(sk)->role_switch    = (opt & L2CAP_LM_MASTER);
-		l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
+		chan->role_switch    = (opt & L2CAP_LM_MASTER);
+		chan->force_reliable = (opt & L2CAP_LM_RELIABLE);
 		break;
 
 	default:
@@ -613,6 +626,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct bt_security sec;
 	int len, err = 0;
 	u32 opt;
@@ -649,7 +663,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 			break;
 		}
 
-		l2cap_pi(sk)->sec_level = sec.level;
+		chan->sec_level = sec.level;
 		break;
 
 	case BT_DEFER_SETUP:
@@ -678,7 +692,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 		}
 
 		if (opt == BT_FLUSHABLE_OFF) {
-			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+			struct l2cap_conn *conn = chan->conn;
 			/* proceed further only when we have l2cap_conn and
 			   No Flush support in the LM */
 			if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
@@ -687,7 +701,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 			}
 		}
 
-		l2cap_pi(sk)->flushable = opt;
+		chan->flushable = opt;
 		break;
 
 	default:
@@ -702,7 +716,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	struct sk_buff *skb;
 	u16 control;
 	int err;
@@ -725,76 +739,77 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
 
 	/* Connectionless channel */
 	if (sk->sk_type == SOCK_DGRAM) {
-		skb = l2cap_create_connless_pdu(sk, msg, len);
+		skb = l2cap_create_connless_pdu(chan, msg, len);
 		if (IS_ERR(skb)) {
 			err = PTR_ERR(skb);
 		} else {
-			l2cap_do_send(sk, skb);
+			l2cap_do_send(chan, skb);
 			err = len;
 		}
 		goto done;
 	}
 
-	switch (pi->mode) {
+	switch (chan->mode) {
 	case L2CAP_MODE_BASIC:
 		/* Check outgoing MTU */
-		if (len > pi->omtu) {
+		if (len > chan->omtu) {
 			err = -EMSGSIZE;
 			goto done;
 		}
 
 		/* Create a basic PDU */
-		skb = l2cap_create_basic_pdu(sk, msg, len);
+		skb = l2cap_create_basic_pdu(chan, msg, len);
 		if (IS_ERR(skb)) {
 			err = PTR_ERR(skb);
 			goto done;
 		}
 
-		l2cap_do_send(sk, skb);
+		l2cap_do_send(chan, skb);
 		err = len;
 		break;
 
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_STREAMING:
 		/* Entire SDU fits into one PDU */
-		if (len <= pi->chan->remote_mps) {
+		if (len <= chan->remote_mps) {
 			control = L2CAP_SDU_UNSEGMENTED;
-			skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
+			skb = l2cap_create_iframe_pdu(chan, msg, len, control,
+									0);
 			if (IS_ERR(skb)) {
 				err = PTR_ERR(skb);
 				goto done;
 			}
-			__skb_queue_tail(&pi->chan->tx_q, skb);
+			__skb_queue_tail(&chan->tx_q, skb);
 
-			if (pi->chan->tx_send_head == NULL)
-				pi->chan->tx_send_head = skb;
+			if (chan->tx_send_head == NULL)
+				chan->tx_send_head = skb;
 
 		} else {
 		/* Segment SDU into multiples PDUs */
-			err = l2cap_sar_segment_sdu(pi->chan, msg, len);
+			err = l2cap_sar_segment_sdu(chan, msg, len);
 			if (err < 0)
 				goto done;
 		}
 
-		if (pi->mode == L2CAP_MODE_STREAMING) {
-			l2cap_streaming_send(pi->chan);
+		if (chan->mode == L2CAP_MODE_STREAMING) {
+			l2cap_streaming_send(chan);
 			err = len;
 			break;
 		}
 
-		if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
-				(pi->chan->conn_state & L2CAP_CONN_WAIT_F)) {
+		if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+				(chan->conn_state & L2CAP_CONN_WAIT_F)) {
 			err = len;
 			break;
 		}
-		err = l2cap_ertm_send(pi->chan);
+		err = l2cap_ertm_send(chan);
 
 		if (err >= 0)
 			err = len;
 		break;
 
 	default:
-		BT_DBG("bad state %1.1x", pi->mode);
+		BT_DBG("bad state %1.1x", chan->mode);
 		err = -EBADFD;
 	}
 
@@ -810,7 +825,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
 	lock_sock(sk);
 
 	if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
-		__l2cap_connect_rsp_defer(sk);
+		sk->sk_state = BT_CONFIG;
+
+		__l2cap_connect_rsp_defer(l2cap_pi(sk)->chan);
 		release_sock(sk);
 		return 0;
 	}
@@ -834,6 +851,8 @@ void l2cap_sock_kill(struct sock *sk)
 	BT_DBG("sk %p state %d", sk, sk->sk_state);
 
 	/* Kill poor orphan */
+
+	l2cap_chan_free(l2cap_pi(sk)->chan);
 	bt_sock_unlink(&l2cap_sk_list, sk);
 	sock_set_flag(sk, SOCK_DEAD);
 	sock_put(sk);
@@ -865,8 +884,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
 
 void __l2cap_sock_close(struct sock *sk, int reason)
 {
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	struct l2cap_conn *conn = chan->conn;
 
 	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
 
@@ -898,8 +917,8 @@ void __l2cap_sock_close(struct sock *sk, int reason)
 			else
 				result = L2CAP_CR_BAD_PSM;
 
-			rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
-			rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+			rsp.scid   = cpu_to_le16(chan->dcid);
+			rsp.dcid   = cpu_to_le16(chan->scid);
 			rsp.result = cpu_to_le16(result);
 			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
@@ -923,6 +942,7 @@ void __l2cap_sock_close(struct sock *sk, int reason)
 static int l2cap_sock_shutdown(struct socket *sock, int how)
 {
 	struct sock *sk = sock->sk;
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 	int err = 0;
 
 	BT_DBG("sock %p, sk %p", sock, sk);
@@ -932,7 +952,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
 
 	lock_sock(sk);
 	if (!sk->sk_shutdown) {
-		if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
+		if (chan->mode == L2CAP_MODE_ERTM)
 			err = __l2cap_wait_ack(sk);
 
 		sk->sk_shutdown = SHUTDOWN_MASK;
@@ -979,44 +999,47 @@ static void l2cap_sock_destruct(struct sock *sk)
 void l2cap_sock_init(struct sock *sk, struct sock *parent)
 {
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct l2cap_chan *chan = pi->chan;
 
 	BT_DBG("sk %p", sk);
 
 	if (parent) {
+		struct l2cap_chan *pchan = l2cap_pi(parent)->chan;
+
 		sk->sk_type = parent->sk_type;
 		bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
 
-		pi->imtu = l2cap_pi(parent)->imtu;
-		pi->omtu = l2cap_pi(parent)->omtu;
-		pi->conf_state = l2cap_pi(parent)->conf_state;
-		pi->mode = l2cap_pi(parent)->mode;
-		pi->fcs  = l2cap_pi(parent)->fcs;
-		pi->max_tx = l2cap_pi(parent)->max_tx;
-		pi->tx_win = l2cap_pi(parent)->tx_win;
-		pi->sec_level = l2cap_pi(parent)->sec_level;
-		pi->role_switch = l2cap_pi(parent)->role_switch;
-		pi->force_reliable = l2cap_pi(parent)->force_reliable;
-		pi->flushable = l2cap_pi(parent)->flushable;
+		chan->imtu = pchan->imtu;
+		chan->omtu = pchan->omtu;
+		chan->conf_state = pchan->conf_state;
+		chan->mode = pchan->mode;
+		chan->fcs  = pchan->fcs;
+		chan->max_tx = pchan->max_tx;
+		chan->tx_win = pchan->tx_win;
+		chan->sec_level = pchan->sec_level;
+		chan->role_switch = pchan->role_switch;
+		chan->force_reliable = pchan->force_reliable;
+		chan->flushable = pchan->flushable;
 	} else {
-		pi->imtu = L2CAP_DEFAULT_MTU;
-		pi->omtu = 0;
+		chan->imtu = L2CAP_DEFAULT_MTU;
+		chan->omtu = 0;
 		if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
-			pi->mode = L2CAP_MODE_ERTM;
-			pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+			chan->mode = L2CAP_MODE_ERTM;
+			chan->conf_state |= L2CAP_CONF_STATE2_DEVICE;
 		} else {
-			pi->mode = L2CAP_MODE_BASIC;
+			chan->mode = L2CAP_MODE_BASIC;
 		}
-		pi->max_tx = L2CAP_DEFAULT_MAX_TX;
-		pi->fcs  = L2CAP_FCS_CRC16;
-		pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
-		pi->sec_level = BT_SECURITY_LOW;
-		pi->role_switch = 0;
-		pi->force_reliable = 0;
-		pi->flushable = BT_FLUSHABLE_OFF;
+		chan->max_tx = L2CAP_DEFAULT_MAX_TX;
+		chan->fcs  = L2CAP_FCS_CRC16;
+		chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+		chan->sec_level = BT_SECURITY_LOW;
+		chan->role_switch = 0;
+		chan->force_reliable = 0;
+		chan->flushable = BT_FLUSHABLE_OFF;
 	}
 
 	/* Default config options */
-	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 }
 
 static struct proto l2cap_proto = {
@@ -1054,6 +1077,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
 			     int kern)
 {
 	struct sock *sk;
+	struct l2cap_chan *chan;
 
 	BT_DBG("sock %p", sock);
 
@@ -1072,11 +1096,19 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
 	if (!sk)
 		return -ENOMEM;
 
+	chan = l2cap_chan_alloc(sk);
+	if (!chan) {
+		l2cap_sock_kill(sk);
+		return -ENOMEM;
+	}
+
+	l2cap_pi(sk)->chan = chan;
+
 	l2cap_sock_init(sk, NULL);
 	return 0;
 }
 
-const struct proto_ops l2cap_sock_ops = {
+static const struct proto_ops l2cap_sock_ops = {
 	.family		= PF_BLUETOOTH,
 	.owner		= THIS_MODULE,
 	.release	= l2cap_sock_release,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c304688252b81c243e9bbc59e84c1dd70740291d..2481d257ed98058c644f5553bf41132a5793dba7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -945,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
 	for (i = 0; i < key_count; i++) {
 		struct mgmt_key_info *key = &cp->keys[i];
 
-		hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
+		hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
 								key->pin_len);
 	}
 
@@ -1569,6 +1569,75 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
 	return err;
 }
 
+static int start_discovery(struct sock *sk, u16 index)
+{
+	u8 lap[3] = { 0x33, 0x8b, 0x9e };
+	struct hci_cp_inquiry cp;
+	struct pending_cmd *cmd;
+	struct hci_dev *hdev;
+	int err;
+
+	BT_DBG("hci%u", index);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	memset(&cp, 0, sizeof(cp));
+	memcpy(&cp.lap, lap, 3);
+	cp.length  = 0x08;
+	cp.num_rsp = 0x00;
+
+	err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+	if (err < 0)
+		mgmt_pending_remove(cmd);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int stop_discovery(struct sock *sk, u16 index)
+{
+	struct hci_dev *hdev;
+	struct pending_cmd *cmd;
+	int err;
+
+	BT_DBG("hci%u", index);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
+	if (!cmd) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+	if (err < 0)
+		mgmt_pending_remove(cmd);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 	unsigned char *buf;
@@ -1677,7 +1746,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 		err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
 									len);
 		break;
-
+	case MGMT_OP_START_DISCOVERY:
+		err = start_discovery(sk, index);
+		break;
+	case MGMT_OP_STOP_DISCOVERY:
+		err = stop_discovery(sk, index);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, index, opcode, 0x01);
@@ -1784,17 +1858,17 @@ int mgmt_connectable(u16 index, u8 connectable)
 	return ret;
 }
 
-int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
+int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
 {
 	struct mgmt_ev_new_key ev;
 
 	memset(&ev, 0, sizeof(ev));
 
+	ev.store_hint = persistent;
 	bacpy(&ev.key.bdaddr, &key->bdaddr);
 	ev.key.type = key->type;
 	memcpy(ev.key.val, key->val, 16);
 	ev.key.pin_len = key->pin_len;
-	ev.old_key_type = old_key_type;
 
 	return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
 }
@@ -1868,11 +1942,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
 	return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
+int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
 {
 	struct mgmt_ev_pin_code_request ev;
 
 	bacpy(&ev.bdaddr, bdaddr);
+	ev.secure = secure;
 
 	return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
 									NULL);
@@ -1920,13 +1995,15 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
 	return err;
 }
 
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value)
+int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
+							u8 confirm_hint)
 {
 	struct mgmt_ev_user_confirm_request ev;
 
 	BT_DBG("hci%u", index);
 
 	bacpy(&ev.bdaddr, bdaddr);
+	ev.confirm_hint = confirm_hint;
 	put_unaligned_le32(value, &ev.value);
 
 	return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
@@ -2075,3 +2152,9 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
 
 	return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
 }
+
+int mgmt_discovering(u16 index, u8 discovering)
+{
+	return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
+						sizeof(discovering), NULL);
+}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index c9973932456f74e68e4dfd8b7f20199a65c9bd4e..121a5c13b98933d9634009173ea502c7ed7b48d0 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -232,6 +232,8 @@ static int rfcomm_l2sock_create(struct socket **sock)
 static inline int rfcomm_check_security(struct rfcomm_dlc *d)
 {
 	struct sock *sk = d->session->sock->sk;
+	struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
+
 	__u8 auth_type;
 
 	switch (d->sec_level) {
@@ -246,8 +248,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d)
 		break;
 	}
 
-	return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level,
-								auth_type);
+	return hci_conn_security(conn->hcon, d->sec_level, auth_type);
 }
 
 static void rfcomm_session_timeout(unsigned long arg)
@@ -710,10 +711,10 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
 	/* Set L2CAP options */
 	sk = sock->sk;
 	lock_sock(sk);
-	l2cap_pi(sk)->imtu = l2cap_mtu;
-	l2cap_pi(sk)->sec_level = sec_level;
+	l2cap_pi(sk)->chan->imtu = l2cap_mtu;
+	l2cap_pi(sk)->chan->sec_level = sec_level;
 	if (l2cap_ertm)
-		l2cap_pi(sk)->mode = L2CAP_MODE_ERTM;
+		l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM;
 	release_sock(sk);
 
 	s = rfcomm_session_add(sock, BT_BOUND);
@@ -1241,6 +1242,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
 void rfcomm_dlc_accept(struct rfcomm_dlc *d)
 {
 	struct sock *sk = d->session->sock->sk;
+	struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
 
 	BT_DBG("dlc %p", d);
 
@@ -1254,7 +1256,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
 	rfcomm_dlc_unlock(d);
 
 	if (d->role_switch)
-		hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
+		hci_conn_switch_role(conn->hcon, 0x00);
 
 	rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
 }
@@ -1890,7 +1892,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
 
 		/* We should adjust MTU on incoming sessions.
 		 * L2CAP MTU minus UIH header and FCS. */
-		s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5;
+		s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
+				l2cap_pi(nsock->sk)->chan->imtu) - 5;
 
 		rfcomm_schedule();
 	} else
@@ -1909,7 +1912,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
 
 		/* We can adjust MTU on outgoing sessions.
 		 * L2CAP MTU minus UIH header and FCS. */
-		s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
+		s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5;
 
 		rfcomm_send_sabm(s, 0);
 		break;
@@ -1992,7 +1995,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
 	/* Set L2CAP options */
 	sk = sock->sk;
 	lock_sock(sk);
-	l2cap_pi(sk)->imtu = l2cap_mtu;
+	l2cap_pi(sk)->chan->imtu = l2cap_mtu;
 	release_sock(sk);
 
 	/* Start listening on the socket */
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 66cc1f0c3df85c5f5b18c8f179ef8434d23f4cf8..386cfaffd4b7569e919c933f89192eeb30cf14e2 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -743,6 +743,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 	struct sock *sk = sock->sk;
 	struct sock *l2cap_sk;
 	struct rfcomm_conninfo cinfo;
+	struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
 	int len, err = 0;
 	u32 opt;
 
@@ -787,8 +788,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 
 		l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
 
-		cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
-		memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
+		cinfo.hci_handle = conn->hcon->handle;
+		memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
 
 		len = min_t(unsigned int, len, sizeof(cinfo));
 		if (copy_to_user(optval, (char *) &cinfo, len))
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 4bd6ef0be38083aae25162a69250164b0afdab68..b9b595c081123d518ff19416f9f6cb705b8d3fb1 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -54,13 +54,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
 			       u8 *cdata, u8 *mic)
 {
 	int i, j, last_len, num_blocks;
-	u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad;
+	u8 *pos, *cpos, *b, *s_0, *e, *b_0;
 
 	b = scratch;
 	s_0 = scratch + AES_BLOCK_LEN;
 	e = scratch + 2 * AES_BLOCK_LEN;
 	b_0 = scratch + 3 * AES_BLOCK_LEN;
-	aad = scratch + 4 * AES_BLOCK_LEN;
 
 	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
 	last_len = data_len % AES_BLOCK_LEN;
@@ -94,13 +93,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
 			      u8 *cdata, size_t data_len, u8 *mic, u8 *data)
 {
 	int i, j, last_len, num_blocks;
-	u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad;
+	u8 *pos, *cpos, *b, *s_0, *a, *b_0;
 
 	b = scratch;
 	s_0 = scratch + AES_BLOCK_LEN;
 	a = scratch + 2 * AES_BLOCK_LEN;
 	b_0 = scratch + 3 * AES_BLOCK_LEN;
-	aad = scratch + 4 * AES_BLOCK_LEN;
 
 	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
 	last_len = data_len % AES_BLOCK_LEN;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a9ddaf63ee14f404a8998297d0e609f7afbf0b87..12d52cec9515183bf020ffb8a42c3ca4e2e59bbc 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1633,16 +1633,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	int i;
-
-	/*
-	 * This _could_ be supported by providing a hook for
-	 * drivers for this function, but at this point it
-	 * doesn't seem worth bothering.
-	 */
-	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
-		return -EOPNOTSUPP;
+	int i, ret;
 
+	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
+		ret = drv_set_bitrate_mask(local, sdata, mask);
+		if (ret)
+			return ret;
+	}
 
 	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
 		sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 00a0685f240355ea136301013a90597180117605..2ddb56e5b51f240093d05347dae78629afe36e84 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -565,4 +565,22 @@ static inline bool drv_tx_frames_pending(struct ieee80211_local *local)
 
 	return ret;
 }
+
+static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
+				       struct ieee80211_sub_if_data *sdata,
+				       const struct cfg80211_bitrate_mask *mask)
+{
+	int ret = -EOPNOTSUPP;
+
+	might_sleep();
+
+	trace_drv_set_bitrate_mask(local, sdata, mask);
+	if (local->ops->set_bitrate_mask)
+		ret = local->ops->set_bitrate_mask(&local->hw,
+						   &sdata->vif, mask);
+	trace_drv_return_int(local, ret);
+
+	return ret;
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index c8c934d48b7ad7c8111bd156c8b244b5c9f85038..191e834ec46b11efdc21689ad45f9cf9bc92ceef 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -989,6 +989,33 @@ DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
 	TP_ARGS(local)
 );
 
+TRACE_EVENT(drv_set_bitrate_mask,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 const struct cfg80211_bitrate_mask *mask),
+
+	TP_ARGS(local, sdata, mask),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(u32, legacy_2g)
+		__field(u32, legacy_5g)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy;
+		__entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g
+	)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 14883966374e76347d5b84e13cc9844526fb6543..b81860c94698ada410d2b145e0f65aa967d14c00 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -40,7 +40,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
 					struct ieee80211_mgmt *mgmt,
 					size_t len)
 {
-	u16 auth_alg, auth_transaction, status_code;
+	u16 auth_alg, auth_transaction;
 
 	lockdep_assert_held(&sdata->u.ibss.mtx);
 
@@ -49,7 +49,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
 
 	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
 	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
-	status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
 	/*
 	 * IEEE 802.11 standard does not require authentication in IBSS
@@ -527,8 +526,6 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
 static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_supported_band *sband;
 	u8 bssid[ETH_ALEN];
 	u16 capability;
 	int i;
@@ -551,8 +548,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
 	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
 	       sdata->name, bssid);
 
-	sband = local->hw.wiphy->bands[ifibss->channel->band];
-
 	capability = WLAN_CAPABILITY_IBSS;
 
 	if (ifibss->privacy)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a77849970914eb15634b8d23d8b30f6f75e8a2ef..027c0467d7a31c42b29215603352716697cf9260 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -766,6 +766,9 @@ struct ieee80211_local {
 
 	int tx_headroom; /* required headroom for hardware/radiotap */
 
+	/* count for keys needing tailroom space allocation */
+	int crypto_tx_tailroom_needed_cnt;
+
 	/* Tasklet and skb queue to process calls from IRQ mode. All frames
 	 * added to skb_queue will be processed, but frames in
 	 * skb_queue_unreliable may be dropped if the total length of these
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index af3c56482c80b519d97d166373c05860b47f28dd..b510721e3b3d78d55153d8cb217693403d59054b 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -101,6 +101,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
 	if (!ret) {
 		key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+		if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+		      (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+			key->local->crypto_tx_tailroom_needed_cnt--;
+
 		return 0;
 	}
 
@@ -156,6 +161,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 			  key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
 	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+	if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+	      (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+		key->local->crypto_tx_tailroom_needed_cnt++;
 }
 
 void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
@@ -388,8 +397,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
 		ieee80211_aes_key_free(key->u.ccmp.tfm);
 	if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
 		ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
-	if (key->local)
+	if (key->local) {
 		ieee80211_debugfs_key_remove(key);
+		key->local->crypto_tx_tailroom_needed_cnt--;
+	}
 
 	kfree(key);
 }
@@ -451,6 +462,8 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
 	ieee80211_debugfs_key_add(key);
 
+	key->local->crypto_tx_tailroom_needed_cnt++;
+
 	ret = ieee80211_key_enable_hw_accel(key);
 
 	mutex_unlock(&sdata->local->key_mtx);
@@ -492,8 +505,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 
 	mutex_lock(&sdata->local->key_mtx);
 
-	list_for_each_entry(key, &sdata->key_list, list)
+	sdata->local->crypto_tx_tailroom_needed_cnt = 0;
+
+	list_for_each_entry(key, &sdata->key_list, list) {
+		sdata->local->crypto_tx_tailroom_needed_cnt++;
 		ieee80211_key_enable_hw_accel(key);
+	}
 
 	mutex_unlock(&sdata->local->key_mtx);
 }
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 0ab2a8df312df03988a4293402743a7fe3ce2cb7..61877662e8f861c78e55038c2add50124098e848 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -33,12 +33,6 @@
 #include "cfg.h"
 #include "debugfs.h"
 
-
-static bool ieee80211_disable_40mhz_24ghz;
-module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
-MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
-		 "Disable 40MHz support in the 2.4GHz band");
-
 static struct lock_class_key ieee80211_rx_skb_queue_class;
 
 void ieee80211_configure_filter(struct ieee80211_local *local)
@@ -728,18 +722,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 		}
 		channels += sband->n_channels;
 
-		/*
-		 * Since ieee80211_disable_40mhz_24ghz is global, we can
-		 * modify the sband's ht data even if the driver uses a
-		 * global structure for that.
-		 */
-		if (ieee80211_disable_40mhz_24ghz &&
-		    band == IEEE80211_BAND_2GHZ &&
-		    sband->ht_cap.ht_supported) {
-			sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-			sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
-		}
-
 		if (max_bitrates < sband->n_bitrates)
 			max_bitrates = sband->n_bitrates;
 		supp_ht = supp_ht || sband->ht_cap.ht_supported;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 11207979e2e29b7a07a6aedf927e527a9f7b01dd..c1299e24954166cde73832d39becf830fb01ef29 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -613,12 +613,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 				   struct sk_buff *skb)
 {
 	struct ieee80211_rx_status *rx_status;
-	struct ieee80211_if_mesh *ifmsh;
 	struct ieee80211_mgmt *mgmt;
 	u16 stype;
 
-	ifmsh = &sdata->u.mesh;
-
 	rx_status = IEEE80211_SKB_RXCB(skb);
 	mgmt = (struct ieee80211_mgmt *) skb->data;
 	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 5bf64d7112b32455eebc2be8d01800bbbfce04b3..e57f2e728cfe5bb08d5e0ededd06209baef36702 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -633,7 +633,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
 	struct mesh_path *mpath;
 	u8 ttl;
 	u8 *ta, *target_addr;
-	u8 target_flags;
 	u32 target_sn;
 	u16 target_rcode;
 
@@ -644,7 +643,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
 		return;
 	}
 	ttl--;
-	target_flags = PERR_IE_TARGET_FLAGS(perr_elem);
 	target_addr = PERR_IE_TARGET_ADDR(perr_elem);
 	target_sn = PERR_IE_TARGET_SN(perr_elem);
 	target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
@@ -675,12 +673,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct mesh_path *mpath;
-	u8 *ta;
 	u8 ttl, flags, hopcount;
 	u8 *orig_addr;
 	u32 orig_sn, metric;
 
-	ta = mgmt->sa;
 	ttl = rann->rann_ttl;
 	if (ttl <= 1) {
 		ifmsh->mshstats.dropped_frames_ttl++;
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index e37355193ed185679aa88b23a1a88789bec09678..042461710880768821dd3c36c6bbdd7bd2728099 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 
 	ieee80211_scan_cancel(local);
 
+	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
+		mutex_lock(&local->sta_mtx);
+		list_for_each_entry(sta, &local->sta_list, list) {
+			set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+			ieee80211_sta_tear_down_BA_sessions(sta, true);
+		}
+		mutex_unlock(&local->sta_mtx);
+	}
+
 	ieee80211_stop_queues_by_reason(hw,
 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
 	/* flush out all packets */
 	synchronize_net();
 
+	drv_flush(local, false);
+
 	local->quiescing = true;
 	/* make quiescing visible to timers everywhere */
 	mb();
@@ -43,11 +54,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 	/* tear down aggregation sessions and remove STAs */
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry(sta, &local->sta_list, list) {
-		if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
-			set_sta_flags(sta, WLAN_STA_BLOCK_BA);
-			ieee80211_sta_tear_down_BA_sessions(sta, true);
-		}
-
 		if (sta->uploaded) {
 			sdata = sta->sdata;
 			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a864890e4d03753c3c50f7a4e8035ea8bdb035d4..13a6697651ad846f5e9979c677ad5f858707817d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -652,7 +652,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
  set_release_timer:
 
 		mod_timer(&tid_agg_rx->reorder_timer,
-			  tid_agg_rx->reorder_time[j] +
+			  tid_agg_rx->reorder_time[j] + 1 +
 			  HT_RX_REORDER_BUF_TIMEOUT);
 	} else {
 		del_timer(&tid_agg_rx->reorder_timer);
@@ -2368,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 	return RX_QUEUED;
 }
 
-static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
-					    struct ieee80211_rx_data *rx)
-{
-	int keyidx;
-	unsigned int hdrlen;
-
-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
-	if (rx->skb->len >= hdrlen + 4)
-		keyidx = rx->skb->data[hdrlen + 3] >> 6;
-	else
-		keyidx = -1;
-
-	if (!rx->sta) {
-		/*
-		 * Some hardware seem to generate incorrect Michael MIC
-		 * reports; ignore them to avoid triggering countermeasures.
-		 */
-		return;
-	}
-
-	if (!ieee80211_has_protected(hdr->frame_control))
-		return;
-
-	if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
-		/*
-		 * APs with pairwise keys should never receive Michael MIC
-		 * errors for non-zero keyidx because these are reserved for
-		 * group keys and only the AP is sending real multicast
-		 * frames in the BSS.
-		 */
-		return;
-	}
-
-	if (!ieee80211_is_data(hdr->frame_control) &&
-	    !ieee80211_is_auth(hdr->frame_control))
-		return;
-
-	mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
-					GFP_ATOMIC);
-}
-
 /* TODO: use IEEE80211_RX_FRAGMENTED */
 static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
 					struct ieee80211_rate *rate)
@@ -2752,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
 	if (!prepares)
 		return false;
 
-	if (status->flag & RX_FLAG_MMIC_ERROR) {
-		if (status->rx_flags & IEEE80211_RX_RA_MATCH)
-			ieee80211_rx_michael_mic_report(hdr, rx);
-		return false;
-	}
-
 	if (!consume) {
 		skb = skb_copy(skb, GFP_ATOMIC);
 		if (!skb) {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a03d8a31287550d85e96467bc385e3eb291c35be..d9e6e81ff6b2a197a42b1f0372b02741a19c6c59 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -587,7 +587,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 {
 	unsigned long flags;
 	struct sk_buff *skb;
-	struct ieee80211_sub_if_data *sdata;
 
 	if (skb_queue_empty(&sta->ps_tx_buf))
 		return false;
@@ -604,7 +603,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 		if (!skb)
 			break;
 
-		sdata = sta->sdata;
 		local->total_ps_buffered--;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 3ed3c835fbbf0e0f57000825150e62d4b737fc91..1658efaa2e8eef4b042ec05ffd875cbd0d3c6ec1 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -446,3 +446,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 	dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(ieee80211_tx_status);
+
+void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
+{
+	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+	cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
+				    num_packets, GFP_ATOMIC);
+}
+EXPORT_SYMBOL(ieee80211_report_low_ack);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 17b10be31f5514a0a2713ca98ee1d404e0b742a4..e3e3aa173af07d324d5fb745c76a1d28fc057985 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1036,14 +1036,11 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 	struct ieee80211_radiotap_iterator iterator;
 	struct ieee80211_radiotap_header *rthdr =
 		(struct ieee80211_radiotap_header *) skb->data;
-	struct ieee80211_supported_band *sband;
 	bool hw_frag;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
 						   NULL);
 
-	sband = tx->local->hw.wiphy->bands[tx->channel->band];
-
 	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
 	tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 
@@ -1442,11 +1439,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_tx_data tx;
 	ieee80211_tx_result res_prepare;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	u16 queue;
 	bool result = true;
 
-	queue = skb_get_queue_mapping(skb);
-
 	if (unlikely(skb->len < 10)) {
 		dev_kfree_skb(skb);
 		return true;
@@ -1482,12 +1476,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
 {
 	int tail_need = 0;
 
-	/*
-	 * This could be optimised, devices that do full hardware
-	 * crypto (including TKIP MMIC) need no tailroom... But we
-	 * have no drivers for such devices currently.
-	 */
-	if (may_encrypt) {
+	if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) {
 		tail_need = IEEE80211_ENCRYPT_TAILROOM;
 		tail_need -= skb_tailroom(skb);
 		tail_need = max_t(int, tail_need, 0);
@@ -2485,7 +2474,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct sk_buff *skb = NULL;
-	struct sta_info *sta;
 	struct ieee80211_tx_data tx;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_ap *bss = NULL;
@@ -2527,7 +2515,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 
 	info = IEEE80211_SKB_CB(skb);
 
-	sta = tx.sta;
 	tx.flags |= IEEE80211_TX_PS_BUFFERED;
 	tx.channel = local->hw.conf.channel;
 	info->band = tx.channel->band;
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index e73c8cae036b42fec668d3473922164b3e22ef26..a94b312dbfacd582ecbd515b8285bbe166141100 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -198,9 +198,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos, qos_info;
-	const u8 *ies;
 	size_t offset = 0, noffset;
-	int i, len, count, rates_len, supp_rates_len;
+	int i, count, rates_len, supp_rates_len;
 	u16 capab;
 	struct ieee80211_supported_band *sband;
 	u32 rates = 0;
@@ -285,7 +284,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 	}
 
 	/* SSID */
-	ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len);
+	pos = skb_put(skb, 2 + wk->assoc.ssid_len);
 	*pos++ = WLAN_EID_SSID;
 	*pos++ = wk->assoc.ssid_len;
 	memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
@@ -295,7 +294,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 	if (supp_rates_len > 8)
 		supp_rates_len = 8;
 
-	len = sband->n_bitrates;
 	pos = skb_put(skb, supp_rates_len + 2);
 	*pos++ = WLAN_EID_SUPP_RATES;
 	*pos++ = supp_rates_len;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index f1765de2f4bf7a42e06794b8155a79d6bb52b694..9dc3b5f26e80c800a306aca5287b0e22fcda5378 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -87,42 +87,76 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
-	/* No way to verify the MIC if the hardware stripped it */
-	if (status->flag & RX_FLAG_MMIC_STRIPPED)
+	/*
+	 * it makes no sense to check for MIC errors on anything other
+	 * than data frames.
+	 */
+	if (!ieee80211_is_data_present(hdr->frame_control))
+		return RX_CONTINUE;
+
+	/*
+	 * No way to verify the MIC if the hardware stripped it or
+	 * the IV with the key index. In this case we have solely rely
+	 * on the driver to set RX_FLAG_MMIC_ERROR in the event of a
+	 * MIC failure report.
+	 */
+	if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
+		if (status->flag & RX_FLAG_MMIC_ERROR)
+			goto mic_fail;
+
+		if (!(status->flag & RX_FLAG_IV_STRIPPED))
+			goto update_iv;
+
 		return RX_CONTINUE;
+	}
 
+	/*
+	 * Some hardware seems to generate Michael MIC failure reports; even
+	 * though, the frame was not encrypted with TKIP and therefore has no
+	 * MIC. Ignore the flag them to avoid triggering countermeasures.
+	 */
 	if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
-	    !ieee80211_has_protected(hdr->frame_control) ||
-	    !ieee80211_is_data_present(hdr->frame_control))
+	    !(status->flag & RX_FLAG_DECRYPTED))
 		return RX_CONTINUE;
 
+	if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) {
+		/*
+		 * APs with pairwise keys should never receive Michael MIC
+		 * errors for non-zero keyidx because these are reserved for
+		 * group keys and only the AP is sending real multicast
+		 * frames in the BSS. (
+		 */
+		return RX_DROP_UNUSABLE;
+	}
+
+	if (status->flag & RX_FLAG_MMIC_ERROR)
+		goto mic_fail;
+
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	if (skb->len < hdrlen + MICHAEL_MIC_LEN)
 		return RX_DROP_UNUSABLE;
 
 	data = skb->data + hdrlen;
 	data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
-
 	key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
 	michael_mic(key, hdr, data, data_len, mic);
-	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) {
-		if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-			return RX_DROP_UNUSABLE;
-
-		mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
-						(void *) skb->data, NULL,
-						GFP_ATOMIC);
-		return RX_DROP_UNUSABLE;
-	}
+	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0)
+		goto mic_fail;
 
 	/* remove Michael MIC from payload */
 	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
 
+update_iv:
 	/* update IV in key information to be able to detect replays */
 	rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
 	rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
 
 	return RX_CONTINUE;
+
+mic_fail:
+	mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
+					(void *) skb->data, NULL, GFP_ATOMIC);
+	return RX_DROP_UNUSABLE;
 }
 
 
diff --git a/net/wireless/core.c b/net/wireless/core.c
index fe01de29bfe8c740edc5e19944663e5d0fd7cd33..bbf1fa11107a91dd5ce05afd4157b141204c3690 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -46,6 +46,11 @@ static struct dentry *ieee80211_debugfs_dir;
 /* for the cleanup, scan and event works */
 struct workqueue_struct *cfg80211_wq;
 
+static bool cfg80211_disable_40mhz_24ghz;
+module_param(cfg80211_disable_40mhz_24ghz, bool, 0644);
+MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz,
+		 "Disable 40MHz support in the 2.4GHz band");
+
 /* requires cfg80211_mutex to be held! */
 struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
 {
@@ -450,6 +455,18 @@ int wiphy_register(struct wiphy *wiphy)
 		if (WARN_ON(!sband->n_channels || !sband->n_bitrates))
 			return -EINVAL;
 
+		/*
+		 * Since cfg80211_disable_40mhz_24ghz is global, we can
+		 * modify the sband's ht data even if the driver uses a
+		 * global structure for that.
+		 */
+		if (cfg80211_disable_40mhz_24ghz &&
+		    band == IEEE80211_BAND_2GHZ &&
+		    sband->ht_cap.ht_supported) {
+			sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
+		}
+
 		/*
 		 * Since we use a u32 for rate bitmaps in
 		 * ieee80211_get_response_rate, we cannot
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 58d69959ab28c033741a61ef836e88a16be11791..1613080a96b9a590f18898a60ce9e5b626582f26 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1455,7 +1455,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 	 * We only time out user hints, given that they should be the only
 	 * source of bogus requests.
 	 */
-	if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
+	if (r != -EALREADY &&
+	    reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
 		schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
 }