Эх сурвалжийг харах

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

David S. Miller 15 жил өмнө
parent
commit
f8f2109d4f
99 өөрчлөгдсөн 2565 нэмэгдсэн , 1416 устгасан
  1. 6 0
      MAINTAINERS
  2. 28 14
      drivers/net/wireless/adm8211.c
  3. 5 7
      drivers/net/wireless/at76c50x-usb.c
  4. 5 11
      drivers/net/wireless/ath/ar9170/ar9170.h
  5. 7 15
      drivers/net/wireless/ath/ar9170/mac.c
  6. 39 73
      drivers/net/wireless/ath/ar9170/main.c
  7. 18 0
      drivers/net/wireless/ath/ath.h
  8. 0 3
      drivers/net/wireless/ath/ath5k/ath5k.h
  9. 46 32
      drivers/net/wireless/ath/ath5k/base.c
  10. 13 0
      drivers/net/wireless/ath/ath5k/base.h
  11. 2 1
      drivers/net/wireless/ath/ath5k/phy.c
  12. 1 5
      drivers/net/wireless/ath/ath9k/ani.c
  13. 3 17
      drivers/net/wireless/ath/ath9k/ani.h
  14. 12 2
      drivers/net/wireless/ath/ath9k/ath9k.h
  15. 30 14
      drivers/net/wireless/ath/ath9k/calib.c
  16. 5 3
      drivers/net/wireless/ath/ath9k/eeprom_4k.c
  17. 11 17
      drivers/net/wireless/ath/ath9k/eeprom_9287.c
  18. 8 6
      drivers/net/wireless/ath/ath9k/eeprom_def.c
  19. 50 31
      drivers/net/wireless/ath/ath9k/hw.c
  20. 1 1
      drivers/net/wireless/ath/ath9k/hw.h
  21. 26 26
      drivers/net/wireless/ath/ath9k/main.c
  22. 3 3
      drivers/net/wireless/ath/ath9k/pci.c
  23. 7 0
      drivers/net/wireless/ath/ath9k/phy.h
  24. 1 1
      drivers/net/wireless/ath/ath9k/recv.c
  25. 8 1
      drivers/net/wireless/ath/ath9k/reg.h
  26. 2 18
      drivers/net/wireless/ath/regd.h
  27. 7 7
      drivers/net/wireless/b43/Kconfig
  28. 1 1
      drivers/net/wireless/b43/dma.c
  29. 1 1
      drivers/net/wireless/b43/lo.c
  30. 180 25
      drivers/net/wireless/b43/main.c
  31. 1 1
      drivers/net/wireless/b43/main.h
  32. 3 3
      drivers/net/wireless/b43/phy_g.c
  33. 950 92
      drivers/net/wireless/b43/phy_lp.c
  34. 17 8
      drivers/net/wireless/b43/phy_lp.h
  35. 2 2
      drivers/net/wireless/b43/pio.c
  36. 11 1
      drivers/net/wireless/b43/tables_lpphy.c
  37. 2 2
      drivers/net/wireless/b43/wa.c
  38. 24 5
      drivers/net/wireless/b43/xmit.c
  39. 1 2
      drivers/net/wireless/b43/xmit.h
  40. 1 3
      drivers/net/wireless/b43legacy/main.c
  41. 8 6
      drivers/net/wireless/ipw2x00/ipw2100.c
  42. 36 37
      drivers/net/wireless/ipw2x00/ipw2200.c
  43. 4 1
      drivers/net/wireless/iwlwifi/iwl-1000.c
  44. 7 4
      drivers/net/wireless/iwlwifi/iwl-3945.c
  45. 2 1
      drivers/net/wireless/iwlwifi/iwl-4965.c
  46. 8 1
      drivers/net/wireless/iwlwifi/iwl-5000.c
  47. 20 5
      drivers/net/wireless/iwlwifi/iwl-6000.c
  48. 39 77
      drivers/net/wireless/iwlwifi/iwl-agn-rs.c
  49. 2 1
      drivers/net/wireless/iwlwifi/iwl-commands.h
  50. 38 36
      drivers/net/wireless/iwlwifi/iwl-core.c
  51. 6 2
      drivers/net/wireless/iwlwifi/iwl-core.h
  52. 11 9
      drivers/net/wireless/iwlwifi/iwl-dev.h
  53. 162 60
      drivers/net/wireless/iwlwifi/iwl-eeprom.c
  54. 8 2
      drivers/net/wireless/iwlwifi/iwl-eeprom.h
  55. 79 128
      drivers/net/wireless/iwlwifi/iwl-rx.c
  56. 5 0
      drivers/net/wireless/iwlwifi/iwl-tx.c
  57. 2 0
      drivers/net/wireless/iwlwifi/iwl3945-base.c
  58. 7 1
      drivers/net/wireless/libertas/assoc.c
  59. 25 12
      drivers/net/wireless/libertas_tf/main.c
  60. 1 3
      drivers/net/wireless/mac80211_hwsim.c
  61. 205 346
      drivers/net/wireless/mwl8k.c
  62. 1 1
      drivers/net/wireless/orinoco/wext.c
  63. 7 1
      drivers/net/wireless/p54/main.c
  64. 0 1
      drivers/net/wireless/rt2x00/rt2500usb.c
  65. 10 9
      drivers/net/wireless/rt2x00/rt2800usb.c
  66. 8 2
      drivers/net/wireless/rt2x00/rt2800usb.h
  67. 1 5
      drivers/net/wireless/rt2x00/rt2x00.h
  68. 17 23
      drivers/net/wireless/rt2x00/rt2x00dev.c
  69. 7 18
      drivers/net/wireless/rt2x00/rt2x00mac.c
  70. 2 0
      drivers/net/wireless/rt2x00/rt2x00queue.h
  71. 0 1
      drivers/net/wireless/rt2x00/rt73usb.c
  72. 9 2
      drivers/net/wireless/rtl818x/rtl8180_dev.c
  73. 9 2
      drivers/net/wireless/rtl818x/rtl8187_dev.c
  74. 3 0
      drivers/net/wireless/wl12xx/wl1251_boot.c
  75. 1 3
      drivers/net/wireless/wl12xx/wl1251_main.c
  76. 2 2
      drivers/net/wireless/wl12xx/wl1251_reg.h
  77. 3 6
      drivers/net/wireless/wl12xx/wl1271_main.c
  78. 29 15
      drivers/net/wireless/zd1211rw/zd_mac.c
  79. 1 1
      drivers/ssb/pci.c
  80. 2 0
      include/net/cfg80211.h
  81. 15 21
      include/net/mac80211.h
  82. 6 0
      net/mac80211/debugfs_netdev.c
  83. 20 4
      net/mac80211/driver-ops.h
  84. 30 6
      net/mac80211/driver-trace.h
  85. 8 1
      net/mac80211/ieee80211_i.h
  86. 3 12
      net/mac80211/iface.c
  87. 22 10
      net/mac80211/main.c
  88. 2 0
      net/mac80211/mesh.h
  89. 21 0
      net/mac80211/mesh_hwmp.c
  90. 1 15
      net/mac80211/rc80211_minstrel.c
  91. 1 15
      net/mac80211/rc80211_pid_algo.c
  92. 7 1
      net/mac80211/rx.c
  93. 2 14
      net/mac80211/scan.c
  94. 0 2
      net/mac80211/util.c
  95. 78 20
      net/wireless/core.c
  96. 2 0
      net/wireless/core.h
  97. 9 0
      net/wireless/mlme.c
  98. 12 17
      net/wireless/sme.c
  99. 1 0
      net/wireless/wext-compat.c

+ 6 - 0
MAINTAINERS

@@ -3272,6 +3272,12 @@ S:	Supported
 F:	drivers/net/mv643xx_eth.*
 F:	include/linux/mv643xx.h
 
+MARVELL MWL8K WIRELESS DRIVER
+M:	Lennert Buytenhek <buytenh@marvell.com>
+L:	linux-wireless@vger.kernel.org
+S:	Supported
+F:	drivers/net/wireless/mwl8k.c
+
 MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
 M:	Nicolas Pitre <nico@cam.org>
 S:	Maintained

+ 28 - 14
drivers/net/wireless/adm8211.c

@@ -1328,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev,
 	}
 }
 
+static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw,
+				     int mc_count, struct dev_addr_list *mclist)
+{
+	unsigned int bit_nr, i;
+	u32 mc_filter[2];
+
+	mc_filter[1] = mc_filter[0] = 0;
+
+	for (i = 0; i < mc_count; i++) {
+		if (!mclist)
+			break;
+		bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+		bit_nr &= 0x3F;
+		mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+		mclist = mclist->next;
+	}
+
+	return mc_filter[0] | ((u64)(mc_filter[1]) << 32);
+}
+
 static void adm8211_configure_filter(struct ieee80211_hw *dev,
 				     unsigned int changed_flags,
 				     unsigned int *total_flags,
-				     int mc_count, struct dev_mc_list *mclist)
+				     u64 multicast)
 {
 	static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 	struct adm8211_priv *priv = dev->priv;
-	unsigned int bit_nr, new_flags;
+	unsigned int new_flags;
 	u32 mc_filter[2];
-	int i;
+
+	mc_filter[0] = multicast;
+	mc_filter[1] = multicast >> 32;
 
 	new_flags = 0;
 
@@ -1346,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
 		priv->nar |= ADM8211_NAR_PR;
 		priv->nar &= ~ADM8211_NAR_MM;
 		mc_filter[1] = mc_filter[0] = ~0;
-	} else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+	} else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
 		new_flags |= FIF_ALLMULTI;
 		priv->nar &= ~ADM8211_NAR_PR;
 		priv->nar |= ADM8211_NAR_MM;
 		mc_filter[1] = mc_filter[0] = ~0;
 	} else {
 		priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
-		mc_filter[1] = mc_filter[0] = 0;
-		for (i = 0; i < mc_count; i++) {
-			if (!mclist)
-				break;
-			bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
-
-			bit_nr &= 0x3F;
-			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
-			mclist = mclist->next;
-		}
 	}
 
 	ADM8211_IDLE_RX();
@@ -1757,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = {
 	.remove_interface	= adm8211_remove_interface,
 	.config			= adm8211_config,
 	.bss_info_changed	= adm8211_bss_info_changed,
+	.prepare_multicast	= adm8211_prepare_multicast,
 	.configure_filter	= adm8211_configure_filter,
 	.get_stats		= adm8211_get_stats,
 	.get_tx_stats		= adm8211_get_tx_stats,

+ 5 - 7
drivers/net/wireless/at76c50x-usb.c

@@ -1950,9 +1950,8 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct at76_priv *priv = hw->priv;
 
-	at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d",
-		 __func__, hw->conf.channel->hw_value,
-		 hw->conf.radio_enabled);
+	at76_dbg(DBG_MAC80211, "%s(): channel %d",
+		 __func__, hw->conf.channel->hw_value);
 	at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:");
 
 	mutex_lock(&priv->mtx);
@@ -1997,15 +1996,14 @@ static void at76_bss_info_changed(struct ieee80211_hw *hw,
 /* must be atomic */
 static void at76_configure_filter(struct ieee80211_hw *hw,
 				  unsigned int changed_flags,
-				  unsigned int *total_flags, int mc_count,
-				  struct dev_addr_list *mc_list)
+				  unsigned int *total_flags, u64 multicast)
 {
 	struct at76_priv *priv = hw->priv;
 	int flags;
 
 	at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
-		 "total_flags=0x%08x mc_count=%d",
-		 __func__, changed_flags, *total_flags, mc_count);
+		 "total_flags=0x%08x",
+		 __func__, changed_flags, *total_flags);
 
 	flags = changed_flags & AT76_SUPPORTED_FILTERS;
 	*total_flags = AT76_SUPPORTED_FILTERS;

+ 5 - 11
drivers/net/wireless/ath/ar9170/ar9170.h

@@ -157,6 +157,7 @@ struct ar9170_sta_tid {
 
 struct ar9170 {
 	struct ieee80211_hw *hw;
+	struct ath_common common;
 	struct mutex mutex;
 	enum ar9170_device_state state;
 	unsigned long bad_hw_nagger;
@@ -184,10 +185,8 @@ struct ar9170 {
 	bool disable_offload;
 
 	/* filter settings */
-	struct work_struct filter_config_work;
-	u64 cur_mc_hash, want_mc_hash;
-	u32 cur_filter, want_filter;
-	unsigned long filter_changed;
+	u64 cur_mc_hash;
+	u32 cur_filter;
 	unsigned int filter_state;
 	bool sniffer_enabled;
 
@@ -222,7 +221,6 @@ struct ar9170 {
 
 	/* EEPROM */
 	struct ar9170_eeprom eeprom;
-	struct ath_regulatory regulatory;
 
 	/* tx queues - as seen by hw - */
 	struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
@@ -261,10 +259,6 @@ struct ar9170_tx_info {
 #define IS_STARTED(a)		(((struct ar9170 *)a)->state >= AR9170_STARTED)
 #define IS_ACCEPTING_CMD(a)	(((struct ar9170 *)a)->state >= AR9170_IDLE)
 
-#define AR9170_FILTER_CHANGED_MODE		BIT(0)
-#define AR9170_FILTER_CHANGED_MULTICAST		BIT(1)
-#define AR9170_FILTER_CHANGED_FRAMEFILTER	BIT(2)
-
 /* exported interface */
 void *ar9170_alloc(size_t priv_size);
 int ar9170_register(struct ar9170 *ar, struct device *pdev);
@@ -278,8 +272,8 @@ int ar9170_nag_limiter(struct ar9170 *ar);
 int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 int ar9170_init_mac(struct ar9170 *ar);
 int ar9170_set_qos(struct ar9170 *ar);
-int ar9170_update_multicast(struct ar9170 *ar);
-int ar9170_update_frame_filter(struct ar9170 *ar);
+int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast);
+int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter);
 int ar9170_set_operating_mode(struct ar9170 *ar);
 int ar9170_set_beacon_timers(struct ar9170 *ar);
 int ar9170_set_dyn_sifs_ack(struct ar9170 *ar);

+ 7 - 15
drivers/net/wireless/ath/ar9170/mac.c

@@ -238,39 +238,31 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac)
 	return ar9170_regwrite_result();
 }
 
-int ar9170_update_multicast(struct ar9170 *ar)
+int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash)
 {
 	int err;
 
 	ar9170_regwrite_begin(ar);
-	ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H,
-		ar->want_mc_hash >> 32);
-	ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L,
-		ar->want_mc_hash);
-
+	ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32);
+	ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash);
 	ar9170_regwrite_finish();
 	err = ar9170_regwrite_result();
-
 	if (err)
 		return err;
 
-	ar->cur_mc_hash = ar->want_mc_hash;
-
+	ar->cur_mc_hash = mc_hash;
 	return 0;
 }
 
-int ar9170_update_frame_filter(struct ar9170 *ar)
+int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter)
 {
 	int err;
 
-	err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER,
-			       ar->want_filter);
-
+	err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter);
 	if (err)
 		return err;
 
-	ar->cur_filter = ar->want_filter;
-
+	ar->cur_filter = filter;
 	return 0;
 }
 

+ 39 - 73
drivers/net/wireless/ath/ar9170/main.c

@@ -1232,8 +1232,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
 
 	mutex_lock(&ar->mutex);
 
-	ar->filter_changed = 0;
-
 	/* reinitialize queues statistics */
 	memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
 	for (i = 0; i < __AR9170_NUM_TXQ; i++)
@@ -1296,7 +1294,6 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
 #ifdef CONFIG_AR9170_LEDS
 	cancel_delayed_work_sync(&ar->led_work);
 #endif
-	cancel_work_sync(&ar->filter_config_work);
 	cancel_work_sync(&ar->beacon_work);
 
 	mutex_lock(&ar->mutex);
@@ -1973,8 +1970,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
 	}
 
 	ar->cur_filter = 0;
-	ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS;
-	err = ar9170_update_frame_filter(ar);
+	err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS);
 	if (err)
 		goto unlock;
 
@@ -1992,8 +1988,7 @@ static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
 
 	mutex_lock(&ar->mutex);
 	ar->vif = NULL;
-	ar->want_filter = 0;
-	ar9170_update_frame_filter(ar);
+	ar9170_update_frame_filter(ar, 0);
 	ar9170_set_beacon_timers(ar);
 	dev_kfree_skb(ar->beacon);
 	ar->beacon = NULL;
@@ -2065,48 +2060,37 @@ out:
 	return err;
 }
 
-static void ar9170_set_filters(struct work_struct *work)
+static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
+				       struct dev_addr_list *mclist)
 {
-	struct ar9170 *ar = container_of(work, struct ar9170,
-					 filter_config_work);
-	int err;
-
-	if (unlikely(!IS_STARTED(ar)))
-		return ;
-
-	mutex_lock(&ar->mutex);
-	if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE,
-			       &ar->filter_changed)) {
-		err = ar9170_set_operating_mode(ar);
-		if (err)
-			goto unlock;
-	}
+	u64 mchash;
+	int i;
 
-	if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST,
-			       &ar->filter_changed)) {
-		err = ar9170_update_multicast(ar);
-		if (err)
-			goto unlock;
-	}
+	/* always get broadcast frames */
+	mchash = 1ULL << (0xff >> 2);
 
-	if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
-			       &ar->filter_changed)) {
-		err = ar9170_update_frame_filter(ar);
-		if (err)
-			goto unlock;
+	for (i = 0; i < mc_count; i++) {
+		if (WARN_ON(!mclist))
+			break;
+		mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
+		mclist = mclist->next;
 	}
 
-unlock:
-	mutex_unlock(&ar->mutex);
+	return mchash;
 }
 
 static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
 				       unsigned int changed_flags,
 				       unsigned int *new_flags,
-				       int mc_count, struct dev_mc_list *mclist)
+				       u64 multicast)
 {
 	struct ar9170 *ar = hw->priv;
 
+	if (unlikely(!IS_ACCEPTING_CMD(ar)))
+		return ;
+
+	mutex_lock(&ar->mutex);
+
 	/* mask supported flags */
 	*new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC |
 		      FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL;
@@ -2116,26 +2100,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
 	 * then checking the error flags, later.
 	 */
 
-	if (changed_flags & FIF_ALLMULTI) {
-		if (*new_flags & FIF_ALLMULTI) {
-			ar->want_mc_hash = ~0ULL;
-		} else {
-			u64 mchash;
-			int i;
+	if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
+		multicast = ~0ULL;
 
-			/* always get broadcast frames */
-			mchash = 1ULL << (0xff >> 2);
-
-			for (i = 0; i < mc_count; i++) {
-				if (WARN_ON(!mclist))
-					break;
-				mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
-				mclist = mclist->next;
-			}
-		ar->want_mc_hash = mchash;
-		}
-		set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed);
-	}
+	if (multicast != ar->cur_mc_hash)
+		ar9170_update_multicast(ar, multicast);
 
 	if (changed_flags & FIF_CONTROL) {
 		u32 filter = AR9170_MAC_REG_FTF_PSPOLL |
@@ -2146,24 +2115,22 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
 			     AR9170_MAC_REG_FTF_CFE_ACK;
 
 		if (*new_flags & FIF_CONTROL)
-			ar->want_filter = ar->cur_filter | filter;
+			filter |= ar->cur_filter;
 		else
-			ar->want_filter = ar->cur_filter & ~filter;
+			filter &= (~ar->cur_filter);
 
-		set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
-			&ar->filter_changed);
+		ar9170_update_frame_filter(ar, filter);
 	}
 
 	if (changed_flags & FIF_PROMISC_IN_BSS) {
 		ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0;
-		set_bit(AR9170_FILTER_CHANGED_MODE,
-			&ar->filter_changed);
+		ar9170_set_operating_mode(ar);
 	}
 
-	if (likely(IS_STARTED(ar)))
-		ieee80211_queue_work(ar->hw, &ar->filter_config_work);
+	mutex_unlock(&ar->mutex);
 }
 
+
 static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
 				       struct ieee80211_vif *vif,
 				       struct ieee80211_bss_conf *bss_conf,
@@ -2417,9 +2384,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
 	default:
 		break;
 	}
-
-	if (IS_STARTED(ar) && ar->filter_changed)
-		ieee80211_queue_work(ar->hw, &ar->filter_config_work);
 }
 
 static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -2543,6 +2507,7 @@ static const struct ieee80211_ops ar9170_ops = {
 	.add_interface		= ar9170_op_add_interface,
 	.remove_interface	= ar9170_op_remove_interface,
 	.config			= ar9170_op_config,
+	.prepare_multicast	= ar9170_op_prepare_multicast,
 	.configure_filter	= ar9170_op_configure_filter,
 	.conf_tx		= ar9170_conf_tx,
 	.bss_info_changed	= ar9170_op_bss_info_changed,
@@ -2589,7 +2554,6 @@ void *ar9170_alloc(size_t priv_size)
 		skb_queue_head_init(&ar->tx_pending[i]);
 	}
 	ar9170_rx_reset_rx_mpdu(ar);
-	INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
 	INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
 	INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
 	INIT_LIST_HEAD(&ar->tx_ampdu_list);
@@ -2634,6 +2598,7 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
 {
 #define RW	8	/* number of words to read at once */
 #define RB	(sizeof(u32) * RW)
+	struct ath_regulatory *regulatory = &ar->common.regulatory;
 	u8 *eeprom = (void *)&ar->eeprom;
 	u8 *addr = ar->eeprom.mac_address;
 	__le32 offsets[RW];
@@ -2700,8 +2665,8 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
 	else
 		ar->hw->channel_change_time = 80 * 1000;
 
-	ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
-	ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
+	regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
+	regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
 
 	/* second part of wiphy init */
 	SET_IEEE80211_PERM_ADDR(ar->hw, addr);
@@ -2715,11 +2680,12 @@ static int ar9170_reg_notifier(struct wiphy *wiphy,
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ar9170 *ar = hw->priv;
 
-	return ath_reg_notifier_apply(wiphy, request, &ar->regulatory);
+	return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
 }
 
 int ar9170_register(struct ar9170 *ar, struct device *pdev)
 {
+	struct ath_regulatory *regulatory = &ar->common.regulatory;
 	int err;
 
 	/* try to read EEPROM, init MAC addr */
@@ -2727,7 +2693,7 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
 	if (err)
 		goto err_out;
 
-	err = ath_regd_init(&ar->regulatory, ar->hw->wiphy,
+	err = ath_regd_init(regulatory, ar->hw->wiphy,
 			    ar9170_reg_notifier);
 	if (err)
 		goto err_out;
@@ -2736,8 +2702,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
 	if (err)
 		goto err_out;
 
-	if (!ath_is_world_regd(&ar->regulatory))
-		regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2);
+	if (!ath_is_world_regd(regulatory))
+		regulatory_hint(ar->hw->wiphy, regulatory->alpha2);
 
 	err = ar9170_init_leds(ar);
 	if (err)

+ 18 - 0
drivers/net/wireless/ath/ath.h

@@ -19,8 +19,26 @@
 
 #include <linux/skbuff.h>
 
+struct reg_dmn_pair_mapping {
+	u16 regDmnEnum;
+	u16 reg_5ghz_ctl;
+	u16 reg_2ghz_ctl;
+};
+
+struct ath_regulatory {
+	char alpha2[2];
+	u16 country_code;
+	u16 max_power_level;
+	u32 tp_scale;
+	u16 current_rd;
+	u16 current_rd_ext;
+	int16_t power_limit;
+	struct reg_dmn_pair_mapping *regpair;
+};
+
 struct ath_common {
 	u16 cachelsz;
+	struct ath_regulatory regulatory;
 };
 
 struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,

+ 0 - 3
drivers/net/wireless/ath/ath5k/ath5k.h

@@ -27,8 +27,6 @@
 #include <linux/types.h>
 #include <net/mac80211.h>
 
-#include "../regd.h"
-
 /* RX/TX descriptor hw structs
  * TODO: Driver part should only see sw structs */
 #include "desc.h"
@@ -1077,7 +1075,6 @@ struct ath5k_hw {
 
 	int			ah_gpio_npins;
 
-	struct ath_regulatory	ah_regulatory;
 	struct ath5k_capabilities ah_capabilities;
 
 	struct ath5k_txq_info	ah_txq[AR5K_NUM_TX_QUEUES];

+ 46 - 32
drivers/net/wireless/ath/ath5k/base.c

@@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
 		struct ieee80211_if_init_conf *conf);
 static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
+static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
+				   int mc_count, struct dev_addr_list *mc_list);
 static void ath5k_configure_filter(struct ieee80211_hw *hw,
 		unsigned int changed_flags,
 		unsigned int *new_flags,
-		int mc_count, struct dev_mc_list *mclist);
+		u64 multicast);
 static int ath5k_set_key(struct ieee80211_hw *hw,
 		enum set_key_cmd cmd,
 		struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
 	.add_interface 	= ath5k_add_interface,
 	.remove_interface = ath5k_remove_interface,
 	.config 	= ath5k_config,
+	.prepare_multicast = ath5k_prepare_multicast,
 	.configure_filter = ath5k_configure_filter,
 	.set_key 	= ath5k_set_key,
 	.get_stats 	= ath5k_get_stats,
@@ -715,9 +718,9 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ath5k_softc *sc = hw->priv;
-	struct ath_regulatory *reg = &sc->ah->ah_regulatory;
+	struct ath_regulatory *regulatory = &sc->common.regulatory;
 
-	return ath_reg_notifier_apply(wiphy, request, reg);
+	return ath_reg_notifier_apply(wiphy, request, regulatory);
 }
 
 static int
@@ -725,6 +728,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_hw *ah = sc->ah;
+	struct ath_regulatory *regulatory = &sc->common.regulatory;
 	u8 mac[ETH_ALEN] = {};
 	int ret;
 
@@ -814,9 +818,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 	memset(sc->bssidmask, 0xff, ETH_ALEN);
 	ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
 
-	ah->ah_regulatory.current_rd =
-		ah->ah_capabilities.cap_eeprom.ee_regdomain;
-	ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier);
+	regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
+	ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
 	if (ret) {
 		ATH5K_ERR(sc, "can't initialize regulatory system\n");
 		goto err_queues;
@@ -828,8 +831,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 		goto err_queues;
 	}
 
-	if (!ath_is_world_regd(&sc->ah->ah_regulatory))
-		regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2);
+	if (!ath_is_world_regd(regulatory))
+		regulatory_hint(hw->wiphy, regulatory->alpha2);
 
 	ath5k_init_leds(sc);
 
@@ -2853,6 +2856,37 @@ unlock:
 	return ret;
 }
 
+static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
+				   int mc_count, struct dev_addr_list *mclist)
+{
+	u32 mfilt[2], val;
+	int i;
+	u8 pos;
+
+	mfilt[0] = 0;
+	mfilt[1] = 1;
+
+	for (i = 0; i < mc_count; i++) {
+		if (!mclist)
+			break;
+		/* calculate XOR of eight 6-bit values */
+		val = get_unaligned_le32(mclist->dmi_addr + 0);
+		pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+		val = get_unaligned_le32(mclist->dmi_addr + 3);
+		pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+		pos &= 0x3f;
+		mfilt[pos / 32] |= (1 << (pos % 32));
+		/* XXX: we might be able to just do this instead,
+		* but not sure, needs testing, if we do use this we'd
+		* neet to inform below to not reset the mcast */
+		/* ath5k_hw_set_mcast_filterindex(ah,
+		 *      mclist->dmi_addr[5]); */
+		mclist = mclist->next;
+	}
+
+	return ((u64)(mfilt[1]) << 32) | mfilt[0];
+}
+
 #define SUPPORTED_FIF_FLAGS \
 	FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
 	FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -2878,16 +2912,14 @@ unlock:
 static void ath5k_configure_filter(struct ieee80211_hw *hw,
 		unsigned int changed_flags,
 		unsigned int *new_flags,
-		int mc_count, struct dev_mc_list *mclist)
+		u64 multicast)
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_hw *ah = sc->ah;
-	u32 mfilt[2], val, rfilt;
-	u8 pos;
-	int i;
+	u32 mfilt[2], rfilt;
 
-	mfilt[0] = 0;
-	mfilt[1] = 0;
+	mfilt[0] = multicast;
+	mfilt[1] = multicast >> 32;
 
 	/* Only deal with supported flags */
 	changed_flags &= SUPPORTED_FIF_FLAGS;
@@ -2913,24 +2945,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
 	if (*new_flags & FIF_ALLMULTI) {
 		mfilt[0] =  ~0;
 		mfilt[1] =  ~0;
-	} else {
-		for (i = 0; i < mc_count; i++) {
-			if (!mclist)
-				break;
-			/* calculate XOR of eight 6-bit values */
-			val = get_unaligned_le32(mclist->dmi_addr + 0);
-			pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
-			val = get_unaligned_le32(mclist->dmi_addr + 3);
-			pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
-			pos &= 0x3f;
-			mfilt[pos / 32] |= (1 << (pos % 32));
-			/* XXX: we might be able to just do this instead,
-			* but not sure, needs testing, if we do use this we'd
-			* neet to inform below to not reset the mcast */
-			/* ath5k_hw_set_mcast_filterindex(ah,
-			 *      mclist->dmi_addr[5]); */
-			mclist = mclist->next;
-		}
 	}
 
 	/* This is the best we can do */

+ 13 - 0
drivers/net/wireless/ath/ath5k/base.h

@@ -50,6 +50,8 @@
 
 #include "ath5k.h"
 #include "debug.h"
+
+#include "../regd.h"
 #include "../ath.h"
 
 #define	ATH_RXBUF	40		/* number of RX buffers */
@@ -200,4 +202,15 @@ struct ath5k_softc {
 #define ath5k_hw_hasveol(_ah) \
 	(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
 
+static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
+{
+	return &ah->ah_sc->common;
+}
+
+static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
+{
+	return &(ath5k_hw_common(ah)->regulatory);
+
+}
+
 #endif

+ 2 - 1
drivers/net/wireless/ath/ath5k/phy.c

@@ -2198,6 +2198,7 @@ static void
 ath5k_get_max_ctl_power(struct ath5k_hw *ah,
 			struct ieee80211_channel *channel)
 {
+	struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
 	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
 	struct ath5k_edge_power *rep = ee->ee_ctl_pwr;
 	u8 *ctl_val = ee->ee_ctl;
@@ -2208,7 +2209,7 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
 	u8 ctl_idx = 0xFF;
 	u32 target = channel->center_freq;
 
-	ctl_mode = ath_regd_get_band_ctl(&ah->ah_regulatory, channel->band);
+	ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band);
 
 	switch (channel->hw_value & CHANNEL_MODES) {
 	case CHANNEL_A:

+ 1 - 5
drivers/net/wireless/ath/ath9k/ani.c

@@ -538,7 +538,6 @@ void ath9k_ani_reset(struct ath_hw *ah)
 }
 
 void ath9k_hw_ani_monitor(struct ath_hw *ah,
-			  const struct ath9k_node_stats *stats,
 			  struct ath9k_channel *chan)
 {
 	struct ar5416AniState *aniState;
@@ -550,7 +549,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
 		return;
 
 	aniState = ah->curani;
-	ah->stats.ast_nodestats = *stats;
 
 	listenTime = ath9k_hw_ani_get_listen_time(ah);
 	if (listenTime < 0) {
@@ -693,8 +691,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
  * any of the MIB counters overflow/trigger so don't assume we're
  * here because a PHY error counter triggered.
  */
-void ath9k_hw_procmibevent(struct ath_hw *ah,
-			   const struct ath9k_node_stats *stats)
+void ath9k_hw_procmibevent(struct ath_hw *ah)
 {
 	u32 phyCnt1, phyCnt2;
 
@@ -706,7 +703,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah,
 
 	/* Clear the mib counters and save them in the stats */
 	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-	ah->stats.ast_nodestats = *stats;
 
 	if (!DO_ANI(ah))
 		return;

+ 3 - 17
drivers/net/wireless/ath/ath9k/ani.h

@@ -18,15 +18,10 @@
 #define ANI_H
 
 #define HAL_PROCESS_ANI           0x00000001
-#define ATH9K_RSSI_EP_MULTIPLIER  (1<<7)
 
 #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI))
 
-#define HAL_EP_RND(x, mul)						\
-	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-#define BEACON_RSSI(ahp)					\
-	HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi,	\
-		   ATH9K_RSSI_EP_MULTIPLIER)
+#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
 
 #define ATH9K_ANI_OFDM_TRIG_HIGH          500
 #define ATH9K_ANI_OFDM_TRIG_LOW           200
@@ -65,13 +60,6 @@ struct ath9k_mib_stats {
 	u32 beacons;
 };
 
-struct ath9k_node_stats {
-	u32 ns_avgbrssi;
-	u32 ns_avgrssi;
-	u32 ns_avgtxrssi;
-	u32 ns_avgtxrate;
-};
-
 struct ar5416AniState {
 	struct ath9k_channel *c;
 	u8 noiseImmunityLevel;
@@ -115,21 +103,19 @@ struct ar5416Stats {
 	u32 ast_ani_reset;
 	u32 ast_ani_lzero;
 	u32 ast_ani_lneg;
+	u32 avgbrssi;
 	struct ath9k_mib_stats ast_mibstats;
-	struct ath9k_node_stats ast_nodestats;
 };
 #define ah_mibStats stats.ast_mibstats
 
 void ath9k_ani_reset(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah,
-			  const struct ath9k_node_stats *stats,
 			  struct ath9k_channel *chan);
 void ath9k_enable_mib_counters(struct ath_hw *ah);
 void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
 				  u32 *rxf_pcnt, u32 *txf_pcnt);
-void ath9k_hw_procmibevent(struct ath_hw *ah,
-			   const struct ath9k_node_stats *stats);
+void ath9k_hw_procmibevent(struct ath_hw *ah);
 void ath9k_hw_ani_setup(struct ath_hw *ah);
 void ath9k_hw_ani_init(struct ath_hw *ah);
 void ath9k_hw_ani_disable(struct ath_hw *ah);

+ 12 - 2
drivers/net/wireless/ath/ath9k/ath9k.h

@@ -454,7 +454,8 @@ struct ath_ani {
 /*   LED Control    */
 /********************/
 
-#define ATH_LED_PIN	1
+#define ATH_LED_PIN_DEF 		1
+#define ATH_LED_PIN_9287		8
 #define ATH_LED_ON_DURATION_IDLE	350	/* in msecs */
 #define ATH_LED_OFF_DURATION_IDLE	250	/* in msecs */
 
@@ -602,7 +603,6 @@ struct ath_softc {
 	int beacon_interval;
 
 	struct ath_ani ani;
-	struct ath9k_node_stats nodestats;
 #ifdef CONFIG_ATH9K_DEBUG
 	struct ath9k_debug debug;
 #endif
@@ -630,6 +630,16 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
 int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
 int ath_cabq_update(struct ath_softc *);
 
+static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
+{
+	return &ah->ah_sc->common;
+}
+
+static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
+{
+	return &(ath9k_hw_common(ah)->regulatory);
+}
+
 static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
 {
 	sc->bus_ops->read_cachesize(sc, csz);

+ 30 - 14
drivers/net/wireless/ath/ath9k/calib.c

@@ -729,26 +729,42 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
 static void ath9k_olc_temp_compensation(struct ath_hw *ah)
 {
 	u32 rddata, i;
-	int delta, currPDADC, regval;
+	int delta, currPDADC, regval, slope;
 
 	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
-
 	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
 
-	if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
-		delta = (currPDADC - ah->initPDADC + 4) / 8;
-	else
-		delta = (currPDADC - ah->initPDADC + 5) / 10;
 
-	if (delta != ah->PDADCdelta) {
-		ah->PDADCdelta = delta;
-		for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
-			regval = ah->originalGain[i] - delta;
-			if (regval < 0)
-				regval = 0;
+	if (OLC_FOR_AR9287_10_LATER) {
+		if (ah->initPDADC == 0 || currPDADC == 0) {
+			return;
+		} else {
+			slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
+			if (slope == 0)
+				delta = 0;
+			else
+				delta = ((currPDADC - ah->initPDADC)*4) / slope;
+			REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
+					AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+			REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
+					AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+		}
+	} else {
+		if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
+			delta = (currPDADC - ah->initPDADC + 4) / 8;
+		else
+			delta = (currPDADC - ah->initPDADC + 5) / 10;
+
+		if (delta != ah->PDADCdelta) {
+			ah->PDADCdelta = delta;
+			for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
+				regval = ah->originalGain[i] - delta;
+				if (regval < 0)
+					regval = 0;
 
-			REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4,
-					AR_PHY_TX_GAIN, regval);
+				REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4,
+						AR_PHY_TX_GAIN, regval);
+			}
 		}
 	}
 }

+ 5 - 3
drivers/net/wireless/ath/ath9k/eeprom_4k.c

@@ -508,6 +508,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
 	|| (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
 	    ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
 
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	int i;
 	int16_t twiceLargestAntenna;
 	u16 twiceMinEdgePower;
@@ -541,9 +542,9 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
 					   twiceLargestAntenna, 0);
 
 	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-	if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) {
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
 		maxRegAllowedPower -=
-			(tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
 	}
 
 	scaledPower = min(powerLimit, maxRegAllowedPower);
@@ -707,6 +708,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
 				    u8 twiceMaxRegulatoryPower,
 				    u8 powerLimit)
 {
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
 	struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
 	int16_t ratesArray[Ar5416RateSize];
@@ -744,7 +746,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
 	else if (IS_CHAN_HT20(chan))
 		i = rateHt20_0;
 
-	ah->regulatory.max_power_level = ratesArray[i];
+	regulatory->max_power_level = ratesArray[i];
 
 	if (AR_SREV_9280_10_OR_LATER(ah)) {
 		for (i = 0; i < Ar5416RateSize; i++)

+ 11 - 17
drivers/net/wireless/ath/ath9k/eeprom_9287.c

@@ -374,7 +374,6 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
 			    u8 *pCalChans,  u16 availPiers,
 			    int8_t *pPwr)
 {
-	u8 pcdac, i = 0;
 	u16  idxL = 0, idxR = 0, numPiers;
 	bool match;
 	struct chan_centers centers;
@@ -392,17 +391,12 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
 			&idxL, &idxR);
 
 	if (match) {
-		pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0];
-		*pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0];
+		*pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
 	} else {
-		pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0];
-		*pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
-				pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+		*pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
+			    (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
 	}
 
-	while ((pcdac > ah->originalGain[i]) &&
-			(i < (AR9280_TX_GAIN_TABLE_SIZE - 1)))
-		i++;
 }
 
 static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
@@ -605,7 +599,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
 {
 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6
 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10
-
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
 	static const u16 tpScaleReductionTable[5] =
 		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
@@ -638,9 +632,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
 					    twiceLargestAntenna, 0);
 
 	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-	if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX)
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
 		maxRegAllowedPower -=
-			(tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
 
 	scaledPower = min(powerLimit, maxRegAllowedPower);
 
@@ -837,7 +831,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
 {
 #define INCREASE_MAXPOW_BY_TWO_CHAIN     6
 #define INCREASE_MAXPOW_BY_THREE_CHAIN   10
-
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
 	struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
 	int16_t ratesArray[Ar5416RateSize];
@@ -955,20 +949,20 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
 		i = rate6mb;
 
 	if (AR_SREV_9280_10_OR_LATER(ah))
-		ah->regulatory.max_power_level =
+		regulatory->max_power_level =
 			ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
 	else
-		ah->regulatory.max_power_level = ratesArray[i];
+		regulatory->max_power_level = ratesArray[i];
 
 	switch (ar5416_get_ntxchains(ah->txchainmask)) {
 	case 1:
 		break;
 	case 2:
-		ah->regulatory.max_power_level +=
+		regulatory->max_power_level +=
 			INCREASE_MAXPOW_BY_TWO_CHAIN;
 		break;
 	case 3:
-		ah->regulatory.max_power_level +=
+		regulatory->max_power_level +=
 			INCREASE_MAXPOW_BY_THREE_CHAIN;
 		break;
 	default:

+ 8 - 6
drivers/net/wireless/ath/ath9k/eeprom_def.c

@@ -904,6 +904,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
 
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
 	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
 	static const u16 tpScaleReductionTable[5] =
@@ -953,9 +954,9 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
 
 	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
 
-	if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) {
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
 		maxRegAllowedPower -=
-			(tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2);
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
 	}
 
 	scaledPower = min(powerLimit, maxRegAllowedPower);
@@ -1163,6 +1164,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
 				    u8 powerLimit)
 {
 #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
 	struct modal_eep_header *pModal =
 		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
@@ -1292,19 +1294,19 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
 		i = rateHt20_0;
 
 	if (AR_SREV_9280_10_OR_LATER(ah))
-		ah->regulatory.max_power_level =
+		regulatory->max_power_level =
 			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
 	else
-		ah->regulatory.max_power_level = ratesArray[i];
+		regulatory->max_power_level = ratesArray[i];
 
 	switch(ar5416_get_ntxchains(ah->txchainmask)) {
 	case 1:
 		break;
 	case 2:
-		ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
 		break;
 	case 3:
-		ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
 		break;
 	default:
 		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,

+ 50 - 31
drivers/net/wireless/ath/ath9k/hw.c

@@ -439,8 +439,13 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
 
 static void ath9k_hw_init_defaults(struct ath_hw *ah)
 {
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+
+	regulatory->country_code = CTRY_DEFAULT;
+	regulatory->power_limit = MAX_RATE_POWER;
+	regulatory->tp_scale = ATH9K_TP_SCALE_MAX;
+
 	ah->hw_version.magic = AR5416_MAGIC;
-	ah->regulatory.country_code = CTRY_DEFAULT;
 	ah->hw_version.subvendorid = 0;
 
 	ah->ah_flags = 0;
@@ -449,8 +454,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
 	if (!AR_SREV_9100(ah))
 		ah->ah_flags = AH_USE_EEPROM;
 
-	ah->regulatory.power_limit = MAX_RATE_POWER;
-	ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX;
 	ah->atim_window = 0;
 	ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
 	ah->beacon_interval = 100;
@@ -1332,11 +1335,21 @@ static void ath9k_olc_init(struct ath_hw *ah)
 {
 	u32 i;
 
-	for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
-		ah->originalGain[i] =
-			MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
-					AR_PHY_TX_GAIN);
-	ah->PDADCdelta = 0;
+	if (OLC_FOR_AR9287_10_LATER) {
+		REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9,
+				AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL);
+		ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0,
+				AR9287_AN_TXPC0_TXPCMODE,
+				AR9287_AN_TXPC0_TXPCMODE_S,
+				AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE);
+		udelay(100);
+	} else {
+		for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
+			ah->originalGain[i] =
+				MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
+						AR_PHY_TX_GAIN);
+		ah->PDADCdelta = 0;
+	}
 }
 
 static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
@@ -1358,6 +1371,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
 				struct ath9k_channel *chan,
 				enum ath9k_ht_macmode macmode)
 {
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	int i, regWrites = 0;
 	struct ieee80211_channel *channel = chan->chan;
 	u32 modesIndex, freqIndex;
@@ -1464,11 +1478,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
 		ath9k_olc_init(ah);
 
 	ah->eep_ops->set_txpower(ah, chan,
-				 ath9k_regd_get_ctl(&ah->regulatory, chan),
+				 ath9k_regd_get_ctl(regulatory, chan),
 				 channel->max_antenna_gain * 2,
 				 channel->max_power * 2,
 				 min((u32) MAX_RATE_POWER,
-				 (u32) ah->regulatory.power_limit));
+				 (u32) regulatory->power_limit));
 
 	if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
@@ -1786,6 +1800,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 				    struct ath9k_channel *chan,
 				    enum ath9k_ht_macmode macmode)
 {
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ieee80211_channel *channel = chan->chan;
 	u32 synthDelay, qnum;
 
@@ -1818,11 +1833,11 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 	}
 
 	ah->eep_ops->set_txpower(ah, chan,
-			     ath9k_regd_get_ctl(&ah->regulatory, chan),
+			     ath9k_regd_get_ctl(regulatory, chan),
 			     channel->max_antenna_gain * 2,
 			     channel->max_power * 2,
 			     min((u32) MAX_RATE_POWER,
-			     (u32) ah->regulatory.power_limit));
+			     (u32) regulatory->power_limit));
 
 	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
 	if (IS_CHAN_B(chan))
@@ -2382,7 +2397,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (AR_SREV_9280_10_OR_LATER(ah))
 		REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
-	if (AR_SREV_9287_10_OR_LATER(ah)) {
+	if (AR_SREV_9287_12_OR_LATER(ah)) {
 		/* Enable ASYNC FIFO */
 		REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
 				AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
@@ -2468,7 +2483,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
 	ath9k_hw_init_user_settings(ah);
 
-	if (AR_SREV_9287_10_OR_LATER(ah)) {
+	if (AR_SREV_9287_12_OR_LATER(ah)) {
 		REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
 			  AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
 		REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
@@ -2484,7 +2499,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
 			      AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
 	}
-	if (AR_SREV_9287_10_OR_LATER(ah)) {
+	if (AR_SREV_9287_12_OR_LATER(ah)) {
 		REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
 				AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
 	}
@@ -3063,7 +3078,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
 	if (ah->config.pcie_waen) {
 		REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
 	} else {
-		if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+		if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah))
 			REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
 		/*
 		 * On AR9280 chips bit 22 of 0x4004 needs to be set to
@@ -3470,27 +3485,29 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
 void ath9k_hw_fill_cap_info(struct ath_hw *ah)
 {
 	struct ath9k_hw_capabilities *pCap = &ah->caps;
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+
 	u16 capField = 0, eeval;
 
 	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
-	ah->regulatory.current_rd = eeval;
+	regulatory->current_rd = eeval;
 
 	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
 	if (AR_SREV_9285_10_OR_LATER(ah))
 		eeval |= AR9285_RDEXT_DEFAULT;
-	ah->regulatory.current_rd_ext = eeval;
+	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 (ah->regulatory.current_rd == 0x64 ||
-		    ah->regulatory.current_rd == 0x65)
-			ah->regulatory.current_rd += 5;
-		else if (ah->regulatory.current_rd == 0x41)
-			ah->regulatory.current_rd = 0x43;
+		if (regulatory->current_rd == 0x64 ||
+		    regulatory->current_rd == 0x65)
+			regulatory->current_rd += 5;
+		else if (regulatory->current_rd == 0x41)
+			regulatory->current_rd = 0x43;
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"regdomain mapped to 0x%x\n", ah->regulatory.current_rd);
+			"regdomain mapped to 0x%x\n", regulatory->current_rd);
 	}
 
 	eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
@@ -3625,7 +3642,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
 	else
 		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
-	if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
+	if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
 		pCap->reg_cap =
 			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
 			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
@@ -3654,6 +3671,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
 bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
 			    u32 capability, u32 *result)
 {
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	switch (type) {
 	case ATH9K_CAP_CIPHER:
 		switch (capability) {
@@ -3702,13 +3720,13 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
 		case 0:
 			return 0;
 		case 1:
-			*result = ah->regulatory.power_limit;
+			*result = regulatory->power_limit;
 			return 0;
 		case 2:
-			*result = ah->regulatory.max_power_level;
+			*result = regulatory->max_power_level;
 			return 0;
 		case 3:
-			*result = ah->regulatory.tp_scale;
+			*result = regulatory->tp_scale;
 			return 0;
 		}
 		return false;
@@ -3946,17 +3964,18 @@ bool ath9k_hw_disable(struct ath_hw *ah)
 
 void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
 {
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
 	struct ath9k_channel *chan = ah->curchan;
 	struct ieee80211_channel *channel = chan->chan;
 
-	ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
+	regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER);
 
 	ah->eep_ops->set_txpower(ah, chan,
-				 ath9k_regd_get_ctl(&ah->regulatory, chan),
+				 ath9k_regd_get_ctl(regulatory, chan),
 				 channel->max_antenna_gain * 2,
 				 channel->max_power * 2,
 				 min((u32) MAX_RATE_POWER,
-				 (u32) ah->regulatory.power_limit));
+				 (u32) regulatory->power_limit));
 }
 
 void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)

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

@@ -396,7 +396,6 @@ struct ath_hw {
 	struct ath9k_hw_version hw_version;
 	struct ath9k_ops_config config;
 	struct ath9k_hw_capabilities caps;
-	struct ath_regulatory regulatory;
 	struct ath9k_channel channels[38];
 	struct ath9k_channel *curchan;
 
@@ -522,6 +521,7 @@ struct ath_hw {
 	u32 originalGain[22];
 	int initPDADC;
 	int PDADCdelta;
+	u8 led_pin;
 
 	struct ar5416IniArray iniModes;
 	struct ar5416IniArray iniCommon;

+ 26 - 26
drivers/net/wireless/ath/ath9k/main.c

@@ -384,7 +384,7 @@ static void ath_ani_calibrate(unsigned long data)
 	if (longcal || shortcal || aniflag) {
 		/* Call ANI routine if necessary */
 		if (aniflag)
-			ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan);
+			ath9k_hw_ani_monitor(ah, ah->curchan);
 
 		/* Perform calibration if necessary */
 		if (longcal || shortcal) {
@@ -589,7 +589,7 @@ irqreturn_t ath_isr(int irq, void *dev)
 		 * it will clear whatever condition caused
 		 * the interrupt.
 		 */
-		ath9k_hw_procmibevent(ah, &sc->nodestats);
+		ath9k_hw_procmibevent(ah);
 		ath9k_hw_set_interrupts(ah, sc->imask);
 	}
 
@@ -940,10 +940,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
 		ath_beacon_config(sc, vif);
 
 		/* Reset rssi stats */
-		sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
+		sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 
 		ath_start_ani(sc);
 	} else {
@@ -968,9 +965,9 @@ static void ath_led_blink_work(struct work_struct *work)
 
 	if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
 	    (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
-		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+		ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
 	else
-		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+		ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
 				  (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
 
 	ieee80211_queue_delayed_work(sc->hw,
@@ -1002,7 +999,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
 	case LED_OFF:
 		if (led->led_type == ATH_LED_ASSOC ||
 		    led->led_type == ATH_LED_RADIO) {
-			ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+			ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
 				(led->led_type == ATH_LED_RADIO));
 			sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
 			if (led->led_type == ATH_LED_RADIO)
@@ -1017,7 +1014,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
 			ieee80211_queue_delayed_work(sc->hw,
 						     &sc->ath_led_blink_work, 0);
 		} else if (led->led_type == ATH_LED_RADIO) {
-			ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+			ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
 			sc->sc_flags |= SC_OP_LED_ON;
 		} else {
 			sc->led_on_cnt++;
@@ -1062,7 +1059,7 @@ static void ath_deinit_leds(struct ath_softc *sc)
 	ath_unregister_led(&sc->tx_led);
 	ath_unregister_led(&sc->rx_led);
 	ath_unregister_led(&sc->radio_led);
-	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 }
 
 static void ath_init_leds(struct ath_softc *sc)
@@ -1070,11 +1067,16 @@ static void ath_init_leds(struct ath_softc *sc)
 	char *trigger;
 	int ret;
 
+	if (AR_SREV_9287(sc->sc_ah))
+		sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+	else
+		sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+
 	/* Configure gpio 1 for output */
-	ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+	ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 	/* LED off, active low */
-	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
 	INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
 
@@ -1153,9 +1155,9 @@ void ath_radio_enable(struct ath_softc *sc)
 	ath9k_hw_set_interrupts(ah, sc->imask);
 
 	/* Enable LED */
-	ath9k_hw_cfg_output(ah, ATH_LED_PIN,
+	ath9k_hw_cfg_output(ah, ah->led_pin,
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
+	ath9k_hw_set_gpio(ah, ah->led_pin, 0);
 
 	ieee80211_wake_queues(sc->hw);
 	ath9k_ps_restore(sc);
@@ -1171,8 +1173,8 @@ void ath_radio_disable(struct ath_softc *sc)
 	ieee80211_stop_queues(sc->hw);
 
 	/* Disable LED */
-	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1);
-	ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN);
+	ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+	ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
 
 	/* Disable interrupts */
 	ath9k_hw_set_interrupts(ah, 0);
@@ -1288,7 +1290,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
-	struct ath_regulatory *reg = &sc->sc_ah->regulatory;
+	struct ath_regulatory *reg = &sc->common.regulatory;
 
 	return ath_reg_notifier_apply(wiphy, request, reg);
 }
@@ -1581,12 +1583,12 @@ int ath_init_device(u16 devid, struct ath_softc *sc)
 
 	ath_set_hw_capab(sc, hw);
 
-	error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
+	error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy,
 			      ath9k_reg_notifier);
 	if (error)
 		return error;
 
-	reg = &sc->sc_ah->regulatory;
+	reg = &sc->common.regulatory;
 
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 		setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
@@ -2100,6 +2102,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 
+	mutex_lock(&sc->mutex);
+
 	aphy->state = ATH_WIPHY_INACTIVE;
 
 	cancel_delayed_work_sync(&sc->ath_led_blink_work);
@@ -2112,13 +2116,10 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
 	if (sc->sc_flags & SC_OP_INVALID) {
 		DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+		mutex_unlock(&sc->mutex);
 		return;
 	}
 
-	mutex_lock(&sc->mutex);
-
-	cancel_delayed_work_sync(&sc->tx_complete_work);
-
 	if (ath9k_wiphy_started(sc)) {
 		mutex_unlock(&sc->mutex);
 		return; /* another wiphy still in use */
@@ -2389,8 +2390,7 @@ skip_chan_change:
 static void ath9k_configure_filter(struct ieee80211_hw *hw,
 				   unsigned int changed_flags,
 				   unsigned int *total_flags,
-				   int mc_count,
-				   struct dev_mc_list *mclist)
+				   u64 multicast)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;

+ 3 - 3
drivers/net/wireless/ath/ath9k/pci.c

@@ -236,7 +236,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 
-	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
@@ -269,9 +269,9 @@ static int ath_pci_resume(struct pci_dev *pdev)
 		pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
 	/* Enable LED */
-	ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+	ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
 	return 0;
 }

+ 7 - 0
drivers/net/wireless/ath/ath9k/phy.h

@@ -490,11 +490,18 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
 #define AR_PHY_TX_PWRCTRL9       0xa27C
 #define AR_PHY_TX_DESIRED_SCALE_CCK        0x00007C00
 #define AR_PHY_TX_DESIRED_SCALE_CCK_S      10
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL  0x80000000
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
 
 #define AR_PHY_TX_GAIN_TBL1      0xa300
 #define AR_PHY_TX_GAIN                     0x0007F000
 #define AR_PHY_TX_GAIN_S                   12
 
+#define AR_PHY_CH0_TX_PWRCTRL11  0xa398
+#define AR_PHY_CH1_TX_PWRCTRL11  0xb398
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP   0x0000FC00
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
+
 #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0
 #define AR_PHY_MASK2_M_31_45     0xa3a4
 #define AR_PHY_MASK2_M_16_30     0xa3a8

+ 1 - 1
drivers/net/wireless/ath/ath9k/recv.c

@@ -222,7 +222,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
 
 	/* Update Beacon RSSI, this is used by ANI. */
 	if (ieee80211_is_beacon(fc))
-		sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi;
+		sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi;
 
 	rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
 	rx_status->band = hw->conf.channel->band;

+ 8 - 1
drivers/net/wireless/ath/ath9k/reg.h

@@ -744,6 +744,7 @@
 #define AR_SREV_VERSION_9287                  0x180
 #define AR_SREV_REVISION_9287_10              0
 #define AR_SREV_REVISION_9287_11              1
+#define AR_SREV_REVISION_9287_12              2
 #define AR_SREV_VERSION_9271			0x140
 #define AR_SREV_REVISION_9271_10		0
 #define AR_SREV_REVISION_9271_11		1
@@ -817,7 +818,13 @@
 	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
 	 (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
 	  ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
-
+#define AR_SREV_9287_12(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12))
+#define AR_SREV_9287_12_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+	 (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+	  ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12)))
 #define AR_SREV_9271(_ah) \
     (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)
 #define AR_SREV_9271_10(_ah) \

+ 2 - 18
drivers/net/wireless/ath/regd.h

@@ -18,9 +18,10 @@
 #define REGD_H
 
 #include <linux/nl80211.h>
-
 #include <net/cfg80211.h>
 
+#include "ath.h"
+
 #define NO_CTL 0xff
 #define SD_NO_CTL               0xE0
 #define NO_CTL                  0xff
@@ -47,29 +48,12 @@
 #define CHANNEL_HALF_BW         10
 #define CHANNEL_QUARTER_BW      5
 
-struct reg_dmn_pair_mapping {
-	u16 regDmnEnum;
-	u16 reg_5ghz_ctl;
-	u16 reg_2ghz_ctl;
-};
-
 struct country_code_to_enum_rd {
 	u16 countryCode;
 	u16 regDmnEnum;
 	const char *isoName;
 };
 
-struct ath_regulatory {
-	char alpha2[2];
-	u16 country_code;
-	u16 max_power_level;
-	u32 tp_scale;
-	u16 current_rd;
-	u16 current_rd_ext;
-	int16_t power_limit;
-	struct reg_dmn_pair_mapping *regpair;
-};
-
 enum CountryCode {
 	CTRY_ALBANIA = 8,
 	CTRY_ALGERIA = 12,

+ 7 - 7
drivers/net/wireless/b43/Kconfig

@@ -80,16 +80,16 @@ config B43_NPHY
 	  SAY N.
 
 config B43_PHY_LP
-	bool "IEEE 802.11g LP-PHY support (BROKEN)"
-	depends on B43 && EXPERIMENTAL && BROKEN
+	bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)"
+	depends on B43 && EXPERIMENTAL
 	---help---
 	  Support for the LP-PHY.
-	  The LP-PHY is an IEEE 802.11g based PHY built into some notebooks
-	  and embedded devices.
-
-	  THIS IS BROKEN AND DOES NOT WORK YET.
+	  The LP-PHY is a low-power PHY built into some notebooks
+	  and embedded devices. It supports 802.11a/g
+	  (802.11a support is optional, and currently disabled).
 
-	  SAY N.
+	  This is heavily experimental, and probably will not work for you.
+	  Say N unless you want to help debug the driver.
 
 # This config option automatically enables b43 LEDS support,
 # if it's possible.

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

@@ -1188,7 +1188,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 	header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]);
 	cookie = generate_cookie(ring, slot);
 	err = b43_generate_txhdr(ring->dev, header,
-				 skb->data, skb->len, info, cookie);
+				 skb, info, cookie);
 	if (unlikely(err)) {
 		ring->current_slot = old_top_slot;
 		ring->used_slots = old_used_slots;

+ 1 - 1
drivers/net/wireless/b43/lo.c

@@ -477,7 +477,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 	} else
 		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
 	if (phy->rev >= 2)
-		b43_dummy_transmission(dev);
+		b43_dummy_transmission(dev, false, true);
 	b43_gphy_channel_switch(dev, 6, 0);
 	b43_radio_read16(dev, 0x51);	/* dummy read */
 	if (phy->type == B43_PHYTYPE_G)

+ 180 - 25
drivers/net/wireless/b43/main.c

@@ -80,6 +80,10 @@ static int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
+static int modparam_hwtkip;
+module_param_named(hwtkip, modparam_hwtkip, int, 0444);
+MODULE_PARM_DESC(hwtkip, "Enable hardware tkip.");
+
 static int modparam_qos = 1;
 module_param_named(qos, modparam_qos, int, 0444);
 MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
@@ -691,9 +695,9 @@ static void b43_synchronize_irq(struct b43_wldev *dev)
 }
 
 /* DummyTransmission function, as documented on
- * http://bcm-specs.sipsolutions.net/DummyTransmission
+ * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission
  */
-void b43_dummy_transmission(struct b43_wldev *dev)
+void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
 {
 	struct b43_wl *wl = dev->wl;
 	struct b43_phy *phy = &dev->phy;
@@ -707,19 +711,12 @@ void b43_dummy_transmission(struct b43_wldev *dev)
 		0x00000000,
 	};
 
-	switch (phy->type) {
-	case B43_PHYTYPE_A:
+	if (ofdm) {
 		max_loop = 0x1E;
 		buffer[0] = 0x000201CC;
-		break;
-	case B43_PHYTYPE_B:
-	case B43_PHYTYPE_G:
+	} else {
 		max_loop = 0xFA;
 		buffer[0] = 0x000B846E;
-		break;
-	default:
-		B43_WARN_ON(1);
-		return;
 	}
 
 	spin_lock_irq(&wl->irq_lock);
@@ -728,20 +725,35 @@ void b43_dummy_transmission(struct b43_wldev *dev)
 	for (i = 0; i < 5; i++)
 		b43_ram_write(dev, i * 4, buffer[i]);
 
-	/* Commit writes */
-	b43_read32(dev, B43_MMIO_MACCTL);
-
 	b43_write16(dev, 0x0568, 0x0000);
-	b43_write16(dev, 0x07C0, 0x0000);
-	value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0);
+	if (dev->dev->id.revision < 11)
+		b43_write16(dev, 0x07C0, 0x0000);
+	else
+		b43_write16(dev, 0x07C0, 0x0100);
+	value = (ofdm ? 0x41 : 0x40);
 	b43_write16(dev, 0x050C, value);
+	if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP))
+		b43_write16(dev, 0x0514, 0x1A02);
 	b43_write16(dev, 0x0508, 0x0000);
 	b43_write16(dev, 0x050A, 0x0000);
 	b43_write16(dev, 0x054C, 0x0000);
 	b43_write16(dev, 0x056A, 0x0014);
 	b43_write16(dev, 0x0568, 0x0826);
 	b43_write16(dev, 0x0500, 0x0000);
-	b43_write16(dev, 0x0502, 0x0030);
+	if (!pa_on && (phy->type == B43_PHYTYPE_N)) {
+		//SPEC TODO
+	}
+
+	switch (phy->type) {
+	case B43_PHYTYPE_N:
+		b43_write16(dev, 0x0502, 0x00D0);
+		break;
+	case B43_PHYTYPE_LP:
+		b43_write16(dev, 0x0502, 0x0050);
+		break;
+	default:
+		b43_write16(dev, 0x0502, 0x0030);
+	}
 
 	if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
 		b43_radio_write16(dev, 0x0051, 0x0017);
@@ -826,6 +838,85 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
 			(index * 2) + 1, addrtmp[1]);
 }
 
+/* The ucode will use phase1 key with TEK key to decrypt rx packets.
+ * When a packet is received, the iv32 is checked.
+ * - if it doesn't the packet is returned without modification (and software
+ *   decryption can be done). That's what happen when iv16 wrap.
+ * - if it does, the rc4 key is computed, and decryption is tried.
+ *   Either it will success and B43_RX_MAC_DEC is returned,
+ *   either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned
+ *   and the packet is not usable (it got modified by the ucode).
+ * So in order to never have B43_RX_MAC_DECERR, we should provide
+ * a iv32 and phase1key that match. Because we drop packets in case of
+ * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all
+ * packets will be lost without higher layer knowing (ie no resync possible
+ * until next wrap).
+ *
+ * NOTE : this should support 50 key like RCMTA because
+ * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50
+ */
+static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
+		u16 *phase1key)
+{
+	unsigned int i;
+	u32 offset;
+	u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
+
+	if (!modparam_hwtkip)
+		return;
+
+	if (b43_new_kidx_api(dev))
+		pairwise_keys_start = B43_NR_GROUP_KEYS;
+
+	B43_WARN_ON(index < pairwise_keys_start);
+	/* We have four default TX keys and possibly four default RX keys.
+	 * Physical mac 0 is mapped to physical key 4 or 8, depending
+	 * on the firmware version.
+	 * So we must adjust the index here.
+	 */
+	index -= pairwise_keys_start;
+	B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
+
+	if (b43_debug(dev, B43_DBG_KEYS)) {
+		b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n",
+				index, iv32);
+	}
+	/* Write the key to the  RX tkip shared mem */
+	offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4);
+	for (i = 0; i < 10; i += 2) {
+		b43_shm_write16(dev, B43_SHM_SHARED, offset + i,
+				phase1key ? phase1key[i / 2] : 0);
+	}
+	b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32);
+	b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16);
+}
+
+static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
+			struct ieee80211_key_conf *keyconf, const u8 *addr,
+			u32 iv32, u16 *phase1key)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev;
+	int index = keyconf->hw_key_idx;
+
+	if (B43_WARN_ON(!modparam_hwtkip))
+		return;
+
+	mutex_lock(&wl->mutex);
+
+	dev = wl->current_dev;
+	if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
+		goto out_unlock;
+
+	keymac_write(dev, index, NULL);	/* First zero out mac to avoid race */
+
+	rx_tkip_phase1_write(dev, index, iv32, phase1key);
+	keymac_write(dev, index, addr);
+
+out_unlock:
+	mutex_unlock(&wl->mutex);
+}
+
 static void do_key_write(struct b43_wldev *dev,
 			 u8 index, u8 algorithm,
 			 const u8 *key, size_t key_len, const u8 *mac_addr)
@@ -841,6 +932,19 @@ static void do_key_write(struct b43_wldev *dev,
 
 	if (index >= pairwise_keys_start)
 		keymac_write(dev, index, NULL);	/* First zero out mac. */
+	if (algorithm == B43_SEC_ALGO_TKIP) {
+		/*
+		 * We should provide an initial iv32, phase1key pair.
+		 * We could start with iv32=0 and compute the corresponding
+		 * phase1key, but this means calling ieee80211_get_tkip_key
+		 * with a fake skb (or export other tkip function).
+		 * Because we are lazy we hope iv32 won't start with
+		 * 0xffffffff and let's b43_op_update_tkip_key provide a
+		 * correct pair.
+		 */
+		rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf);
+	} else if (index >= pairwise_keys_start) /* clear it */
+		rx_tkip_phase1_write(dev, index, 0, NULL);
 	if (key)
 		memcpy(buf, key, key_len);
 	key_write(dev, index, algorithm, buf);
@@ -859,6 +963,15 @@ static int b43_key_write(struct b43_wldev *dev,
 	int i;
 	int pairwise_keys_start;
 
+	/* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block:
+	 * 	- Temporal Encryption Key (128 bits)
+	 * 	- Temporal Authenticator Tx MIC Key (64 bits)
+	 * 	- Temporal Authenticator Rx MIC Key (64 bits)
+	 *
+	 * 	Hardware only store TEK
+	 */
+	if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32)
+		key_len = 16;
 	if (key_len > B43_SEC_KEYSIZE)
 		return -EINVAL;
 	for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
@@ -965,6 +1078,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
 		printk("   Algo: %04X/%02X", algo, key->algorithm);
 
 		if (index >= pairwise_keys_start) {
+			if (key->algorithm == B43_SEC_ALGO_TKIP) {
+				printk("   TKIP: ");
+				offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4);
+				for (i = 0; i < 14; i += 2) {
+					u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
+					printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
+				}
+			}
 			rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
 						((index - pairwise_keys_start) * 2) + 0);
 			rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
@@ -1947,8 +2068,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
 		filename = "ucode5";
 	else if ((rev >= 11) && (rev <= 12))
 		filename = "ucode11";
-	else if (rev >= 13)
+	else if (rev == 13)
 		filename = "ucode13";
+	else if (rev == 14)
+		filename = "ucode14";
+	else if (rev >= 15)
+		filename = "ucode15";
 	else
 		goto err_no_ucode;
 	err = b43_do_request_fw(ctx, filename, &fw->ucode);
@@ -1996,6 +2121,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
 		else
 			goto err_no_initvals;
 		break;
+	case B43_PHYTYPE_LP:
+		if (rev == 13)
+			filename = "lp0initvals13";
+		else if (rev == 14)
+			filename = "lp0initvals14";
+		else if (rev >= 15)
+			filename = "lp0initvals15";
+		else
+			goto err_no_initvals;
+		break;
 	default:
 		goto err_no_initvals;
 	}
@@ -2030,6 +2165,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
 		else
 			goto err_no_initvals;
 		break;
+	case B43_PHYTYPE_LP:
+		if (rev == 13)
+			filename = "lp0bsinitvals13";
+		else if (rev == 14)
+			filename = "lp0bsinitvals14";
+		else if (rev >= 15)
+			filename = "lp0bsinitvals15";
+		else
+			goto err_no_initvals;
+		break;
 	default:
 		goto err_no_initvals;
 	}
@@ -2557,6 +2702,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
 	case B43_PHYTYPE_A:
 	case B43_PHYTYPE_G:
 	case B43_PHYTYPE_N:
+	case B43_PHYTYPE_LP:
 		b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -3587,8 +3733,10 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 	switch (cmd) {
 	case SET_KEY:
-		if (algorithm == B43_SEC_ALGO_TKIP) {
-			/* FIXME: No TKIP hardware encryption for now. */
+		if (algorithm == B43_SEC_ALGO_TKIP &&
+		    (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
+		    !modparam_hwtkip)) {
+			/* We support only pairwise key */
 			err = -EOPNOTSUPP;
 			goto out_unlock;
 		}
@@ -3618,6 +3766,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 				     b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
 		}
 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		if (algorithm == B43_SEC_ALGO_TKIP)
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 		break;
 	case DISABLE_KEY: {
 		err = b43_key_clear(dev, key->hw_key_idx);
@@ -3646,7 +3796,7 @@ out_unlock:
 
 static void b43_op_configure_filter(struct ieee80211_hw *hw,
 				    unsigned int changed, unsigned int *fflags,
-				    int mc_count, struct dev_addr_list *mc_list)
+				    u64 multicast)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -3785,7 +3935,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 #endif
 #ifdef CONFIG_B43_PHY_LP
 	case B43_PHYTYPE_LP:
-		if (phy_rev > 1)
+		if (phy_rev > 2)
 			unsupported = 1;
 		break;
 #endif
@@ -3842,7 +3992,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 			unsupported = 1;
 		break;
 	case B43_PHYTYPE_LP:
-		if (radio_ver != 0x2062)
+		if (radio_ver != 0x2062 && radio_ver != 0x2063)
 			unsupported = 1;
 		break;
 	default:
@@ -4345,6 +4495,7 @@ static const struct ieee80211_ops b43_hw_ops = {
 	.bss_info_changed	= b43_op_bss_info_changed,
 	.configure_filter	= b43_op_configure_filter,
 	.set_key		= b43_op_set_key,
+	.update_tkip_key	= b43_op_update_tkip_key,
 	.get_stats		= b43_op_get_stats,
 	.get_tx_stats		= b43_op_get_tx_stats,
 	.get_tsf		= b43_op_get_tsf,
@@ -4480,9 +4631,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 		case B43_PHYTYPE_A:
 			have_5ghz_phy = 1;
 			break;
+		case B43_PHYTYPE_LP: //FIXME not always!
+#if 0 //FIXME enabling 5GHz causes a NULL pointer dereference
+			have_5ghz_phy = 1;
+#endif
 		case B43_PHYTYPE_G:
 		case B43_PHYTYPE_N:
-		case B43_PHYTYPE_LP:
 			have_2ghz_phy = 1;
 			break;
 		default:
@@ -4497,7 +4651,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 	}
 	if (1 /* disable A-PHY */) {
 		/* FIXME: For now we disable the A-PHY on multi-PHY devices. */
-		if (dev->phy.type != B43_PHYTYPE_N) {
+		if (dev->phy.type != B43_PHYTYPE_N &&
+		    dev->phy.type != B43_PHYTYPE_LP) {
 			have_2ghz_phy = 1;
 			have_5ghz_phy = 0;
 		}

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

@@ -123,7 +123,7 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value
 u64 b43_hf_read(struct b43_wldev *dev);
 void b43_hf_write(struct b43_wldev *dev, u64 value);
 
-void b43_dummy_transmission(struct b43_wldev *dev);
+void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on);
 
 void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
 

+ 3 - 3
drivers/net/wireless/b43/phy_g.c

@@ -333,7 +333,7 @@ static void b43_set_all_gains(struct b43_wldev *dev,
 		b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp);
 		b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp);
 	}
-	b43_dummy_transmission(dev);
+	b43_dummy_transmission(dev, false, true);
 }
 
 static void b43_set_original_gains(struct b43_wldev *dev)
@@ -365,7 +365,7 @@ static void b43_set_original_gains(struct b43_wldev *dev)
 	b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040);
 	b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040);
 	b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000);
-	b43_dummy_transmission(dev);
+	b43_dummy_transmission(dev, false, true);
 }
 
 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
@@ -1964,7 +1964,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
 			}
 			b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
 		}
-		b43_dummy_transmission(dev);
+		b43_dummy_transmission(dev, false, true);
 		gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
 		if (B43_DEBUG) {
 			/* Current-Idle-TSSI sanity check. */

+ 950 - 92
drivers/net/wireless/b43/phy_lp.c

@@ -29,6 +29,25 @@
 #include "tables_lpphy.h"
 
 
+static inline u16 channel2freq_lp(u8 channel)
+{
+	if (channel < 14)
+		return (2407 + 5 * channel);
+	else if (channel == 14)
+		return 2484;
+	else if (channel < 184)
+		return (5000 + 5 * channel);
+	else
+		return (4000 + 5 * channel);
+}
+
+static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
+{
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+		return 1;
+	return 36;
+}
+
 static int b43_lpphy_op_allocate(struct b43_wldev *dev)
 {
 	struct b43_phy_lp *lpphy;
@@ -142,10 +161,9 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
 	}
 }
 
-static void lpphy_adjust_gain_table(struct b43_wldev *dev)
+static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
-	u32 freq = dev->wl->hw->conf.channel->center_freq;
 	u16 temp[3];
 	u16 isolation;
 
@@ -170,6 +188,8 @@ static void lpphy_adjust_gain_table(struct b43_wldev *dev)
 
 static void lpphy_table_init(struct b43_wldev *dev)
 {
+	u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev));
+
 	if (dev->phy.rev < 2)
 		lpphy_rev0_1_table_init(dev);
 	else
@@ -178,14 +198,68 @@ static void lpphy_table_init(struct b43_wldev *dev)
 	lpphy_init_tx_gain_table(dev);
 
 	if (dev->phy.rev < 2)
-		lpphy_adjust_gain_table(dev);
+		lpphy_adjust_gain_table(dev, freq);
 }
 
 static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
 {
 	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy_lp *lpphy = dev->phy.lp;
 	u16 tmp, tmp2;
 
+	b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF);
+	b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0);
+	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
+	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
+	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
+	b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004);
+	b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078);
+	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
+	b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016);
+	b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004);
+	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400);
+	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400);
+	b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
+	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
+	b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
+	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
+	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC10, 0x0180);
+	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3800);
+	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
+	b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
+	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
+	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
+	b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB,
+			0xFF00, lpphy->rx_pwr_offset);
+	if ((bus->sprom.boardflags_lo & B43_BFL_FEM) &&
+	   ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
+	   (bus->sprom.boardflags_hi & B43_BFH_PAREF))) {
+		/* TODO:
+		 * Set the LDO voltage to 0x0028 - FIXME: What is this?
+		 * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage
+		 * 	as arguments
+		 * Call sb_pmu_paref_ldo_enable with argument TRUE
+		 */
+		if (dev->phy.rev == 0) {
+			b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
+					0xFFCF, 0x0010);
+		}
+		b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
+	} else {
+		//TODO: Call ssb_pmu_paref_ldo_enable with argument FALSE
+		b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
+				0xFFCF, 0x0020);
+		b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
+	}
+	tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
+	b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp);
+	if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV)
+		b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
+	else
+		b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
+	b43_lptab_write(dev, B43_LPTAB16(11, 1), 24);
+	b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL,
+			0xFFF9, (lpphy->bx_arch << 1));
 	if (dev->phy.rev == 1 &&
 	   (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) {
 		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
@@ -235,7 +309,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
 		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
 		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
 	}
-	if (dev->phy.rev == 1) {
+	if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) {
 		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
 		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
 		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
@@ -247,6 +321,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
 		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
 		b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
 		b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
+		//FIXME the Broadcom driver caches & delays this HF write!
 		b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W);
 	}
 	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
@@ -364,7 +439,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
 	b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9);
 	b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF);
 	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500);
-	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xF81F, 0xA0);
+	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0);
 	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300);
 	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00);
 	if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
@@ -385,7 +460,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
 	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
 	b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
 
-	if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) {
+	if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
 		b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
 		b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
 	}
@@ -396,6 +471,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
 		b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6);
 		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00);
 		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1);
+		b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
 	} else /* 5GHz */
 		b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40);
 
@@ -435,8 +511,9 @@ struct b2062_freqdata {
 /* Initialize the 2062 radio. */
 static void lpphy_2062_init(struct b43_wldev *dev)
 {
+	struct b43_phy_lp *lpphy = dev->phy.lp;
 	struct ssb_bus *bus = dev->dev->bus;
-	u32 crystalfreq, pdiv, tmp, ref;
+	u32 crystalfreq, tmp, ref;
 	unsigned int i;
 	const struct b2062_freqdata *fd = NULL;
 
@@ -460,10 +537,15 @@ static void lpphy_2062_init(struct b43_wldev *dev)
 	b43_radio_write(dev, B2062_N_TX_CTL3, 0);
 	b43_radio_write(dev, B2062_N_TX_CTL4, 0);
 	b43_radio_write(dev, B2062_N_TX_CTL5, 0);
+	b43_radio_write(dev, B2062_N_TX_CTL6, 0);
 	b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40);
 	b43_radio_write(dev, B2062_N_PDN_CTL0, 0);
 	b43_radio_write(dev, B2062_N_CALIB_TS, 0x10);
 	b43_radio_write(dev, B2062_N_CALIB_TS, 0);
+	if (dev->phy.rev > 0) {
+		b43_radio_write(dev, B2062_S_BG_CTL1,
+			(b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80);
+	}
 	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
 		b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1);
 	else
@@ -475,23 +557,27 @@ static void lpphy_2062_init(struct b43_wldev *dev)
 	B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU));
 	B43_WARN_ON(crystalfreq == 0);
 
-	if (crystalfreq >= 30000000) {
-		pdiv = 1;
+	if (crystalfreq <= 30000000) {
+		lpphy->pdiv = 1;
 		b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB);
 	} else {
-		pdiv = 2;
+		lpphy->pdiv = 2;
 		b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4);
 	}
 
-	tmp = (800000000 * pdiv + crystalfreq) / (32000000 * pdiv);
-	tmp = (tmp - 1) & 0xFF;
+	tmp = (((800000000 * lpphy->pdiv + crystalfreq) /
+	      (2 * crystalfreq)) - 8) & 0xFF;
+	b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp);
+
+	tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) /
+	      (32000000 * lpphy->pdiv)) - 1) & 0xFF;
 	b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp);
 
-	tmp = (2 * crystalfreq + 1000000 * pdiv) / (2000000 * pdiv);
-	tmp = ((tmp & 0xFF) - 1) & 0xFFFF;
+	tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) /
+	      (2000000 * lpphy->pdiv)) - 1) & 0xFF;
 	b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp);
 
-	ref = (1000 * pdiv + 2 * crystalfreq) / (2000 * pdiv);
+	ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv);
 	ref &= 0xFFFF;
 	for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) {
 		if (ref < freqdata_tab[i].freq) {
@@ -523,9 +609,14 @@ static void lpphy_2063_init(struct b43_wldev *dev)
 	b43_radio_write(dev, B2063_PA_SP7, 0);
 	b43_radio_write(dev, B2063_TX_RF_SP6, 0x20);
 	b43_radio_write(dev, B2063_TX_RF_SP9, 0x40);
-	b43_radio_write(dev, B2063_PA_SP3, 0xa0);
-	b43_radio_write(dev, B2063_PA_SP4, 0xa0);
-	b43_radio_write(dev, B2063_PA_SP2, 0x18);
+	if (dev->phy.rev == 2) {
+		b43_radio_write(dev, B2063_PA_SP3, 0xa0);
+		b43_radio_write(dev, B2063_PA_SP4, 0xa0);
+		b43_radio_write(dev, B2063_PA_SP2, 0x18);
+	} else {
+		b43_radio_write(dev, B2063_PA_SP3, 0x20);
+		b43_radio_write(dev, B2063_PA_SP2, 0x20);
+	}
 }
 
 struct lpphy_stx_table_entry {
@@ -592,7 +683,7 @@ static void lpphy_radio_init(struct b43_wldev *dev)
 	b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD);
 	udelay(1);
 
-	if (dev->phy.rev < 2) {
+	if (dev->phy.radio_ver == 0x2062) {
 		lpphy_2062_init(dev);
 	} else {
 		lpphy_2063_init(dev);
@@ -609,11 +700,18 @@ struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
 
 static void lpphy_set_rc_cap(struct b43_wldev *dev)
 {
-	u8 rc_cap = dev->phy.lp->rc_cap;
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+
+	u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1;
+
+	if (dev->phy.rev == 1) //FIXME check channel 14!
+		rc_cap = max_t(u8, rc_cap + 5, 15);
 
-	b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80));
-	b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80);
-	b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80);
+	b43_radio_write(dev, B2062_N_RXBB_CALIB2,
+			max_t(u8, lpphy->rc_cap - 4, 0x80));
+	b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80);
+	b43_radio_write(dev, B2062_S_RXG_CNT16,
+			((lpphy->rc_cap & 0x1F) >> 2) | 0x80);
 }
 
 static u8 lpphy_get_bb_mult(struct b43_wldev *dev)
@@ -626,9 +724,39 @@ static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
 	b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
 }
 
-static void lpphy_disable_crs(struct b43_wldev *dev)
+static void lpphy_set_deaf(struct b43_wldev *dev, bool user)
 {
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+
+	if (user)
+		lpphy->crs_usr_disable = 1;
+	else
+		lpphy->crs_sys_disable = 1;
 	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
+}
+
+static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+
+	if (user)
+		lpphy->crs_usr_disable = 0;
+	else
+		lpphy->crs_sys_disable = 0;
+
+	if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) {
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+			b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
+					0xFF1F, 0x60);
+		else
+			b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
+					0xFF1F, 0x20);
+	}
+}
+
+static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
+{
+	lpphy_set_deaf(dev, user);
 	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1);
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
@@ -656,12 +784,9 @@ static void lpphy_disable_crs(struct b43_wldev *dev)
 	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
 }
 
-static void lpphy_restore_crs(struct b43_wldev *dev)
+static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
 {
-	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
-		b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60);
-	else
-		b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20);
+	lpphy_clear_deaf(dev, user);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
 }
@@ -707,10 +832,11 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,
 		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
 				0xF800, rf_gain);
 	} else {
-		pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00;
+		pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0;
+		pa_gain <<= 2;
 		b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
 			      (gains.pga << 8) | gains.gm);
-		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+		b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
 				0x8000, gains.pad | pa_gain);
 		b43_phy_write(dev, B43_PHY_OFDM(0xFC),
 			      (gains.pga << 8) | gains.gm);
@@ -724,7 +850,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,
 		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7);
 		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14);
 	}
-	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4);
+	b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6);
 }
 
 static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
@@ -764,33 +890,33 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
 	}
 }
 
-static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
+static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
 {
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
 	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
 	if (dev->phy.rev >= 2) {
 		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
-		if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ)
-			return;
-		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
-		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7);
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
+			b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
+		}
 	} else {
 		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
 	}
 }
 
-static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
+static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
 {
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
 	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
 	if (dev->phy.rev >= 2) {
 		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
-		if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ)
-			return;
-		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
-		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8);
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
+			b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
+		}
 	} else {
 		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
 	}
@@ -909,26 +1035,22 @@ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
 {
 	u32 quotient, remainder, rbit, roundup, tmp;
 
-	if (divisor == 0) {
-		quotient = 0;
-		remainder = 0;
-	} else {
-		quotient = dividend / divisor;
-		remainder = dividend % divisor;
-	}
+	if (divisor == 0)
+		return 0;
+
+	quotient = dividend / divisor;
+	remainder = dividend % divisor;
 
 	rbit = divisor & 0x1;
 	roundup = (divisor >> 1) + rbit;
-	precision--;
 
-	while (precision != 0xFF) {
+	while (precision != 0) {
 		tmp = remainder - roundup;
 		quotient <<= 1;
-		remainder <<= 1;
-		if (remainder >= roundup) {
+		if (remainder >= roundup)
 			remainder = (tmp << 1) + rbit;
-			quotient--;
-		}
+		else
+			remainder <<= 1;
 		precision--;
 	}
 
@@ -992,9 +1114,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
 	struct b43_phy_lp *lpphy = dev->phy.lp;
 	enum b43_lpphy_txpctl_mode oldmode;
 
-	oldmode = lpphy->txpctl_mode;
 	lpphy_read_tx_pctl_mode_from_hardware(dev);
-	if (lpphy->txpctl_mode == mode)
+	oldmode = lpphy->txpctl_mode;
+	if (oldmode == mode)
 		return;
 	lpphy->txpctl_mode = mode;
 
@@ -1022,28 +1144,37 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
 	lpphy_write_tx_pctl_mode_to_hardware(dev);
 }
 
+static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
+				       unsigned int new_channel);
+
 static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
 {
 	struct b43_phy_lp *lpphy = dev->phy.lp;
 	struct lpphy_iq_est iq_est;
 	struct lpphy_tx_gains tx_gains;
-	static const u32 ideal_pwr_table[22] = {
+	static const u32 ideal_pwr_table[21] = {
 		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
 		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
 		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
-		0x0004c, 0x0002c, 0x0001a, 0xc0006,
+		0x0004c, 0x0002c, 0x0001a,
 	};
 	bool old_txg_ovr;
 	u8 old_bbmult;
 	u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
-	    old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl;
+	    old_rf2_ovr, old_rf2_ovrval, old_phy_ctl;
+	enum b43_lpphy_txpctl_mode old_txpctl;
 	u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
-	int loopback, i, j, inner_sum;
+	int loopback, i, j, inner_sum, err;
 
 	memset(&iq_est, 0, sizeof(iq_est));
 
-	b43_switch_channel(dev, 7);
-	old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1;
+	err = b43_lpphy_op_switch_channel(dev, 7);
+	if (err) {
+		b43dbg(dev->wl,
+		       "RC calib: Failed to switch to channel 7, error = %d",
+		       err);
+	}
+	old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40);
 	old_bbmult = lpphy_get_bb_mult(dev);
 	if (old_txg_ovr)
 		tx_gains = lpphy_get_tx_gains(dev);
@@ -1054,11 +1185,11 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
 	old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
 	old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
 	old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
-	old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) &
-					B43_LPPHY_TX_PWR_CTL_CMD_MODE;
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
+	old_txpctl = lpphy->txpctl_mode;
 
-	lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
-	lpphy_disable_crs(dev);
+	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+	lpphy_disable_crs(dev, true);
 	loopback = lpphy_loopback(dev);
 	if (loopback == -1)
 		goto finish;
@@ -1091,7 +1222,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
 	lpphy_stop_ddfs(dev);
 
 finish:
-	lpphy_restore_crs(dev);
+	lpphy_restore_crs(dev, true);
 	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
 	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
 	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
@@ -1257,33 +1388,110 @@ static void lpphy_calibration(struct b43_wldev *dev)
 	b43_mac_enable(dev);
 }
 
-/* Initialize TX power control */
-static void lpphy_tx_pctl_init(struct b43_wldev *dev)
+static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode)
 {
-	if (0/*FIXME HWPCTL capable */) {
-		//TODO
-	} else { /* This device is only software TX power control capable. */
-		if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-			//TODO
+	if (mode != TSSI_MUX_EXT) {
+		b43_radio_set(dev, B2063_PA_SP1, 0x2);
+		b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000);
+		b43_radio_write(dev, B2063_PA_CTL10, 0x51);
+		if (mode == TSSI_MUX_POSTPA) {
+			b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE);
+			b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7);
 		} else {
-			//TODO
+			b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1);
+			b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL,
+					0xFFC7, 0x20);
 		}
-		//TODO set BB multiplier to 0x0096
+	} else {
+		B43_WARN_ON(1);
 	}
 }
 
-static int b43_lpphy_op_init(struct b43_wldev *dev)
+static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev)
 {
-	lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
-	lpphy_baseband_init(dev);
-	lpphy_radio_init(dev);
-	lpphy_calibrate_rc(dev);
-	//TODO set channel
-	lpphy_tx_pctl_init(dev);
-	lpphy_calibration(dev);
-	//TODO ACI init
+	u16 tmp;
+	int i;
 
-	return 0;
+	//SPEC TODO Call LP PHY Clear TX Power offsets
+	for (i = 0; i < 64; i++) {
+		if (dev->phy.rev >= 2)
+			b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i);
+		else
+			b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i);
+	}
+
+	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF);
+	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000);
+	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F);
+	if (dev->phy.rev < 2) {
+		b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF);
+		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000);
+	} else {
+		b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE);
+		b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4);
+		b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10);
+		b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1);
+		lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA);
+	}
+	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000);
+	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
+	b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
+	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
+			(u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+			B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
+	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
+	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
+			(u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+			B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
+
+	if (dev->phy.rev < 2) {
+		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000);
+		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF);
+	} else {
+		lpphy_set_tx_power_by_index(dev, 0x7F);
+	}
+
+	b43_dummy_transmission(dev, true, true);
+
+	tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT);
+	if (tmp & 0x8000) {
+		b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI,
+				0xFFC0, (tmp & 0xFF) - 32);
+	}
+
+	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF);
+
+	// (SPEC?) TODO Set "Target TX frequency" variable to 0
+	// SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8!
+}
+
+static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev)
+{
+	struct lpphy_tx_gains gains;
+
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+		gains.gm = 4;
+		gains.pad = 12;
+		gains.pga = 12;
+		gains.dac = 0;
+	} else {
+		gains.gm = 7;
+		gains.pad = 14;
+		gains.pga = 15;
+		gains.dac = 0;
+	}
+	lpphy_set_tx_gains(dev, gains);
+	lpphy_set_bb_mult(dev, 150);
+}
+
+/* Initialize TX power control */
+static void lpphy_tx_pctl_init(struct b43_wldev *dev)
+{
+	if (0/*FIXME HWPCTL capable */) {
+		lpphy_tx_pctl_init_hw(dev);
+	} else { /* This device is only software TX power control capable. */
+		lpphy_tx_pctl_init_sw(dev);
+	}
 }
 
 static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
@@ -1328,18 +1536,668 @@ static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
 	//TODO
 }
 
+struct b206x_channel {
+	u8 channel;
+	u16 freq;
+	u8 data[12];
+};
+
+static const struct b206x_channel b2062_chantbl[] = {
+	{ .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
+	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
+	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
+	{ .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
+	  .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
+	  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
+	  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
+	  .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
+	  .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
+	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
+	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
+	  .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+	{ .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
+	  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+	{ .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
+	  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+	{ .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
+	  .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+	{ .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
+	  .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+	{ .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
+	  .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+	{ .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
+	  .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
+	{ .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
+	  .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+	{ .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
+	  .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
+	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
+};
+
+static const struct b206x_channel b2063_chantbl[] = {
+	{ .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
+	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C,
+	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C,
+	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C,
+	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C,
+	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C,
+	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C,
+	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C,
+	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C,
+	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C,
+	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C,
+	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C,
+	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C,
+	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
+	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x80, .data[11] = 0x70, },
+	{ .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05,
+	  .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05,
+	  .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
+	  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
+	  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
+	  .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04,
+	  .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
+	  .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
+	  .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02,
+	  .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60,
+	  .data[10] = 0x20, .data[11] = 0x00, },
+	{ .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
+	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
+	  .data[10] = 0x10, .data[11] = 0x00, },
+	{ .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
+	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
+	  .data[10] = 0x10, .data[11] = 0x00, },
+	{ .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
+	  .data[10] = 0x10, .data[11] = 0x00, },
+	{ .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
+	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
+	  .data[10] = 0x00, .data[11] = 0x00, },
+	{ .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0,
+	  .data[10] = 0x50, .data[11] = 0x00, },
+	{ .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
+	  .data[10] = 0x50, .data[11] = 0x00, },
+	{ .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
+	  .data[10] = 0x50, .data[11] = 0x00, },
+	{ .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
+	  .data[10] = 0x40, .data[11] = 0x00, },
+	{ .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
+	  .data[10] = 0x40, .data[11] = 0x00, },
+	{ .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
+	  .data[10] = 0x40, .data[11] = 0x00, },
+	{ .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
+	  .data[10] = 0x40, .data[11] = 0x00, },
+	{ .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
+	  .data[10] = 0x40, .data[11] = 0x00, },
+	{ .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C,
+	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08,
+	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
+	  .data[10] = 0x40, .data[11] = 0x00, },
+};
+
+static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+
+	b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
+	udelay(20);
+	if (bus->chip_id == 0x5354) {
+		b43_radio_write(dev, B2062_N_COMM1, 4);
+		b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
+	} else {
+		b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0);
+	}
+	udelay(5);
+}
+
+static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42);
+	b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62);
+	udelay(200);
+}
+
+static int lpphy_b2062_tune(struct b43_wldev *dev,
+			    unsigned int channel)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	struct ssb_bus *bus = dev->dev->bus;
+	const struct b206x_channel *chandata = NULL;
+	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
+	u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
+	int i, err = 0;
+
+	for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) {
+		if (b2062_chantbl[i].channel == channel) {
+			chandata = &b2062_chantbl[i];
+			break;
+		}
+	}
+
+	if (B43_WARN_ON(!chandata))
+		return -EINVAL;
+
+	b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
+	b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
+	b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
+	b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
+	b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
+	b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
+	b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
+	b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
+	b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
+	b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
+
+	tmp1 = crystal_freq / 1000;
+	tmp2 = lpphy->pdiv * 1000;
+	b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC);
+	b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07);
+	lpphy_b2062_reset_pll_bias(dev);
+	tmp3 = tmp2 * channel2freq_lp(channel);
+	if (channel2freq_lp(channel) < 4000)
+		tmp3 *= 2;
+	tmp4 = 48 * tmp1;
+	tmp6 = tmp3 / tmp4;
+	tmp7 = tmp3 % tmp4;
+	b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6);
+	tmp5 = tmp7 * 0x100;
+	tmp6 = tmp5 / tmp4;
+	tmp7 = tmp5 % tmp4;
+	b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6);
+	tmp5 = tmp7 * 0x100;
+	tmp6 = tmp5 / tmp4;
+	tmp7 = tmp5 % tmp4;
+	b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6);
+	tmp5 = tmp7 * 0x100;
+	tmp6 = tmp5 / tmp4;
+	tmp7 = tmp5 % tmp4;
+	b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
+	tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19);
+	tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
+	b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
+	b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
+
+	lpphy_b2062_vco_calib(dev);
+	if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
+		b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC);
+		b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0);
+		lpphy_b2062_reset_pll_bias(dev);
+		lpphy_b2062_vco_calib(dev);
+		if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
+			err = -EIO;
+	}
+
+	b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
+	return err;
+}
+
+
+/* This was previously called lpphy_japan_filter */
+static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
+{
+	struct b43_phy_lp *lpphy = dev->phy.lp;
+	u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
+
+	if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
+		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
+		if ((dev->phy.rev == 1) && (lpphy->rc_cap))
+			lpphy_set_rc_cap(dev);
+	} else {
+		b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
+	}
+}
+
+static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
+{
+	u16 tmp;
+
+	b43_phy_mask(dev, B2063_PLL_SP1, ~0x40);
+	tmp = b43_phy_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
+	b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
+	udelay(1);
+	b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
+	udelay(1);
+	b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
+	udelay(1);
+	b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
+	udelay(300);
+	b43_phy_set(dev, B2063_PLL_SP1, 0x40);
+}
+
+static int lpphy_b2063_tune(struct b43_wldev *dev,
+			    unsigned int channel)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+
+	static const struct b206x_channel *chandata = NULL;
+	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
+	u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count;
+	u16 old_comm15, scale;
+	u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+	int i, div = (crystal_freq <= 26000000 ? 1 : 2);
+
+	for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
+		if (b2063_chantbl[i].channel == channel) {
+			chandata = &b2063_chantbl[i];
+			break;
+		}
+	}
+
+	if (B43_WARN_ON(!chandata))
+		return -EINVAL;
+
+	b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
+	b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
+	b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]);
+	b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]);
+	b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]);
+	b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]);
+	b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]);
+	b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]);
+	b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]);
+	b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]);
+	b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]);
+	b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]);
+
+	old_comm15 = b43_radio_read(dev, B2063_COMM15);
+	b43_radio_set(dev, B2063_COMM15, 0x1E);
+
+	if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */
+		vco_freq = chandata->freq << 1;
+	else
+		vco_freq = chandata->freq << 2;
+
+	freqref = crystal_freq * 3;
+	val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16);
+	val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16);
+	val3 = lpphy_qdiv_roundup(vco_freq, 3, 16);
+	timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1;
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2);
+	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6,
+			  0xFFF8, timeout >> 2);
+	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
+			  0xFF9F,timeout << 5);
+
+	timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) +
+						999999) / 1000000) + 1;
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref);
+
+	count = lpphy_qdiv_roundup(val3, val2 + 16, 16);
+	count *= (timeout + 1) * (timeoutref + 1);
+	count--;
+	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
+						0xF0, count >> 8);
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF);
+
+	tmp1 = ((val3 * 62500) / freqref) << 4;
+	tmp2 = ((val3 * 62500) % freqref) << 4;
+	while (tmp2 >= freqref) {
+		tmp1++;
+		tmp2 -= freqref;
+	}
+	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4);
+	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4);
+	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16);
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF);
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF);
+
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9);
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88);
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28);
+	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63);
+
+	tmp3 = ((41 * (val3 - 3000)) /1200) + 27;
+	tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16);
+
+	if ((tmp4 + tmp3 - 1) / tmp3 > 60) {
+		scale = 1;
+		tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8;
+	} else {
+		scale = 0;
+		tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
+	}
+	b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
+	b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
+
+	tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
+	tmp6 *= (tmp5 * 8) * (scale + 1);
+	if (tmp6 > 150)
+		tmp6 = 0;
+
+	b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
+	b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
+
+	b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
+	if (crystal_freq > 26000000)
+		b43_phy_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
+	else
+		b43_phy_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
+
+	if (val1 == 45)
+		b43_phy_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
+	else
+		b43_phy_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
+
+	b43_phy_set(dev, B2063_PLL_SP2, 0x3);
+	udelay(1);
+	b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC);
+	lpphy_b2063_vco_calib(dev);
+	b43_radio_write(dev, B2063_COMM15, old_comm15);
+
+	return 0;
+}
+
 static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
 				       unsigned int new_channel)
 {
-	//TODO
+	int err;
+
+	b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
+
+	if (dev->phy.radio_ver == 0x2063) {
+		err = lpphy_b2063_tune(dev, new_channel);
+		if (err)
+			return err;
+	} else {
+		err = lpphy_b2062_tune(dev, new_channel);
+		if (err)
+			return err;
+		lpphy_set_analog_filter(dev, new_channel);
+		lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
+	}
+
 	return 0;
 }
 
-static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
+static int b43_lpphy_op_init(struct b43_wldev *dev)
 {
-	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
-		return 1;
-	return 36;
+	int err;
+
+	lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
+	lpphy_baseband_init(dev);
+	lpphy_radio_init(dev);
+	lpphy_calibrate_rc(dev);
+	err = b43_lpphy_op_switch_channel(dev,
+				b43_lpphy_op_get_default_chan(dev));
+	if (err) {
+		b43dbg(dev->wl, "Switch to init channel failed, error = %d.\n",
+		       err);
+	}
+	lpphy_tx_pctl_init(dev);
+	lpphy_calibration(dev);
+	//TODO ACI init
+
+	return 0;
 }
 
 static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)

+ 17 - 8
drivers/net/wireless/b43/phy_lp.h

@@ -825,11 +825,11 @@ struct b43_phy_lp {
 	enum b43_lpphy_txpctl_mode txpctl_mode;
 
 	/* Transmit isolation medium band */
-	u8 tx_isolation_med_band; /* FIXME initial value? */
+	u8 tx_isolation_med_band;
 	/* Transmit isolation low band */
-	u8 tx_isolation_low_band; /* FIXME initial value? */
+	u8 tx_isolation_low_band;
 	/* Transmit isolation high band */
-	u8 tx_isolation_hi_band; /* FIXME initial value? */
+	u8 tx_isolation_hi_band;
 
 	/* Max transmit power medium band */
 	u16 max_tx_pwr_med_band;
@@ -848,7 +848,7 @@ struct b43_phy_lp {
 	s16 txpa[3], txpal[3], txpah[3];
 
 	/* Receive power offset */
-	u8 rx_pwr_offset; /* FIXME initial value? */
+	u8 rx_pwr_offset;
 
 	/* TSSI transmit count */
 	u16 tssi_tx_count;
@@ -864,16 +864,16 @@ struct b43_phy_lp {
 	s8 tx_pwr_idx_over; /* FIXME initial value? */
 
 	/* RSSI vf */
-	u8 rssi_vf; /* FIXME initial value? */
+	u8 rssi_vf;
 	/* RSSI vc */
-	u8 rssi_vc; /* FIXME initial value? */
+	u8 rssi_vc;
 	/* RSSI gs */
-	u8 rssi_gs; /* FIXME initial value? */
+	u8 rssi_gs;
 
 	/* RC cap */
 	u8 rc_cap; /* FIXME initial value? */
 	/* BX arch */
-	u8 bx_arch; /* FIXME initial value? */
+	u8 bx_arch;
 
 	/* Full calibration channel */
 	u8 full_calib_chan; /* FIXME initial value? */
@@ -884,8 +884,17 @@ struct b43_phy_lp {
 
 	/* Used for "Save/Restore Dig Filt State" */
 	u16 dig_flt_state[9];
+
+	bool crs_usr_disable, crs_sys_disable;
+
+	unsigned int pdiv;
 };
 
+enum tssi_mux_mode {
+	TSSI_MUX_PREPA,
+	TSSI_MUX_POSTPA,
+	TSSI_MUX_EXT,
+};
 
 struct b43_phy_operations;
 extern const struct b43_phy_operations b43_phyops_lp;

+ 2 - 2
drivers/net/wireless/b43/pio.c

@@ -461,8 +461,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
 
 	cookie = generate_cookie(q, pack);
 	hdrlen = b43_txhdr_size(q->dev);
-	err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data,
-				 skb->len, info, cookie);
+	err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb,
+				 info, cookie);
 	if (err)
 		return err;
 

+ 11 - 1
drivers/net/wireless/b43/tables_lpphy.c

@@ -2367,7 +2367,17 @@ static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset,
 	tmp  = data.pad << 16;
 	tmp |= data.pga << 8;
 	tmp |= data.gm;
-	tmp |= 0x7f000000;
+	if (dev->phy.rev >= 3) {
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+			tmp |= 0x10 << 24;
+		else
+			tmp |= 0x70 << 24;
+	} else {
+		if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+			tmp |= 0x14 << 24;
+		else
+			tmp |= 0x7F << 24;
+	}
 	b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp);
 	tmp  = data.bb_mult << 20;
 	tmp |= data.dac << 28;

+ 2 - 2
drivers/net/wireless/b43/wa.c

@@ -37,7 +37,7 @@ static void b43_wa_papd(struct b43_wldev *dev)
 	backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0);
 	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7);
 	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0);
-	b43_dummy_transmission(dev);
+	b43_dummy_transmission(dev, true, true);
 	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup);
 }
 
@@ -628,7 +628,7 @@ void b43_wa_all(struct b43_wldev *dev)
 			B43_WARN_ON(1);
 		}
 		b43_wa_boards_g(dev);
-	} else { /* No N PHY support so far */
+	} else { /* No N PHY support so far, LP PHY is in phy_lp.c */
 		B43_WARN_ON(1);
 	}
 

+ 24 - 5
drivers/net/wireless/b43/xmit.c

@@ -180,11 +180,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
 /* Generate a TX data header. */
 int b43_generate_txhdr(struct b43_wldev *dev,
 		       u8 *_txhdr,
-		       const unsigned char *fragment_data,
-		       unsigned int fragment_len,
+		       struct sk_buff *skb_frag,
 		       struct ieee80211_tx_info *info,
 		       u16 cookie)
 {
+	const unsigned char *fragment_data = skb_frag->data;
+	unsigned int fragment_len = skb_frag->len;
 	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
 	const struct b43_phy *phy = &dev->phy;
 	const struct ieee80211_hdr *wlhdr =
@@ -258,9 +259,26 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
 			   B43_TXH_MAC_KEYALG;
 		wlhdr_len = ieee80211_hdrlen(fctl);
-		iv_len = min((size_t) info->control.hw_key->iv_len,
-			     ARRAY_SIZE(txhdr->iv));
-		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
+		if (key->algorithm == B43_SEC_ALGO_TKIP) {
+			u16 phase1key[5];
+			int i;
+			/* we give the phase1key and iv16 here, the key is stored in
+			 * shm. With that the hardware can do phase 2 and encryption.
+			 */
+			ieee80211_get_tkip_key(info->control.hw_key, skb_frag,
+					IEEE80211_TKIP_P1_KEY, (u8*)phase1key);
+			/* phase1key is in host endian */
+			for (i = 0; i < 5; i++)
+				phase1key[i] = cpu_to_le16(phase1key[i]);
+
+			memcpy(txhdr->iv, phase1key, 10);
+			/* iv16 */
+			memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
+		} else {
+			iv_len = min((size_t) info->control.hw_key->iv_len,
+				     ARRAY_SIZE(txhdr->iv));
+			memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
+		}
 	}
 	if (b43_is_old_txhdr_format(dev)) {
 		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
@@ -655,6 +673,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 		status.freq = chanid + 2400;
 		break;
 	case B43_PHYTYPE_N:
+	case B43_PHYTYPE_LP:
 		/* chanid is the SHM channel cookie. Which is the plain
 		 * channel number in b43. */
 		if (chanstat & B43_RX_CHAN_5GHZ) {

+ 1 - 2
drivers/net/wireless/b43/xmit.h

@@ -176,8 +176,7 @@ size_t b43_txhdr_size(struct b43_wldev *dev)
 
 int b43_generate_txhdr(struct b43_wldev *dev,
 		       u8 * txhdr,
-		       const unsigned char *fragment_data,
-		       unsigned int fragment_len,
+		       struct sk_buff *skb_frag,
 		       struct ieee80211_tx_info *txctl, u16 cookie);
 
 /* Transmit Status */

+ 1 - 3
drivers/net/wireless/b43legacy/main.c

@@ -2836,9 +2836,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
 
 static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
 					  unsigned int changed,
-					  unsigned int *fflags,
-					  int mc_count,
-					  struct dev_addr_list *mc_list)
+					  unsigned int *fflags,u64 multicast)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;

+ 8 - 6
drivers/net/wireless/ipw2x00/ipw2100.c

@@ -185,7 +185,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
 static int debug = 0;
-static int mode = 0;
+static int network_mode = 0;
 static int channel = 0;
 static int associate = 0;
 static int disable = 0;
@@ -195,7 +195,7 @@ static struct ipw2100_fw ipw2100_firmware;
 
 #include <linux/moduleparam.h>
 module_param(debug, int, 0444);
-module_param(mode, int, 0444);
+module_param_named(mode, network_mode, int, 0444);
 module_param(channel, int, 0444);
 module_param(associate, int, 0444);
 module_param(disable, int, 0444);
@@ -2844,7 +2844,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv)
 
 #ifdef CONFIG_IPW2100_DEBUG
 	{
-		int i = txq->oldest;
+		i = txq->oldest;
 		IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
 			     &txq->drv[i],
 			     (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
@@ -6076,7 +6076,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
 	priv->ieee->ieee802_1x = 1;
 
 	/* Set module parameters */
-	switch (mode) {
+	switch (network_mode) {
 	case 1:
 		priv->ieee->iw_mode = IW_MODE_ADHOC;
 		break;
@@ -8179,10 +8179,11 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
 	int rssi_qual;
 	int tx_qual;
 	int beacon_qual;
+	int quality;
 
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	struct iw_statistics *wstats;
-	u32 rssi, quality, tx_retries, missed_beacons, tx_failures;
+	u32 rssi, tx_retries, missed_beacons, tx_failures;
 	u32 ord_len = sizeof(u32);
 
 	if (!priv)
@@ -8265,7 +8266,8 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
 			beacon_qual = (20 - missed_beacons) *
 			    (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
 
-		quality = min(beacon_qual, min(tx_qual, rssi_qual));
+		quality = min(tx_qual, rssi_qual);
+		quality = min(beacon_qual, quality);
 
 #ifdef CONFIG_IPW2100_DEBUG
 		if (beacon_qual == quality)

+ 36 - 37
drivers/net/wireless/ipw2x00/ipw2200.c

@@ -83,13 +83,13 @@ MODULE_LICENSE("GPL");
 
 static int cmdlog = 0;
 static int debug = 0;
-static int channel = 0;
-static int mode = 0;
+static int default_channel = 0;
+static int network_mode = 0;
 
 static u32 ipw_debug_level;
 static int associate;
 static int auto_create = 1;
-static int led = 0;
+static int led_support = 0;
 static int disable = 0;
 static int bt_coexist = 0;
 static int hwcrypto = 0;
@@ -4265,9 +4265,10 @@ static void ipw_gather_stats(struct ipw_priv *priv)
 	IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
 			signal_quality, rssi);
 
-	quality = min(beacon_quality,
-		      min(rate_quality,
-			  min(tx_quality, min(rx_quality, signal_quality))));
+	quality = min(rx_quality, signal_quality);
+	quality = min(tx_quality, quality);
+	quality = min(rate_quality, quality);
+	quality = min(beacon_quality, quality);
 	if (quality == beacon_quality)
 		IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n",
 				quality);
@@ -4411,7 +4412,6 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 {
 	DECLARE_SSID_BUF(ssid);
 	u16 size = le16_to_cpu(notif->size);
-	notif->size = le16_to_cpu(notif->size);
 
 	IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
 
@@ -6101,11 +6101,10 @@ static void ipw_debug_config(struct ipw_priv *priv)
 static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
 {
 	/* TODO: Verify that this works... */
-	struct ipw_fixed_rate fr = {
-		.tx_rates = priv->rates_mask
-	};
+	struct ipw_fixed_rate fr;
 	u32 reg;
 	u16 mask = 0;
+	u16 new_tx_rates = priv->rates_mask;
 
 	/* Identify 'current FW band' and match it with the fixed
 	 * Tx rates */
@@ -6117,54 +6116,56 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
 			/* Invalid fixed rate mask */
 			IPW_DEBUG_WX
 			    ("invalid fixed rate mask in ipw_set_fixed_rate\n");
-			fr.tx_rates = 0;
+			new_tx_rates = 0;
 			break;
 		}
 
-		fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A;
+		new_tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A;
 		break;
 
 	default:		/* 2.4Ghz or Mixed */
 		/* IEEE_B */
 		if (mode == IEEE_B) {
-			if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) {
+			if (new_tx_rates & ~IEEE80211_CCK_RATES_MASK) {
 				/* Invalid fixed rate mask */
 				IPW_DEBUG_WX
 				    ("invalid fixed rate mask in ipw_set_fixed_rate\n");
-				fr.tx_rates = 0;
+				new_tx_rates = 0;
 			}
 			break;
 		}
 
 		/* IEEE_G */
-		if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK |
+		if (new_tx_rates & ~(IEEE80211_CCK_RATES_MASK |
 				    IEEE80211_OFDM_RATES_MASK)) {
 			/* Invalid fixed rate mask */
 			IPW_DEBUG_WX
 			    ("invalid fixed rate mask in ipw_set_fixed_rate\n");
-			fr.tx_rates = 0;
+			new_tx_rates = 0;
 			break;
 		}
 
-		if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) {
+		if (IEEE80211_OFDM_RATE_6MB_MASK & new_tx_rates) {
 			mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1);
-			fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK;
+			new_tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK;
 		}
 
-		if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) {
+		if (IEEE80211_OFDM_RATE_9MB_MASK & new_tx_rates) {
 			mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1);
-			fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK;
+			new_tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK;
 		}
 
-		if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) {
+		if (IEEE80211_OFDM_RATE_12MB_MASK & new_tx_rates) {
 			mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1);
-			fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK;
+			new_tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK;
 		}
 
-		fr.tx_rates |= mask;
+		new_tx_rates |= mask;
 		break;
 	}
 
+	fr.tx_rates = cpu_to_le16(new_tx_rates);
+
 	reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE);
 	ipw_write_reg32(priv, reg, *(u32 *) & fr);
 }
@@ -7850,7 +7851,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
 
 	/* Convert signal to DBM */
 	ipw_rt->rt_dbmsignal = antsignal;
-	ipw_rt->rt_dbmnoise = frame->noise;
+	ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise);
 
 	/* Convert the channel data and set the flags */
 	ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
@@ -7964,7 +7965,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
 	u16 channel = frame->received_channel;
 	u8 phy_flags = frame->antennaAndPhy;
 	s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM;
-	s8 noise = frame->noise;
+	s8 noise = (s8) le16_to_cpu(frame->noise);
 	u8 rate = frame->rate;
 	short len = le16_to_cpu(pkt->u.frame.length);
 	struct sk_buff *skb;
@@ -8335,7 +8336,7 @@ static void ipw_rx(struct ipw_priv *priv)
 					.rssi = pkt->u.frame.rssi_dbm -
 					    IPW_RSSI_TO_DBM,
 					.signal =
-					    le16_to_cpu(pkt->u.frame.rssi_dbm) -
+					    pkt->u.frame.rssi_dbm -
 					    IPW_RSSI_TO_DBM + 0x100,
 					.noise =
 					    le16_to_cpu(pkt->u.frame.noise),
@@ -8517,7 +8518,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
 
 	/* We default to disabling the LED code as right now it causes
 	 * too many systems to lock up... */
-	if (!led)
+	if (!led_support)
 		priv->config |= CFG_NO_LED;
 
 	if (associate)
@@ -8539,10 +8540,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
 		IPW_DEBUG_INFO("Radio disabled.\n");
 	}
 
-	if (channel != 0) {
+	if (default_channel != 0) {
 		priv->config |= CFG_STATIC_CHANNEL;
-		priv->channel = channel;
-		IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+		priv->channel = default_channel;
+		IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel);
 		/* TODO: Validate that provided channel is in range */
 	}
 #ifdef CONFIG_IPW2200_QOS
@@ -8550,7 +8551,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
 		     burst_duration_CCK, burst_duration_OFDM);
 #endif				/* CONFIG_IPW2200_QOS */
 
-	switch (mode) {
+	switch (network_mode) {
 	case 1:
 		priv->ieee->iw_mode = IW_MODE_ADHOC;
 		priv->net_dev->type = ARPHRD_ETHER;
@@ -10181,7 +10182,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
 #endif
 	struct clx2_queue *q = &txq->q;
 	u8 id, hdr_len, unicast;
-	u16 remaining_bytes;
 	int fc;
 
 	if (!(priv->status & STATUS_ASSOCIATED))
@@ -10220,7 +10220,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
 
 	tfd->u.data.cmd_id = DINO_CMD_TX;
 	tfd->u.data.len = cpu_to_le16(txb->payload_size);
-	remaining_bytes = txb->payload_size;
 
 	if (priv->assoc_request.ieee_mode == IPW_B_MODE)
 		tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK;
@@ -11946,13 +11945,13 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
 module_param(auto_create, int, 0444);
 MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
 
-module_param(led, int, 0444);
+module_param_named(led, led_support, int, 0444);
 MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)");
 
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
 
-module_param(channel, int, 0444);
+module_param_named(channel, default_channel, int, 0444);
 MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
 
 #ifdef CONFIG_IPW2200_PROMISCUOUS
@@ -11978,10 +11977,10 @@ MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
 #endif				/* CONFIG_IPW2200_QOS */
 
 #ifdef CONFIG_IPW2200_MONITOR
-module_param(mode, int, 0444);
+module_param_named(mode, network_mode, int, 0444);
 MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
 #else
-module_param(mode, int, 0444);
+module_param_named(mode, network_mode, int, 0444);
 MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
 #endif
 

+ 4 - 1
drivers/net/wireless/iwlwifi/iwl-1000.c

@@ -149,12 +149,15 @@ struct iwl_cfg iwl1000_bgn_cfg = {
 	.ucode_api_min = IWL1000_UCODE_API_MIN,
 	.sku = IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl1000_ops,
-	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
 	.valid_tx_ant = ANT_A,
 	.valid_rx_ant = ANT_AB,
 	.need_pll_cfg = true,
+	.max_ll_items = OTP_MAX_LL_ITEMS_1000,
+	.shadow_ram_support = false,
+	.ht_greenfield_support = true,
 };
 

+ 7 - 4
drivers/net/wireless/iwlwifi/iwl-3945.c

@@ -349,12 +349,13 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
  *
  *****************************************************************************/
 
-void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
+		struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
 	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
 		     (int)sizeof(struct iwl3945_notif_statistics),
-		     le32_to_cpu(pkt->len));
+		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
 
 	memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
 
@@ -2889,7 +2890,8 @@ static struct iwl_cfg iwl3945_bg_cfg = {
 	.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
 	.ops = &iwl3945_ops,
 	.mod_params = &iwl3945_mod_params,
-	.use_isr_legacy = true
+	.use_isr_legacy = true,
+	.ht_greenfield_support = false,
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2902,7 +2904,8 @@ static struct iwl_cfg iwl3945_abg_cfg = {
 	.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
 	.ops = &iwl3945_ops,
 	.mod_params = &iwl3945_mod_params,
-	.use_isr_legacy = true
+	.use_isr_legacy = true,
+	.ht_greenfield_support = false,
 };
 
 struct pci_device_id iwl3945_hw_card_ids[] = {

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

@@ -2344,7 +2344,8 @@ struct iwl_cfg iwl4965_agn_cfg = {
 	.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
 	.ops = &iwl4965_ops,
 	.mod_params = &iwl4965_mod_params,
-	.use_isr_legacy = true
+	.use_isr_legacy = true,
+	.ht_greenfield_support = false,
 };
 
 /* Module firmware */

+ 8 - 1
drivers/net/wireless/iwlwifi/iwl-5000.c

@@ -494,7 +494,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
 {
 	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
 	struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
-	int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
+	int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
 	int index;
 
 	/* reduce the size of the length field itself */
@@ -1411,6 +1411,7 @@ static void iwl5150_temperature(struct iwl_priv *priv)
 	vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
 	/* now vt hold the temperature in Kelvin */
 	priv->temperature = KELVIN_TO_CELSIUS(vt);
+	iwl_tt_handler(priv);
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
@@ -1652,6 +1653,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
 	.valid_tx_ant = ANT_ABC,
 	.valid_rx_ant = ANT_ABC,
 	.need_pll_cfg = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5100_bg_cfg = {
@@ -1668,6 +1670,7 @@ struct iwl_cfg iwl5100_bg_cfg = {
 	.valid_tx_ant = ANT_B,
 	.valid_rx_ant = ANT_AB,
 	.need_pll_cfg = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
@@ -1684,6 +1687,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
 	.valid_tx_ant = ANT_B,
 	.valid_rx_ant = ANT_AB,
 	.need_pll_cfg = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
@@ -1700,6 +1704,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
 	.valid_tx_ant = ANT_B,
 	.valid_rx_ant = ANT_AB,
 	.need_pll_cfg = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1716,6 +1721,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
 	.valid_tx_ant = ANT_ABC,
 	.valid_rx_ant = ANT_ABC,
 	.need_pll_cfg = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1732,6 +1738,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
 	.valid_tx_ant = ANT_A,
 	.valid_rx_ant = ANT_AB,
 	.need_pll_cfg = true,
+	.ht_greenfield_support = true,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));

+ 20 - 5
drivers/net/wireless/iwlwifi/iwl-6000.c

@@ -161,7 +161,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
 	.ucode_api_min = IWL6000_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl6000_ops,
-	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
@@ -169,6 +169,9 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
 	.valid_rx_ant = ANT_AB,
 	.need_pll_cfg = false,
 	.pa_type = IWL_PA_HYBRID,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
 };
 
 /*
@@ -181,7 +184,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
 	.ucode_api_min = IWL6000_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl6000_ops,
-	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
@@ -189,6 +192,9 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
 	.valid_rx_ant = ANT_BC,
 	.need_pll_cfg = false,
 	.pa_type = IWL_PA_INTERNAL,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl6050_2agn_cfg = {
@@ -198,7 +204,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
 	.ucode_api_min = IWL6050_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl6000_ops,
-	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
@@ -206,6 +212,9 @@ struct iwl_cfg iwl6050_2agn_cfg = {
 	.valid_rx_ant = ANT_AB,
 	.need_pll_cfg = false,
 	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
@@ -215,7 +224,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
 	.ucode_api_min = IWL6000_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl6000_ops,
-	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
@@ -223,6 +232,9 @@ struct iwl_cfg iwl6000_3agn_cfg = {
 	.valid_rx_ant = ANT_ABC,
 	.need_pll_cfg = false,
 	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
 };
 
 struct iwl_cfg iwl6050_3agn_cfg = {
@@ -232,7 +244,7 @@ struct iwl_cfg iwl6050_3agn_cfg = {
 	.ucode_api_min = IWL6050_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl6000_ops,
-	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
 	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
 	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
@@ -240,6 +252,9 @@ struct iwl_cfg iwl6050_3agn_cfg = {
 	.valid_rx_ant = ANT_ABC,
 	.need_pll_cfg = false,
 	.pa_type = IWL_PA_SYSTEM,
+	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+	.shadow_ram_support = true,
+	.ht_greenfield_support = true,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));

+ 39 - 77
drivers/net/wireless/iwlwifi/iwl-agn-rs.c

@@ -332,6 +332,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
 	} else
 		return MAX_TID_COUNT;
 
+	if (unlikely(tid >= TID_MAX_LOAD_COUNT))
+		return MAX_TID_COUNT;
+
 	tl = &lq_data->load[tid];
 
 	curr_time -= curr_time % TID_ROUND_VALUE;
@@ -654,19 +657,15 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
 	return 1;
 }
 
-/* in 4965 we don't use greenfield at all */
-static inline u8 rs_use_green(struct iwl_priv *priv,
-			      struct ieee80211_conf *conf)
+/**
+ * Green-field mode is valid if the station supports it and
+ * there are no non-GF stations present in the BSS.
+ */
+static inline u8 rs_use_green(struct ieee80211_sta *sta,
+			      struct iwl_ht_info *ht_conf)
 {
-	u8 is_green;
-
-	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
-		is_green = 0;
-	else
-		is_green = (conf_is_ht(conf) &&
-			   priv->current_ht_config.is_green_field &&
-			   !priv->current_ht_config.non_GF_STA_present);
-	return is_green;
+	return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
+		!(ht_conf->non_GF_STA_present);
 }
 
 /**
@@ -1222,18 +1221,6 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
 	else
 		tbl->is_ht40 = 0;
 
-	/* FIXME: - don't toggle SGI here
-	if (tbl->is_ht40) {
-		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
-			tbl->is_SGI = 1;
-		else
-			tbl->is_SGI = 0;
-	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
-		tbl->is_SGI = 1;
-	else
-		tbl->is_SGI = 0;
-	*/
-
 	rs_set_expected_tpt_table(lq_sta, tbl);
 
 	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
@@ -1288,18 +1275,6 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
 	else
 		tbl->is_ht40 = 0;
 
-	/* FIXME: - don't toggle SGI here
-	if (tbl->is_ht40) {
-		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
-			tbl->is_SGI = 1;
-		else
-			tbl->is_SGI = 0;
-	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
-		tbl->is_SGI = 1;
-	else
-		tbl->is_SGI = 0;
-	*/
-
 	rs_set_expected_tpt_table(lq_sta, tbl);
 
 	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
@@ -1347,18 +1322,6 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
 	else
 		tbl->is_ht40 = 0;
 
-	/* FIXME: - don't toggle SGI here
-	if (tbl->is_ht40) {
-		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
-			tbl->is_SGI = 1;
-		else
-			tbl->is_SGI = 0;
-	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
-		tbl->is_SGI = 1;
-	else
-		tbl->is_SGI = 0;
-	*/
-
 	if (is_green)
 		tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
 
@@ -1527,6 +1490,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 	struct iwl_scale_tbl_info *search_tbl =
 				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
 	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
 		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
@@ -1586,13 +1550,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 				goto out;
 			break;
 		case IWL_SISO_SWITCH_GI:
-			if (!tbl->is_ht40 &&
-				!(priv->current_ht_config.sgf &
-						HT_SHORT_GI_20MHZ))
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
 				break;
-			if (tbl->is_ht40 &&
-				!(priv->current_ht_config.sgf &
-						HT_SHORT_GI_40MHZ))
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
 				break;
 
 			IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n");
@@ -1666,6 +1628,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
 	struct iwl_scale_tbl_info *search_tbl =
 				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
 	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
 		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
@@ -1726,13 +1689,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
 			break;
 
 		case IWL_MIMO2_SWITCH_GI:
-			if (!tbl->is_ht40 &&
-				!(priv->current_ht_config.sgf &
-						HT_SHORT_GI_20MHZ))
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
 				break;
-			if (tbl->is_ht40 &&
-				!(priv->current_ht_config.sgf &
-						HT_SHORT_GI_40MHZ))
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
 				break;
 
 			IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
@@ -1808,6 +1769,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
 	struct iwl_scale_tbl_info *search_tbl =
 				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
 	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
 		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
@@ -1890,13 +1852,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
 			break;
 
 		case IWL_MIMO3_SWITCH_GI:
-			if (!tbl->is_ht40 &&
-				!(priv->current_ht_config.sgf &
-						HT_SHORT_GI_20MHZ))
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
 				break;
-			if (tbl->is_ht40 &&
-				!(priv->current_ht_config.sgf &
-						HT_SHORT_GI_40MHZ))
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
 				break;
 
 			IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
@@ -2108,7 +2068,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	if (is_legacy(tbl->lq_type))
 		lq_sta->is_green = 0;
 	else
-		lq_sta->is_green = rs_use_green(priv, conf);
+		lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
 	is_green = lq_sta->is_green;
 
 	/* current tx rate */
@@ -2466,7 +2426,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
 	int rate_idx;
 	int i;
 	u32 rate;
-	u8 use_green = rs_use_green(priv, conf);
+	u8 use_green = rs_use_green(sta, &priv->current_ht_config);
 	u8 active_tbl = 0;
 	u8 valid_tx_ant;
 
@@ -2519,6 +2479,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 	struct ieee80211_supported_band *sband = txrc->sband;
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
 	struct ieee80211_conf *conf = &priv->hw->conf;
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct iwl_lq_sta *lq_sta = priv_sta;
@@ -2551,7 +2512,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 			IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
 				       hdr->addr1);
 			sta_id = iwl_add_station(priv, hdr->addr1,
-						false, CMD_ASYNC, NULL);
+						false, CMD_ASYNC, ht_cap);
 		}
 		if ((sta_id != IWL_INVALID_STATION)) {
 			lq_sta->lq.sta_id = sta_id;
@@ -2620,6 +2581,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 	int i, j;
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
 	struct ieee80211_conf *conf = &priv->hw->conf;
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 	struct iwl_lq_sta *lq_sta = priv_sta;
 	u16 mask_bit = 0;
 	int count;
@@ -2648,7 +2610,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 		if (sta_id == IWL_INVALID_STATION) {
 			IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
 			sta_id = iwl_add_station(priv, sta->addr, false,
-						CMD_ASYNC, NULL);
+						CMD_ASYNC, ht_cap);
 		}
 		if ((sta_id != IWL_INVALID_STATION)) {
 			lq_sta->lq.sta_id = sta_id;
@@ -2661,7 +2623,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 	lq_sta->is_dup = 0;
 	lq_sta->max_rate_idx = -1;
 	lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
-	lq_sta->is_green = rs_use_green(priv, conf);
+	lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
 	lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
 	lq_sta->active_rate_basic = priv->active_rate_basic;
 	lq_sta->band = priv->band;
@@ -2669,19 +2631,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
 	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
 	 */
-	lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1;
-	lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1;
+	lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+	lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
 	lq_sta->active_siso_rate &= ~((u16)0x2);
 	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
 
 	/* Same here */
-	lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1;
-	lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1;
+	lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+	lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
 	lq_sta->active_mimo2_rate &= ~((u16)0x2);
 	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
 
-	lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1;
-	lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1;
+	lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
+	lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
 	lq_sta->active_mimo3_rate &= ~((u16)0x2);
 	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
 

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

@@ -1156,6 +1156,7 @@ struct iwl_wep_cmd {
 #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	cpu_to_le16(1 << 2)
 #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
 #define RX_RES_PHY_FLAGS_ANTENNA_MSK		cpu_to_le16(0xf0)
+#define RX_RES_PHY_FLAGS_ANTENNA_POS		4
 
 #define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
 #define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
@@ -3481,7 +3482,7 @@ struct iwl_wimax_coex_cmd {
  *****************************************************************************/
 
 struct iwl_rx_packet {
-	__le32 len;
+	__le32 len_n_flags;
 	struct iwl_cmd_header hdr;
 	union {
 		struct iwl3945_rx_frame rx_frame;

+ 38 - 36
drivers/net/wireless/iwlwifi/iwl-core.c

@@ -394,7 +394,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
 
 	ht_info->ht_supported = true;
 
-	ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+	if (priv->cfg->ht_greenfield_support)
+		ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
 	ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
 	ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
 			     (WLAN_HT_CAP_SM_PS_DISABLED << 2));
@@ -1513,7 +1514,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error);
 void iwl_configure_filter(struct ieee80211_hw *hw,
 			  unsigned int changed_flags,
 			  unsigned int *total_flags,
-			  int mc_count, struct dev_addr_list *mc_list)
+			  u64 multicast)
 {
 	struct iwl_priv *priv = hw->priv;
 	__le32 *filter_flags = &priv->staging_rxon.filter_flags;
@@ -1579,6 +1580,12 @@ int iwl_setup_mac(struct iwl_priv *priv)
 	/* Firmware does not support this */
 	hw->wiphy->disable_beacon_hints = true;
 
+	/*
+	 * For now, disable PS by default because it affects
+	 * RX performance significantly.
+	 */
+	hw->wiphy->ps_default = false;
+
 	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
 	/* we create the 802.11 header and a zero-length SSID element */
 	hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
@@ -2293,10 +2300,11 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
 				      struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
 	IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
-			"notification for %s:\n",
-			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-	iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+			"notification for %s:\n", len,
+			get_cmd_string(pkt->hdr.cmd));
+	iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len);
 }
 EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
 
@@ -2391,39 +2399,10 @@ static void iwl_ht_conf(struct iwl_priv *priv,
 	}
 	ht_conf = &sta->ht_cap;
 
-	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
-		iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
-	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
-		iwl_conf->sgf |= HT_SHORT_GI_40MHZ;
-
-	iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
-	iwl_conf->max_amsdu_size =
-		!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
-
-	iwl_conf->supported_chan_width =
-		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
-	/*
-	 * XXX: The HT configuration needs to be moved into iwl_mac_config()
-	 *	to be done there correctly.
-	 */
-
-	iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
-	if (conf_is_ht40_minus(&priv->hw->conf))
-		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-	else if (conf_is_ht40_plus(&priv->hw->conf))
-		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-
-	/* If no above or below channel supplied disable HT40 channel */
-	if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
-	    iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
-		iwl_conf->supported_chan_width = 0;
-
 	iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
 
 	memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
 
-	iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
 	iwl_conf->ht_protection =
 		bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
 	iwl_conf->non_GF_STA_present =
@@ -2736,6 +2715,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 	struct iwl_priv *priv = hw->priv;
 	const struct iwl_channel_info *ch_info;
 	struct ieee80211_conf *conf = &hw->conf;
+	struct iwl_ht_info *ht_conf = &priv->current_ht_config;
 	unsigned long flags = 0;
 	int ret = 0;
 	u16 ch;
@@ -2777,10 +2757,32 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 			goto set_ch_out;
 		}
 
-		priv->current_ht_config.is_ht = conf_is_ht(conf);
-
 		spin_lock_irqsave(&priv->lock, flags);
 
+		/* Configure HT40 channels */
+		ht_conf->is_ht = conf_is_ht(conf);
+		if (ht_conf->is_ht) {
+			if (conf_is_ht40_minus(conf)) {
+				ht_conf->extension_chan_offset =
+					IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+				ht_conf->supported_chan_width =
+					IWL_CHANNEL_WIDTH_40MHZ;
+			} else if (conf_is_ht40_plus(conf)) {
+				ht_conf->extension_chan_offset =
+					IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+				ht_conf->supported_chan_width =
+					IWL_CHANNEL_WIDTH_40MHZ;
+			} else {
+				ht_conf->extension_chan_offset =
+					IEEE80211_HT_PARAM_CHA_SEC_NONE;
+				ht_conf->supported_chan_width =
+					IWL_CHANNEL_WIDTH_20MHZ;
+			}
+		} else
+			ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+		/* Default to no protection. Protection mode will later be set
+		 * from BSS config in iwl_ht_conf */
+		ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
 
 		/* if we are switching from ht to 2.4 clear flags
 		 * from any ht related info since 2.4 does not

+ 6 - 2
drivers/net/wireless/iwlwifi/iwl-core.h

@@ -209,6 +209,8 @@ struct iwl_mod_params {
  * @ucode_api_max: Highest version of uCode API supported by driver.
  * @ucode_api_min: Lowest version of uCode API supported by driver.
  * @pa_type: used by 6000 series only to identify the type of Power Amplifier
+ * @max_ll_items: max number of OTP blocks
+ * @shadow_ram_support: shadow support for OTP memory
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -247,6 +249,9 @@ struct iwl_cfg {
 	bool need_pll_cfg;
 	bool use_isr_legacy;
 	enum iwl_pa_type pa_type;
+	const u16 max_ll_items;
+	const bool shadow_ram_support;
+	const bool ht_greenfield_support;
 };
 
 /***************************
@@ -277,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
 void iwl_irq_handle_error(struct iwl_priv *priv);
 void iwl_configure_filter(struct ieee80211_hw *hw,
 			  unsigned int changed_flags,
-			  unsigned int *total_flags,
-			  int mc_count, struct dev_addr_list *mc_list);
+			  unsigned int *total_flags, u64 multicast);
 int iwl_hw_nic_init(struct iwl_priv *priv);
 int iwl_setup_mac(struct iwl_priv *priv);
 int iwl_set_hw_params(struct iwl_priv *priv);

+ 11 - 9
drivers/net/wireless/iwlwifi/iwl-dev.h

@@ -507,15 +507,9 @@ struct iwl_ht_info {
 	u8 is_ht;
 	u8 supported_chan_width;
 	u8 sm_ps;
-	u8 is_green_field;
-	u8 sgf;			/* HT_SHORT_GI_* short guard interval */
-	u8 max_amsdu_size;
-	u8 ampdu_factor;
-	u8 mpdu_density;
 	struct ieee80211_mcs_info mcs;
 	/* BSS related data */
 	u8 extension_chan_offset;
-	u8 tx_chan_width;
 	u8 ht_protection;
 	u8 non_GF_STA_present;
 };
@@ -732,9 +726,6 @@ struct iwl_dma_ptr {
 	size_t size;
 };
 
-#define HT_SHORT_GI_20MHZ	(1 << 0)
-#define HT_SHORT_GI_40MHZ	(1 << 1)
-
 #define IWL_CHANNEL_WIDTH_20MHZ   0
 #define IWL_CHANNEL_WIDTH_40MHZ   1
 
@@ -888,6 +879,17 @@ enum iwl_nvm_type {
 	NVM_DEVICE_TYPE_OTP,
 };
 
+/*
+ * Two types of OTP memory access modes
+ *   IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
+ * 			        based on physical memory addressing
+ *   IWL_OTP_ACCESS_RELATIVE - relative address mode,
+ * 			       based on logical memory addressing
+ */
+enum iwl_access_mode {
+	IWL_OTP_ACCESS_ABSOLUTE,
+	IWL_OTP_ACCESS_RELATIVE,
+};
 
 /**
  * enum iwl_pa_type - Power Amplifier type

+ 162 - 60
drivers/net/wireless/iwlwifi/iwl-eeprom.c

@@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
 
+static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
+{
+	u32 otpgp;
+
+	otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+	if (mode == IWL_OTP_ACCESS_ABSOLUTE)
+		iwl_clear_bit(priv, CSR_OTP_GP_REG,
+				CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+	else
+		iwl_set_bit(priv, CSR_OTP_GP_REG,
+				CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+}
+
 static int iwlcore_get_nvm_type(struct iwl_priv *priv)
 {
 	u32 otpgp;
@@ -252,6 +265,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
 	return ret;
 }
 
+static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
+{
+	int ret = 0;
+	u32 r;
+	u32 otpgp;
+
+	_iwl_write32(priv, CSR_EEPROM_REG,
+		     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+	ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+				  CSR_EEPROM_REG_READ_VALID_MSK,
+				  IWL_EEPROM_ACCESS_TIMEOUT);
+	if (ret < 0) {
+		IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+		return ret;
+	}
+	r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+	/* check for ECC errors: */
+	otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+	if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+		/* stop in this case */
+		/* set the uncorrectable OTP ECC bit for acknowledgement */
+		iwl_set_bit(priv, CSR_OTP_GP_REG,
+			CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+		IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
+		return -EINVAL;
+	}
+	if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+		/* continue in this case */
+		/* set the correctable OTP ECC bit for acknowledgement */
+		iwl_set_bit(priv, CSR_OTP_GP_REG,
+				CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+		IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+	}
+	*eeprom_data = le16_to_cpu((__force __le16)(r >> 16));
+	return 0;
+}
+
+/*
+ * iwl_is_otp_empty: check for empty OTP
+ */
+static bool iwl_is_otp_empty(struct iwl_priv *priv)
+{
+	u16 next_link_addr = 0, link_value;
+	bool is_empty = false;
+
+	/* locate the beginning of OTP link list */
+	if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
+		if (!link_value) {
+			IWL_ERR(priv, "OTP is empty\n");
+			is_empty = true;
+		}
+	} else {
+		IWL_ERR(priv, "Unable to read first block of OTP list.\n");
+		is_empty = true;
+	}
+
+	return is_empty;
+}
+
+
+/*
+ * iwl_find_otp_image: find EEPROM image in OTP
+ *   finding the OTP block that contains the EEPROM image.
+ *   the last valid block on the link list (the block _before_ the last block)
+ *   is the block we should read and used to configure the device.
+ *   If all the available OTP blocks are full, the last block will be the block
+ *   we should read and used to configure the device.
+ *   only perform this operation if shadow RAM is disabled
+ */
+static int iwl_find_otp_image(struct iwl_priv *priv,
+					u16 *validblockaddr)
+{
+	u16 next_link_addr = 0, link_value = 0, valid_addr;
+	int ret = 0;
+	int usedblocks = 0;
+
+	/* set addressing mode to absolute to traverse the link list */
+	iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
+
+	/* checking for empty OTP or error */
+	if (iwl_is_otp_empty(priv))
+		return -EINVAL;
+
+	/*
+	 * start traverse link list
+	 * until reach the max number of OTP blocks
+	 * different devices have different number of OTP blocks
+	 */
+	do {
+		/* save current valid block address
+		 * check for more block on the link list
+		 */
+		valid_addr = next_link_addr;
+		next_link_addr = link_value;
+		IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
+			       usedblocks, next_link_addr);
+		if (iwl_read_otp_word(priv, next_link_addr, &link_value))
+			return -EINVAL;
+		if (!link_value) {
+			/*
+			 * reach the end of link list,
+			 * set address point to the starting address
+			 * of the image
+			 */
+			goto done;
+		}
+		/* more in the link list, continue */
+		usedblocks++;
+	} while (usedblocks < priv->cfg->max_ll_items);
+	/* OTP full, use last block */
+	IWL_DEBUG_INFO(priv, "OTP is full, use last block\n");
+done:
+	*validblockaddr = valid_addr;
+	/* skip first 2 bytes (link list pointer) */
+	*validblockaddr += 2;
+	return ret;
+}
+
 /**
  * iwl_eeprom_init - read EEPROM contents
  *
@@ -266,15 +397,14 @@ int iwl_eeprom_init(struct iwl_priv *priv)
 	int sz;
 	int ret;
 	u16 addr;
-	u32 otpgp;
+	u16 validblockaddr = 0;
+	u16 cache_addr = 0;
 
 	priv->nvm_device_type = iwlcore_get_nvm_type(priv);
 	if (priv->nvm_device_type == -ENOENT)
 		return -ENOENT;
 	/* allocate eeprom */
-	if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-		priv->cfg->eeprom_size =
-			OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
+	IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
 	sz = priv->cfg->eeprom_size;
 	priv->eeprom = kzalloc(sz, GFP_KERNEL);
 	if (!priv->eeprom) {
@@ -302,46 +432,31 @@ int iwl_eeprom_init(struct iwl_priv *priv)
 		if (ret) {
 			IWL_ERR(priv, "Failed to initialize OTP access.\n");
 			ret = -ENOENT;
-			goto err;
+			goto done;
 		}
 		_iwl_write32(priv, CSR_EEPROM_GP,
 			     iwl_read32(priv, CSR_EEPROM_GP) &
 			     ~CSR_EEPROM_GP_IF_OWNER_MSK);
-		/* clear */
-		_iwl_write32(priv, CSR_OTP_GP_REG,
-			     iwl_read32(priv, CSR_OTP_GP_REG) |
+
+		iwl_set_bit(priv, CSR_OTP_GP_REG,
 			     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
 			     CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-
-		for (addr = 0; addr < sz; addr += sizeof(u16)) {
-			u32 r;
-
-			_iwl_write32(priv, CSR_EEPROM_REG,
-				     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-
-			ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
-						  CSR_EEPROM_REG_READ_VALID_MSK,
-						  IWL_EEPROM_ACCESS_TIMEOUT);
-			if (ret < 0) {
-				IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+		/* traversing the linked list if no shadow ram supported */
+		if (!priv->cfg->shadow_ram_support) {
+			if (iwl_find_otp_image(priv, &validblockaddr)) {
+				ret = -ENOENT;
 				goto done;
 			}
-			r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
-			/* check for ECC errors: */
-			otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
-			if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
-				/* stop in this case */
-				IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
+		}
+		for (addr = validblockaddr; addr < validblockaddr + sz;
+		     addr += sizeof(u16)) {
+			u16 eeprom_data;
+
+			ret = iwl_read_otp_word(priv, addr, &eeprom_data);
+			if (ret)
 				goto done;
-			}
-			if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
-				/* continue in this case */
-				_iwl_write32(priv, CSR_OTP_GP_REG,
-					     iwl_read32(priv, CSR_OTP_GP_REG) |
-					     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-				IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
-			}
-			e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+			e[cache_addr / 2] = eeprom_data;
+			cache_addr += sizeof(u16);
 		}
 	} else {
 		/* eeprom is an array of 16bit values */
@@ -484,14 +599,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
 			    ? # x " " : "")
 
 /**
- * iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv.
+ * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv.
  *
  * Does not set up a command, or touch hardware.
  */
-static int iwl_set_ht40_chan_info(struct iwl_priv *priv,
+static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
 			      enum ieee80211_band band, u16 channel,
 			      const struct iwl_eeprom_channel *eeprom_ch,
-			      u8 ht40_extension_channel)
+			      u8 clear_ht40_extension_channel)
 {
 	struct iwl_channel_info *ch_info;
 
@@ -523,7 +638,7 @@ static int iwl_set_ht40_chan_info(struct iwl_priv *priv,
 	ch_info->ht40_min_power = 0;
 	ch_info->ht40_scan_power = eeprom_ch->max_power_avg;
 	ch_info->ht40_flags = eeprom_ch->flags;
-	ch_info->ht40_extension_channel = ht40_extension_channel;
+	ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;
 
 	return 0;
 }
@@ -592,8 +707,7 @@ int iwl_init_channel_map(struct iwl_priv *priv)
 			/* First write that ht40 is not enabled, and then enable
 			 * one by one */
 			ch_info->ht40_extension_channel =
-				(IEEE80211_CHAN_NO_HT40PLUS |
-				 IEEE80211_CHAN_NO_HT40MINUS);
+					IEEE80211_CHAN_NO_HT40;
 
 			if (!(is_channel_valid(ch_info))) {
 				IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - "
@@ -652,7 +766,6 @@ int iwl_init_channel_map(struct iwl_priv *priv)
 	/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
 	for (band = 6; band <= 7; band++) {
 		enum ieee80211_band ieeeband;
-		u8 ht40_extension_chan;
 
 		iwl_init_band_reference(priv, band, &eeprom_ch_count,
 					&eeprom_ch_info, &eeprom_ch_index);
@@ -663,28 +776,17 @@ int iwl_init_channel_map(struct iwl_priv *priv)
 
 		/* Loop through each band adding each of the channels */
 		for (ch = 0; ch < eeprom_ch_count; ch++) {
-
-			if ((band == 6) &&
-				((eeprom_ch_index[ch] == 5) ||
-				 (eeprom_ch_index[ch] == 6) ||
-				 (eeprom_ch_index[ch] == 7)))
-				/* both are allowed: above and below */
-				ht40_extension_chan = 0;
-			else
-				ht40_extension_chan =
-					IEEE80211_CHAN_NO_HT40MINUS;
-
 			/* Set up driver's info for lower half */
-			iwl_set_ht40_chan_info(priv, ieeeband,
+			iwl_mod_ht40_chan_info(priv, ieeeband,
 						eeprom_ch_index[ch],
-						&(eeprom_ch_info[ch]),
-						ht40_extension_chan);
+						&eeprom_ch_info[ch],
+						IEEE80211_CHAN_NO_HT40PLUS);
 
 			/* Set up driver's info for upper half */
-			iwl_set_ht40_chan_info(priv, ieeeband,
-						(eeprom_ch_index[ch] + 4),
-						&(eeprom_ch_info[ch]),
-						IEEE80211_CHAN_NO_HT40PLUS);
+			iwl_mod_ht40_chan_info(priv, ieeeband,
+						eeprom_ch_index[ch] + 4,
+						&eeprom_ch_info[ch],
+						IEEE80211_CHAN_NO_HT40MINUS);
 		}
 	}
 

+ 8 - 2
drivers/net/wireless/iwlwifi/iwl-eeprom.h

@@ -180,8 +180,14 @@ struct iwl_eeprom_channel {
 #define EEPROM_5050_EEPROM_VERSION	(0x21E)
 
 /* OTP */
-#define OTP_LOWER_BLOCKS_TOTAL		(3)
-#define OTP_BLOCK_SIZE			(0x400)
+/* lower blocks contain EEPROM image and calibration data */
+#define OTP_LOW_IMAGE_SIZE		(2 * 512 * sizeof(u16)) /* 2 KB */
+/* high blocks contain PAPD data */
+#define OTP_HIGH_IMAGE_SIZE_6x00        (6 * 512 * sizeof(u16)) /* 6 KB */
+#define OTP_HIGH_IMAGE_SIZE_1000        (0x200 * sizeof(u16)) /* 1024 bytes */
+#define OTP_MAX_LL_ITEMS_1000		(3)	/* OTP blocks for 1000 */
+#define OTP_MAX_LL_ITEMS_6x00		(4)	/* OTP blocks for 6x00 */
+#define OTP_MAX_LL_ITEMS_6x50		(7)	/* OTP blocks for 6x50 */
 
 /* 2.4 GHz */
 extern const u8 iwl_eeprom_band_1[14];

+ 79 - 128
drivers/net/wireless/iwlwifi/iwl-rx.c

@@ -539,7 +539,8 @@ void iwl_rx_statistics(struct iwl_priv *priv,
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
 
 	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
-		     (int)sizeof(priv->statistics), pkt->len);
+		     (int)sizeof(priv->statistics),
+		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
 
 	change = ((priv->statistics.general.temperature !=
 		   pkt->u.stats.general.temperature) ||
@@ -853,61 +854,12 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
 }
 
 static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
-				       int include_phy,
-				       struct iwl_rx_mem_buffer *rxb,
-				       struct ieee80211_rx_status *stats)
+					struct ieee80211_hdr *hdr,
+					u16 len,
+					u32 ampdu_status,
+					struct iwl_rx_mem_buffer *rxb,
+					struct ieee80211_rx_status *stats)
 {
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	struct iwl_rx_phy_res *rx_start = (include_phy) ?
-	    (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
-	struct ieee80211_hdr *hdr;
-	u16 len;
-	__le32 *rx_end;
-	unsigned int skblen;
-	u32 ampdu_status;
-	u32 ampdu_status_legacy;
-
-	if (!include_phy && priv->last_phy_res[0])
-		rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
-
-	if (!rx_start) {
-		IWL_ERR(priv, "MPDU frame without a PHY data\n");
-		return;
-	}
-	if (include_phy) {
-		hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] +
-					       rx_start->cfg_phy_cnt);
-
-		len = le16_to_cpu(rx_start->byte_count);
-
-		rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] +
-				  sizeof(struct iwl_rx_phy_res) +
-				  rx_start->cfg_phy_cnt + len);
-
-	} else {
-		struct iwl4965_rx_mpdu_res_start *amsdu =
-		    (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
-
-		hdr = (struct ieee80211_hdr *)(pkt->u.raw +
-			       sizeof(struct iwl4965_rx_mpdu_res_start));
-		len =  le16_to_cpu(amsdu->byte_count);
-		rx_start->byte_count = amsdu->byte_count;
-		rx_end = (__le32 *) (((u8 *) hdr) + len);
-	}
-
-	ampdu_status = le32_to_cpu(*rx_end);
-	skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32);
-
-	if (!include_phy) {
-		/* New status scheme, need to translate */
-		ampdu_status_legacy = ampdu_status;
-		ampdu_status = iwl_translate_rx_status(priv, ampdu_status);
-	}
-
-	/* start from MAC */
-	skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
-	skb_put(rxb->skb, len);	/* end where data ends */
-
 	/* We only process data packets if the interface is open */
 	if (unlikely(!priv->is_open)) {
 		IWL_DEBUG_DROP_LIMIT(priv,
@@ -915,13 +867,15 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
 		return;
 	}
 
-	hdr = (struct ieee80211_hdr *)rxb->skb->data;
-
-	/*  in case of HW accelerated crypto and bad decryption, drop */
+	/* In case of HW accelerated crypto and bad decryption, drop */
 	if (!priv->cfg->mod_params->sw_crypto &&
 	    iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
 		return;
 
+	/* Resize SKB from mac header to end of packet */
+	skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data);
+	skb_put(rxb->skb, len);
+
 	iwl_update_stats(priv, false, hdr->frame_control, len);
 	memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb);
@@ -955,25 +909,66 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 	struct ieee80211_hdr *header;
 	struct ieee80211_rx_status rx_status;
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	/* Use phy data (Rx signal strength, etc.) contained within
-	 *   this rx packet for legacy frames,
-	 *   or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
-	int include_phy = (pkt->hdr.cmd == REPLY_RX);
-	struct iwl_rx_phy_res *rx_start = (include_phy) ?
-		(struct iwl_rx_phy_res *)&(pkt->u.raw[0]) :
-		(struct iwl_rx_phy_res *)&priv->last_phy_res[1];
-	__le32 *rx_end;
-	unsigned int len = 0;
+	struct iwl_rx_phy_res *phy_res;
+	__le32 rx_pkt_status;
+	struct iwl4965_rx_mpdu_res_start *amsdu;
+	u32 len;
+	u32 ampdu_status;
 	u16 fc;
-	u8 network_packet;
 
-	rx_status.mactime = le64_to_cpu(rx_start->timestamp);
+	/**
+	 * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
+	 *	REPLY_RX: physical layer info is in this buffer
+	 *	REPLY_RX_MPDU_CMD: physical layer info was sent in separate
+	 *		command and cached in priv->last_phy_res
+	 *
+	 * Here we set up local variables depending on which command is
+	 * received.
+	 */
+	if (pkt->hdr.cmd == REPLY_RX) {
+		phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
+		header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
+				+ phy_res->cfg_phy_cnt);
+
+		len = le16_to_cpu(phy_res->byte_count);
+		rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
+				phy_res->cfg_phy_cnt + len);
+		ampdu_status = le32_to_cpu(rx_pkt_status);
+	} else {
+		if (!priv->last_phy_res[0]) {
+			IWL_ERR(priv, "MPDU frame without cached PHY data\n");
+			return;
+		}
+		phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
+		amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+		header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
+		len = le16_to_cpu(amsdu->byte_count);
+		rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
+		ampdu_status = iwl_translate_rx_status(priv,
+				le32_to_cpu(rx_pkt_status));
+	}
+
+	if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
+		IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
+				phy_res->cfg_phy_cnt);
+		return;
+	}
+
+	if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
+	    !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+		IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
+				le32_to_cpu(rx_pkt_status));
+		return;
+	}
+
+	/* rx_status carries information about the packet to mac80211 */
+	rx_status.mactime = le64_to_cpu(phy_res->timestamp);
 	rx_status.freq =
-		ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel));
-	rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+		ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
+	rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
 				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 	rx_status.rate_idx =
-		iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags));
+		iwl_hwrate_to_plcp_idx(le32_to_cpu(phy_res->rate_n_flags));
 	if (rx_status.band == IEEE80211_BAND_5GHZ)
 		rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
 
@@ -983,54 +978,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 	 * this W/A doesn't propagate it to the mac80211 */
 	/*rx_status.flag |= RX_FLAG_TSFT;*/
 
-	if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
-		IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
-				rx_start->cfg_phy_cnt);
-		return;
-	}
-
-	if (!include_phy) {
-		if (priv->last_phy_res[0])
-			rx_start = (struct iwl_rx_phy_res *)
-				&priv->last_phy_res[1];
-		else
-			rx_start = NULL;
-	}
-
-	if (!rx_start) {
-		IWL_ERR(priv, "MPDU frame without a PHY data\n");
-		return;
-	}
-
-	if (include_phy) {
-		header = (struct ieee80211_hdr *)((u8 *) &rx_start[1]
-						  + rx_start->cfg_phy_cnt);
-
-		len = le16_to_cpu(rx_start->byte_count);
-		rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt +
-				  sizeof(struct iwl_rx_phy_res) + len);
-	} else {
-		struct iwl4965_rx_mpdu_res_start *amsdu =
-			(struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
-
-		header = (void *)(pkt->u.raw +
-			sizeof(struct iwl4965_rx_mpdu_res_start));
-		len = le16_to_cpu(amsdu->byte_count);
-		rx_end = (__le32 *) (pkt->u.raw +
-			sizeof(struct iwl4965_rx_mpdu_res_start) + len);
-	}
-
-	if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) ||
-	    !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
-		IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
-				le32_to_cpu(*rx_end));
-		return;
-	}
-
-	priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
+	priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
 
 	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
-	rx_status.signal = iwl_calc_rssi(priv, rx_start);
+	rx_status.signal = iwl_calc_rssi(priv, phy_res);
 
 	/* Meaningful noise values are available only from beacon statistics,
 	 *   which are gathered only when associated, and indicate noise
@@ -1050,10 +1001,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 	if (!iwl_is_associated(priv))
 		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 
-	/* Set "1" to report good data frames in groups of 100 */
 #ifdef CONFIG_IWLWIFI_DEBUG
+	/* Set "1" to report good data frames in groups of 100 */
 	if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
-		iwl_dbg_report_frame(priv, rx_start, len, header, 1);
+		iwl_dbg_report_frame(priv, phy_res, len, header, 1);
 #endif
 	iwl_dbg_log_rx_data_frame(priv, len, header);
 	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
@@ -1073,18 +1024,18 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 	 * new 802.11n radiotap field "RX chains" that is defined
 	 * as a bitmask.
 	 */
-	rx_status.antenna = le16_to_cpu(rx_start->phy_flags &
-					RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+	rx_status.antenna =
+		le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK)
+		>> RX_RES_PHY_FLAGS_ANTENNA_POS;
 
 	/* set the preamble flag if appropriate */
-	if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+	if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
 		rx_status.flag |= RX_FLAG_SHORTPRE;
 
-	network_packet = iwl_is_network_packet(priv, header);
-	if (network_packet) {
+	if (iwl_is_network_packet(priv, header)) {
 		priv->last_rx_rssi = rx_status.signal;
 		priv->last_beacon_time =  priv->ucode_beacon_time;
-		priv->last_tsf = le64_to_cpu(rx_start->timestamp);
+		priv->last_tsf = le64_to_cpu(phy_res->timestamp);
 	}
 
 	fc = le16_to_cpu(header->frame_control);
@@ -1096,8 +1047,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 						header->addr2);
 		/* fall through */
 	default:
-			iwl_pass_packet_to_mac80211(priv, include_phy, rxb,
-				   &rx_status);
+		iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+				rxb, &rx_status);
 		break;
 
 	}

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

@@ -745,6 +745,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	if (ieee80211_is_data_qos(fc)) {
 		qc = ieee80211_get_qos_ctl(hdr);
 		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+		if (unlikely(tid >= MAX_TID_COUNT))
+			goto drop_unlock;
 		seq_number = priv->stations[sta_id].tid[tid].seq_number;
 		seq_number &= IEEE80211_SCTL_SEQ;
 		hdr->seq_ctrl = hdr->seq_ctrl &
@@ -1238,6 +1240,9 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
 		return -EINVAL;
 	}
 
+	if (unlikely(tid >= MAX_TID_COUNT))
+		return -EINVAL;
+
 	if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
 		tx_fifo_id = default_tid_to_tx_fifo[tid];
 	else

+ 2 - 0
drivers/net/wireless/iwlwifi/iwl3945-base.c

@@ -544,6 +544,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	if (ieee80211_is_data_qos(fc)) {
 		qc = ieee80211_get_qos_ctl(hdr);
 		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+		if (unlikely(tid >= MAX_TID_COUNT))
+			goto drop;
 		seq_number = priv->stations[sta_id].tid[tid].seq_number &
 				IEEE80211_SCTL_SEQ;
 		hdr->seq_ctrl = cpu_to_le16(seq_number) |

+ 7 - 1
drivers/net/wireless/libertas/assoc.c

@@ -45,9 +45,14 @@ static int get_common_rates(struct lbs_private *priv,
 	u8 *card_rates = lbs_bg_rates;
 	size_t num_card_rates = sizeof(lbs_bg_rates);
 	int ret = 0, i, j;
-	u8 tmp[30];
+	u8 *tmp;
 	size_t tmp_size = 0;
 
+	tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1),
+			GFP_KERNEL);
+	if (!tmp)
+		return -1;
+
 	/* For each rate in card_rates that exists in rate1, copy to tmp */
 	for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
 		for (j = 0; rates[j] && (j < *rates_size); j++) {
@@ -77,6 +82,7 @@ done:
 	memset(rates, 0, *rates_size);
 	*rates_size = min_t(int, tmp_size, *rates_size);
 	memcpy(rates, tmp, *rates_size);
+	kfree(tmp);
 	return ret;
 }
 

+ 25 - 12
drivers/net/wireless/libertas_tf/main.c

@@ -366,15 +366,35 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
 	return 0;
 }
 
+static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
+				     int mc_count, struct dev_addr_list *mclist)
+{
+	struct lbtf_private *priv = hw->priv;
+	int i;
+
+	if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE)
+		return mc_count;
+
+	priv->nr_of_multicastmacaddr = mc_count;
+	for (i = 0; i < mc_count; i++) {
+		if (!mclist)
+			break;
+		memcpy(&priv->multicastlist[i], mclist->da_addr,
+				ETH_ALEN);
+		mclist = mclist->next;
+	}
+
+	return mc_count;
+}
+
 #define SUPPORTED_FIF_FLAGS  (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
 static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
 			unsigned int changed_flags,
 			unsigned int *new_flags,
-			int mc_count, struct dev_mc_list *mclist)
+			u64 multicast)
 {
 	struct lbtf_private *priv = hw->priv;
 	int old_mac_control = priv->mac_control;
-	int i;
 	changed_flags &= SUPPORTED_FIF_FLAGS;
 	*new_flags &= SUPPORTED_FIF_FLAGS;
 
@@ -386,20 +406,12 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
 	else
 		priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
 	if (*new_flags & (FIF_ALLMULTI) ||
-	    mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+	    multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
 		priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
 		priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
-	} else if (mc_count) {
+	} else if (multicast) {
 		priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
 		priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-		priv->nr_of_multicastmacaddr = mc_count;
-		for (i = 0; i < mc_count; i++) {
-			if (!mclist)
-				break;
-			memcpy(&priv->multicastlist[i], mclist->da_addr,
-					ETH_ALEN);
-			mclist = mclist->next;
-		}
 		lbtf_cmd_set_mac_multicast_addr(priv);
 	} else {
 		priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE |
@@ -461,6 +473,7 @@ static const struct ieee80211_ops lbtf_ops = {
 	.add_interface		= lbtf_op_add_interface,
 	.remove_interface	= lbtf_op_remove_interface,
 	.config			= lbtf_op_config,
+	.prepare_multicast	= lbtf_op_prepare_multicast,
 	.configure_filter	= lbtf_op_configure_filter,
 	.bss_info_changed	= lbtf_op_bss_info_changed,
 };

+ 1 - 3
drivers/net/wireless/mac80211_hwsim.c

@@ -582,9 +582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 
 static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
 					    unsigned int changed_flags,
-					    unsigned int *total_flags,
-					    int mc_count,
-					    struct dev_addr_list *mc_list)
+					    unsigned int *total_flags,u64 multicast)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 205 - 346
drivers/net/wireless/mwl8k.c


+ 1 - 1
drivers/net/wireless/orinoco/wext.c

@@ -1291,7 +1291,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev,
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	priv->ibss_port = val ;
+	priv->ibss_port = val;
 
 	/* Actually update the mode we are using */
 	set_port_type(priv);

+ 7 - 1
drivers/net/wireless/p54/main.c

@@ -302,7 +302,7 @@ out:
 static void p54_configure_filter(struct ieee80211_hw *dev,
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
-				 int mc_count, struct dev_mc_list *mclist)
+				 u64 multicast)
 {
 	struct p54_common *priv = dev->priv;
 
@@ -575,6 +575,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 	dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
 				 sizeof(struct p54_tx_data);
 
+	/*
+	 * For now, disable PS by default because it affects
+	 * link stability significantly.
+	 */
+	dev->wiphy->ps_default = false;
+
 	mutex_init(&priv->conf_mutex);
 	mutex_init(&priv->eeprom_mutex);
 	init_completion(&priv->eeprom_comp);

+ 0 - 1
drivers/net/wireless/rt2x00/rt2500usb.c

@@ -1874,7 +1874,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 	 */
 	__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
 	if (!modparam_nohwcrypt) {
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 		__set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);

+ 10 - 9
drivers/net/wireless/rt2x00/rt2800usb.c

@@ -1463,6 +1463,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * ASIC will keep garbage value after boot, clear encryption keys.
 	 */
+	for (i = 0; i < 4; i++)
+		rt2x00usb_register_write(rt2x00dev,
+					 SHARED_KEY_MODE_ENTRY(i), 0);
+
 	for (i = 0; i < 256; i++) {
 		u32 wcid[2] = { 0xffffffff, 0x00ffffff };
 		rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
@@ -1472,10 +1476,6 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 		rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
 	}
 
-	for (i = 0; i < 16; i++)
-		rt2x00usb_register_write(rt2x00dev,
-					 SHARED_KEY_MODE_ENTRY(i), 0);
-
 	/*
 	 * Clear all beacons
 	 * For the Beacon base registers we only need to clear
@@ -1520,7 +1520,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, &reg);
 	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS0FBK, 8);
 	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS1FBK, 8);
-	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 3);
+	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 9);
 	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS3FBK, 10);
 	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS4FBK, 11);
 	rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS5FBK, 12);
@@ -1995,11 +1995,11 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
 	rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
 			   test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
-			       txdesc->key_idx : 0xff);
+			       (skbdesc->entry->entry_idx + 1) : 0xff);
 	rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
 			   skb->len - txdesc->l2pad);
 	rt2x00_set_field32(&word, TXWI_W1_PACKETID,
-			   skbdesc->entry->entry_idx);
+			   skbdesc->entry->queue->qid + 1);
 	rt2x00_desc_write(txwi, 1, word);
 
 	/*
@@ -2163,8 +2163,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
 	if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
 		rxdesc->dev_flags |= RXDONE_MY_BSS;
 
-	if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
+	if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) {
 		rxdesc->dev_flags |= RXDONE_L2PAD;
+		skbdesc->flags |= SKBDESC_L2_PADDED;
+	}
 
 	if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
 		rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -2632,7 +2634,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 	 * This device requires firmware.
 	 */
 	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);

+ 8 - 2
drivers/net/wireless/rt2x00/rt2800usb.h

@@ -36,6 +36,9 @@
  * RF2750 2.4G/5G 1T2R
  * RF3020 2.4G 1T1R
  * RF2020 2.4G B/G
+ * RF3021 2.4G 1T2R
+ * RF3022 2.4G 2T2R
+ * RF3052 2.4G 2T2R
  */
 #define RF2820				0x0001
 #define RF2850				0x0002
@@ -43,6 +46,9 @@
 #define RF2750				0x0004
 #define RF3020				0x0005
 #define RF2020				0x0006
+#define RF3021				0x0007
+#define RF3022				0x0008
+#define RF3052				0x0009
 
 /*
  * RT2870 version
@@ -1300,8 +1306,8 @@
  * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry
  * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry
  * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry
- * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry
- * SHARED_KEY_MODE_BASE: 4-byte * 16-entry
+ * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry
+ * SHARED_KEY_MODE_BASE: 4 bits * 32-entry
  */
 #define MAC_WCID_BASE			0x1800
 #define PAIRWISE_KEY_TABLE_BASE		0x4000

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

@@ -350,8 +350,6 @@ struct rt2x00_intf {
 	 */
 	unsigned int delayed_flags;
 #define DELAYED_UPDATE_BEACON		0x00000001
-#define DELAYED_CONFIG_ERP		0x00000002
-#define DELAYED_LED_ASSOC		0x00000004
 
 	/*
 	 * Software sequence counter, this is only required
@@ -614,7 +612,6 @@ enum rt2x00_flags {
 	DRIVER_REQUIRE_FIRMWARE,
 	DRIVER_REQUIRE_BEACON_GUARD,
 	DRIVER_REQUIRE_ATIM_QUEUE,
-	DRIVER_REQUIRE_SCHEDULED,
 	DRIVER_REQUIRE_DMA,
 	DRIVER_REQUIRE_COPY_IV,
 	DRIVER_REQUIRE_L2PAD,
@@ -826,7 +823,6 @@ struct rt2x00_dev {
 	 * due to RTNL locking requirements.
 	 */
 	struct work_struct intf_work;
-	struct work_struct filter_work;
 
 	/*
 	 * Data queue arrays for RX, TX and Beacon.
@@ -978,7 +974,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
 void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
 				unsigned int changed_flags,
 				unsigned int *total_flags,
-				int mc_count, struct dev_addr_list *mc_list);
+				u64 multicast);
 int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
 		      bool set);
 #ifdef CONFIG_RT2X00_LIB_CRYPTO

+ 17 - 23
drivers/net/wireless/rt2x00/rt2x00dev.c

@@ -118,20 +118,11 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
 		rt2x00link_start_tuner(rt2x00dev);
 }
 
-static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
-{
-	struct rt2x00_dev *rt2x00dev =
-	    container_of(work, struct rt2x00_dev, filter_work);
-
-	rt2x00dev->ops->lib->config_filter(rt2x00dev, rt2x00dev->packet_filter);
-}
-
 static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 					  struct ieee80211_vif *vif)
 {
 	struct rt2x00_dev *rt2x00dev = data;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
-	struct ieee80211_bss_conf conf;
 	int delayed_flags;
 
 	/*
@@ -141,7 +132,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 	 */
 	spin_lock(&intf->lock);
 
-	memcpy(&conf, &vif->bss_conf, sizeof(conf));
 	delayed_flags = intf->delayed_flags;
 	intf->delayed_flags = 0;
 
@@ -158,12 +148,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 
 	if (delayed_flags & DELAYED_UPDATE_BEACON)
 		rt2x00queue_update_beacon(rt2x00dev, vif, true);
-
-	if (delayed_flags & DELAYED_CONFIG_ERP)
-		rt2x00lib_config_erp(rt2x00dev, intf, &conf);
-
-	if (delayed_flags & DELAYED_LED_ASSOC)
-		rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
 }
 
 static void rt2x00lib_intf_scheduled(struct work_struct *work)
@@ -220,7 +204,8 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
 	unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
-	u8 rate_idx, rate_flags;
+	u8 rate_idx, rate_flags, retry_rates;
+	unsigned int i;
 
 	/*
 	 * Unmap the skb.
@@ -259,16 +244,27 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 
 	rate_idx = skbdesc->tx_rate_idx;
 	rate_flags = skbdesc->tx_rate_flags;
+	retry_rates = test_bit(TXDONE_FALLBACK, &txdesc->flags) ?
+	    (txdesc->retry + 1) : 1;
 
 	/*
 	 * Initialize TX status
 	 */
 	memset(&tx_info->status, 0, sizeof(tx_info->status));
 	tx_info->status.ack_signal = 0;
-	tx_info->status.rates[0].idx = rate_idx;
-	tx_info->status.rates[0].flags = rate_flags;
-	tx_info->status.rates[0].count = txdesc->retry + 1;
-	tx_info->status.rates[1].idx = -1; /* terminate */
+
+	/*
+	 * Frame was send with retries, hardware tried
+	 * different rates to send out the frame, at each
+	 * retry it lowered the rate 1 step.
+	 */
+	for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) {
+		tx_info->status.rates[i].idx = rate_idx - i;
+		tx_info->status.rates[i].flags = rate_flags;
+		tx_info->status.rates[i].count = 1;
+	}
+	if (i < (IEEE80211_TX_MAX_RATES -1))
+		tx_info->status.rates[i].idx = -1; /* terminate */
 
 	if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
 		if (test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
@@ -847,7 +843,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 	 * Initialize configuration work.
 	 */
 	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
-	INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
 
 	/*
 	 * Allocate queue array.
@@ -895,7 +890,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Stop all work.
 	 */
-	cancel_work_sync(&rt2x00dev->filter_work);
 	cancel_work_sync(&rt2x00dev->intf_work);
 
 	/*

+ 7 - 18
drivers/net/wireless/rt2x00/rt2x00mac.c

@@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_config);
 void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
 				unsigned int changed_flags,
 				unsigned int *total_flags,
-				int mc_count, struct dev_addr_list *mc_list)
+				u64 multicast)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 
@@ -430,10 +430,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
 		return;
 	rt2x00dev->packet_filter = *total_flags;
 
-	if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
-		rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
-	else
-		ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work);
+	rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
 
@@ -639,23 +636,15 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 		else
 			rt2x00dev->intf_associated--;
 
-		if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
-			rt2x00leds_led_assoc(rt2x00dev,
-					     !!rt2x00dev->intf_associated);
-		else
-			delayed |= DELAYED_LED_ASSOC;
+		rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
 	}
 
 	/*
 	 * When the erp information has changed, we should perform
 	 * additional configuration steps. For all other changes we are done.
 	 */
-	if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
-		if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
-			rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
-		else
-			delayed |= DELAYED_CONFIG_ERP;
-	}
+	if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT))
+		rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
 
 	spin_lock(&intf->lock);
 	if (delayed) {
@@ -704,8 +693,8 @@ EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
 void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+	bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
 
-	wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+	wiphy_rfkill_set_hw_state(hw->wiphy, !active);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);

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

@@ -214,6 +214,7 @@ struct rxdone_entry_desc {
  *
  * @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
  * @TXDONE_SUCCESS: Frame was successfully send
+ * @TXDONE_FALLBACK: Frame was successfully send using a fallback rate.
  * @TXDONE_FAILURE: Frame was not successfully send
  * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
  *	frame transmission failed due to excessive retries.
@@ -221,6 +222,7 @@ struct rxdone_entry_desc {
 enum txdone_entry_desc_flags {
 	TXDONE_UNKNOWN,
 	TXDONE_SUCCESS,
+	TXDONE_FALLBACK,
 	TXDONE_FAILURE,
 	TXDONE_EXCESSIVE_RETRY,
 };

+ 0 - 1
drivers/net/wireless/rt2x00/rt73usb.c

@@ -2151,7 +2151,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 	 * This device requires firmware.
 	 */
 	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
-	__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
 	if (!modparam_nohwcrypt)
 		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
 

+ 9 - 2
drivers/net/wireless/rtl818x/rtl8180_dev.c

@@ -728,10 +728,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
 	        priv->rf->conf_erp(dev, info);
 }
 
+static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
+				     struct dev_addr_list *mc_list)
+{
+	return mc_count;
+}
+
 static void rtl8180_configure_filter(struct ieee80211_hw *dev,
 				     unsigned int changed_flags,
 				     unsigned int *total_flags,
-				     int mc_count, struct dev_addr_list *mclist)
+				     u64 multicast)
 {
 	struct rtl8180_priv *priv = dev->priv;
 
@@ -741,7 +747,7 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
 		priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
 	if (changed_flags & FIF_OTHER_BSS)
 		priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
-	if (*total_flags & FIF_ALLMULTI || mc_count > 0)
+	if (*total_flags & FIF_ALLMULTI || multicast > 0)
 		priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
 	else
 		priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
@@ -768,6 +774,7 @@ static const struct ieee80211_ops rtl8180_ops = {
 	.remove_interface	= rtl8180_remove_interface,
 	.config			= rtl8180_config,
 	.bss_info_changed	= rtl8180_bss_info_changed,
+	.prepare_multicast	= rtl8180_prepare_multicast,
 	.configure_filter	= rtl8180_configure_filter,
 };
 

+ 9 - 2
drivers/net/wireless/rtl818x/rtl8187_dev.c

@@ -1192,10 +1192,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
 				 info->use_short_preamble);
 }
 
+static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
+				     int mc_count, struct dev_addr_list *mc_list)
+{
+	return mc_count;
+}
+
 static void rtl8187_configure_filter(struct ieee80211_hw *dev,
 				     unsigned int changed_flags,
 				     unsigned int *total_flags,
-				     int mc_count, struct dev_addr_list *mclist)
+				     u64 multicast)
 {
 	struct rtl8187_priv *priv = dev->priv;
 
@@ -1205,7 +1211,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
 		priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
 	if (changed_flags & FIF_OTHER_BSS)
 		priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
-	if (*total_flags & FIF_ALLMULTI || mc_count > 0)
+	if (*total_flags & FIF_ALLMULTI || multicast > 0)
 		priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
 	else
 		priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
@@ -1268,6 +1274,7 @@ static const struct ieee80211_ops rtl8187_ops = {
 	.remove_interface	= rtl8187_remove_interface,
 	.config			= rtl8187_config,
 	.bss_info_changed	= rtl8187_bss_info_changed,
+	.prepare_multicast	= rtl8187_prepare_multicast,
 	.configure_filter	= rtl8187_configure_filter,
 	.conf_tx		= rtl8187_conf_tx
 };

+ 3 - 0
drivers/net/wireless/wl12xx/wl1251_boot.c

@@ -465,6 +465,9 @@ int wl1251_boot(struct wl1251 *wl)
 	int ret = 0, minor_minor_e2_ver;
 	u32 tmp, boot_data;
 
+	/* halt embedded ARM CPU while loading firmware */
+	wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT);
+
 	ret = wl1251_boot_soft_reset(wl);
 	if (ret < 0)
 		goto out;

+ 1 - 3
drivers/net/wireless/wl12xx/wl1251_main.c

@@ -652,9 +652,7 @@ out:
 
 static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
 				       unsigned int changed,
-				       unsigned int *total,
-				       int mc_count,
-				       struct dev_addr_list *mc_list)
+				       unsigned int *total,u64 multicast)
 {
 	struct wl1251 *wl = hw->priv;
 

+ 2 - 2
drivers/net/wireless/wl12xx/wl1251_reg.h

@@ -245,8 +245,8 @@ enum wl12xx_acx_int_reg {
 	ACX_REG_TABLE_LEN
 };
 
-#define ACX_SLV_SOFT_RESET_BIT   BIT(1)
-#define ACX_REG_EEPROM_START_BIT BIT(1)
+#define ACX_SLV_SOFT_RESET_BIT   BIT(0)
+#define ACX_REG_EEPROM_START_BIT BIT(0)
 
 /* Command/Information Mailbox Pointers */
 

+ 3 - 6
drivers/net/wireless/wl12xx/wl1271_main.c

@@ -605,11 +605,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 				   struct ieee80211_if_init_conf *conf)
 {
 	struct wl1271 *wl = hw->priv;
-	DECLARE_MAC_BUF(mac);
 	int ret = 0;
 
-	wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
-		     conf->type, print_mac(mac, conf->mac_addr));
+	wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+		     conf->type, conf->mac_addr);
 
 	mutex_lock(&wl->mutex);
 
@@ -793,9 +792,7 @@ out:
 
 static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
 				       unsigned int changed,
-				       unsigned int *total,
-				       int mc_count,
-				       struct dev_addr_list *mc_list)
+				       unsigned int *total,u64 multicast)
 {
 	struct wl1271 *wl = hw->priv;
 

+ 29 - 15
drivers/net/wireless/zd1211rw/zd_mac.c

@@ -796,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work)
 		dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r);
 }
 
+static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
+				   int mc_count, struct dev_addr_list *mclist)
+{
+	struct zd_mac *mac = zd_hw_mac(hw);
+	struct zd_mc_hash hash;
+	int i;
+
+	zd_mc_clear(&hash);
+
+	for (i = 0; i < mc_count; i++) {
+		if (!mclist)
+			break;
+		dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr);
+		zd_mc_add_addr(&hash, mclist->dmi_addr);
+		mclist = mclist->next;
+	}
+
+	return hash.low | ((u64)hash.high << 32);
+}
+
 #define SUPPORTED_FIF_FLAGS \
 	(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
 	FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
 static void zd_op_configure_filter(struct ieee80211_hw *hw,
 			unsigned int changed_flags,
 			unsigned int *new_flags,
-			int mc_count, struct dev_mc_list *mclist)
+			u64 multicast)
 {
-	struct zd_mc_hash hash;
+	struct zd_mc_hash hash = {
+		.low = multicast,
+		.high = multicast >> 32,
+	};
 	struct zd_mac *mac = zd_hw_mac(hw);
 	unsigned long flags;
-	int i;
 
 	/* Only deal with supported flags */
 	changed_flags &= SUPPORTED_FIF_FLAGS;
@@ -819,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
 	if (!changed_flags)
 		return;
 
-	if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) {
+	if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
 		zd_mc_add_all(&hash);
-	} else {
-		zd_mc_clear(&hash);
-		for (i = 0; i < mc_count; i++) {
-			if (!mclist)
-				break;
-			dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n",
-				  mclist->dmi_addr);
-			zd_mc_add_addr(&hash, mclist->dmi_addr);
-			mclist = mclist->next;
-		}
-	}
 
 	spin_lock_irqsave(&mac->lock, flags);
 	mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL);
 	mac->pass_ctrl = !!(*new_flags & FIF_CONTROL);
 	mac->multicast_hash = hash;
 	spin_unlock_irqrestore(&mac->lock, flags);
+
+	/* XXX: these can be called here now, can sleep now! */
 	queue_work(zd_workqueue, &mac->set_multicast_hash_work);
 
 	if (changed_flags & FIF_CONTROL)
@@ -940,6 +953,7 @@ static const struct ieee80211_ops zd_ops = {
 	.add_interface		= zd_op_add_interface,
 	.remove_interface	= zd_op_remove_interface,
 	.config			= zd_op_config,
+	.prepare_multicast	= zd_op_prepare_multicast,
 	.configure_filter	= zd_op_configure_filter,
 	.bss_info_changed	= zd_op_bss_info_changed,
 	.get_tsf		= zd_op_get_tsf,

+ 1 - 1
drivers/ssb/pci.c

@@ -480,7 +480,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
 
 	/* extract the MAC address */
 	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
+		v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
 		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 	}
 	SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0);

+ 2 - 0
include/net/cfg80211.h

@@ -1325,6 +1325,8 @@ struct wireless_dev {
 
 	struct mutex mtx;
 
+	struct work_struct cleanup_work;
+
 	/* currently used for IBSS and SME - might be rearranged later */
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 ssid_len;

+ 15 - 21
include/net/mac80211.h

@@ -583,7 +583,6 @@ enum ieee80211_conf_flags {
 /**
  * enum ieee80211_conf_changed - denotes which configuration changed
  *
- * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED
  * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
  * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
  * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed
@@ -593,7 +592,6 @@ enum ieee80211_conf_flags {
  * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
  */
 enum ieee80211_conf_changed {
-	_IEEE80211_CONF_CHANGE_RADIO_ENABLED	= BIT(0),
 	IEEE80211_CONF_CHANGE_LISTEN_INTERVAL	= BIT(2),
 	IEEE80211_CONF_CHANGE_RADIOTAP		= BIT(3),
 	IEEE80211_CONF_CHANGE_PS		= BIT(4),
@@ -603,14 +601,6 @@ enum ieee80211_conf_changed {
 	IEEE80211_CONF_CHANGE_IDLE		= BIT(8),
 };
 
-static inline __deprecated enum ieee80211_conf_changed
-__IEEE80211_CONF_CHANGE_RADIO_ENABLED(void)
-{
-	return _IEEE80211_CONF_CHANGE_RADIO_ENABLED;
-}
-#define IEEE80211_CONF_CHANGE_RADIO_ENABLED \
-	__IEEE80211_CONF_CHANGE_RADIO_ENABLED()
-
 /**
  * struct ieee80211_conf - configuration of the device
  *
@@ -618,9 +608,6 @@ __IEEE80211_CONF_CHANGE_RADIO_ENABLED(void)
  *
  * @flags: configuration flags defined above
  *
- * @radio_enabled: when zero, driver is required to switch off the radio.
- * @beacon_int: DEPRECATED, DO NOT USE
- *
  * @listen_interval: listen interval in units of beacon interval
  * @max_sleep_period: the maximum number of beacon intervals to sleep for
  *	before checking the beacon for a TIM bit (managed mode only); this
@@ -644,13 +631,11 @@ __IEEE80211_CONF_CHANGE_RADIO_ENABLED(void)
  *    number of transmissions not the number of retries
  */
 struct ieee80211_conf {
-	int __deprecated beacon_int;
 	u32 flags;
 	int power_level, dynamic_ps_timeout;
 	int max_sleep_period;
 
 	u16 listen_interval;
-	bool __deprecated radio_enabled;
 
 	u8 long_frame_max_tx_count, short_frame_max_tx_count;
 
@@ -1219,10 +1204,13 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * the driver's configure_filter() function which frames should be
  * passed to mac80211 and which should be filtered out.
  *
- * The configure_filter() callback is invoked with the parameters
- * @mc_count and @mc_list for the combined multicast address list
- * of all virtual interfaces, @changed_flags telling which flags
- * were changed and @total_flags with the new flag states.
+ * Before configure_filter() is invoked, the prepare_multicast()
+ * callback is invoked with the parameters @mc_count and @mc_list
+ * for the combined multicast address list of all virtual interfaces.
+ * It's use is optional, and it returns a u64 that is passed to
+ * configure_filter(). Additionally, configure_filter() has the
+ * arguments @changed_flags telling which flags were changed and
+ * @total_flags with the new flag states.
  *
  * If your device has no multicast address filters your driver will
  * need to check both the %FIF_ALLMULTI flag and the @mc_count
@@ -1375,9 +1363,13 @@ enum ieee80211_ampdu_mlme_action {
  *	for association indication. The @changed parameter indicates which
  *	of the bss parameters has changed when a call is made.
  *
+ * @prepare_multicast: Prepare for multicast filter configuration.
+ *	This callback is optional, and its return value is passed
+ *	to configure_filter(). This callback must be atomic.
+ *
  * @configure_filter: Configure the device's RX filter.
  *	See the section "Frame filtering" for more information.
- *	This callback must be implemented and atomic.
+ *	This callback must be implemented.
  *
  * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
  * 	must be set or cleared for a given STA. Must be atomic.
@@ -1479,10 +1471,12 @@ struct ieee80211_ops {
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *info,
 				 u32 changed);
+	u64 (*prepare_multicast)(struct ieee80211_hw *hw,
+				 int mc_count, struct dev_addr_list *mc_list);
 	void (*configure_filter)(struct ieee80211_hw *hw,
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
-				 int mc_count, struct dev_addr_list *mc_list);
+				 u64 multicast);
 	int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
 		       bool set);
 	int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,

+ 6 - 0
net/mac80211/debugfs_netdev.c

@@ -116,6 +116,8 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 
 #ifdef CONFIG_MAC80211_MESH
 /* Mesh stats attributes */
+IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
+IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
 IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
 IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 IEEE80211_IF_FILE(dropped_frames_no_route,
@@ -205,6 +207,8 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
 {
 	sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats",
 				sdata->debugfsdir);
+	MESHSTATS_ADD(fwded_mcast);
+	MESHSTATS_ADD(fwded_unicast);
 	MESHSTATS_ADD(fwded_frames);
 	MESHSTATS_ADD(dropped_frames_ttl);
 	MESHSTATS_ADD(dropped_frames_no_route);
@@ -327,6 +331,8 @@ static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 
 static void del_mesh_stats(struct ieee80211_sub_if_data *sdata)
 {
+	MESHSTATS_DEL(fwded_mcast);
+	MESHSTATS_DEL(fwded_unicast);
 	MESHSTATS_DEL(fwded_frames);
 	MESHSTATS_DEL(dropped_frames_ttl);
 	MESHSTATS_DEL(dropped_frames_no_route);

+ 20 - 4
net/mac80211/driver-ops.h

@@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 	trace_drv_bss_info_changed(local, vif, info, changed);
 }
 
+static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
+					int mc_count,
+					struct dev_addr_list *mc_list)
+{
+	u64 ret = 0;
+
+	if (local->ops->prepare_multicast)
+		ret = local->ops->prepare_multicast(&local->hw, mc_count,
+						    mc_list);
+
+	trace_drv_prepare_multicast(local, mc_count, ret);
+
+	return ret;
+}
+
 static inline void drv_configure_filter(struct ieee80211_local *local,
 					unsigned int changed_flags,
 					unsigned int *total_flags,
-					int mc_count,
-					struct dev_addr_list *mc_list)
+					u64 multicast)
 {
+	might_sleep();
+
 	local->ops->configure_filter(&local->hw, changed_flags, total_flags,
-				     mc_count, mc_list);
+				     multicast);
 	trace_drv_configure_filter(local, changed_flags, total_flags,
-					    mc_count);
+				   multicast);
 }
 
 static inline int drv_set_tim(struct ieee80211_local *local,

+ 30 - 6
net/mac80211/driver-trace.h

@@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed,
 	)
 );
 
+TRACE_EVENT(drv_prepare_multicast,
+	TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
+
+	TP_ARGS(local, mc_count, ret),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(int, mc_count)
+		__field(u64, ret)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->mc_count = mc_count;
+		__entry->ret = ret;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " prepare mc (%d): %llx",
+		LOCAL_PR_ARG, __entry->mc_count,
+		(unsigned long long) __entry->ret
+	)
+);
+
 TRACE_EVENT(drv_configure_filter,
 	TP_PROTO(struct ieee80211_local *local,
 		 unsigned int changed_flags,
 		 unsigned int *total_flags,
-		 int mc_count),
+		 u64 multicast),
 
-	TP_ARGS(local, changed_flags, total_flags, mc_count),
+	TP_ARGS(local, changed_flags, total_flags, multicast),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
 		__field(unsigned int, changed)
 		__field(unsigned int, total)
-		__field(int, mc)
+		__field(u64, multicast)
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
 		__entry->changed = changed_flags;
 		__entry->total = *total_flags;
-		__entry->mc = mc_count;
+		__entry->multicast = multicast;
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " changed:%#x total:%#x mc:%d",
-		LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc
+		LOCAL_PR_FMT " changed:%#x total:%#x",
+		LOCAL_PR_ARG, __entry->changed, __entry->total
 	)
 );
 

+ 8 - 1
net/mac80211/ieee80211_i.h

@@ -212,7 +212,9 @@ struct ieee80211_if_vlan {
 };
 
 struct mesh_stats {
-	__u32 fwded_frames;		/* Mesh forwarded frames */
+	__u32 fwded_mcast;		/* Mesh forwarded multicast frames */
+	__u32 fwded_unicast;		/* Mesh forwarded unicast frames */
+	__u32 fwded_frames;		/* Mesh total forwarded frames */
 	__u32 dropped_frames_ttl;	/* Not transmitted since mesh_ttl == 0*/
 	__u32 dropped_frames_no_route;	/* Not transmitted, no route found */
 	atomic_t estab_plinks;
@@ -506,6 +508,8 @@ struct ieee80211_sub_if_data {
 #ifdef CONFIG_MAC80211_MESH
 	struct dentry *mesh_stats_dir;
 	struct {
+		struct dentry *fwded_mcast;
+		struct dentry *fwded_unicast;
 		struct dentry *fwded_frames;
 		struct dentry *dropped_frames_ttl;
 		struct dentry *dropped_frames_no_route;
@@ -636,6 +640,9 @@ struct ieee80211_local {
 	/* protects the aggregated multicast list and filter calls */
 	spinlock_t filter_lock;
 
+	/* used for uploading changed mc list */
+	struct work_struct reconfig_filter;
+
 	/* aggregated multicast list */
 	struct dev_addr_list *mc_list;
 	int mc_count;

+ 3 - 12
net/mac80211/iface.c

@@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev)
 		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
 			local->fif_other_bss++;
 
-		spin_lock_bh(&local->filter_lock);
 		ieee80211_configure_filter(local);
-		spin_unlock_bh(&local->filter_lock);
 		break;
 	default:
 		conf.vif = &sdata->vif;
@@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev)
 
 		if (ieee80211_vif_is_mesh(&sdata->vif)) {
 			local->fif_other_bss++;
-			spin_lock_bh(&local->filter_lock);
 			ieee80211_configure_filter(local);
-			spin_unlock_bh(&local->filter_lock);
 
 			ieee80211_start_mesh(sdata);
 		} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
 			local->fif_pspoll++;
 
-			spin_lock_bh(&local->filter_lock);
 			ieee80211_configure_filter(local);
-			spin_unlock_bh(&local->filter_lock);
 		}
 
 		changed |= ieee80211_reset_erp_info(sdata);
@@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev)
 	spin_lock_bh(&local->filter_lock);
 	__dev_addr_unsync(&local->mc_list, &local->mc_count,
 			  &dev->mc_list, &dev->mc_count);
-	ieee80211_configure_filter(local);
 	spin_unlock_bh(&local->filter_lock);
 	netif_addr_unlock_bh(dev);
 
+	ieee80211_configure_filter(local);
+
 	del_timer_sync(&local->dynamic_ps_timer);
 	cancel_work_sync(&local->dynamic_ps_enable_work);
 
@@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev)
 		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
 			local->fif_other_bss--;
 
-		spin_lock_bh(&local->filter_lock);
 		ieee80211_configure_filter(local);
-		spin_unlock_bh(&local->filter_lock);
 		break;
 	case NL80211_IFTYPE_STATION:
 		del_timer_sync(&sdata->u.mgd.chswitch_timer);
@@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev)
 			local->fif_other_bss--;
 			atomic_dec(&local->iff_allmultis);
 
-			spin_lock_bh(&local->filter_lock);
 			ieee80211_configure_filter(local);
-			spin_unlock_bh(&local->filter_lock);
 
 			ieee80211_stop_mesh(sdata);
 		}
@@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
 	spin_lock_bh(&local->filter_lock);
 	__dev_addr_sync(&local->mc_list, &local->mc_count,
 			&dev->mc_list, &dev->mc_count);
-	ieee80211_configure_filter(local);
 	spin_unlock_bh(&local->filter_lock);
+	ieee80211_queue_work(&local->hw, &local->reconfig_filter);
 }
 
 /*

+ 22 - 10
net/mac80211/main.c

@@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr {
 } __attribute__ ((packed));
 
 
-/* must be called under mdev tx lock */
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
+	u64 mc;
 	unsigned int changed_flags;
 	unsigned int new_flags = 0;
 
@@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
 	if (atomic_read(&local->iff_allmultis))
 		new_flags |= FIF_ALLMULTI;
 
-	if (local->monitors)
+	if (local->monitors || local->scanning)
 		new_flags |= FIF_BCN_PRBRESP_PROMISC;
 
 	if (local->fif_fcsfail)
@@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
 	if (local->fif_pspoll)
 		new_flags |= FIF_PSPOLL;
 
+	spin_lock_bh(&local->filter_lock);
 	changed_flags = local->filter_flags ^ new_flags;
 
+	mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
+	spin_unlock_bh(&local->filter_lock);
+
 	/* be a bit nasty */
 	new_flags |= (1<<31);
 
-	drv_configure_filter(local, changed_flags, &new_flags,
-			     local->mc_count,
-			     local->mc_list);
+	drv_configure_filter(local, changed_flags, &new_flags, mc);
 
 	WARN_ON(new_flags & (1<<31));
 
 	local->filter_flags = new_flags & ~(1<<31);
 }
 
+static void ieee80211_reconfig_filter(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local, reconfig_filter);
+
+	ieee80211_configure_filter(local);
+}
+
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
 	struct ieee80211_channel *chan, *scan_chan;
@@ -231,9 +241,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 
 	drv_bss_info_changed(local, &sdata->vif,
 			     &sdata->vif.bss_conf, changed);
-
-	/* DEPRECATED */
-	local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
 }
 
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
@@ -475,6 +482,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 		}
 
 		rate_control_tx_status(local, sband, sta, skb);
+		if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+			ieee80211s_update_metric(local, sta, skb);
 	}
 
 	rcu_read_unlock();
@@ -677,7 +686,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	local->hw.max_rates = 1;
 	local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
 	local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
-	local->hw.conf.radio_enabled = true;
 	local->user_power_level = -1;
 
 	INIT_LIST_HEAD(&local->interfaces);
@@ -692,6 +700,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
 	INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
+	INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
+
 	INIT_WORK(&local->dynamic_ps_enable_work,
 		  ieee80211_dynamic_ps_enable_work);
 	INIT_WORK(&local->dynamic_ps_disable_work,
@@ -920,7 +930,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
  fail_workqueue:
 	wiphy_unregister(local->hw.wiphy);
  fail_wiphy_register:
-	kfree(local->int_scan_req->channels);
+	kfree(local->int_scan_req);
 	return result;
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
@@ -946,6 +956,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
 	rtnl_unlock();
 
+	cancel_work_sync(&local->reconfig_filter);
+
 	ieee80211_clear_tx_pending(local);
 	sta_info_stop(local);
 	rate_control_deinitialize(local);

+ 2 - 0
net/mac80211/mesh.h

@@ -226,6 +226,8 @@ void mesh_mgmt_ies_add(struct sk_buff *skb,
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
+void ieee80211s_update_metric(struct ieee80211_local *local,
+		struct sta_info *stainfo, struct sk_buff *skb);
 void ieee80211s_stop(void);
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
 ieee80211_rx_result

+ 21 - 0
net/mac80211/mesh_hwmp.c

@@ -201,6 +201,24 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra,
 	return 0;
 }
 
+void ieee80211s_update_metric(struct ieee80211_local *local,
+		struct sta_info *stainfo, struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	int failed;
+
+	if (!ieee80211_is_data(hdr->frame_control))
+		return;
+
+	failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);
+
+	/* moving average, scaled to 100 */
+	stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed);
+	if (stainfo->fail_avg > 95)
+		mesh_plink_broken(stainfo);
+}
+
 static u32 airtime_link_metric_get(struct ieee80211_local *local,
 				   struct sta_info *sta)
 {
@@ -479,6 +497,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 				hopcount, ttl, cpu_to_le32(lifetime),
 				cpu_to_le32(metric), cpu_to_le32(preq_id),
 				sdata);
+		ifmsh->mshstats.fwded_mcast++;
 		ifmsh->mshstats.fwded_frames++;
 	}
 }
@@ -537,6 +556,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
 		cpu_to_le32(lifetime), cpu_to_le32(metric),
 		0, sdata);
 	rcu_read_unlock();
+
+	sdata->u.mesh.mshstats.fwded_unicast++;
 	sdata->u.mesh.mshstats.fwded_frames++;
 	return;
 

+ 1 - 15
net/mac80211/rc80211_minstrel.c

@@ -51,7 +51,6 @@
 #include <linux/random.h>
 #include <linux/ieee80211.h>
 #include <net/mac80211.h>
-#include "mesh.h"
 #include "rate.h"
 #include "rc80211_minstrel.h"
 
@@ -156,16 +155,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 		   struct sk_buff *skb)
 {
 	struct minstrel_sta_info *mi = priv_sta;
-	struct minstrel_priv *mp = (struct minstrel_priv *)priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_rate *ar = info->status.rates;
-	struct ieee80211_local *local = hw_to_local(mp->hw);
-	struct sta_info *si;
 	int i, ndx;
 	int success;
 
 	success = !!(info->flags & IEEE80211_TX_STAT_ACK);
-	si = sta_info_get(local, sta->addr);
 
 	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
 		if (ar[i].idx < 0)
@@ -177,17 +172,8 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
 		mi->r[ndx].attempts += ar[i].count;
 
-		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) {
+		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
 			mi->r[ndx].success += success;
-			if (si) {
-				si->fail_avg = (18050 - mi->r[ndx].probability)
-					/ 180;
-				WARN_ON(si->fail_avg > 100);
-				if (si->fail_avg == 100 &&
-					ieee80211_vif_is_mesh(&si->sdata->vif))
-					mesh_plink_broken(si);
-			}
-		}
 	}
 
 	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))

+ 1 - 15
net/mac80211/rc80211_pid_algo.c

@@ -169,19 +169,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 	 * still a good measurement and copy it. */
 	if (unlikely(spinfo->tx_num_xmit == 0))
 		pf = spinfo->last_pf;
-	else {
-		/* XXX: BAD HACK!!! */
-		struct sta_info *si = container_of(sta, struct sta_info, sta);
-
+	else
 		pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
 
-		if (ieee80211_vif_is_mesh(&si->sdata->vif) && pf == 100)
-			mesh_plink_broken(si);
-		pf <<= RC_PID_ARITH_SHIFT;
-		si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
-					>> RC_PID_ARITH_SHIFT;
-	}
-
 	spinfo->tx_num_xmit = 0;
 	spinfo->tx_num_failed = 0;
 
@@ -311,7 +301,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	struct rc_pid_sta_info *spinfo = priv_sta;
 	struct rc_pid_info *pinfo = priv;
 	struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
-	struct sta_info *si;
 	int i, j, tmp;
 	bool s;
 
@@ -348,9 +337,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	}
 
 	spinfo->txrate_idx = rate_lowest_index(sband, sta);
-	/* HACK */
-	si = container_of(sta, struct sta_info, sta);
-	si->fail_avg = 0;
 }
 
 static void *rate_control_pid_alloc(struct ieee80211_hw *hw,

+ 7 - 1
net/mac80211/rx.c

@@ -1550,7 +1550,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 			info->control.vif = &rx->sdata->vif;
 			ieee80211_select_queue(local, fwd_skb);
-			if (!is_multicast_ether_addr(fwd_hdr->addr1)) {
+			if (is_multicast_ether_addr(fwd_hdr->addr1))
+				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+								fwded_mcast);
+			else {
 				int err;
 				/*
 				 * Save TA to addr1 to send TA a path error if a
@@ -1564,6 +1567,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 				 * later to the pending skb queue.  */
 				if (err)
 					return RX_DROP_MONITOR;
+
+				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+								fwded_unicast);
 			}
 			IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
 						     fwded_frames);

+ 2 - 14
net/mac80211/scan.c

@@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 	if (was_hw_scan)
 		goto done;
 
-	spin_lock_bh(&local->filter_lock);
-	local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
-	drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
-			     &local->filter_flags,
-			     local->mc_count,
-			     local->mc_list);
-	spin_unlock_bh(&local->filter_lock);
+	ieee80211_configure_filter(local);
 
 	drv_sw_scan_complete(local);
 
@@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 	local->next_scan_state = SCAN_DECISION;
 	local->scan_channel_idx = 0;
 
-	spin_lock_bh(&local->filter_lock);
-	local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
-	drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
-			     &local->filter_flags,
-			     local->mc_count,
-			     local->mc_list);
-	spin_unlock_bh(&local->filter_lock);
+	ieee80211_configure_filter(local);
 
 	/* TODO: start scan as soon as all nullfunc frames are ACKed */
 	ieee80211_queue_delayed_work(&local->hw,

+ 0 - 2
net/mac80211/util.c

@@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 	/* reconfigure hardware */
 	ieee80211_hw_config(local, ~0);
 
-	spin_lock_bh(&local->filter_lock);
 	ieee80211_configure_filter(local);
-	spin_unlock_bh(&local->filter_lock);
 
 	/* Finally also reconfigure all the BSS information */
 	list_for_each_entry(sdata, &local->interfaces, list) {

+ 78 - 20
net/wireless/core.c

@@ -12,6 +12,7 @@
 #include <linux/debugfs.h>
 #include <linux/notifier.h>
 #include <linux/device.h>
+#include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
@@ -309,7 +310,8 @@ static void cfg80211_process_events(struct wireless_dev *wdev)
 		switch (ev->type) {
 		case EVENT_CONNECT_RESULT:
 			__cfg80211_connect_result(
-				wdev->netdev, ev->cr.bssid,
+				wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ?
+				NULL : ev->cr.bssid,
 				ev->cr.req_ie, ev->cr.req_ie_len,
 				ev->cr.resp_ie, ev->cr.resp_ie_len,
 				ev->cr.status,
@@ -430,6 +432,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 	INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
 	INIT_WORK(&rdev->event_work, cfg80211_event_work);
 
+	init_waitqueue_head(&rdev->dev_wait);
+
 	/*
 	 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
 	 * Fragmentation and RTS threshold are disabled by default with the
@@ -574,7 +578,23 @@ void wiphy_unregister(struct wiphy *wiphy)
 	/* protect the device list */
 	mutex_lock(&cfg80211_mutex);
 
+	wait_event(rdev->dev_wait, ({
+		int __count;
+		mutex_lock(&rdev->devlist_mtx);
+		__count = rdev->opencount;
+		mutex_unlock(&rdev->devlist_mtx);
+		__count == 0;}));
+
+	mutex_lock(&rdev->devlist_mtx);
 	BUG_ON(!list_empty(&rdev->netdev_list));
+	mutex_unlock(&rdev->devlist_mtx);
+
+	/*
+	 * First remove the hardware from everywhere, this makes
+	 * it impossible to find from userspace.
+	 */
+	cfg80211_debugfs_rdev_del(rdev);
+	list_del(&rdev->list);
 
 	/*
 	 * Try to grab rdev->mtx. If a command is still in progress,
@@ -582,21 +602,18 @@ void wiphy_unregister(struct wiphy *wiphy)
 	 * down the device already. We wait for this command to complete
 	 * before unlinking the item from the list.
 	 * Note: as codified by the BUG_ON above we cannot get here if
-	 * a virtual interface is still associated. Hence, we can only
-	 * get to lock contention here if userspace issues a command
-	 * that identified the hardware by wiphy index.
+	 * a virtual interface is still present. Hence, we can only get
+	 * to lock contention here if userspace issues a command that
+	 * identified the hardware by wiphy index.
 	 */
-	mutex_lock(&rdev->mtx);
-	/* unlock again before freeing */
-	mutex_unlock(&rdev->mtx);
-
-	cfg80211_debugfs_rdev_del(rdev);
+	cfg80211_lock_rdev(rdev);
+	/* nothing */
+	cfg80211_unlock_rdev(rdev);
 
 	/* If this device got a regulatory hint tell core its
 	 * free to listen now to a new shiny device regulatory hint */
 	reg_device_remove(wiphy);
 
-	list_del(&rdev->list);
 	cfg80211_rdev_list_generation++;
 	device_del(&rdev->wiphy.dev);
 	debugfs_remove(rdev->wiphy.debugfsdir);
@@ -605,7 +622,6 @@ void wiphy_unregister(struct wiphy *wiphy)
 
 	flush_work(&rdev->scan_done_wk);
 	cancel_work_sync(&rdev->conn_work);
-	kfree(rdev->scan_req);
 	flush_work(&rdev->event_work);
 }
 EXPORT_SYMBOL(wiphy_unregister);
@@ -636,6 +652,31 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
+static void wdev_cleanup_work(struct work_struct *work)
+{
+	struct wireless_dev *wdev;
+	struct cfg80211_registered_device *rdev;
+
+	wdev = container_of(work, struct wireless_dev, cleanup_work);
+	rdev = wiphy_to_dev(wdev->wiphy);
+
+	cfg80211_lock_rdev(rdev);
+
+	if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
+		rdev->scan_req->aborted = true;
+		___cfg80211_scan_done(rdev);
+	}
+
+	cfg80211_unlock_rdev(rdev);
+
+	mutex_lock(&rdev->devlist_mtx);
+	rdev->opencount--;
+	mutex_unlock(&rdev->devlist_mtx);
+	wake_up(&rdev->dev_wait);
+
+	dev_put(wdev->netdev);
+}
+
 static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 					 unsigned long state,
 					 void *ndev)
@@ -653,7 +694,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 
 	switch (state) {
 	case NETDEV_REGISTER:
+		/*
+		 * NB: cannot take rdev->mtx here because this may be
+		 * called within code protected by it when interfaces
+		 * are added with nl80211.
+		 */
 		mutex_init(&wdev->mtx);
+		INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
 		INIT_LIST_HEAD(&wdev->event_list);
 		spin_lock_init(&wdev->event_lock);
 		mutex_lock(&rdev->devlist_mtx);
@@ -708,8 +755,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 		default:
 			break;
 		}
+		dev_hold(dev);
+		schedule_work(&wdev->cleanup_work);
 		break;
 	case NETDEV_UP:
+		/*
+		 * If we have a really quick DOWN/UP succession we may
+		 * have this work still pending ... cancel it and see
+		 * if it was pending, in which case we need to account
+		 * for some of the work it would have done.
+		 */
+		if (cancel_work_sync(&wdev->cleanup_work)) {
+			mutex_lock(&rdev->devlist_mtx);
+			rdev->opencount--;
+			mutex_unlock(&rdev->devlist_mtx);
+			dev_put(dev);
+		}
 #ifdef CONFIG_WIRELESS_EXT
 		cfg80211_lock_rdev(rdev);
 		mutex_lock(&rdev->devlist_mtx);
@@ -725,18 +786,17 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 			break;
 		}
 		wdev_unlock(wdev);
+		rdev->opencount++;
 		mutex_unlock(&rdev->devlist_mtx);
 		cfg80211_unlock_rdev(rdev);
 #endif
 		break;
 	case NETDEV_UNREGISTER:
-		cfg80211_lock_rdev(rdev);
-
-		if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) {
-			rdev->scan_req->aborted = true;
-			___cfg80211_scan_done(rdev);
-		}
-
+		/*
+		 * NB: cannot take rdev->mtx here because this may be
+		 * called within code protected by it when interfaces
+		 * are removed with nl80211.
+		 */
 		mutex_lock(&rdev->devlist_mtx);
 		/*
 		 * It is possible to get NETDEV_UNREGISTER
@@ -749,13 +809,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
 			sysfs_remove_link(&dev->dev.kobj, "phy80211");
 			list_del_init(&wdev->list);
 			rdev->devlist_generation++;
-			mutex_destroy(&wdev->mtx);
 #ifdef CONFIG_WIRELESS_EXT
 			kfree(wdev->wext.keys);
 #endif
 		}
 		mutex_unlock(&rdev->devlist_mtx);
-		cfg80211_unlock_rdev(rdev);
 		break;
 	case NETDEV_PRE_UP:
 		if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))

+ 2 - 0
net/wireless/core.h

@@ -50,6 +50,8 @@ struct cfg80211_registered_device {
 	struct mutex devlist_mtx;
 	struct list_head netdev_list;
 	int devlist_generation;
+	int opencount; /* also protected by devlist_mtx */
+	wait_queue_head_t dev_wait;
 
 	/* BSSes/scanning */
 	spinlock_t bss_lock;

+ 9 - 0
net/wireless/mlme.c

@@ -96,6 +96,15 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
 		WARN_ON(!bss);
 	}
 
+	if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
+		/*
+		 * This is for the userspace SME, the CONNECTING
+		 * state will be changed to CONNECTED by
+		 * __cfg80211_connect_result() below.
+		 */
+		wdev->sme_state = CFG80211_SME_CONNECTING;
+	}
+
 	/* this consumes one bss reference (unless bss is NULL) */
 	__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
 				  status_code,

+ 12 - 17
net/wireless/sme.c

@@ -351,15 +351,13 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
 		return;
 
-	if (wdev->sme_state == CFG80211_SME_CONNECTED)
-		nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev,
+	if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING))
+		return;
+
+	nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
 				    bssid, req_ie, req_ie_len,
-				    resp_ie, resp_ie_len, GFP_KERNEL);
-	else
-		nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
-					    bssid, req_ie, req_ie_len,
-					    resp_ie, resp_ie_len,
-					    status, GFP_KERNEL);
+				    resp_ie, resp_ie_len,
+				    status, GFP_KERNEL);
 
 #ifdef CONFIG_WIRELESS_EXT
 	if (wextev) {
@@ -392,18 +390,13 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 		wdev->current_bss = NULL;
 	}
 
-	if (status == WLAN_STATUS_SUCCESS &&
-	    wdev->sme_state == CFG80211_SME_IDLE)
-		goto success;
-
-	if (wdev->sme_state != CFG80211_SME_CONNECTING)
-		return;
-
 	if (wdev->conn)
 		wdev->conn->state = CFG80211_CONN_IDLE;
 
 	if (status != WLAN_STATUS_SUCCESS) {
 		wdev->sme_state = CFG80211_SME_IDLE;
+		if (wdev->conn)
+			kfree(wdev->conn->ie);
 		kfree(wdev->conn);
 		wdev->conn = NULL;
 		kfree(wdev->connect_keys);
@@ -412,7 +405,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 		return;
 	}
 
- success:
 	if (!bss)
 		bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
 				       wdev->ssid, wdev->ssid_len,
@@ -458,7 +450,8 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 		return;
 
 	ev->type = EVENT_CONNECT_RESULT;
-	memcpy(ev->cr.bssid, bssid, ETH_ALEN);
+	if (bssid)
+		memcpy(ev->cr.bssid, bssid, ETH_ALEN);
 	ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
 	ev->cr.req_ie_len = req_ie_len;
 	memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
@@ -789,6 +782,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 			}
 		}
 		if (err) {
+			kfree(wdev->conn->ie);
 			kfree(wdev->conn);
 			wdev->conn = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
@@ -858,6 +852,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 		    (wdev->conn->state == CFG80211_CONN_SCANNING ||
 		     wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
 			wdev->sme_state = CFG80211_SME_IDLE;
+			kfree(wdev->conn->ie);
 			kfree(wdev->conn);
 			wdev->conn = NULL;
 			wdev->ssid_len = 0;

+ 1 - 0
net/wireless/wext-compat.c

@@ -771,6 +771,7 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
 		return err;
 	}
 }
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
 
 int cfg80211_wext_giwfreq(struct net_device *dev,
 			  struct iw_request_info *info,

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно