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

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

David S. Miller 15 жил өмнө
parent
commit
3a999e6eb5
99 өөрчлөгдсөн 4016 нэмэгдсэн , 3120 устгасан
  1. 0 21
      Documentation/feature-removal-schedule.txt
  2. 6 6
      drivers/net/wireless/adm8211.c
  3. 3 3
      drivers/net/wireless/at76c50x-usb.c
  4. 4 4
      drivers/net/wireless/ath/ar9170/main.c
  5. 12 24
      drivers/net/wireless/ath/ath5k/base.c
  6. 3 0
      drivers/net/wireless/ath/ath9k/mac.h
  7. 28 14
      drivers/net/wireless/ath/ath9k/main.c
  8. 1 1
      drivers/net/wireless/ath/ath9k/pci.c
  9. 1 1
      drivers/net/wireless/ath/ath9k/xmit.c
  10. 1 16
      drivers/net/wireless/b43/Kconfig
  11. 1 1
      drivers/net/wireless/b43/Makefile
  12. 0 13
      drivers/net/wireless/b43/b43.h
  13. 45 154
      drivers/net/wireless/b43/dma.c
  14. 1 6
      drivers/net/wireless/b43/dma.h
  15. 19 16
      drivers/net/wireless/b43/main.c
  16. 0 40
      drivers/net/wireless/b43/pio.h
  17. 12 12
      drivers/net/wireless/b43legacy/main.c
  18. 2 8
      drivers/net/wireless/iwlwifi/iwl-3945.c
  19. 0 1
      drivers/net/wireless/iwlwifi/iwl-3945.h
  20. 1 1
      drivers/net/wireless/iwlwifi/iwl-agn-rs.c
  21. 10 10
      drivers/net/wireless/iwlwifi/iwl-core.c
  22. 2 2
      drivers/net/wireless/iwlwifi/iwl-core.h
  23. 2 46
      drivers/net/wireless/iwlwifi/iwl-rx.c
  24. 0 41
      drivers/net/wireless/iwlwifi/iwl3945-base.c
  25. 1 1
      drivers/net/wireless/iwmc3200wifi/iwm.h
  26. 8 14
      drivers/net/wireless/libertas/scan.c
  27. 5 6
      drivers/net/wireless/libertas_tf/main.c
  28. 20 9
      drivers/net/wireless/mac80211_hwsim.c
  29. 477 535
      drivers/net/wireless/mwl8k.c
  30. 3 3
      drivers/net/wireless/orinoco/wext.c
  31. 6 6
      drivers/net/wireless/p54/main.c
  32. 2 2
      drivers/net/wireless/rt2x00/Kconfig
  33. 2 3
      drivers/net/wireless/rt2x00/rt2400pci.c
  34. 19 20
      drivers/net/wireless/rt2x00/rt2500pci.c
  35. 18 20
      drivers/net/wireless/rt2x00/rt2500usb.c
  36. 45 49
      drivers/net/wireless/rt2x00/rt2800lib.c
  37. 8 17
      drivers/net/wireless/rt2x00/rt2800pci.c
  38. 3 2
      drivers/net/wireless/rt2x00/rt2800usb.c
  39. 14 14
      drivers/net/wireless/rt2x00/rt2x00.h
  40. 13 13
      drivers/net/wireless/rt2x00/rt2x00mac.c
  41. 12 17
      drivers/net/wireless/rt2x00/rt61pci.c
  42. 16 20
      drivers/net/wireless/rt2x00/rt73usb.c
  43. 0 1
      drivers/net/wireless/rtl818x/rtl8180.h
  44. 11 15
      drivers/net/wireless/rtl818x/rtl8180_dev.c
  45. 1 1
      drivers/net/wireless/rtl818x/rtl8187.h
  46. 6 9
      drivers/net/wireless/rtl818x/rtl8187_dev.c
  47. 2 2
      drivers/net/wireless/rtl818x/rtl8187_leds.c
  48. 1 1
      drivers/net/wireless/wl12xx/wl1251_boot.c
  49. 7 7
      drivers/net/wireless/wl12xx/wl1251_main.c
  50. 18 17
      drivers/net/wireless/wl12xx/wl1271.h
  51. 74 60
      drivers/net/wireless/wl12xx/wl1271_acx.c
  52. 19 18
      drivers/net/wireless/wl12xx/wl1271_acx.h
  53. 7 1
      drivers/net/wireless/wl12xx/wl1271_boot.c
  54. 45 26
      drivers/net/wireless/wl12xx/wl1271_cmd.c
  55. 28 5
      drivers/net/wireless/wl12xx/wl1271_cmd.h
  56. 57 43
      drivers/net/wireless/wl12xx/wl1271_conf.h
  57. 62 0
      drivers/net/wireless/wl12xx/wl1271_debugfs.c
  58. 9 11
      drivers/net/wireless/wl12xx/wl1271_event.c
  59. 1 1
      drivers/net/wireless/wl12xx/wl1271_event.h
  60. 8 4
      drivers/net/wireless/wl12xx/wl1271_init.c
  61. 311 181
      drivers/net/wireless/wl12xx/wl1271_main.c
  62. 8 7
      drivers/net/wireless/wl12xx/wl1271_ps.c
  63. 40 3
      drivers/net/wireless/wl12xx/wl1271_tx.c
  64. 0 140
      drivers/net/wireless/zd1211rw/zd_chip.c
  65. 0 3
      drivers/net/wireless/zd1211rw/zd_chip.h
  66. 5 8
      drivers/net/wireless/zd1211rw/zd_mac.c
  67. 30 9
      include/linux/ieee80211.h
  68. 36 0
      include/linux/nl80211.h
  69. 59 0
      include/net/cfg80211.h
  70. 50 55
      include/net/mac80211.h
  71. 2 2
      net/mac80211/Makefile
  72. 27 5
      net/mac80211/cfg.c
  73. 0 2
      net/mac80211/debugfs_netdev.c
  74. 68 9
      net/mac80211/driver-ops.h
  75. 21 0
      net/mac80211/driver-trace.h
  76. 32 21
      net/mac80211/ibss.c
  77. 108 33
      net/mac80211/ieee80211_i.h
  78. 19 18
      net/mac80211/iface.c
  79. 2 2
      net/mac80211/key.c
  80. 7 4
      net/mac80211/main.c
  81. 1 1
      net/mac80211/mesh.c
  82. 220 861
      net/mac80211/mlme.c
  83. 168 0
      net/mac80211/offchannel.c
  84. 2 6
      net/mac80211/pm.c
  85. 8 3
      net/mac80211/rx.c
  86. 38 170
      net/mac80211/scan.c
  87. 6 1
      net/mac80211/sta_info.c
  88. 1 1
      net/mac80211/status.c
  89. 5 1
      net/mac80211/tx.c
  90. 132 31
      net/mac80211/util.c
  91. 1086 0
      net/mac80211/work.c
  92. 0 15
      net/wireless/Kconfig
  93. 27 14
      net/wireless/chan.c
  94. 3 0
      net/wireless/core.h
  95. 49 1
      net/wireless/mlme.c
  96. 237 8
      net/wireless/nl80211.c
  97. 15 0
      net/wireless/nl80211.h
  98. 2 87
      net/wireless/reg.c
  99. 9 4
      net/wireless/scan.c

+ 0 - 21
Documentation/feature-removal-schedule.txt

@@ -88,27 +88,6 @@ Who:	Luis R. Rodriguez <lrodriguez@atheros.com>
 
 
 ---------------------------
 ---------------------------
 
 
-What:	CONFIG_WIRELESS_OLD_REGULATORY - old static regulatory information
-When:	March 2010 / desktop catchup
-
-Why:	The old regulatory infrastructure has been replaced with a new one
-	which does not require statically defined regulatory domains. We do
-	not want to keep static regulatory domains in the kernel due to the
-	the dynamic nature of regulatory law and localization. We kept around
-	the old static definitions for the regulatory domains of:
-
-		* US
-		* JP
-		* EU
-
-	and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was
-	set. We will remove this option once the standard Linux desktop catches
-	up with the new userspace APIs we have implemented.
-
-Who:	Luis R. Rodriguez <lrodriguez@atheros.com>
-
----------------------------
-
 What:	dev->power.power_state
 What:	dev->power.power_state
 When:	July 2007
 When:	July 2007
 Why:	Broken design for runtime control over driver power states, confusing
 Why:	Broken design for runtime control over driver power states, confusing

+ 6 - 6
drivers/net/wireless/adm8211.c

@@ -1400,15 +1400,15 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
 }
 }
 
 
 static int adm8211_add_interface(struct ieee80211_hw *dev,
 static int adm8211_add_interface(struct ieee80211_hw *dev,
-				 struct ieee80211_if_init_conf *conf)
+				 struct ieee80211_vif *vif)
 {
 {
 	struct adm8211_priv *priv = dev->priv;
 	struct adm8211_priv *priv = dev->priv;
 	if (priv->mode != NL80211_IFTYPE_MONITOR)
 	if (priv->mode != NL80211_IFTYPE_MONITOR)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
-		priv->mode = conf->type;
+		priv->mode = vif->type;
 		break;
 		break;
 	default:
 	default:
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
@@ -1416,8 +1416,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
 
 
 	ADM8211_IDLE();
 	ADM8211_IDLE();
 
 
-	ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr));
-	ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+	ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)vif->addr));
+	ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(vif->addr + 4)));
 
 
 	adm8211_update_mode(dev);
 	adm8211_update_mode(dev);
 
 
@@ -1427,7 +1427,7 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
 }
 }
 
 
 static void adm8211_remove_interface(struct ieee80211_hw *dev,
 static void adm8211_remove_interface(struct ieee80211_hw *dev,
-				     struct ieee80211_if_init_conf *conf)
+				     struct ieee80211_vif *vif)
 {
 {
 	struct adm8211_priv *priv = dev->priv;
 	struct adm8211_priv *priv = dev->priv;
 	priv->mode = NL80211_IFTYPE_MONITOR;
 	priv->mode = NL80211_IFTYPE_MONITOR;

+ 3 - 3
drivers/net/wireless/at76c50x-usb.c

@@ -1789,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
 }
 }
 
 
 static int at76_add_interface(struct ieee80211_hw *hw,
 static int at76_add_interface(struct ieee80211_hw *hw,
-			      struct ieee80211_if_init_conf *conf)
+			      struct ieee80211_vif *vif)
 {
 {
 	struct at76_priv *priv = hw->priv;
 	struct at76_priv *priv = hw->priv;
 	int ret = 0;
 	int ret = 0;
@@ -1798,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw,
 
 
 	mutex_lock(&priv->mtx);
 	mutex_lock(&priv->mtx);
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
 		priv->iw_mode = IW_MODE_INFRA;
 		priv->iw_mode = IW_MODE_INFRA;
 		break;
 		break;
@@ -1814,7 +1814,7 @@ exit:
 }
 }
 
 
 static void at76_remove_interface(struct ieee80211_hw *hw,
 static void at76_remove_interface(struct ieee80211_hw *hw,
-				  struct ieee80211_if_init_conf *conf)
+				  struct ieee80211_vif *vif)
 {
 {
 	at76_dbg(DBG_MAC80211, "%s()", __func__);
 	at76_dbg(DBG_MAC80211, "%s()", __func__);
 }
 }

+ 4 - 4
drivers/net/wireless/ath/ar9170/main.c

@@ -1939,7 +1939,7 @@ err_free:
 }
 }
 
 
 static int ar9170_op_add_interface(struct ieee80211_hw *hw,
 static int ar9170_op_add_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_if_init_conf *conf)
+				   struct ieee80211_vif *vif)
 {
 {
 	struct ar9170 *ar = hw->priv;
 	struct ar9170 *ar = hw->priv;
 	struct ath_common *common = &ar->common;
 	struct ath_common *common = &ar->common;
@@ -1952,8 +1952,8 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
 		goto unlock;
 		goto unlock;
 	}
 	}
 
 
-	ar->vif = conf->vif;
-	memcpy(common->macaddr, conf->mac_addr, ETH_ALEN);
+	ar->vif = vif;
+	memcpy(common->macaddr, vif->addr, ETH_ALEN);
 
 
 	if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
 	if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
 		ar->rx_software_decryption = true;
 		ar->rx_software_decryption = true;
@@ -1973,7 +1973,7 @@ unlock:
 }
 }
 
 
 static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
 static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
-				       struct ieee80211_if_init_conf *conf)
+				       struct ieee80211_vif *vif)
 {
 {
 	struct ar9170 *ar = hw->priv;
 	struct ar9170 *ar = hw->priv;
 
 

+ 12 - 24
drivers/net/wireless/ath/ath5k/base.c

@@ -225,9 +225,9 @@ static int ath5k_reset_wake(struct ath5k_softc *sc);
 static int ath5k_start(struct ieee80211_hw *hw);
 static int ath5k_start(struct ieee80211_hw *hw);
 static void ath5k_stop(struct ieee80211_hw *hw);
 static void ath5k_stop(struct ieee80211_hw *hw);
 static int ath5k_add_interface(struct ieee80211_hw *hw,
 static int ath5k_add_interface(struct ieee80211_hw *hw,
-		struct ieee80211_if_init_conf *conf);
+		struct ieee80211_vif *vif);
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
-		struct ieee80211_if_init_conf *conf);
+		struct ieee80211_vif *vif);
 static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
 static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
 static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
 static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
 				   int mc_count, struct dev_addr_list *mc_list);
 				   int mc_count, struct dev_addr_list *mc_list);
@@ -1903,17 +1903,6 @@ accept:
 		rxs->noise = sc->ah->ah_noise_floor;
 		rxs->noise = sc->ah->ah_noise_floor;
 		rxs->signal = rxs->noise + rs.rs_rssi;
 		rxs->signal = rxs->noise + rs.rs_rssi;
 
 
-		/* An rssi of 35 indicates you should be able use
-		 * 54 Mbps reliably. A more elaborate scheme can be used
-		 * here but it requires a map of SNR/throughput for each
-		 * possible mode used */
-		rxs->qual = rs.rs_rssi * 100 / 35;
-
-		/* rssi can be more than 35 though, anything above that
-		 * should be considered at 100% */
-		if (rxs->qual > 100)
-			rxs->qual = 100;
-
 		rxs->antenna = rs.rs_antenna;
 		rxs->antenna = rs.rs_antenna;
 		rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
 		rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
 		rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
 		rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
@@ -2381,6 +2370,9 @@ ath5k_init(struct ath5k_softc *sc)
 	 */
 	 */
 	ath5k_stop_locked(sc);
 	ath5k_stop_locked(sc);
 
 
+	/* Set PHY calibration interval */
+	ah->ah_cal_intval = ath5k_calinterval;
+
 	/*
 	/*
 	 * The basic interface to setting the hardware in a good
 	 * The basic interface to setting the hardware in a good
 	 * state is ``reset''.  On return the hardware is known to
 	 * state is ``reset''.  On return the hardware is known to
@@ -2408,10 +2400,6 @@ ath5k_init(struct ath5k_softc *sc)
 
 
 	/* Set ack to be sent at low bit-rates */
 	/* Set ack to be sent at low bit-rates */
 	ath5k_hw_set_ack_bitrate_high(ah, false);
 	ath5k_hw_set_ack_bitrate_high(ah, false);
-
-	/* Set PHY calibration inteval */
-	ah->ah_cal_intval = ath5k_calinterval;
-
 	ret = 0;
 	ret = 0;
 done:
 done:
 	mmiowb();
 	mmiowb();
@@ -2785,7 +2773,7 @@ static void ath5k_stop(struct ieee80211_hw *hw)
 }
 }
 
 
 static int ath5k_add_interface(struct ieee80211_hw *hw,
 static int ath5k_add_interface(struct ieee80211_hw *hw,
-		struct ieee80211_if_init_conf *conf)
+		struct ieee80211_vif *vif)
 {
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_softc *sc = hw->priv;
 	int ret;
 	int ret;
@@ -2796,22 +2784,22 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
 		goto end;
 		goto end;
 	}
 	}
 
 
-	sc->vif = conf->vif;
+	sc->vif = vif;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_MONITOR:
-		sc->opmode = conf->type;
+		sc->opmode = vif->type;
 		break;
 		break;
 	default:
 	default:
 		ret = -EOPNOTSUPP;
 		ret = -EOPNOTSUPP;
 		goto end;
 		goto end;
 	}
 	}
 
 
-	ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
+	ath5k_hw_set_lladdr(sc->ah, vif->addr);
 	ath5k_mode_setup(sc);
 	ath5k_mode_setup(sc);
 
 
 	ret = 0;
 	ret = 0;
@@ -2822,13 +2810,13 @@ end:
 
 
 static void
 static void
 ath5k_remove_interface(struct ieee80211_hw *hw,
 ath5k_remove_interface(struct ieee80211_hw *hw,
-			struct ieee80211_if_init_conf *conf)
+			struct ieee80211_vif *vif)
 {
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_softc *sc = hw->priv;
 	u8 mac[ETH_ALEN] = {};
 	u8 mac[ETH_ALEN] = {};
 
 
 	mutex_lock(&sc->lock);
 	mutex_lock(&sc->lock);
-	if (sc->vif != conf->vif)
+	if (sc->vif != vif)
 		goto end;
 		goto end;
 
 
 	ath5k_hw_set_lladdr(sc->ah, mac);
 	ath5k_hw_set_lladdr(sc->ah, mac);

+ 3 - 0
drivers/net/wireless/ath/ath9k/mac.h

@@ -77,6 +77,9 @@
 #define ATH9K_TXERR_XTXOP          0x08
 #define ATH9K_TXERR_XTXOP          0x08
 #define ATH9K_TXERR_TIMER_EXPIRED  0x10
 #define ATH9K_TXERR_TIMER_EXPIRED  0x10
 #define ATH9K_TX_ACKED		   0x20
 #define ATH9K_TX_ACKED		   0x20
+#define ATH9K_TXERR_MASK						\
+	(ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO |	\
+	 ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED)
 
 
 #define ATH9K_TX_BA                0x01
 #define ATH9K_TX_BA                0x01
 #define ATH9K_TX_PWRMGMT           0x02
 #define ATH9K_TX_PWRMGMT           0x02

+ 28 - 14
drivers/net/wireless/ath/ath9k/main.c

@@ -2504,6 +2504,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 		return; /* another wiphy still in use */
 		return; /* another wiphy still in use */
 	}
 	}
 
 
+	/* Ensure HW is awake when we try to shut it down. */
+	ath9k_ps_wakeup(sc);
+
 	if (ah->btcoex_hw.enabled) {
 	if (ah->btcoex_hw.enabled) {
 		ath9k_hw_btcoex_disable(ah);
 		ath9k_hw_btcoex_disable(ah);
 		if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
 		if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -2524,6 +2527,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 	/* disable HAL and put h/w to sleep */
 	/* disable HAL and put h/w to sleep */
 	ath9k_hw_disable(ah);
 	ath9k_hw_disable(ah);
 	ath9k_hw_configpcipowersave(ah, 1, 1);
 	ath9k_hw_configpcipowersave(ah, 1, 1);
+	ath9k_ps_restore(sc);
+
+	/* Finally, put the chip in FULL SLEEP mode */
 	ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
 	ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
 
 
 	sc->sc_flags |= SC_OP_INVALID;
 	sc->sc_flags |= SC_OP_INVALID;
@@ -2534,12 +2540,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 }
 }
 
 
 static int ath9k_add_interface(struct ieee80211_hw *hw,
 static int ath9k_add_interface(struct ieee80211_hw *hw,
-			       struct ieee80211_if_init_conf *conf)
+			       struct ieee80211_vif *vif)
 {
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ath_vif *avp = (void *)conf->vif->drv_priv;
+	struct ath_vif *avp = (void *)vif->drv_priv;
 	enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
 	enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
 	int ret = 0;
 	int ret = 0;
 
 
@@ -2551,7 +2557,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
 		ic_opmode = NL80211_IFTYPE_STATION;
 		ic_opmode = NL80211_IFTYPE_STATION;
 		break;
 		break;
@@ -2562,11 +2568,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 			ret = -ENOBUFS;
 			ret = -ENOBUFS;
 			goto out;
 			goto out;
 		}
 		}
-		ic_opmode = conf->type;
+		ic_opmode = vif->type;
 		break;
 		break;
 	default:
 	default:
 		ath_print(common, ATH_DBG_FATAL,
 		ath_print(common, ATH_DBG_FATAL,
-			"Interface type %d not yet supported\n", conf->type);
+			"Interface type %d not yet supported\n", vif->type);
 		ret = -EOPNOTSUPP;
 		ret = -EOPNOTSUPP;
 		goto out;
 		goto out;
 	}
 	}
@@ -2598,18 +2604,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 	 * Enable MIB interrupts when there are hardware phy counters.
 	 * Enable MIB interrupts when there are hardware phy counters.
 	 * Note we only do this (at the moment) for station mode.
 	 * Note we only do this (at the moment) for station mode.
 	 */
 	 */
-	if ((conf->type == NL80211_IFTYPE_STATION) ||
-	    (conf->type == NL80211_IFTYPE_ADHOC) ||
-	    (conf->type == NL80211_IFTYPE_MESH_POINT)) {
+	if ((vif->type == NL80211_IFTYPE_STATION) ||
+	    (vif->type == NL80211_IFTYPE_ADHOC) ||
+	    (vif->type == NL80211_IFTYPE_MESH_POINT)) {
 		sc->imask |= ATH9K_INT_MIB;
 		sc->imask |= ATH9K_INT_MIB;
 		sc->imask |= ATH9K_INT_TSFOOR;
 		sc->imask |= ATH9K_INT_TSFOOR;
 	}
 	}
 
 
 	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
 
-	if (conf->type == NL80211_IFTYPE_AP    ||
-	    conf->type == NL80211_IFTYPE_ADHOC ||
-	    conf->type == NL80211_IFTYPE_MONITOR)
+	if (vif->type == NL80211_IFTYPE_AP    ||
+	    vif->type == NL80211_IFTYPE_ADHOC ||
+	    vif->type == NL80211_IFTYPE_MONITOR)
 		ath_start_ani(common);
 		ath_start_ani(common);
 
 
 out:
 out:
@@ -2618,12 +2624,12 @@ out:
 }
 }
 
 
 static void ath9k_remove_interface(struct ieee80211_hw *hw,
 static void ath9k_remove_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_if_init_conf *conf)
+				   struct ieee80211_vif *vif)
 {
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ath_vif *avp = (void *)conf->vif->drv_priv;
+	struct ath_vif *avp = (void *)vif->drv_priv;
 	int i;
 	int i;
 
 
 	ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
 	ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
@@ -2637,14 +2643,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
 	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
 	    (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
 	    (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
 	    (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
 	    (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
+		ath9k_ps_wakeup(sc);
 		ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 		ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 		ath_beacon_return(sc, avp);
 		ath_beacon_return(sc, avp);
+		ath9k_ps_restore(sc);
 	}
 	}
 
 
 	sc->sc_flags &= ~SC_OP_BEACONS;
 	sc->sc_flags &= ~SC_OP_BEACONS;
 
 
 	for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
 	for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
-		if (sc->beacon.bslot[i] == conf->vif) {
+		if (sc->beacon.bslot[i] == vif) {
 			printk(KERN_DEBUG "%s: vif had allocated beacon "
 			printk(KERN_DEBUG "%s: vif had allocated beacon "
 			       "slot\n", __func__);
 			       "slot\n", __func__);
 			sc->beacon.bslot[i] = NULL;
 			sc->beacon.bslot[i] = NULL;
@@ -3087,15 +3095,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 	case IEEE80211_AMPDU_RX_STOP:
 	case IEEE80211_AMPDU_RX_STOP:
 		break;
 		break;
 	case IEEE80211_AMPDU_TX_START:
 	case IEEE80211_AMPDU_TX_START:
+		ath9k_ps_wakeup(sc);
 		ath_tx_aggr_start(sc, sta, tid, ssn);
 		ath_tx_aggr_start(sc, sta, tid, ssn);
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		ath9k_ps_restore(sc);
 		break;
 		break;
 	case IEEE80211_AMPDU_TX_STOP:
 	case IEEE80211_AMPDU_TX_STOP:
+		ath9k_ps_wakeup(sc);
 		ath_tx_aggr_stop(sc, sta, tid);
 		ath_tx_aggr_stop(sc, sta, tid);
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		ath9k_ps_restore(sc);
 		break;
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		ath9k_ps_wakeup(sc);
 		ath_tx_aggr_resume(sc, sta, tid);
 		ath_tx_aggr_resume(sc, sta, tid);
+		ath9k_ps_restore(sc);
 		break;
 		break;
 	default:
 	default:
 		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,

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

@@ -96,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
 	pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
 	pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
 }
 }
 
 
-const static struct ath_bus_ops ath_pci_bus_ops = {
+static const struct ath_bus_ops ath_pci_bus_ops = {
 	.read_cachesize = ath_pci_read_cachesize,
 	.read_cachesize = ath_pci_read_cachesize,
 	.cleanup = ath_pci_cleanup,
 	.cleanup = ath_pci_cleanup,
 	.eeprom_read = ath_pci_eeprom_read,
 	.eeprom_read = ath_pci_eeprom_read,

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

@@ -2072,7 +2072,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 				&txq->axq_q, lastbf->list.prev);
 				&txq->axq_q, lastbf->list.prev);
 
 
 		txq->axq_depth--;
 		txq->axq_depth--;
-		txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_FILT);
+		txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK);
 		txq->axq_tx_inprogress = false;
 		txq->axq_tx_inprogress = false;
 		spin_unlock_bh(&txq->axq_lock);
 		spin_unlock_bh(&txq->axq_lock);
 
 

+ 1 - 16
drivers/net/wireless/b43/Kconfig

@@ -3,6 +3,7 @@ config B43
 	depends on SSB_POSSIBLE && MAC80211 && HAS_DMA
 	depends on SSB_POSSIBLE && MAC80211 && HAS_DMA
 	select SSB
 	select SSB
 	select FW_LOADER
 	select FW_LOADER
+	select SSB_BLOCKIO
 	---help---
 	---help---
 	  b43 is a driver for the Broadcom 43xx series wireless devices.
 	  b43 is a driver for the Broadcom 43xx series wireless devices.
 
 
@@ -78,14 +79,6 @@ config B43_SDIO
 
 
 	  If unsure, say N.
 	  If unsure, say N.
 
 
-# Data transfers to the device via PIO
-# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly.
-config B43_PIO
-	bool
-	depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO)
-	select SSB_BLOCKIO
-	default y
-
 config B43_NPHY
 config B43_NPHY
 	bool "Pre IEEE 802.11n support (BROKEN)"
 	bool "Pre IEEE 802.11n support (BROKEN)"
 	depends on B43 && EXPERIMENTAL && BROKEN
 	depends on B43 && EXPERIMENTAL && BROKEN
@@ -137,12 +130,4 @@ config B43_DEBUG
 	  for production use.
 	  for production use.
 	  Only say Y, if you are debugging a problem in the b43 driver sourcecode.
 	  Only say Y, if you are debugging a problem in the b43 driver sourcecode.
 
 
-config B43_FORCE_PIO
-	bool "Force usage of PIO instead of DMA"
-	depends on B43 && B43_DEBUG
-	---help---
-	  This will disable DMA and always enable PIO instead.
 
 
-	  Say N!
-	  This is only for debugging the PIO engine code. You do
-	  _NOT_ want to enable this.

+ 1 - 1
drivers/net/wireless/b43/Makefile

@@ -12,7 +12,7 @@ b43-y				+= xmit.o
 b43-y				+= lo.o
 b43-y				+= lo.o
 b43-y				+= wa.o
 b43-y				+= wa.o
 b43-y				+= dma.o
 b43-y				+= dma.o
-b43-$(CONFIG_B43_PIO)		+= pio.o
+b43-y				+= pio.o
 b43-y				+= rfkill.o
 b43-y				+= rfkill.o
 b43-$(CONFIG_B43_LEDS)		+= leds.o
 b43-$(CONFIG_B43_LEDS)		+= leds.o
 b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o
 b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o

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

@@ -821,11 +821,9 @@ struct b43_wl {
 	/* The device LEDs. */
 	/* The device LEDs. */
 	struct b43_leds leds;
 	struct b43_leds leds;
 
 
-#ifdef CONFIG_B43_PIO
 	/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
 	/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
 	u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
 	u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
 	u8 pio_tailspace[4] __attribute__((__aligned__(8)));
 	u8 pio_tailspace[4] __attribute__((__aligned__(8)));
-#endif /* CONFIG_B43_PIO */
 };
 };
 
 
 static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
 static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
@@ -876,20 +874,9 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
 
 
 static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
 static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
 {
 {
-#ifdef CONFIG_B43_PIO
 	return dev->__using_pio_transfers;
 	return dev->__using_pio_transfers;
-#else
-	return 0;
-#endif
 }
 }
 
 
-#ifdef CONFIG_B43_FORCE_PIO
-# define B43_FORCE_PIO	1
-#else
-# define B43_FORCE_PIO	0
-#endif
-
-
 /* Message printing */
 /* Message printing */
 void b43info(struct b43_wl *wl, const char *fmt, ...)
 void b43info(struct b43_wl *wl, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
     __attribute__ ((format(printf, 2, 3)));

+ 45 - 154
drivers/net/wireless/b43/dma.c

@@ -383,160 +383,44 @@ static inline
 	}
 	}
 }
 }
 
 
-/* Check if a DMA region fits the device constraints.
- * Returns true, if the region is OK for usage with this device. */
-static inline bool b43_dma_address_ok(struct b43_dmaring *ring,
-				      dma_addr_t addr, size_t size)
-{
-	switch (ring->type) {
-	case B43_DMA_30BIT:
-		if ((u64)addr + size > (1ULL << 30))
-			return 0;
-		break;
-	case B43_DMA_32BIT:
-		if ((u64)addr + size > (1ULL << 32))
-			return 0;
-		break;
-	case B43_DMA_64BIT:
-		/* Currently we can't have addresses beyond
-		 * 64bit in the kernel. */
-		break;
-	}
-	return 1;
-}
-
-#define is_4k_aligned(addr)	(((u64)(addr) & 0x0FFFull) == 0)
-#define is_8k_aligned(addr)	(((u64)(addr) & 0x1FFFull) == 0)
-
-static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base,
-				       dma_addr_t dmaaddr, size_t size)
-{
-	ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE);
-	free_pages((unsigned long)base, get_order(size));
-}
-
-static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring,
-					dma_addr_t *dmaaddr, size_t size,
-					gfp_t gfp_flags)
-{
-	void *base;
-
-	base = (void *)__get_free_pages(gfp_flags, get_order(size));
-	if (!base)
-		return NULL;
-	memset(base, 0, size);
-	*dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size,
-				      DMA_TO_DEVICE);
-	if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) {
-		free_pages((unsigned long)base, get_order(size));
-		return NULL;
-	}
-
-	return base;
-}
-
-static void * b43_get_and_map_ringmem(struct b43_dmaring *ring,
-				      dma_addr_t *dmaaddr, size_t size)
-{
-	void *base;
-
-	base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
-					 GFP_KERNEL);
-	if (!base) {
-		b43err(ring->dev->wl, "Failed to allocate or map pages "
-		       "for DMA ringmemory\n");
-		return NULL;
-	}
-	if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
-		/* The memory does not fit our device constraints.
-		 * Retry with GFP_DMA set to get lower memory. */
-		b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
-		base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
-						 GFP_KERNEL | GFP_DMA);
-		if (!base) {
-			b43err(ring->dev->wl, "Failed to allocate or map pages "
-			       "in the GFP_DMA region for DMA ringmemory\n");
-			return NULL;
-		}
-		if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
-			b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
-			b43err(ring->dev->wl, "Failed to allocate DMA "
-			       "ringmemory that fits device constraints\n");
-			return NULL;
-		}
-	}
-	/* We expect the memory to be 4k aligned, at least. */
-	if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) {
-		b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
-		return NULL;
-	}
-
-	return base;
-}
-
 static int alloc_ringmemory(struct b43_dmaring *ring)
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
 {
-	unsigned int required;
-	void *base;
-	dma_addr_t dmaaddr;
-
-	/* There are several requirements to the descriptor ring memory:
-	 * - The memory region needs to fit the address constraints for the
-	 *   device (same as for frame buffers).
-	 * - For 30/32bit DMA devices, the descriptor ring must be 4k aligned.
-	 * - For 64bit DMA devices, the descriptor ring must be 8k aligned.
+	gfp_t flags = GFP_KERNEL;
+
+	/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
+	 * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
+	 * has shown that 4K is sufficient for the latter as long as the buffer
+	 * does not cross an 8K boundary.
+	 *
+	 * For unknown reasons - possibly a hardware error - the BCM4311 rev
+	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
+	 * which accounts for the GFP_DMA flag below.
+	 *
+	 * The flags here must match the flags in free_ringmemory below!
 	 */
 	 */
-
 	if (ring->type == B43_DMA_64BIT)
 	if (ring->type == B43_DMA_64BIT)
-		required = ring->nr_slots * sizeof(struct b43_dmadesc64);
-	else
-		required = ring->nr_slots * sizeof(struct b43_dmadesc32);
-	if (B43_WARN_ON(required > 0x1000))
+		flags |= GFP_DMA;
+	ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
+						  B43_DMA_RINGMEMSIZE,
+						  &(ring->dmabase), flags);
+	if (!ring->descbase) {
+		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
 		return -ENOMEM;
-
-	ring->alloc_descsize = 0x1000;
-	base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
-	if (!base)
-		return -ENOMEM;
-	ring->alloc_descbase = base;
-	ring->alloc_dmabase = dmaaddr;
-
-	if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) {
-		/* We're on <=32bit DMA, or we already got 8k aligned memory.
-		 * That's all we need, so we're fine. */
-		ring->descbase = base;
-		ring->dmabase = dmaaddr;
-		return 0;
-	}
-	b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize);
-
-	/* Ok, we failed at the 8k alignment requirement.
-	 * Try to force-align the memory region now. */
-	ring->alloc_descsize = 0x2000;
-	base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
-	if (!base)
-		return -ENOMEM;
-	ring->alloc_descbase = base;
-	ring->alloc_dmabase = dmaaddr;
-
-	if (is_8k_aligned(dmaaddr)) {
-		/* We're already 8k aligned. That Ok, too. */
-		ring->descbase = base;
-		ring->dmabase = dmaaddr;
-		return 0;
 	}
 	}
-	/* Force-align it to 8k */
-	ring->descbase = (void *)((u8 *)base + 0x1000);
-	ring->dmabase = dmaaddr + 0x1000;
-	B43_WARN_ON(!is_8k_aligned(ring->dmabase));
+	memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static void free_ringmemory(struct b43_dmaring *ring)
 static void free_ringmemory(struct b43_dmaring *ring)
 {
 {
-	b43_unmap_and_free_ringmem(ring, ring->alloc_descbase,
-				   ring->alloc_dmabase, ring->alloc_descsize);
+	gfp_t flags = GFP_KERNEL;
+
+	if (ring->type == B43_DMA_64BIT)
+		flags |= GFP_DMA;
+
+	ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
+				ring->descbase, ring->dmabase, flags);
 }
 }
 
 
 /* Reset the RX DMA channel */
 /* Reset the RX DMA channel */
@@ -646,14 +530,29 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
 	if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
 	if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
 		return 1;
 		return 1;
 
 
-	if (!b43_dma_address_ok(ring, addr, buffersize)) {
-		/* We can't support this address. Unmap it again. */
-		unmap_descbuffer(ring, addr, buffersize, dma_to_device);
-		return 1;
+	switch (ring->type) {
+	case B43_DMA_30BIT:
+		if ((u64)addr + buffersize > (1ULL << 30))
+			goto address_error;
+		break;
+	case B43_DMA_32BIT:
+		if ((u64)addr + buffersize > (1ULL << 32))
+			goto address_error;
+		break;
+	case B43_DMA_64BIT:
+		/* Currently we can't have addresses beyond
+		 * 64bit in the kernel. */
+		break;
 	}
 	}
 
 
 	/* The address is OK. */
 	/* The address is OK. */
 	return 0;
 	return 0;
+
+address_error:
+	/* We can't support this address. Unmap it again. */
+	unmap_descbuffer(ring, addr, buffersize, dma_to_device);
+
+	return 1;
 }
 }
 
 
 static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
 static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
@@ -715,9 +614,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
 	meta->dmaaddr = dmaaddr;
 	meta->dmaaddr = dmaaddr;
 	ring->ops->fill_descriptor(ring, desc, dmaaddr,
 	ring->ops->fill_descriptor(ring, desc, dmaaddr,
 				   ring->rx_buffersize, 0, 0, 0);
 				   ring->rx_buffersize, 0, 0, 0);
-	ssb_dma_sync_single_for_device(ring->dev->dev,
-				       ring->alloc_dmabase,
-				       ring->alloc_descsize, DMA_TO_DEVICE);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1354,9 +1250,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 	}
 	}
 	/* Now transfer the whole frame. */
 	/* Now transfer the whole frame. */
 	wmb();
 	wmb();
-	ssb_dma_sync_single_for_device(ring->dev->dev,
-				       ring->alloc_dmabase,
-				       ring->alloc_descsize, DMA_TO_DEVICE);
 	ops->poke_tx(ring, next_slot(ring, slot));
 	ops->poke_tx(ring, next_slot(ring, slot));
 	return 0;
 	return 0;
 
 
@@ -1760,7 +1653,6 @@ void b43_dma_tx_resume(struct b43_wldev *dev)
 	b43_power_saving_ctl_bits(dev, 0);
 	b43_power_saving_ctl_bits(dev, 0);
 }
 }
 
 
-#ifdef CONFIG_B43_PIO
 static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type,
 static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type,
 			   u16 mmio_base, bool enable)
 			   u16 mmio_base, bool enable)
 {
 {
@@ -1794,4 +1686,3 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
 	mmio_base = b43_dmacontroller_base(type, engine_index);
 	mmio_base = b43_dmacontroller_base(type, engine_index);
 	direct_fifo_rx(dev, type, mmio_base, enable);
 	direct_fifo_rx(dev, type, mmio_base, enable);
 }
 }
-#endif /* CONFIG_B43_PIO */

+ 1 - 6
drivers/net/wireless/b43/dma.h

@@ -157,6 +157,7 @@ struct b43_dmadesc_generic {
 } __attribute__ ((__packed__));
 } __attribute__ ((__packed__));
 
 
 /* Misc DMA constants */
 /* Misc DMA constants */
+#define B43_DMA_RINGMEMSIZE		PAGE_SIZE
 #define B43_DMA0_RX_FRAMEOFFSET		30
 #define B43_DMA0_RX_FRAMEOFFSET		30
 
 
 /* DMA engine tuning knobs */
 /* DMA engine tuning knobs */
@@ -246,12 +247,6 @@ struct b43_dmaring {
 	/* The QOS priority assigned to this ring. Only used for TX rings.
 	/* The QOS priority assigned to this ring. Only used for TX rings.
 	 * This is the mac80211 "queue" value. */
 	 * This is the mac80211 "queue" value. */
 	u8 queue_prio;
 	u8 queue_prio;
-	/* Pointers and size of the originally allocated and mapped memory
-	 * region for the descriptor ring. */
-	void *alloc_descbase;
-	dma_addr_t alloc_dmabase;
-	unsigned int alloc_descsize;
-	/* Pointer to our wireless device. */
 	struct b43_wldev *dev;
 	struct b43_wldev *dev;
 #ifdef CONFIG_B43_DEBUG
 #ifdef CONFIG_B43_DEBUG
 	/* Maximum number of used slots. */
 	/* Maximum number of used slots. */

+ 19 - 16
drivers/net/wireless/b43/main.c

@@ -102,6 +102,9 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
 module_param_named(verbose, b43_modparam_verbose, int, 0644);
 module_param_named(verbose, b43_modparam_verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
 MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
 
 
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
 
 
 static const struct ssb_device_id b43_ssb_tbl[] = {
 static const struct ssb_device_id b43_ssb_tbl[] = {
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
@@ -1786,8 +1789,8 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
 			       dma_reason[4], dma_reason[5]);
 			       dma_reason[4], dma_reason[5]);
 			b43err(dev->wl, "This device does not support DMA "
 			b43err(dev->wl, "This device does not support DMA "
 			       "on your system. Please use PIO instead.\n");
 			       "on your system. Please use PIO instead.\n");
-			b43err(dev->wl, "CONFIG_B43_FORCE_PIO must be set in "
-			       "your kernel configuration.\n");
+			b43err(dev->wl, "Unload the b43 module and reload "
+			       "with 'pio=1'\n");
 			return;
 			return;
 		}
 		}
 		if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
 		if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
@@ -4353,7 +4356,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 
 
 	if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
 	if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
 	    (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
 	    (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
-	    B43_FORCE_PIO) {
+	    modparam_pio) {
 		dev->__using_pio_transfers = 1;
 		dev->__using_pio_transfers = 1;
 		err = b43_pio_init(dev);
 		err = b43_pio_init(dev);
 	} else {
 	} else {
@@ -4388,7 +4391,7 @@ err_busdown:
 }
 }
 
 
 static int b43_op_add_interface(struct ieee80211_hw *hw,
 static int b43_op_add_interface(struct ieee80211_hw *hw,
-				struct ieee80211_if_init_conf *conf)
+				struct ieee80211_vif *vif)
 {
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
 	struct b43_wldev *dev;
@@ -4396,24 +4399,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
 
 
 	/* TODO: allow WDS/AP devices to coexist */
 	/* TODO: allow WDS/AP devices to coexist */
 
 
-	if (conf->type != NL80211_IFTYPE_AP &&
-	    conf->type != NL80211_IFTYPE_MESH_POINT &&
-	    conf->type != NL80211_IFTYPE_STATION &&
-	    conf->type != NL80211_IFTYPE_WDS &&
-	    conf->type != NL80211_IFTYPE_ADHOC)
+	if (vif->type != NL80211_IFTYPE_AP &&
+	    vif->type != NL80211_IFTYPE_MESH_POINT &&
+	    vif->type != NL80211_IFTYPE_STATION &&
+	    vif->type != NL80211_IFTYPE_WDS &&
+	    vif->type != NL80211_IFTYPE_ADHOC)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 	if (wl->operating)
 	if (wl->operating)
 		goto out_mutex_unlock;
 		goto out_mutex_unlock;
 
 
-	b43dbg(wl, "Adding Interface type %d\n", conf->type);
+	b43dbg(wl, "Adding Interface type %d\n", vif->type);
 
 
 	dev = wl->current_dev;
 	dev = wl->current_dev;
 	wl->operating = 1;
 	wl->operating = 1;
-	wl->vif = conf->vif;
-	wl->if_type = conf->type;
-	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+	wl->vif = vif;
+	wl->if_type = vif->type;
+	memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
 
 
 	b43_adjust_opmode(dev);
 	b43_adjust_opmode(dev);
 	b43_set_pretbtt(dev);
 	b43_set_pretbtt(dev);
@@ -4428,17 +4431,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
 }
 }
 
 
 static void b43_op_remove_interface(struct ieee80211_hw *hw,
 static void b43_op_remove_interface(struct ieee80211_hw *hw,
-				    struct ieee80211_if_init_conf *conf)
+				    struct ieee80211_vif *vif)
 {
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
 	struct b43_wldev *dev = wl->current_dev;
 
 
-	b43dbg(wl, "Removing Interface type %d\n", conf->type);
+	b43dbg(wl, "Removing Interface type %d\n", vif->type);
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
 	B43_WARN_ON(!wl->operating);
 	B43_WARN_ON(!wl->operating);
-	B43_WARN_ON(wl->vif != conf->vif);
+	B43_WARN_ON(wl->vif != vif);
 	wl->vif = NULL;
 	wl->vif = NULL;
 
 
 	wl->operating = 0;
 	wl->operating = 0;

+ 0 - 40
drivers/net/wireless/b43/pio.h

@@ -55,8 +55,6 @@
 #define B43_PIO_MAX_NR_TXPACKETS	32
 #define B43_PIO_MAX_NR_TXPACKETS	32
 
 
 
 
-#ifdef CONFIG_B43_PIO
-
 struct b43_pio_txpacket {
 struct b43_pio_txpacket {
 	/* Pointer to the TX queue we belong to. */
 	/* Pointer to the TX queue we belong to. */
 	struct b43_pio_txqueue *queue;
 	struct b43_pio_txqueue *queue;
@@ -169,42 +167,4 @@ void b43_pio_rx(struct b43_pio_rxqueue *q);
 void b43_pio_tx_suspend(struct b43_wldev *dev);
 void b43_pio_tx_suspend(struct b43_wldev *dev);
 void b43_pio_tx_resume(struct b43_wldev *dev);
 void b43_pio_tx_resume(struct b43_wldev *dev);
 
 
-
-#else /* CONFIG_B43_PIO */
-
-
-static inline int b43_pio_init(struct b43_wldev *dev)
-{
-	return 0;
-}
-static inline void b43_pio_free(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_stop(struct b43_wldev *dev)
-{
-}
-static inline int b43_pio_tx(struct b43_wldev *dev,
-			     struct sk_buff *skb)
-{
-	return 0;
-}
-static inline void b43_pio_handle_txstatus(struct b43_wldev *dev,
-					   const struct b43_txstatus *status)
-{
-}
-static inline void b43_pio_get_tx_stats(struct b43_wldev *dev,
-					struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline void b43_pio_rx(struct b43_pio_rxqueue *q)
-{
-}
-static inline void b43_pio_tx_suspend(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_tx_resume(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_PIO */
 #endif /* B43_PIO_H_ */
 #endif /* B43_PIO_H_ */

+ 12 - 12
drivers/net/wireless/b43legacy/main.c

@@ -3361,7 +3361,7 @@ err_kfree_lo_control:
 }
 }
 
 
 static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
 static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
-				      struct ieee80211_if_init_conf *conf)
+				      struct ieee80211_vif *vif)
 {
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev;
 	struct b43legacy_wldev *dev;
@@ -3370,23 +3370,23 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
 
 
 	/* TODO: allow WDS/AP devices to coexist */
 	/* TODO: allow WDS/AP devices to coexist */
 
 
-	if (conf->type != NL80211_IFTYPE_AP &&
-	    conf->type != NL80211_IFTYPE_STATION &&
-	    conf->type != NL80211_IFTYPE_WDS &&
-	    conf->type != NL80211_IFTYPE_ADHOC)
+	if (vif->type != NL80211_IFTYPE_AP &&
+	    vif->type != NL80211_IFTYPE_STATION &&
+	    vif->type != NL80211_IFTYPE_WDS &&
+	    vif->type != NL80211_IFTYPE_ADHOC)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 	if (wl->operating)
 	if (wl->operating)
 		goto out_mutex_unlock;
 		goto out_mutex_unlock;
 
 
-	b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
+	b43legacydbg(wl, "Adding Interface type %d\n", vif->type);
 
 
 	dev = wl->current_dev;
 	dev = wl->current_dev;
 	wl->operating = 1;
 	wl->operating = 1;
-	wl->vif = conf->vif;
-	wl->if_type = conf->type;
-	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+	wl->vif = vif;
+	wl->if_type = vif->type;
+	memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
 
 
 	spin_lock_irqsave(&wl->irq_lock, flags);
 	spin_lock_irqsave(&wl->irq_lock, flags);
 	b43legacy_adjust_opmode(dev);
 	b43legacy_adjust_opmode(dev);
@@ -3403,18 +3403,18 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
 }
 }
 
 
 static void b43legacy_op_remove_interface(struct ieee80211_hw *hw,
 static void b43legacy_op_remove_interface(struct ieee80211_hw *hw,
-					  struct ieee80211_if_init_conf *conf)
+					  struct ieee80211_vif *vif)
 {
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
 	struct b43legacy_wldev *dev = wl->current_dev;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+	b43legacydbg(wl, "Removing Interface type %d\n", vif->type);
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
 	B43legacy_WARN_ON(!wl->operating);
 	B43legacy_WARN_ON(!wl->operating);
-	B43legacy_WARN_ON(wl->vif != conf->vif);
+	B43legacy_WARN_ON(wl->vif != vif);
 	wl->vif = NULL;
 	wl->vif = NULL;
 
 
 	wl->operating = 0;
 	wl->operating = 0;

+ 2 - 8
drivers/net/wireless/iwlwifi/iwl-3945.c

@@ -681,19 +681,13 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 		snr = rx_stats_sig_avg / rx_stats_noise_diff;
 		snr = rx_stats_sig_avg / rx_stats_noise_diff;
 		rx_status.noise = rx_status.signal -
 		rx_status.noise = rx_status.signal -
 					iwl3945_calc_db_from_ratio(snr);
 					iwl3945_calc_db_from_ratio(snr);
-		rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal,
-							 rx_status.noise);
-
-	/* If noise info not available, calculate signal quality indicator (%)
-	 *   using just the dBm signal level. */
 	} else {
 	} else {
 		rx_status.noise = priv->last_rx_noise;
 		rx_status.noise = priv->last_rx_noise;
-		rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0);
 	}
 	}
 
 
 
 
-	IWL_DEBUG_STATS(priv, "Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
-			rx_status.signal, rx_status.noise, rx_status.qual,
+	IWL_DEBUG_STATS(priv, "Rssi %d noise %d sig_avg %d noise_diff %d\n",
+			rx_status.signal, rx_status.noise,
 			rx_stats_sig_avg, rx_stats_noise_diff);
 			rx_stats_sig_avg, rx_stats_noise_diff);
 
 
 	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);

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

@@ -222,7 +222,6 @@ struct iwl3945_ibss_seq {
  *
  *
  *****************************************************************************/
  *****************************************************************************/
 extern int iwl3945_calc_db_from_ratio(int sig_ratio);
 extern int iwl3945_calc_db_from_ratio(int sig_ratio);
-extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
 extern void iwl3945_rx_replenish(void *data);
 extern void iwl3945_rx_replenish(void *data);
 extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,

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

@@ -150,7 +150,7 @@ static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
 };
 };
 
 
 /* mbps, mcs */
 /* mbps, mcs */
-const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
+static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
 	{  "1", "BPSK DSSS"},
 	{  "1", "BPSK DSSS"},
 	{  "2", "QPSK DSSS"},
 	{  "2", "QPSK DSSS"},
 	{"5.5", "BPSK CCK"},
 	{"5.5", "BPSK CCK"},

+ 10 - 10
drivers/net/wireless/iwlwifi/iwl-core.c

@@ -2584,12 +2584,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode)
 EXPORT_SYMBOL(iwl_set_mode);
 EXPORT_SYMBOL(iwl_set_mode);
 
 
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
-				 struct ieee80211_if_init_conf *conf)
+				 struct ieee80211_vif *vif)
 {
 {
 	struct iwl_priv *priv = hw->priv;
 	struct iwl_priv *priv = hw->priv;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
+	IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
 
 
 	if (priv->vif) {
 	if (priv->vif) {
 		IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
 		IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
@@ -2597,19 +2597,19 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
 	}
 	}
 
 
 	spin_lock_irqsave(&priv->lock, flags);
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->vif = conf->vif;
-	priv->iw_mode = conf->type;
+	priv->vif = vif;
+	priv->iw_mode = vif->type;
 
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 
 	mutex_lock(&priv->mutex);
 	mutex_lock(&priv->mutex);
 
 
-	if (conf->mac_addr) {
-		IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
-		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+	if (vif->addr) {
+		IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
+		memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
 	}
 	}
 
 
-	if (iwl_set_mode(priv, conf->type) == -EAGAIN)
+	if (iwl_set_mode(priv, vif->type) == -EAGAIN)
 		/* we are not ready, will run again when ready */
 		/* we are not ready, will run again when ready */
 		set_bit(STATUS_MODE_PENDING, &priv->status);
 		set_bit(STATUS_MODE_PENDING, &priv->status);
 
 
@@ -2621,7 +2621,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
 EXPORT_SYMBOL(iwl_mac_add_interface);
 EXPORT_SYMBOL(iwl_mac_add_interface);
 
 
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
-				     struct ieee80211_if_init_conf *conf)
+				     struct ieee80211_vif *vif)
 {
 {
 	struct iwl_priv *priv = hw->priv;
 	struct iwl_priv *priv = hw->priv;
 
 
@@ -2634,7 +2634,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		iwlcore_commit_rxon(priv);
 		iwlcore_commit_rxon(priv);
 	}
 	}
-	if (priv->vif == conf->vif) {
+	if (priv->vif == vif) {
 		priv->vif = NULL;
 		priv->vif = NULL;
 		memset(priv->bssid, 0, ETH_ALEN);
 		memset(priv->bssid, 0, ETH_ALEN);
 	}
 	}

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

@@ -332,9 +332,9 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
 int iwl_commit_rxon(struct iwl_priv *priv);
 int iwl_commit_rxon(struct iwl_priv *priv);
 int iwl_set_mode(struct iwl_priv *priv, int mode);
 int iwl_set_mode(struct iwl_priv *priv, int mode);
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
-				 struct ieee80211_if_init_conf *conf);
+			  struct ieee80211_vif *vif);
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
-				 struct ieee80211_if_init_conf *conf);
+			      struct ieee80211_vif *vif);
 int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
 int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
 void iwl_config_ap(struct iwl_priv *priv);
 void iwl_config_ap(struct iwl_priv *priv);
 int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,

+ 2 - 46
drivers/net/wireless/iwlwifi/iwl-rx.c

@@ -650,47 +650,6 @@ void iwl_reply_statistics(struct iwl_priv *priv,
 }
 }
 EXPORT_SYMBOL(iwl_reply_statistics);
 EXPORT_SYMBOL(iwl_reply_statistics);
 
 
-#define PERFECT_RSSI (-20) /* dBm */
-#define WORST_RSSI (-95)   /* dBm */
-#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
-
-/* Calculate an indication of rx signal quality (a percentage, not dBm!).
- * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
- *   about formulas used below. */
-static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
-{
-	int sig_qual;
-	int degradation = PERFECT_RSSI - rssi_dbm;
-
-	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
-	 * as indicator; formula is (signal dbm - noise dbm).
-	 * SNR at or above 40 is a great signal (100%).
-	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
-	 * Weakest usable signal is usually 10 - 15 dB SNR. */
-	if (noise_dbm) {
-		if (rssi_dbm - noise_dbm >= 40)
-			return 100;
-		else if (rssi_dbm < noise_dbm)
-			return 0;
-		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
-
-	/* Else use just the signal level.
-	 * This formula is a least squares fit of data points collected and
-	 *   compared with a reference system that had a percentage (%) display
-	 *   for signal quality. */
-	} else
-		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
-			    (15 * RSSI_RANGE + 62 * degradation)) /
-			   (RSSI_RANGE * RSSI_RANGE);
-
-	if (sig_qual > 100)
-		sig_qual = 100;
-	else if (sig_qual < 1)
-		sig_qual = 0;
-
-	return sig_qual;
-}
-
 /* Calc max signal level (dBm) among 3 possible receivers */
 /* Calc max signal level (dBm) among 3 possible receivers */
 static inline int iwl_calc_rssi(struct iwl_priv *priv,
 static inline int iwl_calc_rssi(struct iwl_priv *priv,
 				struct iwl_rx_phy_res *rx_resp)
 				struct iwl_rx_phy_res *rx_resp)
@@ -1101,11 +1060,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 	if (iwl_is_associated(priv) &&
 	if (iwl_is_associated(priv) &&
 	    !test_bit(STATUS_SCANNING, &priv->status)) {
 	    !test_bit(STATUS_SCANNING, &priv->status)) {
 		rx_status.noise = priv->last_rx_noise;
 		rx_status.noise = priv->last_rx_noise;
-		rx_status.qual = iwl_calc_sig_qual(rx_status.signal,
-							 rx_status.noise);
 	} else {
 	} else {
 		rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 		rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-		rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0);
 	}
 	}
 
 
 	/* Reset beacon noise level if not associated. */
 	/* Reset beacon noise level if not associated. */
@@ -1118,8 +1074,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 		iwl_dbg_report_frame(priv, phy_res, len, header, 1);
 		iwl_dbg_report_frame(priv, phy_res, len, header, 1);
 #endif
 #endif
 	iwl_dbg_log_rx_data_frame(priv, len, header);
 	iwl_dbg_log_rx_data_frame(priv, len, header);
-	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
-		rx_status.signal, rx_status.noise, rx_status.qual,
+	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n",
+		rx_status.signal, rx_status.noise,
 		(unsigned long long)rx_status.mactime);
 		(unsigned long long)rx_status.mactime);
 
 
 	/*
 	/*

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

@@ -1299,47 +1299,6 @@ int iwl3945_calc_db_from_ratio(int sig_ratio)
 	return (int)ratio2dB[sig_ratio];
 	return (int)ratio2dB[sig_ratio];
 }
 }
 
 
-#define PERFECT_RSSI (-20) /* dBm */
-#define WORST_RSSI (-95)   /* dBm */
-#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
-
-/* Calculate an indication of rx signal quality (a percentage, not dBm!).
- * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
- *   about formulas used below. */
-int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm)
-{
-	int sig_qual;
-	int degradation = PERFECT_RSSI - rssi_dbm;
-
-	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
-	 * as indicator; formula is (signal dbm - noise dbm).
-	 * SNR at or above 40 is a great signal (100%).
-	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
-	 * Weakest usable signal is usually 10 - 15 dB SNR. */
-	if (noise_dbm) {
-		if (rssi_dbm - noise_dbm >= 40)
-			return 100;
-		else if (rssi_dbm < noise_dbm)
-			return 0;
-		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
-
-	/* Else use just the signal level.
-	 * This formula is a least squares fit of data points collected and
-	 *   compared with a reference system that had a percentage (%) display
-	 *   for signal quality. */
-	} else
-		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
-			    (15 * RSSI_RANGE + 62 * degradation)) /
-			   (RSSI_RANGE * RSSI_RANGE);
-
-	if (sig_qual > 100)
-		sig_qual = 100;
-	else if (sig_qual < 1)
-		sig_qual = 0;
-
-	return sig_qual;
-}
-
 /**
 /**
  * iwl3945_rx_handle - Main entry function for receiving responses from uCode
  * iwl3945_rx_handle - Main entry function for receiving responses from uCode
  *
  *

+ 1 - 1
drivers/net/wireless/iwmc3200wifi/iwm.h

@@ -268,7 +268,7 @@ struct iwm_priv {
 
 
 	struct sk_buff_head rx_list;
 	struct sk_buff_head rx_list;
 	struct list_head rx_tickets;
 	struct list_head rx_tickets;
-	struct list_head rx_packets[IWM_RX_ID_HASH];
+	struct list_head rx_packets[IWM_RX_ID_HASH + 1];
 	struct workqueue_struct *rx_wq;
 	struct workqueue_struct *rx_wq;
 	struct work_struct rx_worker;
 	struct work_struct rx_worker;
 
 

+ 8 - 14
drivers/net/wireless/libertas/scan.c

@@ -567,11 +567,8 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan)
 	chan_count = lbs_scan_create_channel_list(priv, chan_list);
 	chan_count = lbs_scan_create_channel_list(priv, chan_list);
 
 
 	netif_stop_queue(priv->dev);
 	netif_stop_queue(priv->dev);
-	netif_carrier_off(priv->dev);
-	if (priv->mesh_dev) {
+	if (priv->mesh_dev)
 		netif_stop_queue(priv->mesh_dev);
 		netif_stop_queue(priv->mesh_dev);
-		netif_carrier_off(priv->mesh_dev);
-	}
 
 
 	/* Prepare to continue an interrupted scan */
 	/* Prepare to continue an interrupted scan */
 	lbs_deb_scan("chan_count %d, scan_channel %d\n",
 	lbs_deb_scan("chan_count %d, scan_channel %d\n",
@@ -635,16 +632,13 @@ out2:
 	priv->scan_channel = 0;
 	priv->scan_channel = 0;
 
 
 out:
 out:
-	if (priv->connect_status == LBS_CONNECTED) {
-		netif_carrier_on(priv->dev);
-		if (!priv->tx_pending_len)
-			netif_wake_queue(priv->dev);
-	}
-	if (priv->mesh_dev && lbs_mesh_connected(priv)) {
-		netif_carrier_on(priv->mesh_dev);
-		if (!priv->tx_pending_len)
-			netif_wake_queue(priv->mesh_dev);
-	}
+	if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
+		netif_wake_queue(priv->dev);
+
+	if (priv->mesh_dev && lbs_mesh_connected(priv) &&
+	    !priv->tx_pending_len)
+		netif_wake_queue(priv->mesh_dev);
+
 	kfree(chan_list);
 	kfree(chan_list);
 
 
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);

+ 5 - 6
drivers/net/wireless/libertas_tf/main.c

@@ -318,14 +318,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
 }
 }
 
 
 static int lbtf_op_add_interface(struct ieee80211_hw *hw,
 static int lbtf_op_add_interface(struct ieee80211_hw *hw,
-			struct ieee80211_if_init_conf *conf)
+			struct ieee80211_vif *vif)
 {
 {
 	struct lbtf_private *priv = hw->priv;
 	struct lbtf_private *priv = hw->priv;
 	if (priv->vif != NULL)
 	if (priv->vif != NULL)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
-	priv->vif = conf->vif;
-	switch (conf->type) {
+	priv->vif = vif;
+	switch (vif->type) {
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP:
 		lbtf_set_mode(priv, LBTF_AP_MODE);
 		lbtf_set_mode(priv, LBTF_AP_MODE);
@@ -337,12 +337,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
 		priv->vif = NULL;
 		priv->vif = NULL;
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	}
 	}
-	lbtf_set_mac_address(priv, (u8 *) conf->mac_addr);
+	lbtf_set_mac_address(priv, (u8 *) vif->addr);
 	return 0;
 	return 0;
 }
 }
 
 
 static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
 static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
-			struct ieee80211_if_init_conf *conf)
+			struct ieee80211_vif *vif)
 {
 {
 	struct lbtf_private *priv = hw->priv;
 	struct lbtf_private *priv = hw->priv;
 
 
@@ -495,7 +495,6 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
 	stats.band = IEEE80211_BAND_2GHZ;
 	stats.band = IEEE80211_BAND_2GHZ;
 	stats.signal = prxpd->snr;
 	stats.signal = prxpd->snr;
 	stats.noise = prxpd->nf;
 	stats.noise = prxpd->nf;
-	stats.qual = prxpd->snr - prxpd->nf;
 	/* Marvell rate index has a hole at value 4 */
 	/* Marvell rate index has a hole at value 4 */
 	if (prxpd->rx_rate > 4)
 	if (prxpd->rx_rate > 4)
 		--prxpd->rx_rate;
 		--prxpd->rx_rate;

+ 20 - 9
drivers/net/wireless/mac80211_hwsim.c

@@ -584,24 +584,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
 
 
 
 
 static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
 static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
-					struct ieee80211_if_init_conf *conf)
+					struct ieee80211_vif *vif)
 {
 {
 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
-	       wiphy_name(hw->wiphy), __func__, conf->type,
-	       conf->mac_addr);
-	hwsim_set_magic(conf->vif);
+	       wiphy_name(hw->wiphy), __func__, vif->type,
+	       vif->addr);
+	hwsim_set_magic(vif);
 	return 0;
 	return 0;
 }
 }
 
 
 
 
 static void mac80211_hwsim_remove_interface(
 static void mac80211_hwsim_remove_interface(
-	struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
+	struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
 {
 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
-	       wiphy_name(hw->wiphy), __func__, conf->type,
-	       conf->mac_addr);
-	hwsim_check_magic(conf->vif);
-	hwsim_clear_magic(conf->vif);
+	       wiphy_name(hw->wiphy), __func__, vif->type,
+	       vif->addr);
+	hwsim_check_magic(vif);
+	hwsim_clear_magic(vif);
 }
 }
 
 
 
 
@@ -896,6 +896,16 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
 	return 0;
 	return 0;
 }
 }
 
 
+static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
+{
+	/*
+	 * In this special case, there's nothing we need to
+	 * do because hwsim does transmission synchronously.
+	 * In the future, when it does transmissions via
+	 * userspace, we may need to do something.
+	 */
+}
+
 
 
 static const struct ieee80211_ops mac80211_hwsim_ops =
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
 {
@@ -912,6 +922,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
 	.conf_tx = mac80211_hwsim_conf_tx,
 	.conf_tx = mac80211_hwsim_conf_tx,
 	CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
 	CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
 	.ampdu_action = mac80211_hwsim_ampdu_action,
 	.ampdu_action = mac80211_hwsim_ampdu_action,
+	.flush = mac80211_hwsim_flush,
 };
 };
 
 
 
 

+ 477 - 535
drivers/net/wireless/mwl8k.c

@@ -92,8 +92,7 @@ struct mwl8k_device_info {
 	char *part_name;
 	char *part_name;
 	char *helper_image;
 	char *helper_image;
 	char *fw_image;
 	char *fw_image;
-	struct rxd_ops *rxd_ops;
-	u16 modes;
+	struct rxd_ops *ap_rxd_ops;
 };
 };
 
 
 struct mwl8k_rx_queue {
 struct mwl8k_rx_queue {
@@ -126,29 +125,23 @@ struct mwl8k_tx_queue {
 	struct sk_buff **skb;
 	struct sk_buff **skb;
 };
 };
 
 
-/* Pointers to the firmware data and meta information about it.  */
-struct mwl8k_firmware {
-	/* Boot helper code */
-	struct firmware *helper;
+struct mwl8k_priv {
+	struct ieee80211_hw *hw;
+	struct pci_dev *pdev;
 
 
-	/* Microcode */
-	struct firmware *ucode;
-};
+	struct mwl8k_device_info *device_info;
 
 
-struct mwl8k_priv {
 	void __iomem *sram;
 	void __iomem *sram;
 	void __iomem *regs;
 	void __iomem *regs;
-	struct ieee80211_hw *hw;
 
 
-	struct pci_dev *pdev;
+	/* firmware */
+	struct firmware *fw_helper;
+	struct firmware *fw_ucode;
 
 
-	struct mwl8k_device_info *device_info;
+	/* hardware/firmware parameters */
 	bool ap_fw;
 	bool ap_fw;
 	struct rxd_ops *rxd_ops;
 	struct rxd_ops *rxd_ops;
 
 
-	/* firmware files and meta data */
-	struct mwl8k_firmware fw;
-
 	/* firmware access */
 	/* firmware access */
 	struct mutex fw_mutex;
 	struct mutex fw_mutex;
 	struct task_struct *fw_mutex_owner;
 	struct task_struct *fw_mutex_owner;
@@ -211,17 +204,13 @@ struct mwl8k_priv {
 
 
 /* Per interface specific private data */
 /* Per interface specific private data */
 struct mwl8k_vif {
 struct mwl8k_vif {
-	/* backpointer to parent config block */
-	struct mwl8k_priv *priv;
+	/* Local MAC address.  */
+	u8 mac_addr[ETH_ALEN];
 
 
-	/* BSS config of AP or IBSS from mac80211*/
-	struct ieee80211_bss_conf bss_info;
+	/* BSSID of AP.  */
+	u8 bssid[ETH_ALEN];
 
 
-	/* BSSID of AP or IBSS */
-	u8	bssid[ETH_ALEN];
-	u8	mac_addr[ETH_ALEN];
-
-	 /* Index into station database.Returned by update_sta_db call */
+	/* Index into station database. Returned by UPDATE_STADB.  */
 	u8	peer_id;
 	u8	peer_id;
 
 
 	/* Non AMPDU sequence number assigned by driver */
 	/* Non AMPDU sequence number assigned by driver */
@@ -242,6 +231,9 @@ static const struct ieee80211_channel mwl8k_channels[] = {
 	{ .center_freq = 2452, .hw_value = 9, },
 	{ .center_freq = 2452, .hw_value = 9, },
 	{ .center_freq = 2457, .hw_value = 10, },
 	{ .center_freq = 2457, .hw_value = 10, },
 	{ .center_freq = 2462, .hw_value = 11, },
 	{ .center_freq = 2462, .hw_value = 11, },
+	{ .center_freq = 2467, .hw_value = 12, },
+	{ .center_freq = 2472, .hw_value = 13, },
+	{ .center_freq = 2484, .hw_value = 14, },
 };
 };
 
 
 static const struct ieee80211_rate mwl8k_rates[] = {
 static const struct ieee80211_rate mwl8k_rates[] = {
@@ -355,8 +347,8 @@ static void mwl8k_release_fw(struct firmware **fw)
 
 
 static void mwl8k_release_firmware(struct mwl8k_priv *priv)
 static void mwl8k_release_firmware(struct mwl8k_priv *priv)
 {
 {
-	mwl8k_release_fw(&priv->fw.ucode);
-	mwl8k_release_fw(&priv->fw.helper);
+	mwl8k_release_fw(&priv->fw_ucode);
+	mwl8k_release_fw(&priv->fw_helper);
 }
 }
 
 
 /* Request fw image */
 /* Request fw image */
@@ -377,7 +369,7 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
 	int rc;
 	int rc;
 
 
 	if (di->helper_image != NULL) {
 	if (di->helper_image != NULL) {
-		rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper);
+		rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper);
 		if (rc) {
 		if (rc) {
 			printk(KERN_ERR "%s: Error requesting helper "
 			printk(KERN_ERR "%s: Error requesting helper "
 			       "firmware file %s\n", pci_name(priv->pdev),
 			       "firmware file %s\n", pci_name(priv->pdev),
@@ -386,11 +378,11 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
 		}
 		}
 	}
 	}
 
 
-	rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode);
+	rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode);
 	if (rc) {
 	if (rc) {
 		printk(KERN_ERR "%s: Error requesting firmware file %s\n",
 		printk(KERN_ERR "%s: Error requesting firmware file %s\n",
 		       pci_name(priv->pdev), di->fw_image);
 		       pci_name(priv->pdev), di->fw_image);
-		mwl8k_release_fw(&priv->fw.helper);
+		mwl8k_release_fw(&priv->fw_helper);
 		return rc;
 		return rc;
 	}
 	}
 
 
@@ -551,13 +543,12 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv,
 static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 {
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_priv *priv = hw->priv;
-	struct firmware *fw = priv->fw.ucode;
-	struct mwl8k_device_info *di = priv->device_info;
+	struct firmware *fw = priv->fw_ucode;
 	int rc;
 	int rc;
 	int loops;
 	int loops;
 
 
 	if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
 	if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
-		struct firmware *helper = priv->fw.helper;
+		struct firmware *helper = priv->fw_helper;
 
 
 		if (helper == NULL) {
 		if (helper == NULL) {
 			printk(KERN_ERR "%s: helper image needed but none "
 			printk(KERN_ERR "%s: helper image needed but none "
@@ -584,10 +575,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 		return rc;
 		return rc;
 	}
 	}
 
 
-	if (di->modes & BIT(NL80211_IFTYPE_AP))
-		iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR);
-	else
-		iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
+	iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
 
 
 	loops = 500000;
 	loops = 500000;
 	do {
 	do {
@@ -658,43 +646,6 @@ struct peer_capability_info {
 	__le16	amsdu_enabled;
 	__le16	amsdu_enabled;
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-/* Inline functions to manipulate QoS field in data descriptor.  */
-static inline u16 mwl8k_qos_setbit_eosp(u16 qos)
-{
-	u16 val_mask = 1 << 4;
-
-	/* End of Service Period Bit 4 */
-	return qos | val_mask;
-}
-
-static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy)
-{
-	u16 val_mask = 0x3;
-	u8	shift = 5;
-	u16 qos_mask = ~(val_mask << shift);
-
-	/* Ack Policy Bit 5-6 */
-	return (qos & qos_mask) | ((ack_policy & val_mask) << shift);
-}
-
-static inline u16 mwl8k_qos_setbit_amsdu(u16 qos)
-{
-	u16 val_mask = 1 << 7;
-
-	/* AMSDU present Bit 7 */
-	return qos | val_mask;
-}
-
-static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len)
-{
-	u16 val_mask = 0xff;
-	u8	shift = 8;
-	u16 qos_mask = ~(val_mask << shift);
-
-	/* Queue Length Bits 8-15 */
-	return (qos & qos_mask) | ((len & val_mask) << shift);
-}
-
 /* DMA header used by firmware and hardware.  */
 /* DMA header used by firmware and hardware.  */
 struct mwl8k_dma_data {
 struct mwl8k_dma_data {
 	__le16 fwlen;
 	__le16 fwlen;
@@ -761,9 +712,9 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
 
 
 
 
 /*
 /*
- * Packet reception for 88w8366.
+ * Packet reception for 88w8366 AP firmware.
  */
  */
-struct mwl8k_rxd_8366 {
+struct mwl8k_rxd_8366_ap {
 	__le16 pkt_len;
 	__le16 pkt_len;
 	__u8 sq2;
 	__u8 sq2;
 	__u8 rate;
 	__u8 rate;
@@ -781,23 +732,23 @@ struct mwl8k_rxd_8366 {
 	__u8 rx_ctrl;
 	__u8 rx_ctrl;
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-#define MWL8K_8366_RATE_INFO_MCS_FORMAT		0x80
-#define MWL8K_8366_RATE_INFO_40MHZ		0x40
-#define MWL8K_8366_RATE_INFO_RATEID(x)		((x) & 0x3f)
+#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT	0x80
+#define MWL8K_8366_AP_RATE_INFO_40MHZ		0x40
+#define MWL8K_8366_AP_RATE_INFO_RATEID(x)	((x) & 0x3f)
 
 
-#define MWL8K_8366_RX_CTRL_OWNED_BY_HOST	0x80
+#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST	0x80
 
 
-static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
 {
 {
-	struct mwl8k_rxd_8366 *rxd = _rxd;
+	struct mwl8k_rxd_8366_ap *rxd = _rxd;
 
 
 	rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
 	rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
-	rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST;
+	rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST;
 }
 }
 
 
-static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
 {
 {
-	struct mwl8k_rxd_8366 *rxd = _rxd;
+	struct mwl8k_rxd_8366_ap *rxd = _rxd;
 
 
 	rxd->pkt_len = cpu_to_le16(len);
 	rxd->pkt_len = cpu_to_le16(len);
 	rxd->pkt_phys_addr = cpu_to_le32(addr);
 	rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -806,12 +757,12 @@ static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
 }
 }
 
 
 static int
 static int
-mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
-		       __le16 *qos)
+mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
+			  __le16 *qos)
 {
 {
-	struct mwl8k_rxd_8366 *rxd = _rxd;
+	struct mwl8k_rxd_8366_ap *rxd = _rxd;
 
 
-	if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST))
+	if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST))
 		return -1;
 		return -1;
 	rmb();
 	rmb();
 
 
@@ -820,11 +771,11 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
 	status->signal = -rxd->rssi;
 	status->signal = -rxd->rssi;
 	status->noise = -rxd->noise_floor;
 	status->noise = -rxd->noise_floor;
 
 
-	if (rxd->rate & MWL8K_8366_RATE_INFO_MCS_FORMAT) {
+	if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
 		status->flag |= RX_FLAG_HT;
 		status->flag |= RX_FLAG_HT;
-		if (rxd->rate & MWL8K_8366_RATE_INFO_40MHZ)
+		if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ)
 			status->flag |= RX_FLAG_40MHZ;
 			status->flag |= RX_FLAG_40MHZ;
-		status->rate_idx = MWL8K_8366_RATE_INFO_RATEID(rxd->rate);
+		status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate);
 	} else {
 	} else {
 		int i;
 		int i;
 
 
@@ -844,17 +795,17 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
 	return le16_to_cpu(rxd->pkt_len);
 	return le16_to_cpu(rxd->pkt_len);
 }
 }
 
 
-static struct rxd_ops rxd_8366_ops = {
-	.rxd_size	= sizeof(struct mwl8k_rxd_8366),
-	.rxd_init	= mwl8k_rxd_8366_init,
-	.rxd_refill	= mwl8k_rxd_8366_refill,
-	.rxd_process	= mwl8k_rxd_8366_process,
+static struct rxd_ops rxd_8366_ap_ops = {
+	.rxd_size	= sizeof(struct mwl8k_rxd_8366_ap),
+	.rxd_init	= mwl8k_rxd_8366_ap_init,
+	.rxd_refill	= mwl8k_rxd_8366_ap_refill,
+	.rxd_process	= mwl8k_rxd_8366_ap_process,
 };
 };
 
 
 /*
 /*
- * Packet reception for 88w8687.
+ * Packet reception for STA firmware.
  */
  */
-struct mwl8k_rxd_8687 {
+struct mwl8k_rxd_sta {
 	__le16 pkt_len;
 	__le16 pkt_len;
 	__u8 link_quality;
 	__u8 link_quality;
 	__u8 noise_level;
 	__u8 noise_level;
@@ -871,26 +822,26 @@ struct mwl8k_rxd_8687 {
 	__u8 pad2[2];
 	__u8 pad2[2];
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-#define MWL8K_8687_RATE_INFO_SHORTPRE		0x8000
-#define MWL8K_8687_RATE_INFO_ANTSELECT(x)	(((x) >> 11) & 0x3)
-#define MWL8K_8687_RATE_INFO_RATEID(x)		(((x) >> 3) & 0x3f)
-#define MWL8K_8687_RATE_INFO_40MHZ		0x0004
-#define MWL8K_8687_RATE_INFO_SHORTGI		0x0002
-#define MWL8K_8687_RATE_INFO_MCS_FORMAT		0x0001
+#define MWL8K_STA_RATE_INFO_SHORTPRE		0x8000
+#define MWL8K_STA_RATE_INFO_ANTSELECT(x)	(((x) >> 11) & 0x3)
+#define MWL8K_STA_RATE_INFO_RATEID(x)		(((x) >> 3) & 0x3f)
+#define MWL8K_STA_RATE_INFO_40MHZ		0x0004
+#define MWL8K_STA_RATE_INFO_SHORTGI		0x0002
+#define MWL8K_STA_RATE_INFO_MCS_FORMAT		0x0001
 
 
-#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST	0x02
+#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST		0x02
 
 
-static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr)
 {
 {
-	struct mwl8k_rxd_8687 *rxd = _rxd;
+	struct mwl8k_rxd_sta *rxd = _rxd;
 
 
 	rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
 	rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
-	rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST;
+	rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST;
 }
 }
 
 
-static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len)
 {
 {
-	struct mwl8k_rxd_8687 *rxd = _rxd;
+	struct mwl8k_rxd_sta *rxd = _rxd;
 
 
 	rxd->pkt_len = cpu_to_le16(len);
 	rxd->pkt_len = cpu_to_le16(len);
 	rxd->pkt_phys_addr = cpu_to_le32(addr);
 	rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -899,13 +850,13 @@ static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
 }
 }
 
 
 static int
 static int
-mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
+mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
 		       __le16 *qos)
 		       __le16 *qos)
 {
 {
-	struct mwl8k_rxd_8687 *rxd = _rxd;
+	struct mwl8k_rxd_sta *rxd = _rxd;
 	u16 rate_info;
 	u16 rate_info;
 
 
-	if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST))
+	if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST))
 		return -1;
 		return -1;
 	rmb();
 	rmb();
 
 
@@ -915,16 +866,16 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
 
 
 	status->signal = -rxd->rssi;
 	status->signal = -rxd->rssi;
 	status->noise = -rxd->noise_level;
 	status->noise = -rxd->noise_level;
-	status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info);
-	status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info);
+	status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info);
+	status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info);
 
 
-	if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE)
+	if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE)
 		status->flag |= RX_FLAG_SHORTPRE;
 		status->flag |= RX_FLAG_SHORTPRE;
-	if (rate_info & MWL8K_8687_RATE_INFO_40MHZ)
+	if (rate_info & MWL8K_STA_RATE_INFO_40MHZ)
 		status->flag |= RX_FLAG_40MHZ;
 		status->flag |= RX_FLAG_40MHZ;
-	if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI)
+	if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI)
 		status->flag |= RX_FLAG_SHORT_GI;
 		status->flag |= RX_FLAG_SHORT_GI;
-	if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT)
+	if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT)
 		status->flag |= RX_FLAG_HT;
 		status->flag |= RX_FLAG_HT;
 
 
 	status->band = IEEE80211_BAND_2GHZ;
 	status->band = IEEE80211_BAND_2GHZ;
@@ -935,11 +886,11 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
 	return le16_to_cpu(rxd->pkt_len);
 	return le16_to_cpu(rxd->pkt_len);
 }
 }
 
 
-static struct rxd_ops rxd_8687_ops = {
-	.rxd_size	= sizeof(struct mwl8k_rxd_8687),
-	.rxd_init	= mwl8k_rxd_8687_init,
-	.rxd_refill	= mwl8k_rxd_8687_refill,
-	.rxd_process	= mwl8k_rxd_8687_process,
+static struct rxd_ops rxd_sta_ops = {
+	.rxd_size	= sizeof(struct mwl8k_rxd_sta),
+	.rxd_init	= mwl8k_rxd_sta_init,
+	.rxd_refill	= mwl8k_rxd_sta_refill,
+	.rxd_process	= mwl8k_rxd_sta_process,
 };
 };
 
 
 
 
@@ -1153,16 +1104,18 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
  * Packet transmission.
  * Packet transmission.
  */
  */
 
 
-/* Transmit packet ACK policy */
-#define MWL8K_TXD_ACK_POLICY_NORMAL		0
-#define MWL8K_TXD_ACK_POLICY_BLOCKACK		3
-
 #define MWL8K_TXD_STATUS_OK			0x00000001
 #define MWL8K_TXD_STATUS_OK			0x00000001
 #define MWL8K_TXD_STATUS_OK_RETRY		0x00000002
 #define MWL8K_TXD_STATUS_OK_RETRY		0x00000002
 #define MWL8K_TXD_STATUS_OK_MORE_RETRY		0x00000004
 #define MWL8K_TXD_STATUS_OK_MORE_RETRY		0x00000004
 #define MWL8K_TXD_STATUS_MULTICAST_TX		0x00000008
 #define MWL8K_TXD_STATUS_MULTICAST_TX		0x00000008
 #define MWL8K_TXD_STATUS_FW_OWNED		0x80000000
 #define MWL8K_TXD_STATUS_FW_OWNED		0x80000000
 
 
+#define MWL8K_QOS_QLEN_UNSPEC			0xff00
+#define MWL8K_QOS_ACK_POLICY_MASK		0x0060
+#define MWL8K_QOS_ACK_POLICY_NORMAL		0x0000
+#define MWL8K_QOS_ACK_POLICY_BLOCKACK		0x0060
+#define MWL8K_QOS_EOSP				0x0010
+
 struct mwl8k_tx_desc {
 struct mwl8k_tx_desc {
 	__le32 status;
 	__le32 status;
 	__u8 data_rate;
 	__u8 data_rate;
@@ -1459,24 +1412,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	if (ieee80211_is_mgmt(wh->frame_control) ||
 	if (ieee80211_is_mgmt(wh->frame_control) ||
 	    ieee80211_is_ctl(wh->frame_control)) {
 	    ieee80211_is_ctl(wh->frame_control)) {
 		txdatarate = 0;
 		txdatarate = 0;
-		qos = mwl8k_qos_setbit_eosp(qos);
-		/* Set Queue size to unspecified */
-		qos = mwl8k_qos_setbit_qlen(qos, 0xff);
+		qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP;
 	} else if (ieee80211_is_data(wh->frame_control)) {
 	} else if (ieee80211_is_data(wh->frame_control)) {
 		txdatarate = 1;
 		txdatarate = 1;
 		if (is_multicast_ether_addr(wh->addr1))
 		if (is_multicast_ether_addr(wh->addr1))
 			txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX;
 			txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX;
 
 
-		/* Send pkt in an aggregate if AMPDU frame.  */
+		qos &= ~MWL8K_QOS_ACK_POLICY_MASK;
 		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
 		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
-			qos = mwl8k_qos_setbit_ack(qos,
-				MWL8K_TXD_ACK_POLICY_BLOCKACK);
+			qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK;
 		else
 		else
-			qos = mwl8k_qos_setbit_ack(qos,
-				MWL8K_TXD_ACK_POLICY_NORMAL);
-
-		if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
-			qos = mwl8k_qos_setbit_amsdu(qos);
+			qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
 	}
 	}
 
 
 	dma = pci_map_single(priv->pdev, skb->data,
 	dma = pci_map_single(priv->pdev, skb->data,
@@ -1897,9 +1843,9 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
 }
 }
 
 
 /*
 /*
- * CMD_802_11_GET_STAT.
+ * CMD_GET_STAT.
  */
  */
-struct mwl8k_cmd_802_11_get_stat {
+struct mwl8k_cmd_get_stat {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
 	__le32 stats[64];
 	__le32 stats[64];
 } __attribute__((packed));
 } __attribute__((packed));
@@ -1909,10 +1855,10 @@ struct mwl8k_cmd_802_11_get_stat {
 #define MWL8K_STAT_FCS_ERROR	24
 #define MWL8K_STAT_FCS_ERROR	24
 #define MWL8K_STAT_RTS_SUCCESS	11
 #define MWL8K_STAT_RTS_SUCCESS	11
 
 
-static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
-				struct ieee80211_low_level_stats *stats)
+static int mwl8k_cmd_get_stat(struct ieee80211_hw *hw,
+			      struct ieee80211_low_level_stats *stats)
 {
 {
-	struct mwl8k_cmd_802_11_get_stat *cmd;
+	struct mwl8k_cmd_get_stat *cmd;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -1939,9 +1885,9 @@ static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
 }
 }
 
 
 /*
 /*
- * CMD_802_11_RADIO_CONTROL.
+ * CMD_RADIO_CONTROL.
  */
  */
-struct mwl8k_cmd_802_11_radio_control {
+struct mwl8k_cmd_radio_control {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
 	__le16 action;
 	__le16 control;
 	__le16 control;
@@ -1949,10 +1895,10 @@ struct mwl8k_cmd_802_11_radio_control {
 } __attribute__((packed));
 } __attribute__((packed));
 
 
 static int
 static int
-mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
+mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
 {
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_priv *priv = hw->priv;
-	struct mwl8k_cmd_802_11_radio_control *cmd;
+	struct mwl8k_cmd_radio_control *cmd;
 	int rc;
 	int rc;
 
 
 	if (enable == priv->radio_on && !force)
 	if (enable == priv->radio_on && !force)
@@ -1977,36 +1923,32 @@ mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
 	return rc;
 	return rc;
 }
 }
 
 
-static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw)
+static int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw)
 {
 {
-	return mwl8k_cmd_802_11_radio_control(hw, 0, 0);
+	return mwl8k_cmd_radio_control(hw, 0, 0);
 }
 }
 
 
-static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw)
+static int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw)
 {
 {
-	return mwl8k_cmd_802_11_radio_control(hw, 1, 0);
+	return mwl8k_cmd_radio_control(hw, 1, 0);
 }
 }
 
 
 static int
 static int
 mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
 mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
 {
 {
-	struct mwl8k_priv *priv;
-
-	if (hw == NULL || hw->priv == NULL)
-		return -EINVAL;
-	priv = hw->priv;
+	struct mwl8k_priv *priv = hw->priv;
 
 
 	priv->radio_short_preamble = short_preamble;
 	priv->radio_short_preamble = short_preamble;
 
 
-	return mwl8k_cmd_802_11_radio_control(hw, 1, 1);
+	return mwl8k_cmd_radio_control(hw, 1, 1);
 }
 }
 
 
 /*
 /*
- * CMD_802_11_RF_TX_POWER.
+ * CMD_RF_TX_POWER.
  */
  */
 #define MWL8K_TX_POWER_LEVEL_TOTAL	8
 #define MWL8K_TX_POWER_LEVEL_TOTAL	8
 
 
-struct mwl8k_cmd_802_11_rf_tx_power {
+struct mwl8k_cmd_rf_tx_power {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
 	__le16 action;
 	__le16 support_level;
 	__le16 support_level;
@@ -2015,9 +1957,9 @@ struct mwl8k_cmd_802_11_rf_tx_power {
 	__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
 	__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm)
+static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
 {
 {
-	struct mwl8k_cmd_802_11_rf_tx_power *cmd;
+	struct mwl8k_cmd_rf_tx_power *cmd;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -2159,85 +2101,60 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
 }
 }
 
 
 /*
 /*
- * CMD_SET_SLOT.
+ * CMD_SET_AID.
  */
  */
-struct mwl8k_cmd_set_slot {
-	struct mwl8k_cmd_pkt header;
-	__le16 action;
-	__u8 short_slot;
-} __attribute__((packed));
-
-static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
-{
-	struct mwl8k_cmd_set_slot *cmd;
-	int rc;
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (cmd == NULL)
-		return -ENOMEM;
-
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
-	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->action = cpu_to_le16(MWL8K_CMD_SET);
-	cmd->short_slot = short_slot_time;
-
-	rc = mwl8k_post_cmd(hw, &cmd->header);
-	kfree(cmd);
+#define MWL8K_FRAME_PROT_DISABLED			0x00
+#define MWL8K_FRAME_PROT_11G				0x07
+#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY		0x02
+#define MWL8K_FRAME_PROT_11N_HT_ALL			0x06
 
 
-	return rc;
-}
+struct mwl8k_cmd_update_set_aid {
+	struct	mwl8k_cmd_pkt header;
+	__le16	aid;
 
 
-/*
- * CMD_MIMO_CONFIG.
- */
-struct mwl8k_cmd_mimo_config {
-	struct mwl8k_cmd_pkt header;
-	__le32 action;
-	__u8 rx_antenna_map;
-	__u8 tx_antenna_map;
+	 /* AP's MAC address (BSSID) */
+	__u8	bssid[ETH_ALEN];
+	__le16	protection_mode;
+	__u8	supp_rates[14];
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
+static int
+mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
 {
-	struct mwl8k_cmd_mimo_config *cmd;
+	struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
+	struct mwl8k_cmd_update_set_aid *cmd;
+	u16 prot_mode;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 	if (cmd == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
-	cmd->rx_antenna_map = rx;
-	cmd->tx_antenna_map = tx;
+	cmd->aid = cpu_to_le16(vif->bss_conf.aid);
 
 
-	rc = mwl8k_post_cmd(hw, &cmd->header);
-	kfree(cmd);
-
-	return rc;
-}
-
-/*
- * CMD_ENABLE_SNIFFER.
- */
-struct mwl8k_cmd_enable_sniffer {
-	struct mwl8k_cmd_pkt header;
-	__le32 action;
-} __attribute__((packed));
-
-static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
-{
-	struct mwl8k_cmd_enable_sniffer *cmd;
-	int rc;
+	memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN);
 
 
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (cmd == NULL)
-		return -ENOMEM;
+	if (vif->bss_conf.use_cts_prot) {
+		prot_mode = MWL8K_FRAME_PROT_11G;
+	} else {
+		switch (vif->bss_conf.ht_operation_mode &
+			IEEE80211_HT_OP_MODE_PROTECTION) {
+		case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+			prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
+			break;
+		case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+			prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
+			break;
+		default:
+			prot_mode = MWL8K_FRAME_PROT_DISABLED;
+			break;
+		}
+	}
+	cmd->protection_mode = cpu_to_le16(prot_mode);
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
-	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->action = cpu_to_le32(!!enable);
+	memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
 
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
 	kfree(cmd);
@@ -2246,37 +2163,30 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
 }
 }
 
 
 /*
 /*
- * CMD_SET_MAC_ADDR.
+ * CMD_SET_RATE.
  */
  */
-struct mwl8k_cmd_set_mac_addr {
-	struct mwl8k_cmd_pkt header;
-	union {
-		struct {
-			__le16 mac_type;
-			__u8 mac_addr[ETH_ALEN];
-		} mbss;
-		__u8 mac_addr[ETH_ALEN];
-	};
+struct mwl8k_cmd_set_rate {
+	struct	mwl8k_cmd_pkt header;
+	__u8	legacy_rates[14];
+
+	/* Bitmap for supported MCS codes.  */
+	__u8	mcs_set[16];
+	__u8	reserved[16];
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
+static int
+mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
 {
-	struct mwl8k_priv *priv = hw->priv;
-	struct mwl8k_cmd_set_mac_addr *cmd;
+	struct mwl8k_cmd_set_rate *cmd;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 	if (cmd == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	if (priv->ap_fw) {
-		cmd->mbss.mac_type = 0;
-		memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
-	} else {
-		memcpy(cmd->mac_addr, mac, ETH_ALEN);
-	}
+	memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
 
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
 	kfree(cmd);
@@ -2284,29 +2194,40 @@ static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
 	return rc;
 	return rc;
 }
 }
 
 
-
 /*
 /*
- * CMD_SET_RATEADAPT_MODE.
+ * CMD_FINALIZE_JOIN.
  */
  */
-struct mwl8k_cmd_set_rate_adapt_mode {
+#define MWL8K_FJ_BEACON_MAXLEN	128
+
+struct mwl8k_cmd_finalize_join {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
-	__le16 action;
-	__le16 mode;
+	__le32 sleep_interval;	/* Number of beacon periods to sleep */
+	__u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
+static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame,
+				   int framelen, int dtim)
 {
 {
-	struct mwl8k_cmd_set_rate_adapt_mode *cmd;
+	struct mwl8k_cmd_finalize_join *cmd;
+	struct ieee80211_mgmt *payload = frame;
+	int payload_len;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 	if (cmd == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->action = cpu_to_le16(MWL8K_CMD_SET);
-	cmd->mode = cpu_to_le16(mode);
+	cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
+
+	payload_len = framelen - ieee80211_hdrlen(payload->frame_control);
+	if (payload_len < 0)
+		payload_len = 0;
+	else if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
+		payload_len = MWL8K_FJ_BEACON_MAXLEN;
+
+	memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
 
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
 	kfree(cmd);
@@ -2315,59 +2236,57 @@ static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
 }
 }
 
 
 /*
 /*
- * CMD_SET_WMM_MODE.
+ * CMD_SET_RTS_THRESHOLD.
  */
  */
-struct mwl8k_cmd_set_wmm {
+struct mwl8k_cmd_set_rts_threshold {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
 	__le16 action;
+	__le16 threshold;
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable)
+static int mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw,
+				       u16 action, u16 threshold)
 {
 {
-	struct mwl8k_priv *priv = hw->priv;
-	struct mwl8k_cmd_set_wmm *cmd;
+	struct mwl8k_cmd_set_rts_threshold *cmd;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 	if (cmd == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->action = cpu_to_le16(!!enable);
+	cmd->action = cpu_to_le16(action);
+	cmd->threshold = cpu_to_le16(threshold);
 
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
 	kfree(cmd);
 
 
-	if (!rc)
-		priv->wmm_enabled = enable;
-
 	return rc;
 	return rc;
 }
 }
 
 
 /*
 /*
- * CMD_SET_RTS_THRESHOLD.
+ * CMD_SET_SLOT.
  */
  */
-struct mwl8k_cmd_rts_threshold {
+struct mwl8k_cmd_set_slot {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
 	__le16 action;
 	__le16 action;
-	__le16 threshold;
+	__u8 short_slot;
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
-			       u16 action, u16 threshold)
+static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
 {
 {
-	struct mwl8k_cmd_rts_threshold *cmd;
+	struct mwl8k_cmd_set_slot *cmd;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 	if (cmd == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->action = cpu_to_le16(action);
-	cmd->threshold = cpu_to_le16(threshold);
+	cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+	cmd->short_slot = short_slot_time;
 
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
 	kfree(cmd);
@@ -2426,9 +2345,9 @@ struct mwl8k_cmd_set_edca_params {
 				 MWL8K_SET_EDCA_AIFS)
 				 MWL8K_SET_EDCA_AIFS)
 
 
 static int
 static int
-mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
-		__u16 cw_min, __u16 cw_max,
-		__u8 aifs, __u16 txop)
+mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
+			  __u16 cw_min, __u16 cw_max,
+			  __u8 aifs, __u16 txop)
 {
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_cmd_set_edca_params *cmd;
 	struct mwl8k_cmd_set_edca_params *cmd;
@@ -2467,202 +2386,60 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
 }
 }
 
 
 /*
 /*
- * CMD_FINALIZE_JOIN.
+ * CMD_SET_WMM_MODE.
  */
  */
-#define MWL8K_FJ_BEACON_MAXLEN	128
-
-struct mwl8k_cmd_finalize_join {
+struct mwl8k_cmd_set_wmm_mode {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
-	__le32 sleep_interval;	/* Number of beacon periods to sleep */
-	__u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
+	__le16 action;
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
-			       int framelen, int dtim)
+static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
 {
 {
-	struct mwl8k_cmd_finalize_join *cmd;
-	struct ieee80211_mgmt *payload = frame;
-	int payload_len;
+	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_cmd_set_wmm_mode *cmd;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 	if (cmd == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
-
-	payload_len = framelen - ieee80211_hdrlen(payload->frame_control);
-	if (payload_len < 0)
-		payload_len = 0;
-	else if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
-		payload_len = MWL8K_FJ_BEACON_MAXLEN;
-
-	memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
+	cmd->action = cpu_to_le16(!!enable);
 
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
 	kfree(cmd);
 
 
+	if (!rc)
+		priv->wmm_enabled = enable;
+
 	return rc;
 	return rc;
 }
 }
 
 
 /*
 /*
- * CMD_UPDATE_STADB.
+ * CMD_MIMO_CONFIG.
  */
  */
-struct mwl8k_cmd_update_sta_db {
+struct mwl8k_cmd_mimo_config {
 	struct mwl8k_cmd_pkt header;
 	struct mwl8k_cmd_pkt header;
+	__le32 action;
+	__u8 rx_antenna_map;
+	__u8 tx_antenna_map;
+} __attribute__((packed));
 
 
-	/* See STADB_ACTION_TYPE */
-	__le32	action;
-
-	/* Peer MAC address */
-	__u8	peer_addr[ETH_ALEN];
-
-	__le32	reserved;
-
-	/* Peer info - valid during add/update.  */
-	struct peer_capability_info	peer_info;
-} __attribute__((packed));
-
-static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
-		struct ieee80211_vif *vif, __u32 action)
-{
-	struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
-	struct ieee80211_bss_conf *info = &mv_vif->bss_info;
-	struct mwl8k_cmd_update_sta_db *cmd;
-	struct peer_capability_info *peer_info;
-	int rc;
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (cmd == NULL)
-		return -ENOMEM;
-
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
-	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-
-	cmd->action = cpu_to_le32(action);
-	peer_info = &cmd->peer_info;
-	memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN);
-
-	switch (action) {
-	case MWL8K_STA_DB_ADD_ENTRY:
-	case MWL8K_STA_DB_MODIFY_ENTRY:
-		/* Build peer_info block */
-		peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
-		peer_info->basic_caps = cpu_to_le16(info->assoc_capability);
-		memcpy(peer_info->legacy_rates, mwl8k_rateids,
-		       sizeof(mwl8k_rateids));
-		peer_info->interop = 1;
-		peer_info->amsdu_enabled = 0;
-
-		rc = mwl8k_post_cmd(hw, &cmd->header);
-		if (rc == 0)
-			mv_vif->peer_id = peer_info->station_id;
-
-		break;
-
-	case MWL8K_STA_DB_DEL_ENTRY:
-	case MWL8K_STA_DB_FLUSH:
-	default:
-		rc = mwl8k_post_cmd(hw, &cmd->header);
-		if (rc == 0)
-			mv_vif->peer_id = 0;
-		break;
-	}
-	kfree(cmd);
-
-	return rc;
-}
-
-/*
- * CMD_SET_AID.
- */
-#define MWL8K_FRAME_PROT_DISABLED			0x00
-#define MWL8K_FRAME_PROT_11G				0x07
-#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY		0x02
-#define MWL8K_FRAME_PROT_11N_HT_ALL			0x06
-
-struct mwl8k_cmd_update_set_aid {
-	struct	mwl8k_cmd_pkt header;
-	__le16	aid;
-
-	 /* AP's MAC address (BSSID) */
-	__u8	bssid[ETH_ALEN];
-	__le16	protection_mode;
-	__u8	supp_rates[14];
-} __attribute__((packed));
-
-static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
-					struct ieee80211_vif *vif)
-{
-	struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
-	struct ieee80211_bss_conf *info = &mv_vif->bss_info;
-	struct mwl8k_cmd_update_set_aid *cmd;
-	u16 prot_mode;
-	int rc;
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (cmd == NULL)
-		return -ENOMEM;
-
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
-	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	cmd->aid = cpu_to_le16(info->aid);
-
-	memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN);
-
-	if (info->use_cts_prot) {
-		prot_mode = MWL8K_FRAME_PROT_11G;
-	} else {
-		switch (info->ht_operation_mode &
-			IEEE80211_HT_OP_MODE_PROTECTION) {
-		case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
-			prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
-			break;
-		case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
-			prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
-			break;
-		default:
-			prot_mode = MWL8K_FRAME_PROT_DISABLED;
-			break;
-		}
-	}
-	cmd->protection_mode = cpu_to_le16(prot_mode);
-
-	memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
-
-	rc = mwl8k_post_cmd(hw, &cmd->header);
-	kfree(cmd);
-
-	return rc;
-}
-
-/*
- * CMD_SET_RATE.
- */
-struct mwl8k_cmd_update_rateset {
-	struct	mwl8k_cmd_pkt header;
-	__u8	legacy_rates[14];
-
-	/* Bitmap for supported MCS codes.  */
-	__u8	mcs_set[16];
-	__u8	reserved[16];
-} __attribute__((packed));
-
-static int mwl8k_update_rateset(struct ieee80211_hw *hw,
-		struct ieee80211_vif *vif)
+static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
 {
 {
-	struct mwl8k_cmd_update_rateset *cmd;
+	struct mwl8k_cmd_mimo_config *cmd;
 	int rc;
 	int rc;
 
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 	if (cmd == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
-	memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+	cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
+	cmd->rx_antenna_map = rx;
+	cmd->tx_antenna_map = tx;
 
 
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	rc = mwl8k_post_cmd(hw, &cmd->header);
 	kfree(cmd);
 	kfree(cmd);
@@ -2755,6 +2532,169 @@ static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw,
 	return rc;
 	return rc;
 }
 }
 
 
+/*
+ * CMD_ENABLE_SNIFFER.
+ */
+struct mwl8k_cmd_enable_sniffer {
+	struct mwl8k_cmd_pkt header;
+	__le32 action;
+} __attribute__((packed));
+
+static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable)
+{
+	struct mwl8k_cmd_enable_sniffer *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	cmd->action = cpu_to_le32(!!enable);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+	kfree(cmd);
+
+	return rc;
+}
+
+/*
+ * CMD_SET_MAC_ADDR.
+ */
+struct mwl8k_cmd_set_mac_addr {
+	struct mwl8k_cmd_pkt header;
+	union {
+		struct {
+			__le16 mac_type;
+			__u8 mac_addr[ETH_ALEN];
+		} mbss;
+		__u8 mac_addr[ETH_ALEN];
+	};
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
+{
+	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_cmd_set_mac_addr *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	if (priv->ap_fw) {
+		cmd->mbss.mac_type = 0;
+		memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
+	} else {
+		memcpy(cmd->mac_addr, mac, ETH_ALEN);
+	}
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+	kfree(cmd);
+
+	return rc;
+}
+
+/*
+ * CMD_SET_RATEADAPT_MODE.
+ */
+struct mwl8k_cmd_set_rate_adapt_mode {
+	struct mwl8k_cmd_pkt header;
+	__le16 action;
+	__le16 mode;
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
+{
+	struct mwl8k_cmd_set_rate_adapt_mode *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+	cmd->mode = cpu_to_le16(mode);
+
+	rc = mwl8k_post_cmd(hw, &cmd->header);
+	kfree(cmd);
+
+	return rc;
+}
+
+/*
+ * CMD_UPDATE_STADB.
+ */
+struct mwl8k_cmd_update_stadb {
+	struct mwl8k_cmd_pkt header;
+
+	/* See STADB_ACTION_TYPE */
+	__le32	action;
+
+	/* Peer MAC address */
+	__u8	peer_addr[ETH_ALEN];
+
+	__le32	reserved;
+
+	/* Peer info - valid during add/update.  */
+	struct peer_capability_info	peer_info;
+} __attribute__((packed));
+
+static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw,
+		struct ieee80211_vif *vif, __u32 action)
+{
+	struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
+	struct mwl8k_cmd_update_stadb *cmd;
+	struct peer_capability_info *peer_info;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+	cmd->action = cpu_to_le32(action);
+	peer_info = &cmd->peer_info;
+	memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN);
+
+	switch (action) {
+	case MWL8K_STA_DB_ADD_ENTRY:
+	case MWL8K_STA_DB_MODIFY_ENTRY:
+		/* Build peer_info block */
+		peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
+		peer_info->basic_caps =
+			cpu_to_le16(vif->bss_conf.assoc_capability);
+		memcpy(peer_info->legacy_rates, mwl8k_rateids,
+		       sizeof(mwl8k_rateids));
+		peer_info->interop = 1;
+		peer_info->amsdu_enabled = 0;
+
+		rc = mwl8k_post_cmd(hw, &cmd->header);
+		if (rc == 0)
+			mv_vif->peer_id = peer_info->station_id;
+
+		break;
+
+	case MWL8K_STA_DB_DEL_ENTRY:
+	case MWL8K_STA_DB_FLUSH:
+	default:
+		rc = mwl8k_post_cmd(hw, &cmd->header);
+		if (rc == 0)
+			mv_vif->peer_id = 0;
+		break;
+	}
+	kfree(cmd);
+
+	return rc;
+}
+
 
 
 /*
 /*
  * Interrupt handling.
  * Interrupt handling.
@@ -2836,11 +2776,11 @@ static int mwl8k_start(struct ieee80211_hw *hw)
 
 
 	rc = mwl8k_fw_lock(hw);
 	rc = mwl8k_fw_lock(hw);
 	if (!rc) {
 	if (!rc) {
-		rc = mwl8k_cmd_802_11_radio_enable(hw);
+		rc = mwl8k_cmd_radio_enable(hw);
 
 
 		if (!priv->ap_fw) {
 		if (!priv->ap_fw) {
 			if (!rc)
 			if (!rc)
-				rc = mwl8k_enable_sniffer(hw, 0);
+				rc = mwl8k_cmd_enable_sniffer(hw, 0);
 
 
 			if (!rc)
 			if (!rc)
 				rc = mwl8k_cmd_set_pre_scan(hw);
 				rc = mwl8k_cmd_set_pre_scan(hw);
@@ -2851,10 +2791,10 @@ static int mwl8k_start(struct ieee80211_hw *hw)
 		}
 		}
 
 
 		if (!rc)
 		if (!rc)
-			rc = mwl8k_cmd_setrateadaptmode(hw, 0);
+			rc = mwl8k_cmd_set_rateadapt_mode(hw, 0);
 
 
 		if (!rc)
 		if (!rc)
-			rc = mwl8k_set_wmm(hw, 0);
+			rc = mwl8k_cmd_set_wmm_mode(hw, 0);
 
 
 		mwl8k_fw_unlock(hw);
 		mwl8k_fw_unlock(hw);
 	}
 	}
@@ -2873,7 +2813,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_priv *priv = hw->priv;
 	int i;
 	int i;
 
 
-	mwl8k_cmd_802_11_radio_disable(hw);
+	mwl8k_cmd_radio_disable(hw);
 
 
 	ieee80211_stop_queues(hw);
 	ieee80211_stop_queues(hw);
 
 
@@ -2895,7 +2835,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
 }
 }
 
 
 static int mwl8k_add_interface(struct ieee80211_hw *hw,
 static int mwl8k_add_interface(struct ieee80211_hw *hw,
-				struct ieee80211_if_init_conf *conf)
+				struct ieee80211_vif *vif)
 {
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_vif *mwl8k_vif;
 	struct mwl8k_vif *mwl8k_vif;
@@ -2909,7 +2849,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
 	/*
 	/*
 	 * We only support managed interfaces for now.
 	 * We only support managed interfaces for now.
 	 */
 	 */
-	if (conf->type != NL80211_IFTYPE_STATION)
+	if (vif->type != NL80211_IFTYPE_STATION)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	/*
 	/*
@@ -2925,34 +2865,31 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
 	}
 	}
 
 
 	/* Clean out driver private area */
 	/* Clean out driver private area */
-	mwl8k_vif = MWL8K_VIF(conf->vif);
+	mwl8k_vif = MWL8K_VIF(vif);
 	memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
 	memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
 
 
 	/* Set and save the mac address */
 	/* Set and save the mac address */
-	mwl8k_set_mac_addr(hw, conf->mac_addr);
-	memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN);
-
-	/* Back pointer to parent config block */
-	mwl8k_vif->priv = priv;
+	mwl8k_cmd_set_mac_addr(hw, vif->addr);
+	memcpy(mwl8k_vif->mac_addr, vif->addr, ETH_ALEN);
 
 
 	/* Set Initial sequence number to zero */
 	/* Set Initial sequence number to zero */
 	mwl8k_vif->seqno = 0;
 	mwl8k_vif->seqno = 0;
 
 
-	priv->vif = conf->vif;
+	priv->vif = vif;
 	priv->current_channel = NULL;
 	priv->current_channel = NULL;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static void mwl8k_remove_interface(struct ieee80211_hw *hw,
 static void mwl8k_remove_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_if_init_conf *conf)
+				   struct ieee80211_vif *vif)
 {
 {
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_priv *priv = hw->priv;
 
 
 	if (priv->vif == NULL)
 	if (priv->vif == NULL)
 		return;
 		return;
 
 
-	mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+	mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
 
 
 	priv->vif = NULL;
 	priv->vif = NULL;
 }
 }
@@ -2964,7 +2901,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
 	int rc;
 	int rc;
 
 
 	if (conf->flags & IEEE80211_CONF_IDLE) {
 	if (conf->flags & IEEE80211_CONF_IDLE) {
-		mwl8k_cmd_802_11_radio_disable(hw);
+		mwl8k_cmd_radio_disable(hw);
 		priv->current_channel = NULL;
 		priv->current_channel = NULL;
 		return 0;
 		return 0;
 	}
 	}
@@ -2973,7 +2910,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
 	if (rc)
 	if (rc)
 		return rc;
 		return rc;
 
 
-	rc = mwl8k_cmd_802_11_radio_enable(hw);
+	rc = mwl8k_cmd_radio_enable(hw);
 	if (rc)
 	if (rc)
 		goto out;
 		goto out;
 
 
@@ -2985,7 +2922,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
 
 
 	if (conf->power_level > 18)
 	if (conf->power_level > 18)
 		conf->power_level = 18;
 		conf->power_level = 18;
-	rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level);
+	rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level);
 	if (rc)
 	if (rc)
 		goto out;
 		goto out;
 
 
@@ -3021,14 +2958,11 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
 	if (rc)
 	if (rc)
 		return;
 		return;
 
 
-	if (info->assoc) {
-		memcpy(&mwl8k_vif->bss_info, info,
-			sizeof(struct ieee80211_bss_conf));
-
-		memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN);
+	if (vif->bss_conf.assoc) {
+		memcpy(mwl8k_vif->bssid, vif->bss_conf.bssid, ETH_ALEN);
 
 
 		/* Install rates */
 		/* Install rates */
-		rc = mwl8k_update_rateset(hw, vif);
+		rc = mwl8k_cmd_set_rate(hw, vif);
 		if (rc)
 		if (rc)
 			goto out;
 			goto out;
 
 
@@ -3039,17 +2973,18 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
 			goto out;
 			goto out;
 
 
 		/* Set radio preamble */
 		/* Set radio preamble */
-		rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble);
+		rc = mwl8k_set_radio_preamble(hw,
+				vif->bss_conf.use_short_preamble);
 		if (rc)
 		if (rc)
 			goto out;
 			goto out;
 
 
 		/* Set slot time */
 		/* Set slot time */
-		rc = mwl8k_cmd_set_slot(hw, info->use_short_slot);
+		rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot);
 		if (rc)
 		if (rc)
 			goto out;
 			goto out;
 
 
 		/* Update peer rate info */
 		/* Update peer rate info */
-		rc = mwl8k_cmd_update_sta_db(hw, vif,
+		rc = mwl8k_cmd_update_stadb(hw, vif,
 				MWL8K_STA_DB_MODIFY_ENTRY);
 				MWL8K_STA_DB_MODIFY_ENTRY);
 		if (rc)
 		if (rc)
 			goto out;
 			goto out;
@@ -3066,9 +3001,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
 		memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
 		memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
 		priv->capture_beacon = true;
 		priv->capture_beacon = true;
 	} else {
 	} else {
-		rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
-		memset(&mwl8k_vif->bss_info, 0,
-			sizeof(struct ieee80211_bss_conf));
+		rc = mwl8k_cmd_update_stadb(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
 		memset(mwl8k_vif->bssid, 0, ETH_ALEN);
 		memset(mwl8k_vif->bssid, 0, ETH_ALEN);
 	}
 	}
 
 
@@ -3114,7 +3047,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
 	}
 	}
 
 
 	if (!priv->sniffer_enabled) {
 	if (!priv->sniffer_enabled) {
-		if (mwl8k_enable_sniffer(hw, 1))
+		if (mwl8k_cmd_enable_sniffer(hw, 1))
 			return 0;
 			return 0;
 		priv->sniffer_enabled = true;
 		priv->sniffer_enabled = true;
 	}
 	}
@@ -3161,7 +3094,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 		return;
 		return;
 
 
 	if (priv->sniffer_enabled) {
 	if (priv->sniffer_enabled) {
-		mwl8k_enable_sniffer(hw, 0);
+		mwl8k_cmd_enable_sniffer(hw, 0);
 		priv->sniffer_enabled = false;
 		priv->sniffer_enabled = false;
 	}
 	}
 
 
@@ -3211,7 +3144,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 
 
 static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
 {
-	return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value);
+	return mwl8k_cmd_set_rts_threshold(hw, MWL8K_CMD_SET, value);
 }
 }
 
 
 static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
 static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -3223,14 +3156,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
 	rc = mwl8k_fw_lock(hw);
 	rc = mwl8k_fw_lock(hw);
 	if (!rc) {
 	if (!rc) {
 		if (!priv->wmm_enabled)
 		if (!priv->wmm_enabled)
-			rc = mwl8k_set_wmm(hw, 1);
+			rc = mwl8k_cmd_set_wmm_mode(hw, 1);
 
 
 		if (!rc)
 		if (!rc)
-			rc = mwl8k_set_edca_params(hw, queue,
-						   params->cw_min,
-						   params->cw_max,
-						   params->aifs,
-						   params->txop);
+			rc = mwl8k_cmd_set_edca_params(hw, queue,
+						       params->cw_min,
+						       params->cw_max,
+						       params->aifs,
+						       params->txop);
 
 
 		mwl8k_fw_unlock(hw);
 		mwl8k_fw_unlock(hw);
 	}
 	}
@@ -3259,7 +3192,7 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
 static int mwl8k_get_stats(struct ieee80211_hw *hw,
 static int mwl8k_get_stats(struct ieee80211_hw *hw,
 			   struct ieee80211_low_level_stats *stats)
 			   struct ieee80211_low_level_stats *stats)
 {
 {
-	return mwl8k_cmd_802_11_get_stat(hw, stats);
+	return mwl8k_cmd_get_stat(hw, stats);
 }
 }
 
 
 static const struct ieee80211_ops mwl8k_ops = {
 static const struct ieee80211_ops mwl8k_ops = {
@@ -3300,9 +3233,9 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
 	struct mwl8k_priv *priv =
 	struct mwl8k_priv *priv =
 		container_of(work, struct mwl8k_priv, finalize_join_worker);
 		container_of(work, struct mwl8k_priv, finalize_join_worker);
 	struct sk_buff *skb = priv->beacon_skb;
 	struct sk_buff *skb = priv->beacon_skb;
-	u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period;
 
 
-	mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim);
+	mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len,
+				priv->vif->bss_conf.dtim_period);
 	dev_kfree_skb(skb);
 	dev_kfree_skb(skb);
 
 
 	priv->beacon_skb = NULL;
 	priv->beacon_skb = NULL;
@@ -3314,19 +3247,16 @@ enum {
 };
 };
 
 
 static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = {
 static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = {
-	{
+	[MWL8687] = {
 		.part_name	= "88w8687",
 		.part_name	= "88w8687",
 		.helper_image	= "mwl8k/helper_8687.fw",
 		.helper_image	= "mwl8k/helper_8687.fw",
 		.fw_image	= "mwl8k/fmimage_8687.fw",
 		.fw_image	= "mwl8k/fmimage_8687.fw",
-		.rxd_ops	= &rxd_8687_ops,
-		.modes		= BIT(NL80211_IFTYPE_STATION),
 	},
 	},
-	{
+	[MWL8366] = {
 		.part_name	= "88w8366",
 		.part_name	= "88w8366",
 		.helper_image	= "mwl8k/helper_8366.fw",
 		.helper_image	= "mwl8k/helper_8366.fw",
 		.fw_image	= "mwl8k/fmimage_8366.fw",
 		.fw_image	= "mwl8k/fmimage_8366.fw",
-		.rxd_ops	= &rxd_8366_ops,
-		.modes		= 0,
+		.ap_rxd_ops	= &rxd_8366_ap_ops,
 	},
 	},
 };
 };
 
 
@@ -3352,6 +3282,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		printed_version = 1;
 		printed_version = 1;
 	}
 	}
 
 
+
 	rc = pci_enable_device(pdev);
 	rc = pci_enable_device(pdev);
 	if (rc) {
 	if (rc) {
 		printk(KERN_ERR "%s: Cannot enable new PCI device\n",
 		printk(KERN_ERR "%s: Cannot enable new PCI device\n",
@@ -3368,6 +3299,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
 
 	pci_set_master(pdev);
 	pci_set_master(pdev);
 
 
+
 	hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
 	hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
 	if (hw == NULL) {
 	if (hw == NULL) {
 		printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
 		printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
@@ -3375,17 +3307,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		goto err_free_reg;
 		goto err_free_reg;
 	}
 	}
 
 
+	SET_IEEE80211_DEV(hw, &pdev->dev);
+	pci_set_drvdata(pdev, hw);
+
 	priv = hw->priv;
 	priv = hw->priv;
 	priv->hw = hw;
 	priv->hw = hw;
 	priv->pdev = pdev;
 	priv->pdev = pdev;
 	priv->device_info = &mwl8k_info_tbl[id->driver_data];
 	priv->device_info = &mwl8k_info_tbl[id->driver_data];
-	priv->rxd_ops = priv->device_info->rxd_ops;
-	priv->sniffer_enabled = false;
-	priv->wmm_enabled = false;
-	priv->pending_tx_pkts = 0;
 
 
-	SET_IEEE80211_DEV(hw, &pdev->dev);
-	pci_set_drvdata(pdev, hw);
 
 
 	priv->sram = pci_iomap(pdev, 0, 0x10000);
 	priv->sram = pci_iomap(pdev, 0, 0x10000);
 	if (priv->sram == NULL) {
 	if (priv->sram == NULL) {
@@ -3408,6 +3337,40 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		}
 		}
 	}
 	}
 
 
+
+	/* Reset firmware and hardware */
+	mwl8k_hw_reset(priv);
+
+	/* Ask userland hotplug daemon for the device firmware */
+	rc = mwl8k_request_firmware(priv);
+	if (rc) {
+		printk(KERN_ERR "%s: Firmware files not found\n",
+		       wiphy_name(hw->wiphy));
+		goto err_stop_firmware;
+	}
+
+	/* Load firmware into hardware */
+	rc = mwl8k_load_firmware(hw);
+	if (rc) {
+		printk(KERN_ERR "%s: Cannot start firmware\n",
+		       wiphy_name(hw->wiphy));
+		goto err_stop_firmware;
+	}
+
+	/* Reclaim memory once firmware is successfully loaded */
+	mwl8k_release_firmware(priv);
+
+
+	if (priv->ap_fw)
+		priv->rxd_ops = priv->device_info->ap_rxd_ops;
+	else
+		priv->rxd_ops = &rxd_sta_ops;
+
+	priv->sniffer_enabled = false;
+	priv->wmm_enabled = false;
+	priv->pending_tx_pkts = 0;
+
+
 	memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
 	memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
 	priv->band.band = IEEE80211_BAND_2GHZ;
 	priv->band.band = IEEE80211_BAND_2GHZ;
 	priv->band.channels = priv->channels;
 	priv->band.channels = priv->channels;
@@ -3430,8 +3393,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
 
 	hw->queues = MWL8K_TX_QUEUES;
 	hw->queues = MWL8K_TX_QUEUES;
 
 
-	hw->wiphy->interface_modes = priv->device_info->modes;
-
 	/* Set rssi and noise values to dBm */
 	/* Set rssi and noise values to dBm */
 	hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
 	hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
 	hw->vif_data_size = sizeof(struct mwl8k_vif);
 	hw->vif_data_size = sizeof(struct mwl8k_vif);
@@ -3452,11 +3413,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	/* Power management cookie */
 	/* Power management cookie */
 	priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
 	priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
 	if (priv->cookie == NULL)
 	if (priv->cookie == NULL)
-		goto err_iounmap;
+		goto err_stop_firmware;
 
 
 	rc = mwl8k_rxq_init(hw, 0);
 	rc = mwl8k_rxq_init(hw, 0);
 	if (rc)
 	if (rc)
-		goto err_iounmap;
+		goto err_free_cookie;
 	rxq_refill(hw, 0, INT_MAX);
 	rxq_refill(hw, 0, INT_MAX);
 
 
 	mutex_init(&priv->fw_mutex);
 	mutex_init(&priv->fw_mutex);
@@ -3487,28 +3448,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		goto err_free_queues;
 		goto err_free_queues;
 	}
 	}
 
 
-	/* Reset firmware and hardware */
-	mwl8k_hw_reset(priv);
-
-	/* Ask userland hotplug daemon for the device firmware */
-	rc = mwl8k_request_firmware(priv);
-	if (rc) {
-		printk(KERN_ERR "%s: Firmware files not found\n",
-		       wiphy_name(hw->wiphy));
-		goto err_free_irq;
-	}
-
-	/* Load firmware into hardware */
-	rc = mwl8k_load_firmware(hw);
-	if (rc) {
-		printk(KERN_ERR "%s: Cannot start firmware\n",
-		       wiphy_name(hw->wiphy));
-		goto err_stop_firmware;
-	}
-
-	/* Reclaim memory once firmware is successfully loaded */
-	mwl8k_release_firmware(priv);
-
 	/*
 	/*
 	 * Temporarily enable interrupts.  Initial firmware host
 	 * Temporarily enable interrupts.  Initial firmware host
 	 * commands use interrupts and avoids polling.  Disable
 	 * commands use interrupts and avoids polling.  Disable
@@ -3523,26 +3462,28 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 			rc = mwl8k_cmd_set_hw_spec(hw);
 			rc = mwl8k_cmd_set_hw_spec(hw);
 	} else {
 	} else {
 		rc = mwl8k_cmd_get_hw_spec_sta(hw);
 		rc = mwl8k_cmd_get_hw_spec_sta(hw);
+
+		hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 	}
 	}
 	if (rc) {
 	if (rc) {
 		printk(KERN_ERR "%s: Cannot initialise firmware\n",
 		printk(KERN_ERR "%s: Cannot initialise firmware\n",
 		       wiphy_name(hw->wiphy));
 		       wiphy_name(hw->wiphy));
-		goto err_stop_firmware;
+		goto err_free_irq;
 	}
 	}
 
 
 	/* Turn radio off */
 	/* Turn radio off */
-	rc = mwl8k_cmd_802_11_radio_disable(hw);
+	rc = mwl8k_cmd_radio_disable(hw);
 	if (rc) {
 	if (rc) {
 		printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy));
 		printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy));
-		goto err_stop_firmware;
+		goto err_free_irq;
 	}
 	}
 
 
 	/* Clear MAC address */
 	/* Clear MAC address */
-	rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+	rc = mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
 	if (rc) {
 	if (rc) {
 		printk(KERN_ERR "%s: Cannot clear MAC address\n",
 		printk(KERN_ERR "%s: Cannot clear MAC address\n",
 		       wiphy_name(hw->wiphy));
 		       wiphy_name(hw->wiphy));
-		goto err_stop_firmware;
+		goto err_free_irq;
 	}
 	}
 
 
 	/* Disable interrupts */
 	/* Disable interrupts */
@@ -3553,7 +3494,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 	if (rc) {
 	if (rc) {
 		printk(KERN_ERR "%s: Cannot register device\n",
 		printk(KERN_ERR "%s: Cannot register device\n",
 		       wiphy_name(hw->wiphy));
 		       wiphy_name(hw->wiphy));
-		goto err_stop_firmware;
+		goto err_free_irq;
 	}
 	}
 
 
 	printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n",
 	printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n",
@@ -3565,10 +3506,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
 
 	return 0;
 	return 0;
 
 
-err_stop_firmware:
-	mwl8k_hw_reset(priv);
-	mwl8k_release_firmware(priv);
-
 err_free_irq:
 err_free_irq:
 	iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
 	iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
 	free_irq(priv->pdev->irq, hw);
 	free_irq(priv->pdev->irq, hw);
@@ -3578,11 +3515,16 @@ err_free_queues:
 		mwl8k_txq_deinit(hw, i);
 		mwl8k_txq_deinit(hw, i);
 	mwl8k_rxq_deinit(hw, 0);
 	mwl8k_rxq_deinit(hw, 0);
 
 
-err_iounmap:
+err_free_cookie:
 	if (priv->cookie != NULL)
 	if (priv->cookie != NULL)
 		pci_free_consistent(priv->pdev, 4,
 		pci_free_consistent(priv->pdev, 4,
 				priv->cookie, priv->cookie_dma);
 				priv->cookie, priv->cookie_dma);
 
 
+err_stop_firmware:
+	mwl8k_hw_reset(priv);
+	mwl8k_release_firmware(priv);
+
+err_iounmap:
 	if (priv->regs != NULL)
 	if (priv->regs != NULL)
 		pci_iounmap(pdev, priv->regs);
 		pci_iounmap(pdev, priv->regs);
 
 

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

@@ -23,7 +23,7 @@
 #define MAX_RID_LEN 1024
 #define MAX_RID_LEN 1024
 
 
 /* Helper routine to record keys
 /* Helper routine to record keys
- * Do not call from interrupt context */
+ * It is called under orinoco_lock so it may not sleep */
 static int orinoco_set_key(struct orinoco_private *priv, int index,
 static int orinoco_set_key(struct orinoco_private *priv, int index,
 			   enum orinoco_alg alg, const u8 *key, int key_len,
 			   enum orinoco_alg alg, const u8 *key, int key_len,
 			   const u8 *seq, int seq_len)
 			   const u8 *seq, int seq_len)
@@ -32,14 +32,14 @@ static int orinoco_set_key(struct orinoco_private *priv, int index,
 	kzfree(priv->keys[index].seq);
 	kzfree(priv->keys[index].seq);
 
 
 	if (key_len) {
 	if (key_len) {
-		priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
+		priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
 		if (!priv->keys[index].key)
 		if (!priv->keys[index].key)
 			goto nomem;
 			goto nomem;
 	} else
 	} else
 		priv->keys[index].key = NULL;
 		priv->keys[index].key = NULL;
 
 
 	if (seq_len) {
 	if (seq_len) {
-		priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
+		priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
 		if (!priv->keys[index].seq)
 		if (!priv->keys[index].seq)
 			goto free_key;
 			goto free_key;
 	} else
 	} else

+ 6 - 6
drivers/net/wireless/p54/main.c

@@ -216,7 +216,7 @@ static void p54_stop(struct ieee80211_hw *dev)
 }
 }
 
 
 static int p54_add_interface(struct ieee80211_hw *dev,
 static int p54_add_interface(struct ieee80211_hw *dev,
-			     struct ieee80211_if_init_conf *conf)
+			     struct ieee80211_vif *vif)
 {
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
 
 
@@ -226,28 +226,28 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	}
 	}
 
 
-	priv->vif = conf->vif;
+	priv->vif = vif;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_MESH_POINT:
-		priv->mode = conf->type;
+		priv->mode = vif->type;
 		break;
 		break;
 	default:
 	default:
 		mutex_unlock(&priv->conf_mutex);
 		mutex_unlock(&priv->conf_mutex);
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	}
 	}
 
 
-	memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+	memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
 	p54_setup_mac(priv);
 	p54_setup_mac(priv);
 	mutex_unlock(&priv->conf_mutex);
 	mutex_unlock(&priv->conf_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
 static void p54_remove_interface(struct ieee80211_hw *dev,
 static void p54_remove_interface(struct ieee80211_hw *dev,
-				 struct ieee80211_if_init_conf *conf)
+				 struct ieee80211_vif *vif)
 {
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_common *priv = dev->priv;
 
 

+ 2 - 2
drivers/net/wireless/rt2x00/Kconfig

@@ -54,12 +54,12 @@ config RT61PCI
 	  When compiled as a module, this driver will be called rt61pci.
 	  When compiled as a module, this driver will be called rt61pci.
 
 
 config RT2800PCI_PCI
 config RT2800PCI_PCI
-	tristate
+	boolean
 	depends on PCI
 	depends on PCI
 	default y
 	default y
 
 
 config RT2800PCI_SOC
 config RT2800PCI_SOC
-	tristate
+	boolean
 	depends on RALINK_RT288X || RALINK_RT305X
 	depends on RALINK_RT288X || RALINK_RT305X
 	default y
 	default y
 
 

+ 2 - 3
drivers/net/wireless/rt2x00/rt2400pci.c

@@ -451,7 +451,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
 	/*
 	/*
 	 * RF2420 chipset don't need any additional actions.
 	 * RF2420 chipset don't need any additional actions.
 	 */
 	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2420))
+	if (rt2x00_rf(rt2x00dev, RF2420))
 		return;
 		return;
 
 
 	/*
 	/*
@@ -1343,8 +1343,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 	rt2x00_print_chip(rt2x00dev);
 	rt2x00_print_chip(rt2x00dev);
 
 
-	if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2421)) {
+	if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) {
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}

+ 19 - 20
drivers/net/wireless/rt2x00/rt2500pci.c

@@ -440,8 +440,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
 	/*
 	/*
 	 * RT2525E and RT5222 need to flip TX I/Q
 	 * RT2525E and RT5222 need to flip TX I/Q
 	 */
 	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+	if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
 		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
 		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
 		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
 		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
 		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
 		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
@@ -449,7 +448,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
 		/*
 		/*
 		 * RT2525E does not need RX I/Q Flip.
 		 * RT2525E does not need RX I/Q Flip.
 		 */
 		 */
-		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+		if (rt2x00_rf(rt2x00dev, RF2525E))
 			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
 			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
 	} else {
 	} else {
 		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
 		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
@@ -475,14 +474,14 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
 	 * Switch on tuning bits.
 	 * Switch on tuning bits.
 	 * For RT2523 devices we do not need to update the R1 register.
 	 * For RT2523 devices we do not need to update the R1 register.
 	 */
 	 */
-	if (!rt2x00_rf(&rt2x00dev->chip, RF2523))
+	if (!rt2x00_rf(rt2x00dev, RF2523))
 		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
 		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
 	rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
 	rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
 
 
 	/*
 	/*
 	 * For RT2525 we should first set the channel to half band higher.
 	 * For RT2525 we should first set the channel to half band higher.
 	 */
 	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+	if (rt2x00_rf(rt2x00dev, RF2525)) {
 		static const u32 vals[] = {
 		static const u32 vals[] = {
 			0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
 			0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
 			0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
 			0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
@@ -516,7 +515,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
 	 * Switch off tuning bits.
 	 * Switch off tuning bits.
 	 * For RT2523 devices we do not need to update the R1 register.
 	 * For RT2523 devices we do not need to update the R1 register.
 	 */
 	 */
-	if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+	if (!rt2x00_rf(rt2x00dev, RF2523)) {
 		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
 		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
 		rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
 		rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
 	}
 	}
@@ -640,7 +639,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
 	 * up to version C the link tuning should halt after 20
 	 * up to version C the link tuning should halt after 20
 	 * seconds while being associated.
 	 * seconds while being associated.
 	 */
 	 */
-	if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
+	if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D &&
 	    rt2x00dev->intf_associated && count > 20)
 	    rt2x00dev->intf_associated && count > 20)
 		return;
 		return;
 
 
@@ -650,7 +649,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
 	 * should go straight to dynamic CCA tuning when they
 	 * should go straight to dynamic CCA tuning when they
 	 * are not associated.
 	 * are not associated.
 	 */
 	 */
-	if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D ||
+	if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D ||
 	    !rt2x00dev->intf_associated)
 	    !rt2x00dev->intf_associated)
 		goto dynamic_cca_tune;
 		goto dynamic_cca_tune;
 
 
@@ -1507,12 +1506,12 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 	rt2x00_print_chip(rt2x00dev);
 	rt2x00_print_chip(rt2x00dev);
 
 
-	if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+	if (!rt2x00_rf(rt2x00dev, RF2522) &&
+	    !rt2x00_rf(rt2x00dev, RF2523) &&
+	    !rt2x00_rf(rt2x00dev, RF2524) &&
+	    !rt2x00_rf(rt2x00dev, RF2525) &&
+	    !rt2x00_rf(rt2x00dev, RF2525E) &&
+	    !rt2x00_rf(rt2x00dev, RF5222)) {
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -1744,22 +1743,22 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
 
-	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+	if (rt2x00_rf(rt2x00dev, RF2522)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
 		spec->channels = rf_vals_bg_2522;
 		spec->channels = rf_vals_bg_2522;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2523)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
 		spec->channels = rf_vals_bg_2523;
 		spec->channels = rf_vals_bg_2523;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2524)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
 		spec->channels = rf_vals_bg_2524;
 		spec->channels = rf_vals_bg_2524;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2525)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
 		spec->channels = rf_vals_bg_2525;
 		spec->channels = rf_vals_bg_2525;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2525E)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
 		spec->channels = rf_vals_bg_2525e;
 		spec->channels = rf_vals_bg_2525e;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+	} else if (rt2x00_rf(rt2x00dev, RF5222)) {
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
 		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
 		spec->channels = rf_vals_5222;
 		spec->channels = rf_vals_5222;

+ 18 - 20
drivers/net/wireless/rt2x00/rt2500usb.c

@@ -565,8 +565,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
 	/*
 	/*
 	 * RT2525E and RT5222 need to flip TX I/Q
 	 * RT2525E and RT5222 need to flip TX I/Q
 	 */
 	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+	if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
 		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
 		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
 		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
 		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
@@ -574,7 +573,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
 		/*
 		/*
 		 * RT2525E does not need RX I/Q Flip.
 		 * RT2525E does not need RX I/Q Flip.
 		 */
 		 */
-		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+		if (rt2x00_rf(rt2x00dev, RF2525E))
 			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
 			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
 	} else {
 	} else {
 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
@@ -598,7 +597,7 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
 	/*
 	/*
 	 * For RT2525E we should first set the channel to half band higher.
 	 * For RT2525E we should first set the channel to half band higher.
 	 */
 	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+	if (rt2x00_rf(rt2x00dev, RF2525E)) {
 		static const u32 vals[] = {
 		static const u32 vals[] = {
 			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
 			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
 			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
 			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
@@ -793,7 +792,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
 	rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
 	rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
 	rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
 
-	if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
+	if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) {
 		rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
 		rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
 		rt2x00_set_field16(&reg, PHY_CSR2_LNA, 0);
 		rt2x00_set_field16(&reg, PHY_CSR2_LNA, 0);
 	} else {
 	} else {
@@ -1411,19 +1410,18 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
 	rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
 	rt2x00_print_chip(rt2x00dev);
 	rt2x00_print_chip(rt2x00dev);
 
 
-	if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) ||
-	    rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
-
+	if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) ||
+	    rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
 		ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+	if (!rt2x00_rf(rt2x00dev, RF2522) &&
+	    !rt2x00_rf(rt2x00dev, RF2523) &&
+	    !rt2x00_rf(rt2x00dev, RF2524) &&
+	    !rt2x00_rf(rt2x00dev, RF2525) &&
+	    !rt2x00_rf(rt2x00dev, RF2525E) &&
+	    !rt2x00_rf(rt2x00dev, RF5222)) {
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -1667,22 +1665,22 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
 
-	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+	if (rt2x00_rf(rt2x00dev, RF2522)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
 		spec->channels = rf_vals_bg_2522;
 		spec->channels = rf_vals_bg_2522;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2523)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
 		spec->channels = rf_vals_bg_2523;
 		spec->channels = rf_vals_bg_2523;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2524)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
 		spec->channels = rf_vals_bg_2524;
 		spec->channels = rf_vals_bg_2524;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2525)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
 		spec->channels = rf_vals_bg_2525;
 		spec->channels = rf_vals_bg_2525;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2525E)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
 		spec->channels = rf_vals_bg_2525e;
 		spec->channels = rf_vals_bg_2525e;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+	} else if (rt2x00_rf(rt2x00dev, RF5222)) {
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
 		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
 		spec->channels = rf_vals_5222;
 		spec->channels = rf_vals_5222;

+ 45 - 49
drivers/net/wireless/rt2x00/rt2800lib.c

@@ -37,7 +37,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 
 
 #include "rt2x00.h"
 #include "rt2x00.h"
-#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
+#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
 #include "rt2x00usb.h"
 #include "rt2x00usb.h"
 #endif
 #endif
 #include "rt2800lib.h"
 #include "rt2800lib.h"
@@ -220,8 +220,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
 	/*
 	/*
 	 * RT2880 and RT3052 don't support MCU requests.
 	 * RT2880 and RT3052 don't support MCU requests.
 	 */
 	 */
-	if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
-	    rt2x00_rt(&rt2x00dev->chip, RT3052))
+	if (rt2x00_rt(rt2x00dev, RT2880) || rt2x00_rt(rt2x00dev, RT3052))
 		return;
 		return;
 
 
 	mutex_lock(&rt2x00dev->csr_mutex);
 	mutex_lock(&rt2x00dev->csr_mutex);
@@ -806,12 +805,12 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
 	unsigned int tx_pin;
 	unsigned int tx_pin;
 	u8 bbp;
 	u8 bbp;
 
 
-	if ((rt2x00_rt(&rt2x00dev->chip, RT3070) ||
-	     rt2x00_rt(&rt2x00dev->chip, RT3090)) &&
-	    (rt2x00_rf(&rt2x00dev->chip, RF2020) ||
-	     rt2x00_rf(&rt2x00dev->chip, RF3020) ||
-	     rt2x00_rf(&rt2x00dev->chip, RF3021) ||
-	     rt2x00_rf(&rt2x00dev->chip, RF3022)))
+	if ((rt2x00_rt(rt2x00dev, RT3070) ||
+	     rt2x00_rt(rt2x00dev, RT3090)) &&
+	    (rt2x00_rf(rt2x00dev, RF2020) ||
+	     rt2x00_rf(rt2x00dev, RF3020) ||
+	     rt2x00_rf(rt2x00dev, RF3021) ||
+	     rt2x00_rf(rt2x00dev, RF3022)))
 		rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info);
 		rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info);
 	else
 	else
 		rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
 		rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
@@ -878,7 +877,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
 	rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
 	rt2800_bbp_write(rt2x00dev, 3, bbp);
 	rt2800_bbp_write(rt2x00dev, 3, bbp);
 
 
-	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+	if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
 		if (conf_is_ht40(conf)) {
 		if (conf_is_ht40(conf)) {
 			rt2800_bbp_write(rt2x00dev, 69, 0x1a);
 			rt2800_bbp_write(rt2x00dev, 69, 0x1a);
 			rt2800_bbp_write(rt2x00dev, 70, 0x0a);
 			rt2800_bbp_write(rt2x00dev, 70, 0x0a);
@@ -1041,7 +1040,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
 {
 {
 	if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
 	if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
 		if (rt2x00_intf_is_usb(rt2x00dev) &&
 		if (rt2x00_intf_is_usb(rt2x00dev) &&
-		    rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION)
+		    rt2x00_rev(rt2x00dev) == RT3070_VERSION)
 			return 0x1c + (2 * rt2x00dev->lna_gain);
 			return 0x1c + (2 * rt2x00dev->lna_gain);
 		else
 		else
 			return 0x2e + rt2x00dev->lna_gain;
 			return 0x2e + rt2x00dev->lna_gain;
@@ -1072,7 +1071,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
 		       const u32 count)
 		       const u32 count)
 {
 {
-	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION)
+	if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)
 		return;
 		return;
 
 
 	/*
 	/*
@@ -1121,7 +1120,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
 
 	if (rt2x00_intf_is_usb(rt2x00dev)) {
 	if (rt2x00_intf_is_usb(rt2x00dev)) {
 		rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
 		rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
-#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
+#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
 		rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
 		rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
 					    USB_MODE_RESET, REGISTER_TIMEOUT);
 					    USB_MODE_RESET, REGISTER_TIMEOUT);
 #endif
 #endif
@@ -1158,7 +1157,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
 
 	if (rt2x00_intf_is_usb(rt2x00dev) &&
 	if (rt2x00_intf_is_usb(rt2x00dev) &&
-	    rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
+	    rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -1185,8 +1184,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
 
 	rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
 	rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
 	rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
 	rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
-	if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION &&
-	    rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION)
+	if (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION &&
+	    rt2x00_rev(rt2x00dev) < RT3070_VERSION)
 		rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
 		rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
 	else
 	else
 		rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
 		rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
@@ -1465,22 +1464,22 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 	rt2800_bbp_write(rt2x00dev, 103, 0x00);
 	rt2800_bbp_write(rt2x00dev, 103, 0x00);
 	rt2800_bbp_write(rt2x00dev, 105, 0x05);
 	rt2800_bbp_write(rt2x00dev, 105, 0x05);
 
 
-	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+	if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
 		rt2800_bbp_write(rt2x00dev, 69, 0x16);
 		rt2800_bbp_write(rt2x00dev, 69, 0x16);
 		rt2800_bbp_write(rt2x00dev, 73, 0x12);
 		rt2800_bbp_write(rt2x00dev, 73, 0x12);
 	}
 	}
 
 
-	if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION)
+	if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION)
 		rt2800_bbp_write(rt2x00dev, 84, 0x19);
 		rt2800_bbp_write(rt2x00dev, 84, 0x19);
 
 
 	if (rt2x00_intf_is_usb(rt2x00dev) &&
 	if (rt2x00_intf_is_usb(rt2x00dev) &&
-	    rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
+	    rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
 		rt2800_bbp_write(rt2x00dev, 70, 0x0a);
 		rt2800_bbp_write(rt2x00dev, 70, 0x0a);
 		rt2800_bbp_write(rt2x00dev, 84, 0x99);
 		rt2800_bbp_write(rt2x00dev, 84, 0x99);
 		rt2800_bbp_write(rt2x00dev, 105, 0x05);
 		rt2800_bbp_write(rt2x00dev, 105, 0x05);
 	}
 	}
 
 
-	if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
+	if (rt2x00_rt(rt2x00dev, RT3052)) {
 		rt2800_bbp_write(rt2x00dev, 31, 0x08);
 		rt2800_bbp_write(rt2x00dev, 31, 0x08);
 		rt2800_bbp_write(rt2x00dev, 78, 0x0e);
 		rt2800_bbp_write(rt2x00dev, 78, 0x0e);
 		rt2800_bbp_write(rt2x00dev, 80, 0x08);
 		rt2800_bbp_write(rt2x00dev, 80, 0x08);
@@ -1566,13 +1565,13 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 	u8 bbp;
 	u8 bbp;
 
 
 	if (rt2x00_intf_is_usb(rt2x00dev) &&
 	if (rt2x00_intf_is_usb(rt2x00dev) &&
-	    rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
+	    rt2x00_rev(rt2x00dev) != RT3070_VERSION)
 		return 0;
 		return 0;
 
 
 	if (rt2x00_intf_is_pci(rt2x00dev)) {
 	if (rt2x00_intf_is_pci(rt2x00dev)) {
-		if (!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
-		    !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
-		    !rt2x00_rf(&rt2x00dev->chip, RF3022))
+		if (!rt2x00_rf(rt2x00dev, RF3020) &&
+		    !rt2x00_rf(rt2x00dev, RF3021) &&
+		    !rt2x00_rf(rt2x00dev, RF3022))
 			return 0;
 			return 0;
 	}
 	}
 
 
@@ -1737,7 +1736,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
 		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
 		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
-	} else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
+	} else if (rt2x00_rev(rt2x00dev) < RT2883_VERSION) {
 		/*
 		/*
 		 * There is a max of 2 RX streams for RT28x0 series
 		 * There is a max of 2 RX streams for RT28x0 series
 		 */
 		 */
@@ -1839,17 +1838,15 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 
 
 	if (rt2x00_intf_is_usb(rt2x00dev)) {
 	if (rt2x00_intf_is_usb(rt2x00dev)) {
-		struct rt2x00_chip *chip = &rt2x00dev->chip;
-
 		/*
 		/*
 		 * The check for rt2860 is not a typo, some rt2870 hardware
 		 * The check for rt2860 is not a typo, some rt2870 hardware
 		 * identifies itself as rt2860 in the CSR register.
 		 * identifies itself as rt2860 in the CSR register.
 		 */
 		 */
-		if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) ||
-		    rt2x00_check_rev(chip, 0xfff00000, 0x28700000) ||
-		    rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) {
+		if (rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28600000) ||
+		    rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28700000) ||
+		    rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28800000)) {
 			rt2x00_set_chip_rt(rt2x00dev, RT2870);
 			rt2x00_set_chip_rt(rt2x00dev, RT2870);
-		} else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) {
+		} else if (rt2x00_check_rev(rt2x00dev, 0xffff0000, 0x30700000)) {
 			rt2x00_set_chip_rt(rt2x00dev, RT3070);
 			rt2x00_set_chip_rt(rt2x00dev, RT3070);
 		} else {
 		} else {
 			ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
 			ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
@@ -1858,14 +1855,14 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	}
 	}
 	rt2x00_print_chip(rt2x00dev);
 	rt2x00_print_chip(rt2x00dev);
 
 
-	if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2850) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2720) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2750) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF3020) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2020) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF3022)) {
+	if (!rt2x00_rf(rt2x00dev, RF2820) &&
+	    !rt2x00_rf(rt2x00dev, RF2850) &&
+	    !rt2x00_rf(rt2x00dev, RF2720) &&
+	    !rt2x00_rf(rt2x00dev, RF2750) &&
+	    !rt2x00_rf(rt2x00dev, RF3020) &&
+	    !rt2x00_rf(rt2x00dev, RF2020) &&
+	    !rt2x00_rf(rt2x00dev, RF3021) &&
+	    !rt2x00_rf(rt2x00dev, RF3022)) {
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -2013,7 +2010,6 @@ static const struct rf_channel rf_vals_302x[] = {
 
 
 int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
 {
-	struct rt2x00_chip *chip = &rt2x00dev->chip;
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
 	struct hw_mode_spec *spec = &rt2x00dev->spec;
 	struct channel_info *info;
 	struct channel_info *info;
 	char *tx_power1;
 	char *tx_power1;
@@ -2049,19 +2045,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
 
-	if (rt2x00_rf(chip, RF2820) ||
-	    rt2x00_rf(chip, RF2720) ||
-	    (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) {
+	if (rt2x00_rf(rt2x00dev, RF2820) ||
+	    rt2x00_rf(rt2x00dev, RF2720) ||
+	    (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(rt2x00dev, RF3052))) {
 		spec->num_channels = 14;
 		spec->num_channels = 14;
 		spec->channels = rf_vals;
 		spec->channels = rf_vals;
-	} else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) {
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->num_channels = ARRAY_SIZE(rf_vals);
 		spec->num_channels = ARRAY_SIZE(rf_vals);
 		spec->channels = rf_vals;
 		spec->channels = rf_vals;
-	} else if (rt2x00_rf(chip, RF3020) ||
-		   rt2x00_rf(chip, RF2020) ||
-		   rt2x00_rf(chip, RF3021) ||
-		   rt2x00_rf(chip, RF3022)) {
+	} else if (rt2x00_rf(rt2x00dev, RF3020) ||
+		   rt2x00_rf(rt2x00dev, RF2020) ||
+		   rt2x00_rf(rt2x00dev, RF3021) ||
+		   rt2x00_rf(rt2x00dev, RF3022)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_302x);
 		spec->num_channels = ARRAY_SIZE(rf_vals_302x);
 		spec->channels = rf_vals_302x;
 		spec->channels = rf_vals_302x;
 	}
 	}
@@ -2069,7 +2065,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	/*
 	/*
 	 * Initialize HT information.
 	 * Initialize HT information.
 	 */
 	 */
-	if (!rt2x00_rf(chip, RF2020))
+	if (!rt2x00_rf(rt2x00dev, RF2020))
 		spec->ht.ht_supported = true;
 		spec->ht.ht_supported = true;
 	else
 	else
 		spec->ht.ht_supported = false;
 		spec->ht.ht_supported = false;

+ 8 - 17
drivers/net/wireless/rt2x00/rt2800pci.c

@@ -48,14 +48,6 @@
 #include "rt2800.h"
 #include "rt2800.h"
 #include "rt2800pci.h"
 #include "rt2800pci.h"
 
 
-#ifdef CONFIG_RT2800PCI_PCI_MODULE
-#define CONFIG_RT2800PCI_PCI
-#endif
-
-#ifdef CONFIG_RT2800PCI_WISOC_MODULE
-#define CONFIG_RT2800PCI_WISOC
-#endif
-
 /*
 /*
  * Allow hardware encryption to be disabled.
  * Allow hardware encryption to be disabled.
  */
  */
@@ -87,7 +79,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
 	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
 	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
 }
 }
 
 
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
 static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
 {
 	u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
 	u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
@@ -98,7 +90,7 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
 {
 }
 }
-#endif /* CONFIG_RT2800PCI_WISOC */
+#endif /* CONFIG_RT2800PCI_SOC */
 
 
 #ifdef CONFIG_RT2800PCI_PCI
 #ifdef CONFIG_RT2800PCI_PCI
 static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
 static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@@ -1129,8 +1121,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 	/*
 	/*
 	 * This device requires firmware.
 	 * This device requires firmware.
 	 */
 	 */
-	if (!rt2x00_rt(&rt2x00dev->chip, RT2880) &&
-	    !rt2x00_rt(&rt2x00dev->chip, RT3052))
+	if (!rt2x00_rt(rt2x00dev, RT2880) && !rt2x00_rt(rt2x00dev, RT3052))
 		__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
 		__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
@@ -1251,7 +1242,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
 #endif /* CONFIG_RT2800PCI_PCI */
 #endif /* CONFIG_RT2800PCI_PCI */
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
 #if defined(CONFIG_RALINK_RT288X)
 #if defined(CONFIG_RALINK_RT288X)
 __rt2x00soc_probe(RT2880, &rt2800pci_ops);
 __rt2x00soc_probe(RT2880, &rt2800pci_ops);
 #elif defined(CONFIG_RALINK_RT305X)
 #elif defined(CONFIG_RALINK_RT305X)
@@ -1269,7 +1260,7 @@ static struct platform_driver rt2800soc_driver = {
 	.suspend	= rt2x00soc_suspend,
 	.suspend	= rt2x00soc_suspend,
 	.resume		= rt2x00soc_resume,
 	.resume		= rt2x00soc_resume,
 };
 };
-#endif /* CONFIG_RT2800PCI_WISOC */
+#endif /* CONFIG_RT2800PCI_SOC */
 
 
 #ifdef CONFIG_RT2800PCI_PCI
 #ifdef CONFIG_RT2800PCI_PCI
 static struct pci_driver rt2800pci_driver = {
 static struct pci_driver rt2800pci_driver = {
@@ -1286,7 +1277,7 @@ static int __init rt2800pci_init(void)
 {
 {
 	int ret = 0;
 	int ret = 0;
 
 
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
 	ret = platform_driver_register(&rt2800soc_driver);
 	ret = platform_driver_register(&rt2800soc_driver);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
@@ -1294,7 +1285,7 @@ static int __init rt2800pci_init(void)
 #ifdef CONFIG_RT2800PCI_PCI
 #ifdef CONFIG_RT2800PCI_PCI
 	ret = pci_register_driver(&rt2800pci_driver);
 	ret = pci_register_driver(&rt2800pci_driver);
 	if (ret) {
 	if (ret) {
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
 		platform_driver_unregister(&rt2800soc_driver);
 		platform_driver_unregister(&rt2800soc_driver);
 #endif
 #endif
 		return ret;
 		return ret;
@@ -1309,7 +1300,7 @@ static void __exit rt2800pci_exit(void)
 #ifdef CONFIG_RT2800PCI_PCI
 #ifdef CONFIG_RT2800PCI_PCI
 	pci_unregister_driver(&rt2800pci_driver);
 	pci_unregister_driver(&rt2800pci_driver);
 #endif
 #endif
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
 	platform_driver_unregister(&rt2800soc_driver);
 	platform_driver_unregister(&rt2800soc_driver);
 #endif
 #endif
 }
 }

+ 3 - 2
drivers/net/wireless/rt2x00/rt2800usb.c

@@ -92,7 +92,7 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len)
 static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
 static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
 				    const u8 *data, const size_t len)
 				    const u8 *data, const size_t len)
 {
 {
-	u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
+	u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
 	size_t offset = 0;
 	size_t offset = 0;
 
 
 	/*
 	/*
@@ -138,7 +138,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
 	u32 reg;
 	u32 reg;
 	u32 offset;
 	u32 offset;
 	u32 length;
 	u32 length;
-	u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
+	u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
 
 
 	/*
 	/*
 	 * Check which section of the firmware we need.
 	 * Check which section of the firmware we need.
@@ -933,6 +933,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
+	{ USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
 	/* Logitec */
 	/* Logitec */
 	{ USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },
 	{ USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },

+ 14 - 14
drivers/net/wireless/rt2x00/rt2x00.h

@@ -937,25 +937,25 @@ static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev)
 	     rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
 	     rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
 }
 }
 
 
-static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
+static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
 {
 {
-	return (chipset->rt == chip);
+	return (rt2x00dev->chip.rt == rt);
 }
 }
 
 
-static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip)
+static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
 {
 {
-	return (chipset->rf == chip);
+	return (rt2x00dev->chip.rf == rf);
 }
 }
 
 
-static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset)
+static inline u32 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
 {
 {
-	return chipset->rev;
+	return rt2x00dev->chip.rev;
 }
 }
 
 
-static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset,
+static inline bool rt2x00_check_rev(struct rt2x00_dev *rt2x00dev,
 				    const u32 mask, const u32 rev)
 				    const u32 mask, const u32 rev)
 {
 {
-	return ((chipset->rev & mask) == rev);
+	return ((rt2x00dev->chip.rev & mask) == rev);
 }
 }
 
 
 static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
 static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
@@ -964,20 +964,20 @@ static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
 	rt2x00dev->chip.intf = intf;
 	rt2x00dev->chip.intf = intf;
 }
 }
 
 
-static inline bool rt2x00_intf(const struct rt2x00_chip *chipset,
+static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev,
 			       enum rt2x00_chip_intf intf)
 			       enum rt2x00_chip_intf intf)
 {
 {
-	return (chipset->intf == intf);
+	return (rt2x00dev->chip.intf == intf);
 }
 }
 
 
 static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev)
 static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev)
 {
 {
-	return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI);
+	return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
 }
 }
 
 
 static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev)
 static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev)
 {
 {
-	return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB);
+	return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
 }
 }
 
 
 /**
 /**
@@ -1019,9 +1019,9 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 int rt2x00mac_start(struct ieee80211_hw *hw);
 int rt2x00mac_start(struct ieee80211_hw *hw);
 void rt2x00mac_stop(struct ieee80211_hw *hw);
 void rt2x00mac_stop(struct ieee80211_hw *hw);
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
-			    struct ieee80211_if_init_conf *conf);
+			    struct ieee80211_vif *vif);
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
-				struct ieee80211_if_init_conf *conf);
+				struct ieee80211_vif *vif);
 int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
 int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
 void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
 void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
 				unsigned int changed_flags,
 				unsigned int changed_flags,

+ 13 - 13
drivers/net/wireless/rt2x00/rt2x00mac.c

@@ -187,10 +187,10 @@ void rt2x00mac_stop(struct ieee80211_hw *hw)
 EXPORT_SYMBOL_GPL(rt2x00mac_stop);
 EXPORT_SYMBOL_GPL(rt2x00mac_stop);
 
 
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
-			    struct ieee80211_if_init_conf *conf)
+			    struct ieee80211_vif *vif)
 {
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct rt2x00_intf *intf = vif_to_intf(conf->vif);
+	struct rt2x00_intf *intf = vif_to_intf(vif);
 	struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
 	struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
 	struct queue_entry *entry = NULL;
 	struct queue_entry *entry = NULL;
 	unsigned int i;
 	unsigned int i;
@@ -203,7 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 	    !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 	    !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 		return -ENODEV;
 		return -ENODEV;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP:
 		/*
 		/*
 		 * We don't support mixed combinations of
 		 * We don't support mixed combinations of
@@ -263,7 +263,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 	 * increase interface count and start initialization.
 	 * increase interface count and start initialization.
 	 */
 	 */
 
 
-	if (conf->type == NL80211_IFTYPE_AP)
+	if (vif->type == NL80211_IFTYPE_AP)
 		rt2x00dev->intf_ap_count++;
 		rt2x00dev->intf_ap_count++;
 	else
 	else
 		rt2x00dev->intf_sta_count++;
 		rt2x00dev->intf_sta_count++;
@@ -273,16 +273,16 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 	mutex_init(&intf->beacon_skb_mutex);
 	mutex_init(&intf->beacon_skb_mutex);
 	intf->beacon = entry;
 	intf->beacon = entry;
 
 
-	if (conf->type == NL80211_IFTYPE_AP)
-		memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
-	memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
+	if (vif->type == NL80211_IFTYPE_AP)
+		memcpy(&intf->bssid, vif->addr, ETH_ALEN);
+	memcpy(&intf->mac, vif->addr, ETH_ALEN);
 
 
 	/*
 	/*
 	 * The MAC adddress must be configured after the device
 	 * The MAC adddress must be configured after the device
 	 * has been initialized. Otherwise the device can reset
 	 * has been initialized. Otherwise the device can reset
 	 * the MAC registers.
 	 * the MAC registers.
 	 */
 	 */
-	rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL);
+	rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);
 
 
 	/*
 	/*
 	 * Some filters depend on the current working mode. We can force
 	 * Some filters depend on the current working mode. We can force
@@ -296,10 +296,10 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
 EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
 
 
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
-				struct ieee80211_if_init_conf *conf)
+				struct ieee80211_vif *vif)
 {
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct rt2x00_intf *intf = vif_to_intf(conf->vif);
+	struct rt2x00_intf *intf = vif_to_intf(vif);
 
 
 	/*
 	/*
 	 * Don't allow interfaces to be remove while
 	 * Don't allow interfaces to be remove while
@@ -307,11 +307,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
 	 * no interface is present.
 	 * no interface is present.
 	 */
 	 */
 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
-	    (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
-	    (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
+	    (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
+	    (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
 		return;
 		return;
 
 
-	if (conf->type == NL80211_IFTYPE_AP)
+	if (vif->type == NL80211_IFTYPE_AP)
 		rt2x00dev->intf_ap_count--;
 		rt2x00dev->intf_ap_count--;
 	else
 	else
 		rt2x00dev->intf_sta_count--;
 		rt2x00dev->intf_sta_count--;

+ 12 - 17
drivers/net/wireless/rt2x00/rt61pci.c

@@ -637,8 +637,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
 	rt61pci_bbp_read(rt2x00dev, 4, &r4);
 	rt61pci_bbp_read(rt2x00dev, 4, &r4);
 	rt61pci_bbp_read(rt2x00dev, 77, &r77);
 	rt61pci_bbp_read(rt2x00dev, 77, &r77);
 
 
-	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
-			  rt2x00_rf(&rt2x00dev->chip, RF5325));
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325));
 
 
 	/*
 	/*
 	 * Configure the RX antenna.
 	 * Configure the RX antenna.
@@ -684,8 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
 	rt61pci_bbp_read(rt2x00dev, 4, &r4);
 	rt61pci_bbp_read(rt2x00dev, 4, &r4);
 	rt61pci_bbp_read(rt2x00dev, 77, &r77);
 	rt61pci_bbp_read(rt2x00dev, 77, &r77);
 
 
-	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
-			  rt2x00_rf(&rt2x00dev->chip, RF2529));
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
 	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
 	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
 			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
 			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
 
 
@@ -833,12 +831,11 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
 
 
 	rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
 	rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
 
 
-	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5325))
+	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325))
 		rt61pci_config_antenna_5x(rt2x00dev, ant);
 		rt61pci_config_antenna_5x(rt2x00dev, ant);
-	else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
+	else if (rt2x00_rf(rt2x00dev, RF2527))
 		rt61pci_config_antenna_2x(rt2x00dev, ant);
 		rt61pci_config_antenna_2x(rt2x00dev, ant);
-	else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+	else if (rt2x00_rf(rt2x00dev, RF2529)) {
 		if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
 		if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
 			rt61pci_config_antenna_2x(rt2x00dev, ant);
 			rt61pci_config_antenna_2x(rt2x00dev, ant);
 		else
 		else
@@ -879,8 +876,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
 	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
 	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 
 
-	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+	smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
 
 
 	rt61pci_bbp_read(rt2x00dev, 3, &r3);
 	rt61pci_bbp_read(rt2x00dev, 3, &r3);
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@@ -2302,10 +2298,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 	rt2x00_set_chip_rf(rt2x00dev, value, reg);
 	rt2x00_print_chip(rt2x00dev);
 	rt2x00_print_chip(rt2x00dev);
 
 
-	if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF5325) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2527) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+	if (!rt2x00_rf(rt2x00dev, RF5225) &&
+	    !rt2x00_rf(rt2x00dev, RF5325) &&
+	    !rt2x00_rf(rt2x00dev, RF2527) &&
+	    !rt2x00_rf(rt2x00dev, RF2529)) {
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -2360,7 +2356,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	 * the antenna settings should be gathered from the NIC
 	 * the antenna settings should be gathered from the NIC
 	 * eeprom word.
 	 * eeprom word.
 	 */
 	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2529) &&
+	if (rt2x00_rf(rt2x00dev, RF2529) &&
 	    !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
 	    !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
 		rt2x00dev->default_ant.rx =
 		rt2x00dev->default_ant.rx =
 		    ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
 		    ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
@@ -2571,8 +2567,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 		spec->channels = rf_vals_seq;
 		spec->channels = rf_vals_seq;
 	}
 	}
 
 
-	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5325)) {
+	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) {
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->num_channels = ARRAY_SIZE(rf_vals_seq);
 		spec->num_channels = ARRAY_SIZE(rf_vals_seq);
 	}
 	}

+ 16 - 20
drivers/net/wireless/rt2x00/rt73usb.c

@@ -136,8 +136,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
 		 * all others contain 20 bits.
 		 * all others contain 20 bits.
 		 */
 		 */
 		rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
 		rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
-				   20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-					 rt2x00_rf(&rt2x00dev->chip, RF2527)));
+				   20 + (rt2x00_rf(rt2x00dev, RF5225) ||
+					 rt2x00_rf(rt2x00dev, RF2527)));
 		rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
 		rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
 		rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
 		rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
 
 
@@ -741,11 +741,9 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
 
 
 	rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
 	rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
 
 
-	if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5225))
+	if (rt2x00_rf(rt2x00dev, RF5226) || rt2x00_rf(rt2x00dev, RF5225))
 		rt73usb_config_antenna_5x(rt2x00dev, ant);
 		rt73usb_config_antenna_5x(rt2x00dev, ant);
-	else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
-		 rt2x00_rf(&rt2x00dev->chip, RF2527))
+	else if (rt2x00_rf(rt2x00dev, RF2528) || rt2x00_rf(rt2x00dev, RF2527))
 		rt73usb_config_antenna_2x(rt2x00dev, ant);
 		rt73usb_config_antenna_2x(rt2x00dev, ant);
 }
 }
 
 
@@ -779,8 +777,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
 	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
 	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 
 
-	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+	smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
 
 
 	rt73usb_bbp_read(rt2x00dev, 3, &r3);
 	rt73usb_bbp_read(rt2x00dev, 3, &r3);
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@@ -1210,8 +1207,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
 	rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
 
 
 	reg = 0x000023b0;
 	reg = 0x000023b0;
-	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF2527))
+	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527))
 		rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
 		rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
 	rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
 	rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
 
 
@@ -1827,16 +1823,16 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
 	rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
 	rt2x00_print_chip(rt2x00dev);
 	rt2x00_print_chip(rt2x00dev);
 
 
-	if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) ||
-	    rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
+	if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) ||
+	    rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
 		ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	if (!rt2x00_rf(&rt2x00dev->chip, RF5226) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2528) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF5225) &&
-	    !rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+	if (!rt2x00_rf(rt2x00dev, RF5226) &&
+	    !rt2x00_rf(rt2x00dev, RF2528) &&
+	    !rt2x00_rf(rt2x00dev, RF5225) &&
+	    !rt2x00_rf(rt2x00dev, RF2527)) {
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -2081,17 +2077,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_bands = SUPPORT_BAND_2GHZ;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
 
-	if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
+	if (rt2x00_rf(rt2x00dev, RF2528)) {
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
 		spec->channels = rf_vals_bg_2528;
 		spec->channels = rf_vals_bg_2528;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+	} else if (rt2x00_rf(rt2x00dev, RF5226)) {
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->num_channels = ARRAY_SIZE(rf_vals_5226);
 		spec->num_channels = ARRAY_SIZE(rf_vals_5226);
 		spec->channels = rf_vals_5226;
 		spec->channels = rf_vals_5226;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+	} else if (rt2x00_rf(rt2x00dev, RF2527)) {
 		spec->num_channels = 14;
 		spec->num_channels = 14;
 		spec->channels = rf_vals_5225_2527;
 		spec->channels = rf_vals_5225_2527;
-	} else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
+	} else if (rt2x00_rf(rt2x00dev, RF5225)) {
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->supported_bands |= SUPPORT_BAND_5GHZ;
 		spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
 		spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
 		spec->channels = rf_vals_5225_2527;
 		spec->channels = rf_vals_5225_2527;

+ 0 - 1
drivers/net/wireless/rtl818x/rtl8180.h

@@ -60,7 +60,6 @@ struct rtl8180_priv {
 	struct rtl818x_csr __iomem *map;
 	struct rtl818x_csr __iomem *map;
 	const struct rtl818x_rf_ops *rf;
 	const struct rtl818x_rf_ops *rf;
 	struct ieee80211_vif *vif;
 	struct ieee80211_vif *vif;
-	int mode;
 
 
 	/* rtl8180 driver specific */
 	/* rtl8180 driver specific */
 	spinlock_t lock;
 	spinlock_t lock;

+ 11 - 15
drivers/net/wireless/rtl818x/rtl8180_dev.c

@@ -82,8 +82,6 @@ static const struct ieee80211_channel rtl818x_channels[] = {
 };
 };
 
 
 
 
-
-
 void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 {
 {
 	struct rtl8180_priv *priv = dev->priv;
 	struct rtl8180_priv *priv = dev->priv;
@@ -615,7 +613,6 @@ static int rtl8180_start(struct ieee80211_hw *dev)
 	reg |= RTL818X_CMD_TX_ENABLE;
 	reg |= RTL818X_CMD_TX_ENABLE;
 	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
 	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
 
 
-	priv->mode = NL80211_IFTYPE_MONITOR;
 	return 0;
 	return 0;
 
 
  err_free_rings:
  err_free_rings:
@@ -633,8 +630,6 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
 	u8 reg;
 	u8 reg;
 	int i;
 	int i;
 
 
-	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-
 	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
 
 	reg = rtl818x_ioread8(priv, &priv->map->CMD);
 	reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -657,38 +652,39 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
 }
 }
 
 
 static int rtl8180_add_interface(struct ieee80211_hw *dev,
 static int rtl8180_add_interface(struct ieee80211_hw *dev,
-				 struct ieee80211_if_init_conf *conf)
+				 struct ieee80211_vif *vif)
 {
 {
 	struct rtl8180_priv *priv = dev->priv;
 	struct rtl8180_priv *priv = dev->priv;
 
 
-	if (priv->mode != NL80211_IFTYPE_MONITOR)
-		return -EOPNOTSUPP;
+	/*
+	 * We only support one active interface at a time.
+	 */
+	if (priv->vif)
+		return -EBUSY;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
-		priv->mode = conf->type;
 		break;
 		break;
 	default:
 	default:
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	}
 	}
 
 
-	priv->vif = conf->vif;
+	priv->vif = vif;
 
 
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
 	rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
-			  le32_to_cpu(*(__le32 *)conf->mac_addr));
+			  le32_to_cpu(*(__le32 *)vif->addr));
 	rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4],
 	rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4],
-			  le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+			  le16_to_cpu(*(__le16 *)(vif->addr + 4)));
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static void rtl8180_remove_interface(struct ieee80211_hw *dev,
 static void rtl8180_remove_interface(struct ieee80211_hw *dev,
-				     struct ieee80211_if_init_conf *conf)
+				     struct ieee80211_vif *vif)
 {
 {
 	struct rtl8180_priv *priv = dev->priv;
 	struct rtl8180_priv *priv = dev->priv;
-	priv->mode = NL80211_IFTYPE_MONITOR;
 	priv->vif = NULL;
 	priv->vif = NULL;
 }
 }
 
 

+ 1 - 1
drivers/net/wireless/rtl818x/rtl8187.h

@@ -92,7 +92,7 @@ struct rtl8187_priv {
 	struct rtl818x_csr *map;
 	struct rtl818x_csr *map;
 	const struct rtl818x_rf_ops *rf;
 	const struct rtl818x_rf_ops *rf;
 	struct ieee80211_vif *vif;
 	struct ieee80211_vif *vif;
-	int mode;
+
 	/* The mutex protects the TX loopback state.
 	/* The mutex protects the TX loopback state.
 	 * Any attempt to set channels concurrently locks the device.
 	 * Any attempt to set channels concurrently locks the device.
 	 */
 	 */

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

@@ -1018,31 +1018,30 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
 }
 }
 
 
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
-				 struct ieee80211_if_init_conf *conf)
+				 struct ieee80211_vif *vif)
 {
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 	int i;
 	int ret = -EOPNOTSUPP;
 	int ret = -EOPNOTSUPP;
 
 
 	mutex_lock(&priv->conf_mutex);
 	mutex_lock(&priv->conf_mutex);
-	if (priv->mode != NL80211_IFTYPE_MONITOR)
+	if (priv->vif)
 		goto exit;
 		goto exit;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
-		priv->mode = conf->type;
 		break;
 		break;
 	default:
 	default:
 		goto exit;
 		goto exit;
 	}
 	}
 
 
 	ret = 0;
 	ret = 0;
-	priv->vif = conf->vif;
+	priv->vif = vif;
 
 
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	for (i = 0; i < ETH_ALEN; i++)
 	for (i = 0; i < ETH_ALEN; i++)
 		rtl818x_iowrite8(priv, &priv->map->MAC[i],
 		rtl818x_iowrite8(priv, &priv->map->MAC[i],
-				 ((u8 *)conf->mac_addr)[i]);
+				 ((u8 *)vif->addr)[i]);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
 
 exit:
 exit:
@@ -1051,11 +1050,10 @@ exit:
 }
 }
 
 
 static void rtl8187_remove_interface(struct ieee80211_hw *dev,
 static void rtl8187_remove_interface(struct ieee80211_hw *dev,
-				     struct ieee80211_if_init_conf *conf)
+				     struct ieee80211_vif *vif)
 {
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct rtl8187_priv *priv = dev->priv;
 	mutex_lock(&priv->conf_mutex);
 	mutex_lock(&priv->conf_mutex);
-	priv->mode = NL80211_IFTYPE_MONITOR;
 	priv->vif = NULL;
 	priv->vif = NULL;
 	mutex_unlock(&priv->conf_mutex);
 	mutex_unlock(&priv->conf_mutex);
 }
 }
@@ -1365,7 +1363,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 	dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 	dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 
 
 
 
-	priv->mode = NL80211_IFTYPE_MONITOR;
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 		     IEEE80211_HW_SIGNAL_DBM |
 		     IEEE80211_HW_SIGNAL_DBM |
 		     IEEE80211_HW_RX_INCLUDES_FCS;
 		     IEEE80211_HW_RX_INCLUDES_FCS;

+ 2 - 2
drivers/net/wireless/rtl818x/rtl8187_leds.c

@@ -33,7 +33,7 @@ static void led_turn_on(struct work_struct *work)
 	struct rtl8187_led *led = &priv->led_tx;
 	struct rtl8187_led *led = &priv->led_tx;
 
 
 	/* Don't change the LED, when the device is down. */
 	/* Don't change the LED, when the device is down. */
-	if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+	if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
 		return ;
 		return ;
 
 
 	/* Skip if the LED is not registered. */
 	/* Skip if the LED is not registered. */
@@ -71,7 +71,7 @@ static void led_turn_off(struct work_struct *work)
 	struct rtl8187_led *led = &priv->led_tx;
 	struct rtl8187_led *led = &priv->led_tx;
 
 
 	/* Don't change the LED, when the device is down. */
 	/* Don't change the LED, when the device is down. */
-	if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+	if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
 		return ;
 		return ;
 
 
 	/* Skip if the LED is not registered. */
 	/* Skip if the LED is not registered. */

+ 1 - 1
drivers/net/wireless/wl12xx/wl1251_boot.c

@@ -256,7 +256,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
 		}
 		}
 	}
 	}
 
 
-	if (loop >= INIT_LOOP) {
+	if (loop > INIT_LOOP) {
 		wl1251_error("timeout waiting for the hardware to "
 		wl1251_error("timeout waiting for the hardware to "
 			     "complete initialization");
 			     "complete initialization");
 		return -EIO;
 		return -EIO;

+ 7 - 7
drivers/net/wireless/wl12xx/wl1251_main.c

@@ -511,13 +511,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
 }
 }
 
 
 static int wl1251_op_add_interface(struct ieee80211_hw *hw,
 static int wl1251_op_add_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_if_init_conf *conf)
+				   struct ieee80211_vif *vif)
 {
 {
 	struct wl1251 *wl = hw->priv;
 	struct wl1251 *wl = hw->priv;
 	int ret = 0;
 	int ret = 0;
 
 
 	wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
 	wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
-		     conf->type, conf->mac_addr);
+		     vif->type, vif->addr);
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 	if (wl->vif) {
 	if (wl->vif) {
@@ -525,9 +525,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	wl->vif = conf->vif;
+	wl->vif = vif;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
 		wl->bss_type = BSS_TYPE_STA_BSS;
 		wl->bss_type = BSS_TYPE_STA_BSS;
 		break;
 		break;
@@ -539,8 +539,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
-		memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+	if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) {
+		memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
 		SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
 		SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
 		ret = wl1251_acx_station_id(wl);
 		ret = wl1251_acx_station_id(wl);
 		if (ret < 0)
 		if (ret < 0)
@@ -553,7 +553,7 @@ out:
 }
 }
 
 
 static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
 static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
-					 struct ieee80211_if_init_conf *conf)
+					 struct ieee80211_vif *vif)
 {
 {
 	struct wl1251 *wl = hw->priv;
 	struct wl1251 *wl = hw->priv;
 
 

+ 18 - 17
drivers/net/wireless/wl12xx/wl1271.h

@@ -107,10 +107,9 @@ enum {
 				  CFG_RX_CTL_EN | CFG_RX_BCN_EN |     \
 				  CFG_RX_CTL_EN | CFG_RX_BCN_EN |     \
 				  CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
 				  CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
 
 
-#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL)
-
 #define WL1271_FW_NAME "wl1271-fw.bin"
 #define WL1271_FW_NAME "wl1271-fw.bin"
 #define WL1271_NVS_NAME "wl1271-nvs.bin"
 #define WL1271_NVS_NAME "wl1271-nvs.bin"
+#define WL1271_NVS_LEN  468
 
 
 /*
 /*
  * Enable/disable 802.11a support for WL1273
  * Enable/disable 802.11a support for WL1273
@@ -276,6 +275,7 @@ struct wl1271_debugfs {
 
 
 	struct dentry *retry_count;
 	struct dentry *retry_count;
 	struct dentry *excessive_retries;
 	struct dentry *excessive_retries;
+	struct dentry *gpio_power;
 };
 };
 
 
 #define NUM_TX_QUEUES              4
 #define NUM_TX_QUEUES              4
@@ -322,6 +322,17 @@ struct wl1271 {
 	enum wl1271_state state;
 	enum wl1271_state state;
 	struct mutex mutex;
 	struct mutex mutex;
 
 
+#define WL1271_FLAG_STA_RATES_CHANGED  (0)
+#define WL1271_FLAG_STA_ASSOCIATED     (1)
+#define WL1271_FLAG_JOINED             (2)
+#define WL1271_FLAG_GPIO_POWER         (3)
+#define WL1271_FLAG_TX_QUEUE_STOPPED   (4)
+#define WL1271_FLAG_SCANNING           (5)
+#define WL1271_FLAG_IN_ELP             (6)
+#define WL1271_FLAG_PSM                (7)
+#define WL1271_FLAG_PSM_REQUESTED      (8)
+	unsigned long flags;
+
 	struct wl1271_partition_set part;
 	struct wl1271_partition_set part;
 
 
 	struct wl1271_chip chip;
 	struct wl1271_chip chip;
@@ -359,7 +370,6 @@ struct wl1271 {
 
 
 	/* Frames scheduled for transmission, not handled yet */
 	/* Frames scheduled for transmission, not handled yet */
 	struct sk_buff_head tx_queue;
 	struct sk_buff_head tx_queue;
-	bool tx_queue_stopped;
 
 
 	struct work_struct tx_work;
 	struct work_struct tx_work;
 
 
@@ -387,14 +397,15 @@ struct wl1271 {
 	u32 mbox_ptr[2];
 	u32 mbox_ptr[2];
 
 
 	/* Are we currently scanning */
 	/* Are we currently scanning */
-	bool scanning;
 	struct wl1271_scan scan;
 	struct wl1271_scan scan;
 
 
 	/* Our association ID */
 	/* Our association ID */
 	u16 aid;
 	u16 aid;
 
 
 	/* currently configured rate set */
 	/* currently configured rate set */
+	u32 sta_rate_set;
 	u32 basic_rate_set;
 	u32 basic_rate_set;
+	u32 rate_set;
 
 
 	/* The current band */
 	/* The current band */
 	enum ieee80211_band band;
 	enum ieee80211_band band;
@@ -405,18 +416,9 @@ struct wl1271 {
 	unsigned int rx_config;
 	unsigned int rx_config;
 	unsigned int rx_filter;
 	unsigned int rx_filter;
 
 
-	/* is firmware in elp mode */
-	bool elp;
-
 	struct completion *elp_compl;
 	struct completion *elp_compl;
 	struct delayed_work elp_work;
 	struct delayed_work elp_work;
 
 
-	/* we can be in psm, but not in elp, we have to differentiate */
-	bool psm;
-
-	/* PSM mode requested */
-	bool psm_requested;
-
 	/* retry counter for PSM entries */
 	/* retry counter for PSM entries */
 	u8 psm_entry_retry;
 	u8 psm_entry_retry;
 
 
@@ -435,9 +437,6 @@ struct wl1271 {
 
 
 	struct ieee80211_vif *vif;
 	struct ieee80211_vif *vif;
 
 
-	/* Used for a workaround to send disconnect before rejoining */
-	bool joined;
-
 	/* Current chipset configuration */
 	/* Current chipset configuration */
 	struct conf_drv_settings conf;
 	struct conf_drv_settings conf;
 
 
@@ -455,7 +454,9 @@ int wl1271_plt_stop(struct wl1271 *wl);
 
 
 #define WL1271_TX_QUEUE_MAX_LENGTH 20
 #define WL1271_TX_QUEUE_MAX_LENGTH 20
 
 
-/* WL1271 needs a 200ms sleep after power on */
+/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
+   on in case is has been shut down shortly before */
+#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
 #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
 #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
 
 
 static inline bool wl1271_11a_enabled(void)
 static inline bool wl1271_11a_enabled(void)

+ 74 - 60
drivers/net/wireless/wl12xx/wl1271_acx.c

@@ -390,6 +390,35 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
+int wl1271_acx_dco_itrim_params(struct wl1271 *wl)
+{
+	struct acx_dco_itrim_params *dco;
+	struct conf_itrim_settings *c = &wl->conf.itrim;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx dco itrim parameters");
+
+	dco = kzalloc(sizeof(*dco), GFP_KERNEL);
+	if (!dco) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	dco->enable = c->enable;
+	dco->timeout = cpu_to_le32(c->timeout);
+
+	ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS,
+				   dco, sizeof(*dco));
+	if (ret < 0) {
+		wl1271_warning("failed to set dco itrim parameters: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(dco);
+	return ret;
+}
+
 int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
 int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
 {
 {
 	struct acx_beacon_filter_option *beacon_filter = NULL;
 	struct acx_beacon_filter_option *beacon_filter = NULL;
@@ -758,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
 	return 0;
 	return 0;
 }
 }
 
 
-int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
+int wl1271_acx_rate_policies(struct wl1271 *wl)
 {
 {
 	struct acx_rate_policy *acx;
 	struct acx_rate_policy *acx;
 	struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
 	struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
+	int idx = 0;
 	int ret = 0;
 	int ret = 0;
 
 
 	wl1271_debug(DEBUG_ACX, "acx rate policies");
 	wl1271_debug(DEBUG_ACX, "acx rate policies");
@@ -773,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	/* configure one default (one-size-fits-all) rate class */
-	acx->rate_class_cnt = cpu_to_le32(1);
-	acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates);
-	acx->rate_class[0].short_retry_limit = c->short_retry_limit;
-	acx->rate_class[0].long_retry_limit = c->long_retry_limit;
-	acx->rate_class[0].aflags = c->aflags;
+	/* configure one basic rate class */
+	idx = ACX_TX_BASIC_RATE;
+	acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set);
+	acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
+	acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
+	acx->rate_class[idx].aflags = c->aflags;
+
+	/* configure one AP supported rate class */
+	idx = ACX_TX_AP_FULL_RATE;
+	acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
+	acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
+	acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
+	acx->rate_class[idx].aflags = c->aflags;
+
+	acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
 
 
 	ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
 	ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
 	if (ret < 0) {
 	if (ret < 0) {
@@ -1012,59 +1051,6 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
-int wl1271_acx_smart_reflex(struct wl1271 *wl)
-{
-	struct acx_smart_reflex_state *sr_state = NULL;
-	struct acx_smart_reflex_config_params *sr_param = NULL;
-	int i, ret;
-
-	wl1271_debug(DEBUG_ACX, "acx smart reflex");
-
-	sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL);
-	if (!sr_param) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) {
-		struct conf_mart_reflex_err_table *e =
-			&(wl->conf.init.sr_err_tbl[i]);
-
-		sr_param->error_table[i].len = e->len;
-		sr_param->error_table[i].upper_limit = e->upper_limit;
-		memcpy(sr_param->error_table[i].values, e->values, e->len);
-	}
-
-	ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS,
-				   sr_param, sizeof(*sr_param));
-	if (ret < 0) {
-		wl1271_warning("failed to set smart reflex params: %d", ret);
-		goto out;
-	}
-
-	sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
-	if (!sr_state) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	/* enable smart reflex */
-	sr_state->enable = wl->conf.init.sr_enable;
-
-	ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE,
-				   sr_state, sizeof(*sr_state));
-	if (ret < 0) {
-		wl1271_warning("failed to set smart reflex params: %d", ret);
-		goto out;
-	}
-
-out:
-	kfree(sr_state);
-	kfree(sr_param);
-	return ret;
-
-}
-
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
 {
 {
 	struct wl1271_acx_bet_enable *acx = NULL;
 	struct wl1271_acx_bet_enable *acx = NULL;
@@ -1132,3 +1118,31 @@ out:
 	kfree(acx);
 	kfree(acx);
 	return ret;
 	return ret;
 }
 }
+
+int wl1271_acx_pm_config(struct wl1271 *wl)
+{
+	struct wl1271_acx_pm_config *acx = NULL;
+	struct  conf_pm_config_settings *c = &wl->conf.pm_config;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_ACX, "acx pm config");
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time);
+	acx->host_fast_wakeup_support = c->host_fast_wakeup_support;
+
+	ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx));
+	if (ret < 0) {
+		wl1271_warning("acx pm config failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+}

+ 19 - 18
drivers/net/wireless/wl12xx/wl1271_acx.h

@@ -415,23 +415,12 @@ struct acx_bt_wlan_coex {
 	u8 pad[3];
 	u8 pad[3];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
-struct acx_smart_reflex_state {
+struct acx_dco_itrim_params {
 	struct acx_header header;
 	struct acx_header header;
 
 
 	u8 enable;
 	u8 enable;
 	u8 padding[3];
 	u8 padding[3];
-} __attribute__ ((packed));
-
-struct smart_reflex_err_table {
-	u8 len;
-	s8 upper_limit;
-	s8 values[14];
-} __attribute__ ((packed));
-
-struct acx_smart_reflex_config_params {
-	struct acx_header header;
-
-	struct smart_reflex_err_table error_table[3];
+	__le32 timeout;
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
 #define PTA_ANTENNA_TYPE_DEF		  (0)
 #define PTA_ANTENNA_TYPE_DEF		  (0)
@@ -837,6 +826,9 @@ struct acx_rate_class {
 	u8 reserved;
 	u8 reserved;
 };
 };
 
 
+#define ACX_TX_BASIC_RATE      0
+#define ACX_TX_AP_FULL_RATE    1
+#define ACX_TX_RATE_POLICY_CNT 2
 struct acx_rate_policy {
 struct acx_rate_policy {
 	struct acx_header header;
 	struct acx_header header;
 
 
@@ -877,8 +869,8 @@ struct acx_tx_config_options {
 	__le16 tx_compl_threshold;   /* number of packets */
 	__le16 tx_compl_threshold;   /* number of packets */
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
-#define ACX_RX_MEM_BLOCKS     64
-#define ACX_TX_MIN_MEM_BLOCKS 64
+#define ACX_RX_MEM_BLOCKS     70
+#define ACX_TX_MIN_MEM_BLOCKS 40
 #define ACX_TX_DESCRIPTORS    32
 #define ACX_TX_DESCRIPTORS    32
 #define ACX_NUM_SSID_PROFILES 1
 #define ACX_NUM_SSID_PROFILES 1
 
 
@@ -969,6 +961,13 @@ struct wl1271_acx_arp_filter {
 			       used. */
 			       used. */
 } __attribute__((packed));
 } __attribute__((packed));
 
 
+struct wl1271_acx_pm_config {
+	struct acx_header header;
+
+	__le32 host_clk_settling_time;
+	u8 host_fast_wakeup_support;
+	u8 padding[3];
+} __attribute__ ((packed));
 
 
 enum {
 enum {
 	ACX_WAKE_UP_CONDITIONS      = 0x0002,
 	ACX_WAKE_UP_CONDITIONS      = 0x0002,
@@ -1027,13 +1026,13 @@ enum {
 	ACX_HT_BSS_OPERATION        = 0x0058,
 	ACX_HT_BSS_OPERATION        = 0x0058,
 	ACX_COEX_ACTIVITY           = 0x0059,
 	ACX_COEX_ACTIVITY           = 0x0059,
 	ACX_SET_SMART_REFLEX_DEBUG  = 0x005A,
 	ACX_SET_SMART_REFLEX_DEBUG  = 0x005A,
-	ACX_SET_SMART_REFLEX_STATE  = 0x005B,
-	ACX_SET_SMART_REFLEX_PARAMS = 0x005F,
+	ACX_SET_DCO_ITRIM_PARAMS    = 0x0061,
 	DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
 	DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
 	DOT11_CUR_TX_PWR            = 0x100D,
 	DOT11_CUR_TX_PWR            = 0x100D,
 	DOT11_RX_DOT11_MODE         = 0x1012,
 	DOT11_RX_DOT11_MODE         = 0x1012,
 	DOT11_RTS_THRESHOLD         = 0x1013,
 	DOT11_RTS_THRESHOLD         = 0x1013,
 	DOT11_GROUP_ADDRESS_TBL     = 0x1014,
 	DOT11_GROUP_ADDRESS_TBL     = 0x1014,
+	ACX_PM_CONFIG               = 0x1016,
 
 
 	MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
 	MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
 
 
@@ -1056,6 +1055,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
 				 void *mc_list, u32 mc_list_len);
 				 void *mc_list, u32 mc_list_len);
 int wl1271_acx_service_period_timeout(struct wl1271 *wl);
 int wl1271_acx_service_period_timeout(struct wl1271 *wl);
 int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
 int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
+int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
 int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
 int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
 int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
 int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
 int wl1271_acx_conn_monit_params(struct wl1271 *wl);
 int wl1271_acx_conn_monit_params(struct wl1271 *wl);
@@ -1069,7 +1069,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
 int wl1271_acx_cts_protect(struct wl1271 *wl,
 int wl1271_acx_cts_protect(struct wl1271 *wl,
 			   enum acx_ctsprotect_type ctsprotect);
 			   enum acx_ctsprotect_type ctsprotect);
 int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
 int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
-int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates);
+int wl1271_acx_rate_policies(struct wl1271 *wl);
 int wl1271_acx_ac_cfg(struct wl1271 *wl);
 int wl1271_acx_ac_cfg(struct wl1271 *wl);
 int wl1271_acx_tid_cfg(struct wl1271 *wl);
 int wl1271_acx_tid_cfg(struct wl1271 *wl);
 int wl1271_acx_frag_threshold(struct wl1271 *wl);
 int wl1271_acx_frag_threshold(struct wl1271 *wl);
@@ -1081,5 +1081,6 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl);
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
 int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
 int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
 			     u8 version);
 			     u8 version);
+int wl1271_acx_pm_config(struct wl1271 *wl);
 
 
 #endif /* __WL1271_ACX_H__ */
 #endif /* __WL1271_ACX_H__ */

+ 7 - 1
drivers/net/wireless/wl12xx/wl1271_boot.c

@@ -225,9 +225,15 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
 	if (nvs == NULL)
 	if (nvs == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	if (wl->nvs_len < WL1271_NVS_LEN)
+		return -EINVAL;
+
 	nvs_ptr = nvs;
 	nvs_ptr = nvs;
 
 
-	nvs_len = wl->nvs_len;
+	/* only the first part of the NVS needs to be uploaded */
+	nvs_len = WL1271_NVS_LEN;
+
+	/* FIXME: read init settings from the remaining part of the NVS */
 
 
 	/* Update the device MAC address into the nvs */
 	/* Update the device MAC address into the nvs */
 	nvs[11] = wl->mac_addr[0];
 	nvs[11] = wl->mac_addr[0];

+ 45 - 26
drivers/net/wireless/wl12xx/wl1271_cmd.c

@@ -209,6 +209,26 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
 	gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
 	gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
 	gen_parms->settings = g->settings;
 	gen_parms->settings = g->settings;
 
 
+	gen_parms->sr_state = g->sr_state;
+
+	memcpy(gen_parms->srf1,
+	       g->srf1,
+	       CONF_MAX_SMART_REFLEX_PARAMS);
+	memcpy(gen_parms->srf2,
+	       g->srf2,
+	       CONF_MAX_SMART_REFLEX_PARAMS);
+	memcpy(gen_parms->srf3,
+	       g->srf3,
+	       CONF_MAX_SMART_REFLEX_PARAMS);
+	memcpy(gen_parms->sr_debug_table,
+	       g->sr_debug_table,
+	       CONF_MAX_SMART_REFLEX_PARAMS);
+
+	gen_parms->sr_sen_n_p = g->sr_sen_n_p;
+	gen_parms->sr_sen_n_p_gain = g->sr_sen_n_p_gain;
+	gen_parms->sr_sen_nrn = g->sr_sen_nrn;
+	gen_parms->sr_sen_prn = g->sr_sen_prn;
+
 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
 	if (ret < 0)
 	if (ret < 0)
 		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
 		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@@ -253,6 +273,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	       CONF_NUMBER_OF_RATE_GROUPS);
 	       CONF_NUMBER_OF_RATE_GROUPS);
 	memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
 	memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
 	       CONF_NUMBER_OF_RATE_GROUPS);
 	       CONF_NUMBER_OF_RATE_GROUPS);
+	memcpy(radio_parms->tx_rate_limits_extreme, r->tx_rate_limits_extreme,
+	       CONF_NUMBER_OF_RATE_GROUPS);
 
 
 	memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
 	memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
 	       CONF_NUMBER_OF_CHANNELS_2_4);
 	       CONF_NUMBER_OF_CHANNELS_2_4);
@@ -263,6 +285,11 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
 	memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
 
 
 	radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
 	radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
+	radio_parms->degraded_low_to_normal_threshold =
+		r->degraded_low_to_normal_threshold;
+	radio_parms->degraded_normal_to_high_threshold =
+		r->degraded_normal_to_high_threshold;
+
 
 
 	for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
 	for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
 		radio_parms->tx_ref_pd_voltage_5[i] =
 		radio_parms->tx_ref_pd_voltage_5[i] =
@@ -275,6 +302,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	       r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
 	       r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
 	memcpy(radio_parms->tx_rate_limits_degraded_5,
 	memcpy(radio_parms->tx_rate_limits_degraded_5,
 	       r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
 	       r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
+	memcpy(radio_parms->tx_rate_limits_extreme_5,
+	       r->tx_rate_limits_extreme_5, CONF_NUMBER_OF_RATE_GROUPS);
 	memcpy(radio_parms->tx_channel_limits_ofdm_5,
 	memcpy(radio_parms->tx_channel_limits_ofdm_5,
 	       r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
 	       r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
 	memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
 	memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
@@ -283,6 +312,10 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 	       CONF_NUMBER_OF_RATE_GROUPS);
 	       CONF_NUMBER_OF_RATE_GROUPS);
 	memcpy(radio_parms->rx_fem_insertion_loss_5,
 	memcpy(radio_parms->rx_fem_insertion_loss_5,
 	       r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
 	       r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
+	radio_parms->degraded_low_to_normal_threshold_5 =
+		r->degraded_low_to_normal_threshold_5;
+	radio_parms->degraded_normal_to_high_threshold_5 =
+		r->degraded_normal_to_high_threshold_5;
 
 
 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
 		    radio_parms, sizeof(*radio_parms));
 		    radio_parms, sizeof(*radio_parms));
@@ -311,19 +344,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
 			do_cal = false;
 			do_cal = false;
 	}
 	}
 
 
-	/* FIXME: This is a workaround, because with the current stack, we
-	 * cannot know when we have disassociated.  So, if we have already
-	 * joined, we disconnect before joining again. */
-	if (wl->joined) {
-		ret = wl1271_cmd_disconnect(wl);
-		if (ret < 0) {
-			wl1271_error("failed to disconnect before rejoining");
-			goto out;
-		}
-
-		wl->joined = false;
-	}
-
 	join = kzalloc(sizeof(*join), GFP_KERNEL);
 	join = kzalloc(sizeof(*join), GFP_KERNEL);
 	if (!join) {
 	if (!join) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
@@ -388,8 +408,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
 		goto out_free;
 		goto out_free;
 	}
 	}
 
 
-	wl->joined = true;
-
 	/*
 	/*
 	 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
 	 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
 	 * simplify locking we just sleep instead, for now
 	 * simplify locking we just sleep instead, for now
@@ -487,7 +505,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
 	return 0;
 	return 0;
 }
 }
 
 
-int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
+int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
 {
 {
 	struct cmd_enabledisable_path *cmd;
 	struct cmd_enabledisable_path *cmd;
 	int ret;
 	int ret;
@@ -501,7 +519,8 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	cmd->channel = channel;
+	/* the channel here is only used for calibration, so hardcoded to 1 */
+	cmd->channel = 1;
 
 
 	if (enable) {
 	if (enable) {
 		cmd_rx = CMD_ENABLE_RX;
 		cmd_rx = CMD_ENABLE_RX;
@@ -514,22 +533,22 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
 	ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
 	ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
 	if (ret < 0) {
 	if (ret < 0) {
 		wl1271_error("rx %s cmd for channel %d failed",
 		wl1271_error("rx %s cmd for channel %d failed",
-			     enable ? "start" : "stop", channel);
+			     enable ? "start" : "stop", cmd->channel);
 		goto out;
 		goto out;
 	}
 	}
 
 
 	wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
 	wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
-		     enable ? "start" : "stop", channel);
+		     enable ? "start" : "stop", cmd->channel);
 
 
 	ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
 	ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
 	if (ret < 0) {
 	if (ret < 0) {
 		wl1271_error("tx %s cmd for channel %d failed",
 		wl1271_error("tx %s cmd for channel %d failed",
-			     enable ? "start" : "stop", channel);
+			     enable ? "start" : "stop", cmd->channel);
 		return ret;
 		return ret;
 	}
 	}
 
 
 	wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
 	wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
-		     enable ? "start" : "stop", channel);
+		     enable ? "start" : "stop", cmd->channel);
 
 
 out:
 out:
 	kfree(cmd);
 	kfree(cmd);
@@ -636,7 +655,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
 	channels = wl->hw->wiphy->bands[ieee_band]->channels;
 	channels = wl->hw->wiphy->bands[ieee_band]->channels;
 	n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
 	n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
 
 
-	if (wl->scanning)
+	if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
 		return -EINVAL;
 		return -EINVAL;
 
 
 	params = kzalloc(sizeof(*params), GFP_KERNEL);
 	params = kzalloc(sizeof(*params), GFP_KERNEL);
@@ -711,7 +730,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
 
 
 	wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
 	wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
 
 
-	wl->scanning = true;
+	set_bit(WL1271_FLAG_SCANNING, &wl->flags);
 	if (wl1271_11a_enabled()) {
 	if (wl1271_11a_enabled()) {
 		wl->scan.state = band;
 		wl->scan.state = band;
 		if (band == WL1271_SCAN_BAND_DUAL) {
 		if (band == WL1271_SCAN_BAND_DUAL) {
@@ -729,7 +748,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
 	ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
 	ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
 	if (ret < 0) {
 	if (ret < 0) {
 		wl1271_error("SCAN failed");
 		wl1271_error("SCAN failed");
-		wl->scanning = false;
+		clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -777,7 +796,7 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
-static int wl1271_build_basic_rates(char *rates, u8 band)
+static int wl1271_build_basic_rates(u8 *rates, u8 band)
 {
 {
 	u8 index = 0;
 	u8 index = 0;
 
 
@@ -804,7 +823,7 @@ static int wl1271_build_basic_rates(char *rates, u8 band)
 	return index;
 	return index;
 }
 }
 
 
-static int wl1271_build_extended_rates(char *rates, u8 band)
+static int wl1271_build_extended_rates(u8 *rates, u8 band)
 {
 {
 	u8 index = 0;
 	u8 index = 0;
 
 

+ 28 - 5
drivers/net/wireless/wl12xx/wl1271_cmd.h

@@ -37,7 +37,7 @@ int wl1271_cmd_join(struct wl1271 *wl);
 int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
 int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
 int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
-int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable);
+int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
 int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
 int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
 			   size_t len);
 			   size_t len);
@@ -437,6 +437,21 @@ struct wl1271_general_parms_cmd {
 	u8 tx_bip_fem_autodetect;
 	u8 tx_bip_fem_autodetect;
 	u8 tx_bip_fem_manufacturer;
 	u8 tx_bip_fem_manufacturer;
 	u8 settings;
 	u8 settings;
+
+	u8 sr_state;
+
+	s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
+	s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
+	s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
+
+	s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
+
+	u8 sr_sen_n_p;
+	u8 sr_sen_n_p_gain;
+	u8 sr_sen_nrn;
+	u8 sr_sen_prn;
+
+	u8 padding[3];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
 struct wl1271_radio_parms_cmd {
 struct wl1271_radio_parms_cmd {
@@ -458,11 +473,12 @@ struct wl1271_radio_parms_cmd {
 	/* Dynamic radio parameters */
 	/* Dynamic radio parameters */
 	/* 2.4GHz */
 	/* 2.4GHz */
 	__le16 tx_ref_pd_voltage;
 	__le16 tx_ref_pd_voltage;
-	s8  tx_ref_power;
+	u8  tx_ref_power;
 	s8  tx_offset_db;
 	s8  tx_offset_db;
 
 
 	s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
+	s8  tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
 
 
 	s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
 	s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
 	s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
 	s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
@@ -471,15 +487,19 @@ struct wl1271_radio_parms_cmd {
 	u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
 	u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
 	u8  rx_fem_insertion_loss;
 	u8  rx_fem_insertion_loss;
 
 
-	u8 padding2;
+	u8  degraded_low_to_normal_threshold;
+	u8  degraded_normal_to_high_threshold;
+
+	u8  padding1; /* our own padding, not in ref driver */
 
 
 	/* 5GHz */
 	/* 5GHz */
 	__le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
 	__le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
-	s8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+	u8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
 	s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
 	s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
 
 
 	s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
+	s8  tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
 
 
 	s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
 	s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
 	s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
@@ -488,7 +508,10 @@ struct wl1271_radio_parms_cmd {
 	s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
 	s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
 
 
-	u8 padding3[2];
+	u8  degraded_low_to_normal_threshold_5;
+	u8  degraded_normal_to_high_threshold_5;
+
+	u8 padding2[2];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
 struct wl1271_cmd_cal_channel_tune {
 struct wl1271_cmd_cal_channel_tune {

+ 57 - 43
drivers/net/wireless/wl12xx/wl1271_conf.h

@@ -258,7 +258,8 @@ struct conf_rx_settings {
 #define CONF_TX_MAX_RATE_CLASSES       8
 #define CONF_TX_MAX_RATE_CLASSES       8
 
 
 #define CONF_TX_RATE_MASK_UNSPECIFIED  0
 #define CONF_TX_RATE_MASK_UNSPECIFIED  0
-#define CONF_TX_RATE_MASK_ALL          0x1eff
+#define CONF_TX_RATE_MASK_BASIC        (CONF_HW_BIT_RATE_1MBPS | \
+					CONF_HW_BIT_RATE_2MBPS)
 #define CONF_TX_RATE_RETRY_LIMIT       10
 #define CONF_TX_RATE_RETRY_LIMIT       10
 
 
 struct conf_tx_rate_class {
 struct conf_tx_rate_class {
@@ -722,31 +723,6 @@ struct conf_conn_settings {
 	u8 psm_entry_retries;
 	u8 psm_entry_retries;
 };
 };
 
 
-#define CONF_SR_ERR_TBL_MAX_VALUES   14
-
-struct conf_mart_reflex_err_table {
-	/*
-	 * Length of the error table values table.
-	 *
-	 * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES
-	 */
-	u8 len;
-
-	/*
-	 * Smart Reflex error table upper limit.
-	 *
-	 * Range: s8
-	 */
-	s8 upper_limit;
-
-	/*
-	 * Smart Reflex error table values.
-	 *
-	 * Range: s8
-	 */
-	s8 values[CONF_SR_ERR_TBL_MAX_VALUES];
-};
-
 enum {
 enum {
 	CONF_REF_CLK_19_2_E,
 	CONF_REF_CLK_19_2_E,
 	CONF_REF_CLK_26_E,
 	CONF_REF_CLK_26_E,
@@ -759,6 +735,9 @@ enum single_dual_band_enum {
 	CONF_DUAL_BAND
 	CONF_DUAL_BAND
 };
 };
 
 
+
+#define CONF_MAX_SMART_REFLEX_PARAMS 16
+
 struct conf_general_parms {
 struct conf_general_parms {
 	/*
 	/*
 	 * RF Reference Clock type / speed
 	 * RF Reference Clock type / speed
@@ -815,6 +794,20 @@ struct conf_general_parms {
 	 * Range: Unknown
 	 * Range: Unknown
 	 */
 	 */
 	u8 settings;
 	u8 settings;
+
+	/* Smart reflex settings */
+	u8 sr_state;
+
+	s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
+	s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
+	s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
+
+	s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
+
+	u8 sr_sen_n_p;
+	u8 sr_sen_n_p_gain;
+	u8 sr_sen_nrn;
+	u8 sr_sen_prn;
 };
 };
 
 
 #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
 #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
@@ -847,12 +840,13 @@ struct conf_radio_parms {
 	 *
 	 *
 	 * Range: unknown
 	 * Range: unknown
 	 */
 	 */
-	s16 tx_ref_pd_voltage;
-	s8  tx_ref_power;
+	u16 tx_ref_pd_voltage;
+	u8  tx_ref_power;
 	s8  tx_offset_db;
 	s8  tx_offset_db;
 
 
 	s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
+	s8  tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
 
 
 	s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
 	s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
 	s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
 	s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
@@ -861,17 +855,22 @@ struct conf_radio_parms {
 	u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
 	u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
 	u8  rx_fem_insertion_loss;
 	u8  rx_fem_insertion_loss;
 
 
+	u8  degraded_low_to_normal_threshold;
+	u8  degraded_normal_to_high_threshold;
+
+
 	/*
 	/*
 	 * Dynamic radio parameters for 5GHz
 	 * Dynamic radio parameters for 5GHz
 	 *
 	 *
 	 * Range: unknown
 	 * Range: unknown
 	 */
 	 */
-	s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
-	s8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+	u16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
+	u8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
 	s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
 	s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
 
 
 	s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
+	s8  tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
 
 
 	s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
 	s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
 	s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
@@ -879,33 +878,46 @@ struct conf_radio_parms {
 	/* FIXME: this is inconsistent with the types for 2.4GHz */
 	/* FIXME: this is inconsistent with the types for 2.4GHz */
 	s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
 	s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
 	s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
-};
 
 
-#define CONF_SR_ERR_TBL_COUNT        3
+	u8  degraded_low_to_normal_threshold_5;
+	u8  degraded_normal_to_high_threshold_5;
+};
 
 
 struct conf_init_settings {
 struct conf_init_settings {
 	/*
 	/*
-	 * Configure Smart Reflex error table values.
+	 * Configure general parameters.
 	 */
 	 */
-	struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT];
+	struct conf_general_parms genparam;
 
 
 	/*
 	/*
-	 * Smart Reflex enable flag.
-	 *
-	 * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled
+	 * Configure radio parameters.
 	 */
 	 */
-	u8 sr_enable;
+	struct conf_radio_parms radioparam;
 
 
+};
+
+struct conf_itrim_settings {
+	/* enable dco itrim */
+	u8 enable;
+
+	/* moderation timeout in microsecs from the last TX */
+	u32 timeout;
+};
+
+struct conf_pm_config_settings {
 	/*
 	/*
-	 * Configure general parameters.
+	 * Host clock settling time
+	 *
+	 * Range: 0 - 30000 us
 	 */
 	 */
-	struct conf_general_parms genparam;
+	u32 host_clk_settling_time;
 
 
 	/*
 	/*
-	 * Configure radio parameters.
+	 * Host fast wakeup support
+	 *
+	 * Range: true, false
 	 */
 	 */
-	struct conf_radio_parms radioparam;
-
+	bool host_fast_wakeup_support;
 };
 };
 
 
 struct conf_drv_settings {
 struct conf_drv_settings {
@@ -914,6 +926,8 @@ struct conf_drv_settings {
 	struct conf_tx_settings tx;
 	struct conf_tx_settings tx;
 	struct conf_conn_settings conn;
 	struct conf_conn_settings conn;
 	struct conf_init_settings init;
 	struct conf_init_settings init;
+	struct conf_itrim_settings itrim;
+	struct conf_pm_config_settings pm_config;
 };
 };
 
 
 #endif
 #endif

+ 62 - 0
drivers/net/wireless/wl12xx/wl1271_debugfs.c

@@ -237,6 +237,64 @@ static const struct file_operations tx_queue_len_ops = {
 	.open = wl1271_open_file_generic,
 	.open = wl1271_open_file_generic,
 };
 };
 
 
+static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
+			  size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+
+	int res;
+	char buf[10];
+
+	res = scnprintf(buf, sizeof(buf), "%d\n", state);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static ssize_t gpio_power_write(struct file *file,
+			   const char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	char buf[10];
+	size_t len;
+	unsigned long value;
+	int ret;
+
+	mutex_lock(&wl->mutex);
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len)) {
+		ret = -EFAULT;
+		goto out;
+	}
+	buf[len] = '\0';
+
+	ret = strict_strtoul(buf, 0, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in gpio_power");
+		goto out;
+	}
+
+	if (value) {
+		wl->set_power(true);
+		set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+	} else {
+		wl->set_power(false);
+		clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+	}
+
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static const struct file_operations gpio_power_ops = {
+	.read = gpio_power_read,
+	.write = gpio_power_write,
+	.open = wl1271_open_file_generic
+};
+
 static void wl1271_debugfs_delete_files(struct wl1271 *wl)
 static void wl1271_debugfs_delete_files(struct wl1271 *wl)
 {
 {
 	DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
 	DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -333,6 +391,8 @@ static void wl1271_debugfs_delete_files(struct wl1271 *wl)
 	DEBUGFS_DEL(tx_queue_len);
 	DEBUGFS_DEL(tx_queue_len);
 	DEBUGFS_DEL(retry_count);
 	DEBUGFS_DEL(retry_count);
 	DEBUGFS_DEL(excessive_retries);
 	DEBUGFS_DEL(excessive_retries);
+
+	DEBUGFS_DEL(gpio_power);
 }
 }
 
 
 static int wl1271_debugfs_add_files(struct wl1271 *wl)
 static int wl1271_debugfs_add_files(struct wl1271 *wl)
@@ -434,6 +494,8 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
 	DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
 	DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
 	DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
 	DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
 
 
+	DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir);
+
 out:
 out:
 	if (ret < 0)
 	if (ret < 0)
 		wl1271_debugfs_delete_files(wl);
 		wl1271_debugfs_delete_files(wl);

+ 9 - 11
drivers/net/wireless/wl12xx/wl1271_event.c

@@ -35,7 +35,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
 	wl1271_debug(DEBUG_EVENT, "status: 0x%x",
 	wl1271_debug(DEBUG_EVENT, "status: 0x%x",
 		     mbox->scheduled_scan_status);
 		     mbox->scheduled_scan_status);
 
 
-	if (wl->scanning) {
+	if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
 		if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
 		if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
 			wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
 			wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
 						NULL, size);
 						NULL, size);
@@ -43,7 +43,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
 			 * to the wl1271_cmd_scan function that we are not
 			 * to the wl1271_cmd_scan function that we are not
 			 * scanning as it checks that.
 			 * scanning as it checks that.
 			 */
 			 */
-			wl->scanning = false;
+			clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
 			wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
 			wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
 						wl->scan.active,
 						wl->scan.active,
 						wl->scan.high_prio,
 						wl->scan.high_prio,
@@ -62,7 +62,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
 			mutex_unlock(&wl->mutex);
 			mutex_unlock(&wl->mutex);
 			ieee80211_scan_completed(wl->hw, false);
 			ieee80211_scan_completed(wl->hw, false);
 			mutex_lock(&wl->mutex);
 			mutex_lock(&wl->mutex);
-			wl->scanning = false;
+			clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
 		}
 		}
 	}
 	}
 	return 0;
 	return 0;
@@ -78,7 +78,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 
 
 	switch (mbox->ps_status) {
 	switch (mbox->ps_status) {
 	case EVENT_ENTER_POWER_SAVE_FAIL:
 	case EVENT_ENTER_POWER_SAVE_FAIL:
-		if (!wl->psm) {
+		if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
 			wl->psm_entry_retry = 0;
 			wl->psm_entry_retry = 0;
 			break;
 			break;
 		}
 		}
@@ -89,7 +89,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 		} else {
 		} else {
 			wl1271_error("PSM entry failed, giving up.\n");
 			wl1271_error("PSM entry failed, giving up.\n");
 			wl->psm_entry_retry = 0;
 			wl->psm_entry_retry = 0;
-			*beacon_loss = true;
 		}
 		}
 		break;
 		break;
 	case EVENT_ENTER_POWER_SAVE_SUCCESS:
 	case EVENT_ENTER_POWER_SAVE_SUCCESS:
@@ -136,7 +135,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 	 * filtering) is enabled. Without PSM, the stack will receive all
 	 * filtering) is enabled. Without PSM, the stack will receive all
 	 * beacons and can detect beacon loss by itself.
 	 * beacons and can detect beacon loss by itself.
 	 */
 	 */
-	if (vector & BSS_LOSE_EVENT_ID && wl->psm) {
+	if (vector & BSS_LOSE_EVENT_ID &&
+	    test_bit(WL1271_FLAG_PSM, &wl->flags)) {
 		wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
 		wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
 
 
 		/* indicate to the stack, that beacons have been lost */
 		/* indicate to the stack, that beacons have been lost */
@@ -150,7 +150,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 			return ret;
 			return ret;
 	}
 	}
 
 
-	if (beacon_loss) {
+	if (wl->vif && beacon_loss) {
 		/* Obviously, it's dangerous to release the mutex while
 		/* Obviously, it's dangerous to release the mutex while
 		   we are holding many of the variables in the wl struct.
 		   we are holding many of the variables in the wl struct.
 		   That's why it's done last in the function, and care must
 		   That's why it's done last in the function, and care must
@@ -184,7 +184,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl)
 		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
 		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
 }
 }
 
 
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
 {
 {
 	struct event_mailbox mbox;
 	struct event_mailbox mbox;
 	int ret;
 	int ret;
@@ -204,9 +204,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
 		return ret;
 		return ret;
 
 
 	/* then we let the firmware know it can go on...*/
 	/* then we let the firmware know it can go on...*/
-	if (do_ack)
-		wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG,
-				   INTR_TRIG_EVENT_ACK);
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 1
drivers/net/wireless/wl12xx/wl1271_event.h

@@ -112,6 +112,6 @@ struct event_mailbox {
 
 
 int wl1271_event_unmask(struct wl1271 *wl);
 int wl1271_event_unmask(struct wl1271 *wl);
 void wl1271_event_mbox_config(struct wl1271 *wl);
 void wl1271_event_mbox_config(struct wl1271 *wl);
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack);
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
 
 
 #endif
 #endif

+ 8 - 4
drivers/net/wireless/wl12xx/wl1271_init.c

@@ -229,6 +229,10 @@ int wl1271_hw_init(struct wl1271 *wl)
 	if (ret < 0)
 	if (ret < 0)
 		goto out_free_memmap;
 		goto out_free_memmap;
 
 
+	ret = wl1271_acx_dco_itrim_params(wl);
+	if (ret < 0)
+		goto out_free_memmap;
+
 	/* Initialize connection monitoring thresholds */
 	/* Initialize connection monitoring thresholds */
 	ret = wl1271_acx_conn_monit_params(wl);
 	ret = wl1271_acx_conn_monit_params(wl);
 	if (ret < 0)
 	if (ret < 0)
@@ -280,12 +284,12 @@ int wl1271_hw_init(struct wl1271 *wl)
 		goto out_free_memmap;
 		goto out_free_memmap;
 
 
 	/* Configure TX rate classes */
 	/* Configure TX rate classes */
-	ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL);
+	ret = wl1271_acx_rate_policies(wl);
 	if (ret < 0)
 	if (ret < 0)
 		goto out_free_memmap;
 		goto out_free_memmap;
 
 
 	/* Enable data path */
 	/* Enable data path */
-	ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+	ret = wl1271_cmd_data_path(wl, 1);
 	if (ret < 0)
 	if (ret < 0)
 		goto out_free_memmap;
 		goto out_free_memmap;
 
 
@@ -299,8 +303,8 @@ int wl1271_hw_init(struct wl1271 *wl)
 	if (ret < 0)
 	if (ret < 0)
 		goto out_free_memmap;
 		goto out_free_memmap;
 
 
-	/* Configure smart reflex */
-	ret = wl1271_acx_smart_reflex(wl);
+	/* configure PM */
+	ret = wl1271_acx_pm_config(wl);
 	if (ret < 0)
 	if (ret < 0)
 		goto out_free_memmap;
 		goto out_free_memmap;
 
 

+ 311 - 181
drivers/net/wireless/wl12xx/wl1271_main.c

@@ -47,6 +47,8 @@
 #include "wl1271_cmd.h"
 #include "wl1271_cmd.h"
 #include "wl1271_boot.h"
 #include "wl1271_boot.h"
 
 
+#define WL1271_BOOT_RETRIES 3
+
 static struct conf_drv_settings default_conf = {
 static struct conf_drv_settings default_conf = {
 	.sg = {
 	.sg = {
 		.per_threshold               = 7500,
 		.per_threshold               = 7500,
@@ -67,16 +69,17 @@ static struct conf_drv_settings default_conf = {
 		.ps_poll_timeout             = 15,
 		.ps_poll_timeout             = 15,
 		.upsd_timeout                = 15,
 		.upsd_timeout                = 15,
 		.rts_threshold               = 2347,
 		.rts_threshold               = 2347,
-		.rx_cca_threshold            = 0xFFEF,
-		.irq_blk_threshold           = 0,
-		.irq_pkt_threshold           = USHORT_MAX,
-		.irq_timeout                 = 5,
+		.rx_cca_threshold            = 0,
+		.irq_blk_threshold           = 0xFFFF,
+		.irq_pkt_threshold           = 0,
+		.irq_timeout                 = 600,
 		.queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
 		.queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
 	},
 	},
 	.tx = {
 	.tx = {
 		.tx_energy_detection         = 0,
 		.tx_energy_detection         = 0,
 		.rc_conf                     = {
 		.rc_conf                     = {
-			.enabled_rates       = CONF_TX_RATE_MASK_UNSPECIFIED,
+			.enabled_rates       = CONF_HW_BIT_RATE_1MBPS |
+					       CONF_HW_BIT_RATE_2MBPS,
 			.short_retry_limit   = 10,
 			.short_retry_limit   = 10,
 			.long_retry_limit    = 10,
 			.long_retry_limit    = 10,
 			.aflags              = 0
 			.aflags              = 0
@@ -172,8 +175,8 @@ static struct conf_drv_settings default_conf = {
 			}
 			}
 		},
 		},
 		.frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
 		.frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
-		.tx_compl_timeout            = 5,
-		.tx_compl_threshold          = 5
+		.tx_compl_timeout            = 700,
+		.tx_compl_threshold          = 4
 	},
 	},
 	.conn = {
 	.conn = {
 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
@@ -186,12 +189,12 @@ static struct conf_drv_settings default_conf = {
 				.rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE,
 				.rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE,
 			}
 			}
 		},
 		},
-		.synch_fail_thold            = 5,
+		.synch_fail_thold            = 10,
 		.bss_lose_timeout            = 100,
 		.bss_lose_timeout            = 100,
 		.beacon_rx_timeout           = 10000,
 		.beacon_rx_timeout           = 10000,
 		.broadcast_timeout           = 20000,
 		.broadcast_timeout           = 20000,
 		.rx_broadcast_in_ps          = 1,
 		.rx_broadcast_in_ps          = 1,
-		.ps_poll_threshold           = 4,
+		.ps_poll_threshold           = 20,
 		.sig_trigger_count           = 2,
 		.sig_trigger_count           = 2,
 		.sig_trigger = {
 		.sig_trigger = {
 			[0] = {
 			[0] = {
@@ -226,46 +229,35 @@ static struct conf_drv_settings default_conf = {
 		.psm_entry_retries           = 3
 		.psm_entry_retries           = 3
 	},
 	},
 	.init = {
 	.init = {
-		.sr_err_tbl = {
-			[0] = {
-				.len         = 7,
-				.upper_limit = 0x03,
-				.values      = {
-					0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
-					0x00 }
-			},
-			[1] = {
-				.len         = 7,
-				.upper_limit = 0x03,
-				.values      = {
-					0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
-					0x00 }
-			},
-			[2] = {
-				.len         = 7,
-				.upper_limit = 0x03,
-				.values      = {
-					0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
-					0x00 }
-			}
-		},
-		.sr_enable                   = 1,
 		.genparam                    = {
 		.genparam                    = {
 			.ref_clk             = CONF_REF_CLK_38_4_E,
 			.ref_clk             = CONF_REF_CLK_38_4_E,
 			.settling_time       = 5,
 			.settling_time       = 5,
 			.clk_valid_on_wakeup = 0,
 			.clk_valid_on_wakeup = 0,
 			.dc2dcmode           = 0,
 			.dc2dcmode           = 0,
 			.single_dual_band    = CONF_SINGLE_BAND,
 			.single_dual_band    = CONF_SINGLE_BAND,
-			.tx_bip_fem_autodetect = 0,
+			.tx_bip_fem_autodetect = 1,
 			.tx_bip_fem_manufacturer = 1,
 			.tx_bip_fem_manufacturer = 1,
 			.settings = 1,
 			.settings = 1,
+			.sr_state = 1,
+			.srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
+				  0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
+			.srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
+				  0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
+			.srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
+				  0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
+			.sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0,
+					    0, 0, 0, 0, 0, 0, 0, 0 },
+			.sr_sen_n_p = 0,
+			.sr_sen_n_p_gain = 0,
+			.sr_sen_nrn = 0,
+			.sr_sen_prn = 0,
 		},
 		},
 		.radioparam = {
 		.radioparam = {
-			.rx_trace_loss       = 10,
-			.tx_trace_loss       = 10,
+			.rx_trace_loss       = 0x24,
+			.tx_trace_loss       = 0x0,
 			.rx_rssi_and_proc_compens = {
 			.rx_rssi_and_proc_compens = {
 				0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
 				0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
-				0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
+				0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8,
 				0x00, 0x0a, 0x14 },
 				0x00, 0x0a, 0x14 },
 			.rx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 },
 			.rx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 },
 			.tx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 },
 			.tx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 },
@@ -273,13 +265,15 @@ static struct conf_drv_settings default_conf = {
 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 				0x00, 0x00, 0x00 },
 				0x00, 0x00, 0x00 },
-			.tx_ref_pd_voltage   = 0x24e,
-			.tx_ref_power        = 0x78,
+			.tx_ref_pd_voltage   = 0x1a9,
+			.tx_ref_power        = 0x80,
 			.tx_offset_db        = 0x0,
 			.tx_offset_db        = 0x0,
 			.tx_rate_limits_normal = {
 			.tx_rate_limits_normal = {
-				0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
+				0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 },
 			.tx_rate_limits_degraded = {
 			.tx_rate_limits_degraded = {
-				0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
+				0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 },
+			.tx_rate_limits_extreme = {
+				0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
 			.tx_channel_limits_11b = {
 			.tx_channel_limits_11b = {
 				0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
 				0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
 				0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
 				0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
@@ -289,10 +283,12 @@ static struct conf_drv_settings default_conf = {
 				0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
 				0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
 				0x20, 0x50 },
 				0x20, 0x50 },
 			.tx_pdv_rate_offsets = {
 			.tx_pdv_rate_offsets = {
-				0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+				0x07, 0x08, 0x04, 0x02, 0x02, 0x00 },
 			.tx_ibias            = {
 			.tx_ibias            = {
-				0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
-			.rx_fem_insertion_loss = 0x14,
+				0x11, 0x11, 0x15, 0x11, 0x15, 0x0f },
+			.rx_fem_insertion_loss = 0x0e,
+			.degraded_low_to_normal_threshold = 0x1e,
+			.degraded_normal_to_high_threshold = 0x2d,
 			.tx_ref_pd_voltage_5 = {
 			.tx_ref_pd_voltage_5 = {
 				0x0190, 0x01a4, 0x01c3, 0x01d8,
 				0x0190, 0x01a4, 0x01c3, 0x01d8,
 				0x020a, 0x021c },
 				0x020a, 0x021c },
@@ -304,6 +300,8 @@ static struct conf_drv_settings default_conf = {
 				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
 				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
 			.tx_rate_limits_degraded_5 = {
 			.tx_rate_limits_degraded_5 = {
 				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
 				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
+			.tx_rate_limits_extreme_5 = {
+				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
 			.tx_channel_limits_ofdm_5 = {
 			.tx_channel_limits_ofdm_5 = {
 				0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
 				0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
 				0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
 				0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
@@ -315,8 +313,18 @@ static struct conf_drv_settings default_conf = {
 			.tx_ibias_5          = {
 			.tx_ibias_5          = {
 				0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
 				0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
 			.rx_fem_insertion_loss_5 = {
 			.rx_fem_insertion_loss_5 = {
-				0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
+				0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
+			.degraded_low_to_normal_threshold_5 = 0x00,
+			.degraded_normal_to_high_threshold_5 = 0x00
 		}
 		}
+	},
+	.itrim = {
+		.enable = false,
+		.timeout = 50000,
+	},
+	.pm_config = {
+		.host_clk_settling_time = 5000,
+		.host_fast_wakeup_support = false
 	}
 	}
 };
 };
 
 
@@ -359,7 +367,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+	ret = wl1271_cmd_data_path(wl, 1);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
@@ -374,11 +382,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl)
 static void wl1271_power_off(struct wl1271 *wl)
 static void wl1271_power_off(struct wl1271 *wl)
 {
 {
 	wl->set_power(false);
 	wl->set_power(false);
+	clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 }
 }
 
 
 static void wl1271_power_on(struct wl1271 *wl)
 static void wl1271_power_on(struct wl1271 *wl)
 {
 {
 	wl->set_power(true);
 	wl->set_power(true);
+	set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 }
 }
 
 
 static void wl1271_fw_status(struct wl1271 *wl,
 static void wl1271_fw_status(struct wl1271 *wl,
@@ -447,14 +457,13 @@ static void wl1271_irq_work(struct work_struct *work)
 	intr &= WL1271_INTR_MASK;
 	intr &= WL1271_INTR_MASK;
 
 
 	if (intr & WL1271_ACX_INTR_EVENT_A) {
 	if (intr & WL1271_ACX_INTR_EVENT_A) {
-		bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
 		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
 		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
-		wl1271_event_handle(wl, 0, do_ack);
+		wl1271_event_handle(wl, 0);
 	}
 	}
 
 
 	if (intr & WL1271_ACX_INTR_EVENT_B) {
 	if (intr & WL1271_ACX_INTR_EVENT_B) {
 		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
 		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
-		wl1271_event_handle(wl, 1, true);
+		wl1271_event_handle(wl, 1);
 	}
 	}
 
 
 	if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
 	if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
@@ -614,6 +623,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 	struct wl1271_partition_set partition;
 	struct wl1271_partition_set partition;
 	int ret = 0;
 	int ret = 0;
 
 
+	msleep(WL1271_PRE_POWER_ON_SLEEP);
 	wl1271_power_on(wl);
 	wl1271_power_on(wl);
 	msleep(WL1271_POWER_ON_SLEEP);
 	msleep(WL1271_POWER_ON_SLEEP);
 	wl1271_spi_reset(wl);
 	wl1271_spi_reset(wl);
@@ -643,7 +653,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 
 
 		ret = wl1271_setup(wl);
 		ret = wl1271_setup(wl);
 		if (ret < 0)
 		if (ret < 0)
-			goto out_power_off;
+			goto out;
 		break;
 		break;
 	case CHIP_ID_1271_PG20:
 	case CHIP_ID_1271_PG20:
 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
@@ -651,38 +661,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 
 
 		ret = wl1271_setup(wl);
 		ret = wl1271_setup(wl);
 		if (ret < 0)
 		if (ret < 0)
-			goto out_power_off;
+			goto out;
 		break;
 		break;
 	default:
 	default:
-		wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
+		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
 		ret = -ENODEV;
 		ret = -ENODEV;
-		goto out_power_off;
+		goto out;
 	}
 	}
 
 
 	if (wl->fw == NULL) {
 	if (wl->fw == NULL) {
 		ret = wl1271_fetch_firmware(wl);
 		ret = wl1271_fetch_firmware(wl);
 		if (ret < 0)
 		if (ret < 0)
-			goto out_power_off;
+			goto out;
 	}
 	}
 
 
 	/* No NVS from netlink, try to get it from the filesystem */
 	/* No NVS from netlink, try to get it from the filesystem */
 	if (wl->nvs == NULL) {
 	if (wl->nvs == NULL) {
 		ret = wl1271_fetch_nvs(wl);
 		ret = wl1271_fetch_nvs(wl);
 		if (ret < 0)
 		if (ret < 0)
-			goto out_power_off;
+			goto out;
 	}
 	}
 
 
-	goto out;
-
-out_power_off:
-	wl1271_power_off(wl);
-
 out:
 out:
 	return ret;
 	return ret;
 }
 }
 
 
 int wl1271_plt_start(struct wl1271 *wl)
 int wl1271_plt_start(struct wl1271 *wl)
 {
 {
+	int retries = WL1271_BOOT_RETRIES;
 	int ret;
 	int ret;
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
@@ -696,35 +702,48 @@ int wl1271_plt_start(struct wl1271 *wl)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	wl->state = WL1271_STATE_PLT;
-
-	ret = wl1271_chip_wakeup(wl);
-	if (ret < 0)
-		goto out;
-
-	ret = wl1271_boot(wl);
-	if (ret < 0)
-		goto out_power_off;
-
-	wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
+	while (retries) {
+		retries--;
+		ret = wl1271_chip_wakeup(wl);
+		if (ret < 0)
+			goto power_off;
 
 
-	ret = wl1271_plt_init(wl);
-	if (ret < 0)
-		goto out_irq_disable;
+		ret = wl1271_boot(wl);
+		if (ret < 0)
+			goto power_off;
 
 
-	/* Make sure power saving is disabled */
-	ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-	if (ret < 0)
-		goto out_irq_disable;
+		ret = wl1271_plt_init(wl);
+		if (ret < 0)
+			goto irq_disable;
 
 
-	goto out;
+		/* Make sure power saving is disabled */
+		ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+		if (ret < 0)
+			goto irq_disable;
 
 
-out_irq_disable:
-	wl1271_disable_interrupts(wl);
+		wl->state = WL1271_STATE_PLT;
+		wl1271_notice("firmware booted in PLT mode (%s)",
+			      wl->chip.fw_ver);
+		goto out;
 
 
-out_power_off:
-	wl1271_power_off(wl);
+irq_disable:
+		wl1271_disable_interrupts(wl);
+		mutex_unlock(&wl->mutex);
+		/* Unlocking the mutex in the middle of handling is
+		   inherently unsafe. In this case we deem it safe to do,
+		   because we need to let any possibly pending IRQ out of
+		   the system (and while we are WL1271_STATE_OFF the IRQ
+		   work function will not do anything.) Also, any other
+		   possible concurrent operations will fail due to the
+		   current state, hence the wl1271 struct should be safe. */
+		cancel_work_sync(&wl->irq_work);
+		mutex_lock(&wl->mutex);
+power_off:
+		wl1271_power_off(wl);
+	}
 
 
+	wl1271_error("firmware boot in PLT mode failed despite %d retries",
+		     WL1271_BOOT_RETRIES);
 out:
 out:
 	mutex_unlock(&wl->mutex);
 	mutex_unlock(&wl->mutex);
 
 
@@ -762,7 +781,20 @@ out:
 static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl1271 *wl = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+	struct ieee80211_sta *sta = txinfo->control.sta;
+	unsigned long flags;
 
 
+	/* peek into the rates configured in the STA entry */
+	spin_lock_irqsave(&wl->wl_lock, flags);
+	if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
+		wl->sta_rate_set = sta->supp_rates[conf->channel->band];
+		set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
+	}
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+	/* queue the packet */
 	skb_queue_tail(&wl->tx_queue, skb);
 	skb_queue_tail(&wl->tx_queue, skb);
 
 
 	/*
 	/*
@@ -784,7 +816,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		 * protected. Maybe fix this by removing the stupid
 		 * protected. Maybe fix this by removing the stupid
 		 * variable altogether and checking the real queue state?
 		 * variable altogether and checking the real queue state?
 		 */
 		 */
-		wl->tx_queue_stopped = true;
+		set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
 	}
 	}
 
 
 	return NETDEV_TX_OK;
 	return NETDEV_TX_OK;
@@ -880,6 +912,7 @@ static struct notifier_block wl1271_dev_notifier = {
 static int wl1271_op_start(struct ieee80211_hw *hw)
 static int wl1271_op_start(struct ieee80211_hw *hw)
 {
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl1271 *wl = hw->priv;
+	int retries = WL1271_BOOT_RETRIES;
 	int ret = 0;
 	int ret = 0;
 
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 start");
 	wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -893,30 +926,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	ret = wl1271_chip_wakeup(wl);
-	if (ret < 0)
-		goto out;
-
-	ret = wl1271_boot(wl);
-	if (ret < 0)
-		goto out_power_off;
-
-	ret = wl1271_hw_init(wl);
-	if (ret < 0)
-		goto out_irq_disable;
-
-	wl->state = WL1271_STATE_ON;
+	while (retries) {
+		retries--;
+		ret = wl1271_chip_wakeup(wl);
+		if (ret < 0)
+			goto power_off;
 
 
-	wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+		ret = wl1271_boot(wl);
+		if (ret < 0)
+			goto power_off;
 
 
-	goto out;
+		ret = wl1271_hw_init(wl);
+		if (ret < 0)
+			goto irq_disable;
 
 
-out_irq_disable:
-	wl1271_disable_interrupts(wl);
+		wl->state = WL1271_STATE_ON;
+		wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+		goto out;
 
 
-out_power_off:
-	wl1271_power_off(wl);
+irq_disable:
+		wl1271_disable_interrupts(wl);
+		mutex_unlock(&wl->mutex);
+		/* Unlocking the mutex in the middle of handling is
+		   inherently unsafe. In this case we deem it safe to do,
+		   because we need to let any possibly pending IRQ out of
+		   the system (and while we are WL1271_STATE_OFF the IRQ
+		   work function will not do anything.) Also, any other
+		   possible concurrent operations will fail due to the
+		   current state, hence the wl1271 struct should be safe. */
+		cancel_work_sync(&wl->irq_work);
+		mutex_lock(&wl->mutex);
+power_off:
+		wl1271_power_off(wl);
+	}
 
 
+	wl1271_error("firmware boot failed despite %d retries",
+		     WL1271_BOOT_RETRIES);
 out:
 out:
 	mutex_unlock(&wl->mutex);
 	mutex_unlock(&wl->mutex);
 
 
@@ -944,11 +989,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 
 
 	WARN_ON(wl->state != WL1271_STATE_ON);
 	WARN_ON(wl->state != WL1271_STATE_ON);
 
 
-	if (wl->scanning) {
+	if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
 		mutex_unlock(&wl->mutex);
 		mutex_unlock(&wl->mutex);
 		ieee80211_scan_completed(wl->hw, true);
 		ieee80211_scan_completed(wl->hw, true);
 		mutex_lock(&wl->mutex);
 		mutex_lock(&wl->mutex);
-		wl->scanning = false;
 	}
 	}
 
 
 	wl->state = WL1271_STATE_OFF;
 	wl->state = WL1271_STATE_OFF;
@@ -973,10 +1017,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 	wl->band = IEEE80211_BAND_2GHZ;
 	wl->band = IEEE80211_BAND_2GHZ;
 
 
 	wl->rx_counter = 0;
 	wl->rx_counter = 0;
-	wl->elp = false;
-	wl->psm = 0;
 	wl->psm_entry_retry = 0;
 	wl->psm_entry_retry = 0;
-	wl->tx_queue_stopped = false;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
 	wl->tx_blocks_available = 0;
 	wl->tx_blocks_available = 0;
 	wl->tx_results_count = 0;
 	wl->tx_results_count = 0;
@@ -986,7 +1027,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 	wl->tx_security_seq_32 = 0;
 	wl->tx_security_seq_32 = 0;
 	wl->time_offset = 0;
 	wl->time_offset = 0;
 	wl->session_counter = 0;
 	wl->session_counter = 0;
-	wl->joined = false;
+	wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+	wl->sta_rate_set = 0;
+	wl->flags = 0;
 
 
 	for (i = 0; i < NUM_TX_QUEUES; i++)
 	for (i = 0; i < NUM_TX_QUEUES; i++)
 		wl->tx_blocks_freed[i] = 0;
 		wl->tx_blocks_freed[i] = 0;
@@ -996,13 +1039,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 }
 }
 
 
 static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 static int wl1271_op_add_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_if_init_conf *conf)
+				   struct ieee80211_vif *vif)
 {
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl1271 *wl = hw->priv;
 	int ret = 0;
 	int ret = 0;
 
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
 	wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
-		     conf->type, conf->mac_addr);
+		     vif->type, vif->addr);
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 	if (wl->vif) {
 	if (wl->vif) {
@@ -1010,9 +1053,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	wl->vif = conf->vif;
+	wl->vif = vif;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
 		wl->bss_type = BSS_TYPE_STA_BSS;
 		wl->bss_type = BSS_TYPE_STA_BSS;
 		break;
 		break;
@@ -1032,7 +1075,7 @@ out:
 }
 }
 
 
 static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
 static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
-					 struct ieee80211_if_init_conf *conf)
+					 struct ieee80211_vif *vif)
 {
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl1271 *wl = hw->priv;
 
 
@@ -1109,6 +1152,51 @@ out:
 }
 }
 #endif
 #endif
 
 
+static int wl1271_join_channel(struct wl1271 *wl, int channel)
+{
+	int ret = 0;
+	/* we need to use a dummy BSSID for now */
+	static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
+						  0xad, 0xbe, 0xef };
+
+	/* the dummy join is not required for ad-hoc */
+	if (wl->bss_type == BSS_TYPE_IBSS)
+		goto out;
+
+	/* disable mac filter, so we hear everything */
+	wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+
+	wl->channel = channel;
+	memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
+
+	ret = wl1271_cmd_join(wl);
+	if (ret < 0)
+		goto out;
+
+	set_bit(WL1271_FLAG_JOINED, &wl->flags);
+
+out:
+	return ret;
+}
+
+static int wl1271_unjoin_channel(struct wl1271 *wl)
+{
+	int ret;
+
+	/* to stop listening to a channel, we disconnect */
+	ret = wl1271_cmd_disconnect(wl);
+	if (ret < 0)
+		goto out;
+
+	clear_bit(WL1271_FLAG_JOINED, &wl->flags);
+	wl->channel = 0;
+	memset(wl->bssid, 0, ETH_ALEN);
+	wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
+
+out:
+	return ret;
+}
+
 static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 {
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl1271 *wl = hw->priv;
@@ -1117,10 +1205,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
 
 	channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 	channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 
 
-	wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+	wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
 		     channel,
 		     channel,
 		     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
 		     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
-		     conf->power_level);
+		     conf->power_level,
+		     conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
@@ -1130,34 +1219,44 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	if (channel != wl->channel) {
-		/*
-		 * We assume that the stack will configure the right channel
-		 * before associating, so we don't need to send a join
-		 * command here.  We will join the right channel when the
-		 * BSSID changes
-		 */
-		wl->channel = channel;
+	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+		if (conf->flags & IEEE80211_CONF_IDLE &&
+		    test_bit(WL1271_FLAG_JOINED, &wl->flags))
+			wl1271_unjoin_channel(wl);
+		else if (!(conf->flags & IEEE80211_CONF_IDLE))
+			wl1271_join_channel(wl, channel);
+
+		if (conf->flags & IEEE80211_CONF_IDLE) {
+			wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+			wl->sta_rate_set = 0;
+			wl1271_acx_rate_policies(wl);
+		}
 	}
 	}
 
 
-	if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
-		wl1271_info("psm enabled");
+	/* if the channel changes while joined, join again */
+	if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags))
+		wl1271_join_channel(wl, channel);
 
 
-		wl->psm_requested = true;
+	if (conf->flags & IEEE80211_CONF_PS &&
+	    !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
+		set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
 
 
 		/*
 		/*
 		 * We enter PSM only if we're already associated.
 		 * We enter PSM only if we're already associated.
 		 * If we're not, we'll enter it when joining an SSID,
 		 * If we're not, we'll enter it when joining an SSID,
 		 * through the bss_info_changed() hook.
 		 * through the bss_info_changed() hook.
 		 */
 		 */
-		ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+		if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+			wl1271_info("psm enabled");
+			ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+		}
 	} else if (!(conf->flags & IEEE80211_CONF_PS) &&
 	} else if (!(conf->flags & IEEE80211_CONF_PS) &&
-		   wl->psm_requested) {
+		   test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
 		wl1271_info("psm disabled");
 		wl1271_info("psm disabled");
 
 
-		wl->psm_requested = false;
+		clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
 
 
-		if (wl->psm)
+		if (test_bit(WL1271_FLAG_PSM, &wl->flags))
 			ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
 			ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
 	}
 	}
 
 
@@ -1440,22 +1539,6 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
-static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
-{
-	struct ieee80211_supported_band *band;
-	u32 enabled_rates = 0;
-	int bit;
-
-	band = wl->hw->wiphy->bands[wl->band];
-	for (bit = 0; bit < band->n_bitrates; bit++) {
-		if (basic_rate_set & 0x1)
-			enabled_rates |= band->bitrates[bit].hw_value;
-		basic_rate_set >>= 1;
-	}
-
-	return enabled_rates;
-}
-
 static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 				       struct ieee80211_vif *vif,
 				       struct ieee80211_vif *vif,
 				       struct ieee80211_bss_conf *bss_conf,
 				       struct ieee80211_bss_conf *bss_conf,
@@ -1473,9 +1556,68 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
+	if ((changed & BSS_CHANGED_BSSID) &&
+	    /*
+	     * Now we know the correct bssid, so we send a new join command
+	     * and enable the BSSID filter
+	     */
+	    memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
+			wl->rx_config |= CFG_BSSID_FILTER_EN;
+			memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
+			ret = wl1271_cmd_build_null_data(wl);
+			if (ret < 0) {
+				wl1271_warning("cmd buld null data failed %d",
+					       ret);
+				goto out_sleep;
+			}
+			ret = wl1271_cmd_join(wl);
+			if (ret < 0) {
+				wl1271_warning("cmd join failed %d", ret);
+				goto out_sleep;
+			}
+			set_bit(WL1271_FLAG_JOINED, &wl->flags);
+	}
+
+	if (wl->bss_type == BSS_TYPE_IBSS) {
+		/* FIXME: This implements rudimentary ad-hoc support -
+		   proper templates are on the wish list and notification
+		   on when they change. This patch will update the templates
+		   on every call to this function. Also, the firmware will not
+		   answer to probe-requests as it does not have the proper
+		   SSID set in the JOIN command. The probe-response template
+		   is set nevertheless, as the FW will ASSERT without it */
+		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+
+		if (beacon) {
+			struct ieee80211_hdr *hdr;
+			ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
+						      beacon->data,
+						      beacon->len);
+
+			if (ret < 0) {
+				dev_kfree_skb(beacon);
+				goto out_sleep;
+			}
+
+			hdr = (struct ieee80211_hdr *) beacon->data;
+			hdr->frame_control = cpu_to_le16(
+				IEEE80211_FTYPE_MGMT |
+				IEEE80211_STYPE_PROBE_RESP);
+
+			ret = wl1271_cmd_template_set(wl,
+						      CMD_TEMPL_PROBE_RESPONSE,
+						      beacon->data,
+						      beacon->len);
+			dev_kfree_skb(beacon);
+			if (ret < 0)
+				goto out_sleep;
+		}
+	}
+
 	if (changed & BSS_CHANGED_ASSOC) {
 	if (changed & BSS_CHANGED_ASSOC) {
 		if (bss_conf->assoc) {
 		if (bss_conf->assoc) {
 			wl->aid = bss_conf->aid;
 			wl->aid = bss_conf->aid;
+			set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
 
 
 			/*
 			/*
 			 * with wl1271, we don't need to update the
 			 * with wl1271, we don't need to update the
@@ -1492,7 +1634,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 				goto out_sleep;
 				goto out_sleep;
 
 
 			/* If we want to go in PSM but we're not there yet */
 			/* If we want to go in PSM but we're not there yet */
-			if (wl->psm_requested && !wl->psm) {
+			if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
+			    !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
 				mode = STATION_POWER_SAVE_MODE;
 				mode = STATION_POWER_SAVE_MODE;
 				ret = wl1271_ps_set_mode(wl, mode);
 				ret = wl1271_ps_set_mode(wl, mode);
 				if (ret < 0)
 				if (ret < 0)
@@ -1500,7 +1643,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 			}
 			}
 		} else {
 		} else {
 			/* use defaults when not associated */
 			/* use defaults when not associated */
-			wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+			clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
 			wl->aid = 0;
 			wl->aid = 0;
 		}
 		}
 
 
@@ -1535,17 +1678,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 		}
 		}
 	}
 	}
 
 
-	if (changed & BSS_CHANGED_BASIC_RATES) {
-		wl->basic_rate_set = wl1271_enabled_rates_get(
-			wl, bss_conf->basic_rates);
-
-		ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
-		if (ret < 0) {
-			wl1271_warning("Set rate policies failed %d", ret);
-			goto out_sleep;
-		}
-	}
-
 out_sleep:
 out_sleep:
 	wl1271_ps_elp_sleep(wl);
 	wl1271_ps_elp_sleep(wl);
 
 
@@ -1599,19 +1731,19 @@ static struct ieee80211_rate wl1271_rates[] = {
 
 
 /* can't be const, mac80211 writes to this */
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_channel wl1271_channels[] = {
 static struct ieee80211_channel wl1271_channels[] = {
-	{ .hw_value = 1, .center_freq = 2412},
-	{ .hw_value = 2, .center_freq = 2417},
-	{ .hw_value = 3, .center_freq = 2422},
-	{ .hw_value = 4, .center_freq = 2427},
-	{ .hw_value = 5, .center_freq = 2432},
-	{ .hw_value = 6, .center_freq = 2437},
-	{ .hw_value = 7, .center_freq = 2442},
-	{ .hw_value = 8, .center_freq = 2447},
-	{ .hw_value = 9, .center_freq = 2452},
-	{ .hw_value = 10, .center_freq = 2457},
-	{ .hw_value = 11, .center_freq = 2462},
-	{ .hw_value = 12, .center_freq = 2467},
-	{ .hw_value = 13, .center_freq = 2472},
+	{ .hw_value = 1, .center_freq = 2412, .max_power = 25 },
+	{ .hw_value = 2, .center_freq = 2417, .max_power = 25 },
+	{ .hw_value = 3, .center_freq = 2422, .max_power = 25 },
+	{ .hw_value = 4, .center_freq = 2427, .max_power = 25 },
+	{ .hw_value = 5, .center_freq = 2432, .max_power = 25 },
+	{ .hw_value = 6, .center_freq = 2437, .max_power = 25 },
+	{ .hw_value = 7, .center_freq = 2442, .max_power = 25 },
+	{ .hw_value = 8, .center_freq = 2447, .max_power = 25 },
+	{ .hw_value = 9, .center_freq = 2452, .max_power = 25 },
+	{ .hw_value = 10, .center_freq = 2457, .max_power = 25 },
+	{ .hw_value = 11, .center_freq = 2462, .max_power = 25 },
+	{ .hw_value = 12, .center_freq = 2467, .max_power = 25 },
+	{ .hw_value = 13, .center_freq = 2472, .max_power = 25 },
 };
 };
 
 
 /* can't be const, mac80211 writes to this */
 /* can't be const, mac80211 writes to this */
@@ -1757,7 +1889,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
 		IEEE80211_HW_BEACON_FILTER |
 		IEEE80211_HW_BEACON_FILTER |
 		IEEE80211_HW_SUPPORTS_PS;
 		IEEE80211_HW_SUPPORTS_PS;
 
 
-	wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC);
 	wl->hw->wiphy->max_scan_ssids = 1;
 	wl->hw->wiphy->max_scan_ssids = 1;
 	wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
 	wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
 
 
@@ -1818,21 +1951,18 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 
 
 	INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
 	INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
 	wl->channel = WL1271_DEFAULT_CHANNEL;
 	wl->channel = WL1271_DEFAULT_CHANNEL;
-	wl->scanning = false;
 	wl->default_key = 0;
 	wl->default_key = 0;
 	wl->rx_counter = 0;
 	wl->rx_counter = 0;
 	wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
 	wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
 	wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
 	wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
-	wl->elp = false;
-	wl->psm = 0;
-	wl->psm_requested = false;
 	wl->psm_entry_retry = 0;
 	wl->psm_entry_retry = 0;
-	wl->tx_queue_stopped = false;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
-	wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+	wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
+	wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+	wl->sta_rate_set = 0;
 	wl->band = IEEE80211_BAND_2GHZ;
 	wl->band = IEEE80211_BAND_2GHZ;
 	wl->vif = NULL;
 	wl->vif = NULL;
-	wl->joined = false;
+	wl->flags = 0;
 
 
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
 		wl->tx_frames[i] = NULL;
 		wl->tx_frames[i] = NULL;

+ 8 - 7
drivers/net/wireless/wl12xx/wl1271_ps.c

@@ -39,12 +39,13 @@ void wl1271_elp_work(struct work_struct *work)
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
-	if (wl->elp || !wl->psm)
+	if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
+	    !test_bit(WL1271_FLAG_PSM, &wl->flags))
 		goto out;
 		goto out;
 
 
 	wl1271_debug(DEBUG_PSM, "chip to elp");
 	wl1271_debug(DEBUG_PSM, "chip to elp");
 	wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
 	wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
-	wl->elp = true;
+	set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
 
 
 out:
 out:
 	mutex_unlock(&wl->mutex);
 	mutex_unlock(&wl->mutex);
@@ -55,7 +56,7 @@ out:
 /* Routines to toggle sleep mode while in ELP */
 /* Routines to toggle sleep mode while in ELP */
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 {
 {
-	if (wl->psm) {
+	if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
 		cancel_delayed_work(&wl->elp_work);
 		cancel_delayed_work(&wl->elp_work);
 		ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
 		ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
 					msecs_to_jiffies(ELP_ENTRY_DELAY));
 					msecs_to_jiffies(ELP_ENTRY_DELAY));
@@ -70,7 +71,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
 	u32 start_time = jiffies;
 	u32 start_time = jiffies;
 	bool pending = false;
 	bool pending = false;
 
 
-	if (!wl->elp)
+	if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
 		return 0;
 		return 0;
 
 
 	wl1271_debug(DEBUG_PSM, "waking up chip from elp");
 	wl1271_debug(DEBUG_PSM, "waking up chip from elp");
@@ -101,7 +102,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
 		}
 		}
 	}
 	}
 
 
-	wl->elp = false;
+	clear_bit(WL1271_FLAG_IN_ELP, &wl->flags);
 
 
 	wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
 	wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
 		     jiffies_to_msecs(jiffies - start_time));
 		     jiffies_to_msecs(jiffies - start_time));
@@ -143,7 +144,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
 
 
-		wl->psm = 1;
+		set_bit(WL1271_FLAG_PSM, &wl->flags);
 		break;
 		break;
 	case STATION_ACTIVE_MODE:
 	case STATION_ACTIVE_MODE:
 	default:
 	default:
@@ -166,7 +167,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
 
 
-		wl->psm = 0;
+		clear_bit(WL1271_FLAG_PSM, &wl->flags);
 		break;
 		break;
 	}
 	}
 
 

+ 40 - 3
drivers/net/wireless/wl12xx/wl1271_tx.c

@@ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
 	pad = pad - skb->len;
 	pad = pad - skb->len;
 	tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
 	tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
 
 
+	/* if the packets are destined for AP (have a STA entry) send them
+	   with AP rate policies, otherwise use default basic rates */
+	if (control->control.sta)
+		tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
+
 	desc->tx_attr = cpu_to_le16(tx_attr);
 	desc->tx_attr = cpu_to_le16(tx_attr);
 
 
 	wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
 	wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
@@ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
 	return ret;
 	return ret;
 }
 }
 
 
+static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+{
+	struct ieee80211_supported_band *band;
+	u32 enabled_rates = 0;
+	int bit;
+
+	band = wl->hw->wiphy->bands[wl->band];
+	for (bit = 0; bit < band->n_bitrates; bit++) {
+		if (rate_set & 0x1)
+			enabled_rates |= band->bitrates[bit].hw_value;
+		rate_set >>= 1;
+	}
+
+	return enabled_rates;
+}
+
 void wl1271_tx_work(struct work_struct *work)
 void wl1271_tx_work(struct work_struct *work)
 {
 {
 	struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
 	struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	bool woken_up = false;
 	bool woken_up = false;
+	u32 sta_rates = 0;
 	int ret;
 	int ret;
 
 
+	/* check if the rates supported by the AP have changed */
+	if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
+					&wl->flags))) {
+		unsigned long flags;
+		spin_lock_irqsave(&wl->wl_lock, flags);
+		sta_rates = wl->sta_rate_set;
+		spin_unlock_irqrestore(&wl->wl_lock, flags);
+	}
+
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
 	if (unlikely(wl->state == WL1271_STATE_OFF))
 	if (unlikely(wl->state == WL1271_STATE_OFF))
 		goto out;
 		goto out;
 
 
+	/* if rates have changed, re-configure the rate policy */
+	if (unlikely(sta_rates)) {
+		wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
+		wl1271_acx_rate_policies(wl);
+	}
+
 	while ((skb = skb_dequeue(&wl->tx_queue))) {
 	while ((skb = skb_dequeue(&wl->tx_queue))) {
 		if (!woken_up) {
 		if (!woken_up) {
 			ret = wl1271_ps_elp_wakeup(wl, false);
 			ret = wl1271_ps_elp_wakeup(wl, false);
@@ -240,18 +277,18 @@ void wl1271_tx_work(struct work_struct *work)
 			wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
 			wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
 				     "stop queues");
 				     "stop queues");
 			ieee80211_stop_queues(wl->hw);
 			ieee80211_stop_queues(wl->hw);
-			wl->tx_queue_stopped = true;
+			set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
 			skb_queue_head(&wl->tx_queue, skb);
 			skb_queue_head(&wl->tx_queue, skb);
 			goto out;
 			goto out;
 		} else if (ret < 0) {
 		} else if (ret < 0) {
 			dev_kfree_skb(skb);
 			dev_kfree_skb(skb);
 			goto out;
 			goto out;
-		} else if (wl->tx_queue_stopped) {
+		} else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED,
+					      &wl->flags)) {
 			/* firmware buffer has space, restart queues */
 			/* firmware buffer has space, restart queues */
 			wl1271_debug(DEBUG_TX,
 			wl1271_debug(DEBUG_TX,
 				     "complete_packet: waking queues");
 				     "complete_packet: waking queues");
 			ieee80211_wake_queues(wl->hw);
 			ieee80211_wake_queues(wl->hw);
-			wl->tx_queue_stopped = false;
 		}
 		}
 	}
 	}
 
 

+ 0 - 140
drivers/net/wireless/zd1211rw/zd_chip.c

@@ -1325,151 +1325,11 @@ int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
 	return r;
 	return r;
 }
 }
 
 
-static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
-{
-	static const u16 constants[] = {
-		715, 655, 585, 540, 470, 410, 360, 315,
-		270, 235, 205, 175, 150, 125, 105,  85,
-		 65,  50,  40,  25,  15
-	};
-
-	int i;
-	u32 x;
-
-	/* It seems that their quality parameter is somehow per signal
-	 * and is now transferred per bit.
-	 */
-	switch (zd_rate) {
-	case ZD_OFDM_RATE_6M:
-	case ZD_OFDM_RATE_12M:
-	case ZD_OFDM_RATE_24M:
-		size *= 2;
-		break;
-	case ZD_OFDM_RATE_9M:
-	case ZD_OFDM_RATE_18M:
-	case ZD_OFDM_RATE_36M:
-	case ZD_OFDM_RATE_54M:
-		size *= 4;
-		size /= 3;
-		break;
-	case ZD_OFDM_RATE_48M:
-		size *= 3;
-		size /= 2;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	x = (10000 * status_quality)/size;
-	for (i = 0; i < ARRAY_SIZE(constants); i++) {
-		if (x > constants[i])
-			break;
-	}
-
-	switch (zd_rate) {
-	case ZD_OFDM_RATE_6M:
-	case ZD_OFDM_RATE_9M:
-		i += 3;
-		break;
-	case ZD_OFDM_RATE_12M:
-	case ZD_OFDM_RATE_18M:
-		i += 5;
-		break;
-	case ZD_OFDM_RATE_24M:
-	case ZD_OFDM_RATE_36M:
-		i += 9;
-		break;
-	case ZD_OFDM_RATE_48M:
-	case ZD_OFDM_RATE_54M:
-		i += 15;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return i;
-}
-
-static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size)
-{
-	int r;
-
-	r = ofdm_qual_db(status_quality, zd_rate, size);
-	ZD_ASSERT(r >= 0);
-	if (r < 0)
-		r = 0;
-
-	r = (r * 100)/29;
-	return r <= 100 ? r : 100;
-}
-
-static unsigned int log10times100(unsigned int x)
-{
-	static const u8 log10[] = {
-		  0,
-		  0,   30,   47,   60,   69,   77,   84,   90,   95,  100,
-		104,  107,  111,  114,  117,  120,  123,  125,  127,  130,
-		132,  134,  136,  138,  139,  141,  143,  144,  146,  147,
-		149,  150,  151,  153,  154,  155,  156,  157,  159,  160,
-		161,  162,  163,  164,  165,  166,  167,  168,  169,  169,
-		170,  171,  172,  173,  174,  174,  175,  176,  177,  177,
-		178,  179,  179,  180,  181,  181,  182,  183,  183,  184,
-		185,  185,  186,  186,  187,  188,  188,  189,  189,  190,
-		190,  191,  191,  192,  192,  193,  193,  194,  194,  195,
-		195,  196,  196,  197,  197,  198,  198,  199,  199,  200,
-		200,  200,  201,  201,  202,  202,  202,  203,  203,  204,
-		204,  204,  205,  205,  206,  206,  206,  207,  207,  207,
-		208,  208,  208,  209,  209,  210,  210,  210,  211,  211,
-		211,  212,  212,  212,  213,  213,  213,  213,  214,  214,
-		214,  215,  215,  215,  216,  216,  216,  217,  217,  217,
-		217,  218,  218,  218,  219,  219,  219,  219,  220,  220,
-		220,  220,  221,  221,  221,  222,  222,  222,  222,  223,
-		223,  223,  223,  224,  224,  224,  224,
-	};
-
-	return x < ARRAY_SIZE(log10) ? log10[x] : 225;
-}
-
-enum {
-	MAX_CCK_EVM_DB = 45,
-};
-
-static int cck_evm_db(u8 status_quality)
-{
-	return (20 * log10times100(status_quality)) / 100;
-}
-
-static int cck_snr_db(u8 status_quality)
-{
-	int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality);
-	ZD_ASSERT(r >= 0);
-	return r;
-}
-
-static int cck_qual_percent(u8 status_quality)
-{
-	int r;
-
-	r = cck_snr_db(status_quality);
-	r = (100*r)/17;
-	return r <= 100 ? r : 100;
-}
-
 static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame)
 static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame)
 {
 {
 	return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
 	return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
 }
 }
 
 
-u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
-	              const struct rx_status *status)
-{
-	return (status->frame_status&ZD_RX_OFDM) ?
-		ofdm_qual_percent(status->signal_quality_ofdm,
-				  zd_rate_from_ofdm_plcp_header(rx_frame),
-			          size) :
-		cck_qual_percent(status->signal_quality_cck);
-}
-
 /**
 /**
  * zd_rx_rate - report zd-rate
  * zd_rx_rate - report zd-rate
  * @rx_frame - received frame
  * @rx_frame - received frame

+ 0 - 3
drivers/net/wireless/zd1211rw/zd_chip.h

@@ -929,9 +929,6 @@ static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval)
 
 
 struct rx_status;
 struct rx_status;
 
 
-u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
-	               const struct rx_status *status);
-
 u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
 u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
 
 
 struct zd_mc_hash {
 struct zd_mc_hash {

+ 5 - 8
drivers/net/wireless/zd1211rw/zd_mac.c

@@ -828,9 +828,6 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
 	stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
 	stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
 	stats.band = IEEE80211_BAND_2GHZ;
 	stats.band = IEEE80211_BAND_2GHZ;
 	stats.signal = status->signal_strength;
 	stats.signal = status->signal_strength;
-	stats.qual = zd_rx_qual_percent(buffer,
-		                          length - sizeof(struct rx_status),
-		                          status);
 
 
 	rate = zd_rx_rate(buffer, status);
 	rate = zd_rx_rate(buffer, status);
 
 
@@ -872,7 +869,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
 }
 }
 
 
 static int zd_op_add_interface(struct ieee80211_hw *hw,
 static int zd_op_add_interface(struct ieee80211_hw *hw,
-				struct ieee80211_if_init_conf *conf)
+				struct ieee80211_vif *vif)
 {
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_mac *mac = zd_hw_mac(hw);
 
 
@@ -880,22 +877,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
 	if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
 	if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
-	switch (conf->type) {
+	switch (vif->type) {
 	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_ADHOC:
-		mac->type = conf->type;
+		mac->type = vif->type;
 		break;
 		break;
 	default:
 	default:
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	}
 	}
 
 
-	return zd_write_mac_addr(&mac->chip, conf->mac_addr);
+	return zd_write_mac_addr(&mac->chip, vif->addr);
 }
 }
 
 
 static void zd_op_remove_interface(struct ieee80211_hw *hw,
 static void zd_op_remove_interface(struct ieee80211_hw *hw,
-				    struct ieee80211_if_init_conf *conf)
+				    struct ieee80211_vif *vif)
 {
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_mac *mac = zd_hw_mac(hw);
 	mac->type = NL80211_IFTYPE_UNSPECIFIED;
 	mac->type = NL80211_IFTYPE_UNSPECIFIED;

+ 30 - 9
include/linux/ieee80211.h

@@ -1085,12 +1085,12 @@ enum ieee80211_eid {
 	WLAN_EID_TIM = 5,
 	WLAN_EID_TIM = 5,
 	WLAN_EID_IBSS_PARAMS = 6,
 	WLAN_EID_IBSS_PARAMS = 6,
 	WLAN_EID_CHALLENGE = 16,
 	WLAN_EID_CHALLENGE = 16,
-	/* 802.11d */
+
 	WLAN_EID_COUNTRY = 7,
 	WLAN_EID_COUNTRY = 7,
 	WLAN_EID_HP_PARAMS = 8,
 	WLAN_EID_HP_PARAMS = 8,
 	WLAN_EID_HP_TABLE = 9,
 	WLAN_EID_HP_TABLE = 9,
 	WLAN_EID_REQUEST = 10,
 	WLAN_EID_REQUEST = 10,
-	/* 802.11e */
+
 	WLAN_EID_QBSS_LOAD = 11,
 	WLAN_EID_QBSS_LOAD = 11,
 	WLAN_EID_EDCA_PARAM_SET = 12,
 	WLAN_EID_EDCA_PARAM_SET = 12,
 	WLAN_EID_TSPEC = 13,
 	WLAN_EID_TSPEC = 13,
@@ -1113,7 +1113,7 @@ enum ieee80211_eid {
 	WLAN_EID_PREP = 69,
 	WLAN_EID_PREP = 69,
 	WLAN_EID_PERR = 70,
 	WLAN_EID_PERR = 70,
 	WLAN_EID_RANN = 49,	/* compatible with FreeBSD */
 	WLAN_EID_RANN = 49,	/* compatible with FreeBSD */
-	/* 802.11h */
+
 	WLAN_EID_PWR_CONSTRAINT = 32,
 	WLAN_EID_PWR_CONSTRAINT = 32,
 	WLAN_EID_PWR_CAPABILITY = 33,
 	WLAN_EID_PWR_CAPABILITY = 33,
 	WLAN_EID_TPC_REQUEST = 34,
 	WLAN_EID_TPC_REQUEST = 34,
@@ -1124,20 +1124,41 @@ enum ieee80211_eid {
 	WLAN_EID_MEASURE_REPORT = 39,
 	WLAN_EID_MEASURE_REPORT = 39,
 	WLAN_EID_QUIET = 40,
 	WLAN_EID_QUIET = 40,
 	WLAN_EID_IBSS_DFS = 41,
 	WLAN_EID_IBSS_DFS = 41,
-	/* 802.11g */
+
 	WLAN_EID_ERP_INFO = 42,
 	WLAN_EID_ERP_INFO = 42,
 	WLAN_EID_EXT_SUPP_RATES = 50,
 	WLAN_EID_EXT_SUPP_RATES = 50,
-	/* 802.11n */
+
 	WLAN_EID_HT_CAPABILITY = 45,
 	WLAN_EID_HT_CAPABILITY = 45,
 	WLAN_EID_HT_INFORMATION = 61,
 	WLAN_EID_HT_INFORMATION = 61,
-	/* 802.11i */
+
 	WLAN_EID_RSN = 48,
 	WLAN_EID_RSN = 48,
-	WLAN_EID_TIMEOUT_INTERVAL = 56,
-	WLAN_EID_MMIE = 76 /* 802.11w */,
+	WLAN_EID_MMIE = 76,
 	WLAN_EID_WPA = 221,
 	WLAN_EID_WPA = 221,
 	WLAN_EID_GENERIC = 221,
 	WLAN_EID_GENERIC = 221,
 	WLAN_EID_VENDOR_SPECIFIC = 221,
 	WLAN_EID_VENDOR_SPECIFIC = 221,
-	WLAN_EID_QOS_PARAMETER = 222
+	WLAN_EID_QOS_PARAMETER = 222,
+
+	WLAN_EID_AP_CHAN_REPORT = 51,
+	WLAN_EID_NEIGHBOR_REPORT = 52,
+	WLAN_EID_RCPI = 53,
+	WLAN_EID_BSS_AVG_ACCESS_DELAY = 63,
+	WLAN_EID_ANTENNA_INFO = 64,
+	WLAN_EID_RSNI = 65,
+	WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66,
+	WLAN_EID_BSS_AVAILABLE_CAPACITY = 67,
+	WLAN_EID_BSS_AC_ACCESS_DELAY = 68,
+	WLAN_EID_RRM_ENABLED_CAPABILITIES = 70,
+	WLAN_EID_MULTIPLE_BSSID = 71,
+
+	WLAN_EID_MOBILITY_DOMAIN = 54,
+	WLAN_EID_FAST_BSS_TRANSITION = 55,
+	WLAN_EID_TIMEOUT_INTERVAL = 56,
+	WLAN_EID_RIC_DATA = 57,
+	WLAN_EID_RIC_DESCRIPTOR = 75,
+
+	WLAN_EID_DSE_REGISTERED_LOCATION = 58,
+	WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59,
+	WLAN_EID_EXT_CHANSWITCH_ANN = 60,
 };
 };
 
 
 /* Action category code */
 /* Action category code */

+ 36 - 0
include/linux/nl80211.h

@@ -270,6 +270,31 @@
  * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
  * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
  *	associated with this wiphy must be down and will follow.
  *	associated with this wiphy must be down and will follow.
  *
  *
+ * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
+ *	channel for the specified amount of time. This can be used to do
+ *	off-channel operations like transmit a Public Action frame and wait for
+ *	a response while being associated to an AP on another channel.
+ *	%NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
+ *	radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ *	frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
+ *	optionally used to specify additional channel parameters.
+ *	%NL80211_ATTR_DURATION is used to specify the duration in milliseconds
+ *	to remain on the channel. This command is also used as an event to
+ *	notify when the requested duration starts (it may take a while for the
+ *	driver to schedule this time due to other concurrent needs for the
+ *	radio).
+ *	When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
+ *	that will be included with any events pertaining to this request;
+ *	the cookie is also used to cancel the request.
+ * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
+ *	pending remain-on-channel duration if the desired operation has been
+ *	completed prior to expiration of the originally requested duration.
+ *	%NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
+ *	radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
+ *	uniquely identify the request.
+ *	This command is also used as an event to notify when a requested
+ *	remain-on-channel duration has expired.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
  */
@@ -353,6 +378,9 @@ enum nl80211_commands {
 	NL80211_CMD_DEL_PMKSA,
 	NL80211_CMD_DEL_PMKSA,
 	NL80211_CMD_FLUSH_PMKSA,
 	NL80211_CMD_FLUSH_PMKSA,
 
 
+	NL80211_CMD_REMAIN_ON_CHANNEL,
+	NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+
 	/* add new commands above here */
 	/* add new commands above here */
 
 
 	/* used to define NL80211_CMD_MAX below */
 	/* used to define NL80211_CMD_MAX below */
@@ -606,6 +634,10 @@ enum nl80211_commands {
  * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
  * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
  *	cache, a wiphy attribute.
  *	cache, a wiphy attribute.
  *
  *
+ * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
+ *
+ * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
  */
@@ -743,6 +775,10 @@ enum nl80211_attrs {
 	NL80211_ATTR_PMKID,
 	NL80211_ATTR_PMKID,
 	NL80211_ATTR_MAX_NUM_PMKIDS,
 	NL80211_ATTR_MAX_NUM_PMKIDS,
 
 
+	NL80211_ATTR_DURATION,
+
+	NL80211_ATTR_COOKIE,
+
 	/* add attributes here, update the policy in nl80211.c */
 	/* add attributes here, update the policy in nl80211.c */
 
 
 	__NL80211_ATTR_AFTER_LAST,
 	__NL80211_ATTR_AFTER_LAST,

+ 59 - 0
include/net/cfg80211.h

@@ -988,6 +988,15 @@ struct cfg80211_pmksa {
  *
  *
  * @dump_survey: get site survey information.
  * @dump_survey: get site survey information.
  *
  *
+ * @remain_on_channel: Request the driver to remain awake on the specified
+ *	channel for the specified duration to complete an off-channel
+ *	operation (e.g., public action frame exchange). When the driver is
+ *	ready on the requested channel, it must indicate this with an event
+ *	notification by calling cfg80211_ready_on_channel().
+ * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
+ *	This allows the operation to be terminated prior to timeout based on
+ *	the duration value.
+ *
  * @testmode_cmd: run a test mode command
  * @testmode_cmd: run a test mode command
  *
  *
  * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
  * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
@@ -1123,6 +1132,16 @@ struct cfg80211_ops {
 			     struct cfg80211_pmksa *pmksa);
 			     struct cfg80211_pmksa *pmksa);
 	int	(*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev);
 	int	(*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev);
 
 
+	int	(*remain_on_channel)(struct wiphy *wiphy,
+				     struct net_device *dev,
+				     struct ieee80211_channel *chan,
+				     enum nl80211_channel_type channel_type,
+				     unsigned int duration,
+				     u64 *cookie);
+	int	(*cancel_remain_on_channel)(struct wiphy *wiphy,
+					    struct net_device *dev,
+					    u64 cookie);
+
 	/* some temporary stuff to finish wext */
 	/* some temporary stuff to finish wext */
 	int	(*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
 	int	(*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
 				  bool enabled, int timeout);
 				  bool enabled, int timeout);
@@ -2147,5 +2166,45 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
 void cfg80211_disconnected(struct net_device *dev, u16 reason,
 void cfg80211_disconnected(struct net_device *dev, u16 reason,
 			   u8 *ie, size_t ie_len, gfp_t gfp);
 			   u8 *ie, size_t ie_len, gfp_t gfp);
 
 
+/**
+ * cfg80211_ready_on_channel - notification of remain_on_channel start
+ * @dev: network device
+ * @cookie: the request cookie
+ * @chan: The current channel (from remain_on_channel request)
+ * @channel_type: Channel type
+ * @duration: Duration in milliseconds that the driver intents to remain on the
+ *	channel
+ * @gfp: allocation flags
+ */
+void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
+			       struct ieee80211_channel *chan,
+			       enum nl80211_channel_type channel_type,
+			       unsigned int duration, gfp_t gfp);
+
+/**
+ * cfg80211_remain_on_channel_expired - remain_on_channel duration expired
+ * @dev: network device
+ * @cookie: the request cookie
+ * @chan: The current channel (from remain_on_channel request)
+ * @channel_type: Channel type
+ * @gfp: allocation flags
+ */
+void cfg80211_remain_on_channel_expired(struct net_device *dev,
+					u64 cookie,
+					struct ieee80211_channel *chan,
+					enum nl80211_channel_type channel_type,
+					gfp_t gfp);
+
+
+/**
+ * cfg80211_new_sta - notify userspace about station
+ *
+ * @dev: the netdev
+ * @mac_addr: the station's address
+ * @sinfo: the station information
+ * @gfp: allocation flags
+ */
+void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
+		      struct station_info *sinfo, gfp_t gfp);
 
 
 #endif /* __NET_CFG80211_H */
 #endif /* __NET_CFG80211_H */

+ 50 - 55
include/net/mac80211.h

@@ -547,7 +547,6 @@ enum mac80211_rx_flags {
  *	unspecified depending on the hardware capabilities flags
  *	unspecified depending on the hardware capabilities flags
  *	@IEEE80211_HW_SIGNAL_*
  *	@IEEE80211_HW_SIGNAL_*
  * @noise: noise when receiving this frame, in dBm.
  * @noise: noise when receiving this frame, in dBm.
- * @qual: overall signal quality indication, in percent (0-100).
  * @antenna: antenna used
  * @antenna: antenna used
  * @rate_idx: index of data rate into band's supported rates or MCS index if
  * @rate_idx: index of data rate into band's supported rates or MCS index if
  *	HT rates are use (RX_FLAG_HT)
  *	HT rates are use (RX_FLAG_HT)
@@ -559,7 +558,6 @@ struct ieee80211_rx_status {
 	int freq;
 	int freq;
 	int signal;
 	int signal;
 	int noise;
 	int noise;
-	int __deprecated qual;
 	int antenna;
 	int antenna;
 	int rate_idx;
 	int rate_idx;
 	int flag;
 	int flag;
@@ -701,33 +699,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
 	return false;
 	return false;
 }
 }
 
 
-/**
- * struct ieee80211_if_init_conf - initial configuration of an interface
- *
- * @vif: pointer to a driver-use per-interface structure. The pointer
- *	itself is also used for various functions including
- *	ieee80211_beacon_get() and ieee80211_get_buffered_bc().
- * @type: one of &enum nl80211_iftype constants. Determines the type of
- *	added/removed interface.
- * @mac_addr: pointer to MAC address of the interface. This pointer is valid
- *	until the interface is removed (i.e. it cannot be used after
- *	remove_interface() callback was called for this interface).
- *
- * This structure is used in add_interface() and remove_interface()
- * callbacks of &struct ieee80211_hw.
- *
- * When you allow multiple interfaces to be added to your PHY, take care
- * that the hardware can actually handle multiple MAC addresses. However,
- * also take care that when there's no interface left with mac_addr != %NULL
- * you remove the MAC address from the device to avoid acknowledging packets
- * in pure monitor mode.
- */
-struct ieee80211_if_init_conf {
-	enum nl80211_iftype type;
-	struct ieee80211_vif *vif;
-	void *mac_addr;
-};
-
 /**
 /**
  * enum ieee80211_key_alg - key algorithm
  * enum ieee80211_key_alg - key algorithm
  * @ALG_WEP: WEP40 or WEP104
  * @ALG_WEP: WEP40 or WEP104
@@ -1410,7 +1381,7 @@ enum ieee80211_ampdu_mlme_action {
  *	When the device is started it should not have a MAC address
  *	When the device is started it should not have a MAC address
  *	to avoid acknowledging frames before a non-monitor device
  *	to avoid acknowledging frames before a non-monitor device
  *	is added.
  *	is added.
- *	Must be implemented.
+ *	Must be implemented and can sleep.
  *
  *
  * @stop: Called after last netdevice attached to the hardware
  * @stop: Called after last netdevice attached to the hardware
  *	is disabled. This should turn off the hardware (at least
  *	is disabled. This should turn off the hardware (at least
@@ -1418,7 +1389,7 @@ enum ieee80211_ampdu_mlme_action {
  *	May be called right after add_interface if that rejects
  *	May be called right after add_interface if that rejects
  *	an interface. If you added any work onto the mac80211 workqueue
  *	an interface. If you added any work onto the mac80211 workqueue
  *	you should ensure to cancel it on this callback.
  *	you should ensure to cancel it on this callback.
- *	Must be implemented.
+ *	Must be implemented and can sleep.
  *
  *
  * @add_interface: Called when a netdevice attached to the hardware is
  * @add_interface: Called when a netdevice attached to the hardware is
  *	enabled. Because it is not called for monitor mode devices, @start
  *	enabled. Because it is not called for monitor mode devices, @start
@@ -1428,7 +1399,7 @@ enum ieee80211_ampdu_mlme_action {
  *	interface is given in the conf parameter.
  *	interface is given in the conf parameter.
  *	The callback may refuse to add an interface by returning a
  *	The callback may refuse to add an interface by returning a
  *	negative error code (which will be seen in userspace.)
  *	negative error code (which will be seen in userspace.)
- *	Must be implemented.
+ *	Must be implemented and can sleep.
  *
  *
  * @remove_interface: Notifies a driver that an interface is going down.
  * @remove_interface: Notifies a driver that an interface is going down.
  *	The @stop callback is called after this if it is the last interface
  *	The @stop callback is called after this if it is the last interface
@@ -1437,19 +1408,20 @@ enum ieee80211_ampdu_mlme_action {
  *	must be cleared so the device no longer acknowledges packets,
  *	must be cleared so the device no longer acknowledges packets,
  *	the mac_addr member of the conf structure is, however, set to the
  *	the mac_addr member of the conf structure is, however, set to the
  *	MAC address of the device going away.
  *	MAC address of the device going away.
- *	Hence, this callback must be implemented.
+ *	Hence, this callback must be implemented. It can sleep.
  *
  *
  * @config: Handler for configuration requests. IEEE 802.11 code calls this
  * @config: Handler for configuration requests. IEEE 802.11 code calls this
  *	function to change hardware configuration, e.g., channel.
  *	function to change hardware configuration, e.g., channel.
  *	This function should never fail but returns a negative error code
  *	This function should never fail but returns a negative error code
- *	if it does.
+ *	if it does. The callback can sleep.
  *
  *
  * @bss_info_changed: Handler for configuration requests related to BSS
  * @bss_info_changed: Handler for configuration requests related to BSS
  *	parameters that may vary during BSS's lifespan, and may affect low
  *	parameters that may vary during BSS's lifespan, and may affect low
  *	level driver (e.g. assoc/disassoc status, erp parameters).
  *	level driver (e.g. assoc/disassoc status, erp parameters).
  *	This function should not be used if no BSS has been set, unless
  *	This function should not be used if no BSS has been set, unless
  *	for association indication. The @changed parameter indicates which
  *	for association indication. The @changed parameter indicates which
- *	of the bss parameters has changed when a call is made.
+ *	of the bss parameters has changed when a call is made. The callback
+ *	can sleep.
  *
  *
  * @prepare_multicast: Prepare for multicast filter configuration.
  * @prepare_multicast: Prepare for multicast filter configuration.
  *	This callback is optional, and its return value is passed
  *	This callback is optional, and its return value is passed
@@ -1457,20 +1429,22 @@ enum ieee80211_ampdu_mlme_action {
  *
  *
  * @configure_filter: Configure the device's RX filter.
  * @configure_filter: Configure the device's RX filter.
  *	See the section "Frame filtering" for more information.
  *	See the section "Frame filtering" for more information.
- *	This callback must be implemented.
+ *	This callback must be implemented and can sleep.
  *
  *
  * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
  * @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.
  * 	must be set or cleared for a given STA. Must be atomic.
  *
  *
  * @set_key: See the section "Hardware crypto acceleration"
  * @set_key: See the section "Hardware crypto acceleration"
- *	This callback can sleep, and is only called between add_interface
- *	and remove_interface calls, i.e. while the given virtual interface
+ *	This callback is only called between add_interface and
+ *	remove_interface calls, i.e. while the given virtual interface
  *	is enabled.
  *	is enabled.
  *	Returns a negative error code if the key can't be added.
  *	Returns a negative error code if the key can't be added.
+ *	The callback can sleep.
  *
  *
  * @update_tkip_key: See the section "Hardware crypto acceleration"
  * @update_tkip_key: See the section "Hardware crypto acceleration"
  * 	This callback will be called in the context of Rx. Called for drivers
  * 	This callback will be called in the context of Rx. Called for drivers
  * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
  * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
+ *	The callback can sleep.
  *
  *
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  *	the scan state machine in stack. The scan must honour the channel
  *	the scan state machine in stack. The scan must honour the channel
@@ -1484,21 +1458,28 @@ enum ieee80211_ampdu_mlme_action {
  *	When the scan finishes, ieee80211_scan_completed() must be called;
  *	When the scan finishes, ieee80211_scan_completed() must be called;
  *	note that it also must be called when the scan cannot finish due to
  *	note that it also must be called when the scan cannot finish due to
  *	any error unless this callback returned a negative error code.
  *	any error unless this callback returned a negative error code.
+ *	The callback can sleep.
  *
  *
  * @sw_scan_start: Notifier function that is called just before a software scan
  * @sw_scan_start: Notifier function that is called just before a software scan
  *	is started. Can be NULL, if the driver doesn't need this notification.
  *	is started. Can be NULL, if the driver doesn't need this notification.
+ *	The callback can sleep.
  *
  *
- * @sw_scan_complete: Notifier function that is called just after a software scan
- *	finished. Can be NULL, if the driver doesn't need this notification.
+ * @sw_scan_complete: Notifier function that is called just after a
+ *	software scan finished. Can be NULL, if the driver doesn't need
+ *	this notification.
+ *	The callback can sleep.
  *
  *
  * @get_stats: Return low-level statistics.
  * @get_stats: Return low-level statistics.
  * 	Returns zero if statistics are available.
  * 	Returns zero if statistics are available.
+ *	The callback can sleep.
  *
  *
  * @get_tkip_seq: If your device implements TKIP encryption in hardware this
  * @get_tkip_seq: If your device implements TKIP encryption in hardware this
  *	callback should be provided to read the TKIP transmit IVs (both IV32
  *	callback should be provided to read the TKIP transmit IVs (both IV32
  *	and IV16) for the given key from hardware.
  *	and IV16) for the given key from hardware.
+ *	The callback must be atomic.
  *
  *
  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
+ *	The callback can sleep.
  *
  *
  * @sta_notify: Notifies low level driver about addition, removal or power
  * @sta_notify: Notifies low level driver about addition, removal or power
  *	state transition of an associated station, AP,  IBSS/WDS/mesh peer etc.
  *	state transition of an associated station, AP,  IBSS/WDS/mesh peer etc.
@@ -1507,30 +1488,36 @@ enum ieee80211_ampdu_mlme_action {
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *	bursting) for a hardware TX queue.
  *	bursting) for a hardware TX queue.
  *	Returns a negative error code on failure.
  *	Returns a negative error code on failure.
+ *	The callback can sleep.
  *
  *
  * @get_tx_stats: Get statistics of the current TX queue status. This is used
  * @get_tx_stats: Get statistics of the current TX queue status. This is used
  *	to get number of currently queued packets (queue length), maximum queue
  *	to get number of currently queued packets (queue length), maximum queue
  *	size (limit), and total number of packets sent using each TX queue
  *	size (limit), and total number of packets sent using each TX queue
  *	(count). The 'stats' pointer points to an array that has hw->queues
  *	(count). The 'stats' pointer points to an array that has hw->queues
  *	items.
  *	items.
+ *	The callback must be atomic.
  *
  *
  * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
  * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
  *	this is only used for IBSS mode BSSID merging and debugging. Is not a
  *	this is only used for IBSS mode BSSID merging and debugging. Is not a
  *	required function.
  *	required function.
+ *	The callback can sleep.
  *
  *
  * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
  * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
  *      Currently, this is only used for IBSS mode debugging. Is not a
  *      Currently, this is only used for IBSS mode debugging. Is not a
  *	required function.
  *	required function.
+ *	The callback can sleep.
  *
  *
  * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
  * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
  *	with other STAs in the IBSS. This is only used in IBSS mode. This
  *	with other STAs in the IBSS. This is only used in IBSS mode. This
  *	function is optional if the firmware/hardware takes full care of
  *	function is optional if the firmware/hardware takes full care of
  *	TSF synchronization.
  *	TSF synchronization.
+ *	The callback can sleep.
  *
  *
  * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
  * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
  *	This is needed only for IBSS mode and the result of this function is
  *	This is needed only for IBSS mode and the result of this function is
  *	used to determine whether to reply to Probe Requests.
  *	used to determine whether to reply to Probe Requests.
  *	Returns non-zero if this device sent the last beacon.
  *	Returns non-zero if this device sent the last beacon.
+ *	The callback can sleep.
  *
  *
  * @ampdu_action: Perform a certain A-MPDU action
  * @ampdu_action: Perform a certain A-MPDU action
  * 	The RA/TID combination determines the destination and TID we want
  * 	The RA/TID combination determines the destination and TID we want
@@ -1539,21 +1526,28 @@ enum ieee80211_ampdu_mlme_action {
  * 	is the first frame we expect to perform the action on. Notice
  * 	is the first frame we expect to perform the action on. Notice
  * 	that TX/RX_STOP can pass NULL for this parameter.
  * 	that TX/RX_STOP can pass NULL for this parameter.
  *	Returns a negative error code on failure.
  *	Returns a negative error code on failure.
+ *	The callback must be atomic.
  *
  *
  * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
  * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
  *	need to set wiphy->rfkill_poll to %true before registration,
  *	need to set wiphy->rfkill_poll to %true before registration,
  *	and need to call wiphy_rfkill_set_hw_state() in the callback.
  *	and need to call wiphy_rfkill_set_hw_state() in the callback.
+ *	The callback can sleep.
  *
  *
  * @testmode_cmd: Implement a cfg80211 test mode command.
  * @testmode_cmd: Implement a cfg80211 test mode command.
+ *	The callback can sleep.
+ *
+ * @flush: Flush all pending frames from the hardware queue, making sure
+ *	that the hardware queues are empty. If the parameter @drop is set
+ *	to %true, pending frames may be dropped. The callback can sleep.
  */
  */
 struct ieee80211_ops {
 struct ieee80211_ops {
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
 	int (*start)(struct ieee80211_hw *hw);
 	int (*start)(struct ieee80211_hw *hw);
 	void (*stop)(struct ieee80211_hw *hw);
 	void (*stop)(struct ieee80211_hw *hw);
 	int (*add_interface)(struct ieee80211_hw *hw,
 	int (*add_interface)(struct ieee80211_hw *hw,
-			     struct ieee80211_if_init_conf *conf);
+			     struct ieee80211_vif *vif);
 	void (*remove_interface)(struct ieee80211_hw *hw,
 	void (*remove_interface)(struct ieee80211_hw *hw,
-				 struct ieee80211_if_init_conf *conf);
+				 struct ieee80211_vif *vif);
 	int (*config)(struct ieee80211_hw *hw, u32 changed);
 	int (*config)(struct ieee80211_hw *hw, u32 changed);
 	void (*bss_info_changed)(struct ieee80211_hw *hw,
 	void (*bss_info_changed)(struct ieee80211_hw *hw,
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_vif *vif,
@@ -1601,6 +1595,7 @@ struct ieee80211_ops {
 #ifdef CONFIG_NL80211_TESTMODE
 #ifdef CONFIG_NL80211_TESTMODE
 	int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
 	int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
 #endif
 #endif
+	void (*flush)(struct ieee80211_hw *hw, bool drop);
 };
 };
 
 
 /**
 /**
@@ -1840,7 +1835,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_beacon_get_tim - beacon generation function
  * ieee80211_beacon_get_tim - beacon generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @tim_offset: pointer to variable that will receive the TIM IE offset.
  * @tim_offset: pointer to variable that will receive the TIM IE offset.
  *	Set to 0 if invalid (in non-AP modes).
  *	Set to 0 if invalid (in non-AP modes).
  * @tim_length: pointer to variable that will receive the TIM IE length,
  * @tim_length: pointer to variable that will receive the TIM IE length,
@@ -1868,7 +1863,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_beacon_get - beacon generation function
  * ieee80211_beacon_get - beacon generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  *
  * See ieee80211_beacon_get_tim().
  * See ieee80211_beacon_get_tim().
  */
  */
@@ -1881,7 +1876,7 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_rts_get - RTS frame generation function
  * ieee80211_rts_get - RTS frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame: pointer to the frame that is going to be protected by the RTS.
  * @frame: pointer to the frame that is going to be protected by the RTS.
  * @frame_len: the frame length (in octets).
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
@@ -1900,7 +1895,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 /**
 /**
  * ieee80211_rts_duration - Get the duration field for an RTS frame
  * ieee80211_rts_duration - Get the duration field for an RTS frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame_len: the length of the frame that is going to be protected by the RTS.
  * @frame_len: the length of the frame that is going to be protected by the RTS.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  *
  *
@@ -1915,7 +1910,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_ctstoself_get - CTS-to-self frame generation function
  * ieee80211_ctstoself_get - CTS-to-self frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
  * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
  * @frame_len: the frame length (in octets).
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
@@ -1935,7 +1930,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
  * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
  * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  *
  *
@@ -1951,7 +1946,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_generic_frame_duration - Calculate the duration field for a frame
  * ieee80211_generic_frame_duration - Calculate the duration field for a frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame_len: the length of the frame.
  * @frame_len: the length of the frame.
  * @rate: the rate at which the frame is going to be transmitted.
  * @rate: the rate at which the frame is going to be transmitted.
  *
  *
@@ -1966,7 +1961,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
  * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
  * @hw: pointer as obtained from ieee80211_alloc_hw().
  * @hw: pointer as obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  *
  * Function for accessing buffered broadcast and multicast frames. If
  * Function for accessing buffered broadcast and multicast frames. If
  * hardware/firmware does not implement buffering of broadcast/multicast
  * hardware/firmware does not implement buffering of broadcast/multicast
@@ -2134,7 +2129,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
 
 
 /**
 /**
  * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
  * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @ra: receiver address of the BA session recipient.
  * @tid: the TID to BA on.
  * @tid: the TID to BA on.
  *
  *
@@ -2145,7 +2140,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
 
 
 /**
 /**
  * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
  * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @ra: receiver address of the BA session recipient.
  * @tid: the TID to BA on.
  * @tid: the TID to BA on.
  *
  *
@@ -2173,7 +2168,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
 
 
 /**
 /**
  * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
  * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @ra: receiver address of the BA session recipient.
  * @tid: the desired TID to BA on.
  * @tid: the desired TID to BA on.
  *
  *
@@ -2184,7 +2179,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
 
 
 /**
 /**
  * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
  * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @ra: receiver address of the BA session recipient.
  * @tid: the desired TID to BA on.
  * @tid: the desired TID to BA on.
  *
  *
@@ -2263,7 +2258,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 /**
 /**
  * ieee80211_beacon_loss - inform hardware does not receive beacons
  * ieee80211_beacon_loss - inform hardware does not receive beacons
  *
  *
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  *
  * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
  * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
  * IEEE80211_CONF_PS is set, the driver needs to inform whenever the
  * IEEE80211_CONF_PS is set, the driver needs to inform whenever the

+ 2 - 2
net/mac80211/Makefile

@@ -6,10 +6,10 @@ mac80211-y := \
 	sta_info.o \
 	sta_info.o \
 	wep.o \
 	wep.o \
 	wpa.o \
 	wpa.o \
-	scan.o \
+	scan.o offchannel.o \
 	ht.o agg-tx.o agg-rx.o \
 	ht.o agg-tx.o agg-rx.o \
 	ibss.o \
 	ibss.o \
-	mlme.o \
+	mlme.o work.o \
 	iface.o \
 	iface.o \
 	rate.o \
 	rate.o \
 	michael.o \
 	michael.o \

+ 27 - 5
net/mac80211/cfg.c

@@ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 				  enum nl80211_iftype type, u32 *flags,
 				  enum nl80211_iftype type, u32 *flags,
 				  struct vif_params *params)
 				  struct vif_params *params)
 {
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	int ret;
 	int ret;
 
 
-	if (netif_running(dev))
+	if (ieee80211_sdata_running(sdata))
 		return -EBUSY;
 		return -EBUSY;
 
 
 	if (!nl80211_params_check(type, params))
 	if (!nl80211_params_check(type, params))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
 	ret = ieee80211_if_change_type(sdata, type);
 	ret = ieee80211_if_change_type(sdata, type);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
@@ -1345,7 +1343,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	ap = sdata->u.mgd.associated->cbss.bssid;
+	ap = sdata->u.mgd.associated->bssid;
 
 
 	if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
 	if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
 		if (sdata->u.mgd.powersave)
 		if (sdata->u.mgd.powersave)
@@ -1443,6 +1441,28 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
+static int ieee80211_remain_on_channel(struct wiphy *wiphy,
+				       struct net_device *dev,
+				       struct ieee80211_channel *chan,
+				       enum nl80211_channel_type channel_type,
+				       unsigned int duration,
+				       u64 *cookie)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
+					      duration, cookie);
+}
+
+static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
+					      struct net_device *dev,
+					      u64 cookie)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
+}
+
 struct cfg80211_ops mac80211_config_ops = {
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -1489,4 +1509,6 @@ struct cfg80211_ops mac80211_config_ops = {
 	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
 	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
 	.set_power_mgmt = ieee80211_set_power_mgmt,
 	.set_power_mgmt = ieee80211_set_power_mgmt,
 	.set_bitrate_mask = ieee80211_set_bitrate_mask,
 	.set_bitrate_mask = ieee80211_set_bitrate_mask,
+	.remain_on_channel = ieee80211_remain_on_channel,
+	.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
 };
 };

+ 0 - 2
net/mac80211/debugfs_netdev.c

@@ -133,7 +133,6 @@ IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
 /* STA attributes */
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
-IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
 
 
 static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
 static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
 			      enum ieee80211_smps_mode smps_mode)
 			      enum ieee80211_smps_mode smps_mode)
@@ -270,7 +269,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 
 
 	DEBUGFS_ADD(bssid, sta);
 	DEBUGFS_ADD(bssid, sta);
 	DEBUGFS_ADD(aid, sta);
 	DEBUGFS_ADD(aid, sta);
-	DEBUGFS_ADD(capab, sta);
 	DEBUGFS_ADD_MODE(smps, 0600);
 	DEBUGFS_ADD_MODE(smps, 0600);
 }
 }
 
 

+ 68 - 9
net/mac80211/driver-ops.h

@@ -14,6 +14,8 @@ static inline int drv_start(struct ieee80211_local *local)
 {
 {
 	int ret;
 	int ret;
 
 
+	might_sleep();
+
 	local->started = true;
 	local->started = true;
 	smp_mb();
 	smp_mb();
 	ret = local->ops->start(&local->hw);
 	ret = local->ops->start(&local->hw);
@@ -23,6 +25,8 @@ static inline int drv_start(struct ieee80211_local *local)
 
 
 static inline void drv_stop(struct ieee80211_local *local)
 static inline void drv_stop(struct ieee80211_local *local)
 {
 {
+	might_sleep();
+
 	local->ops->stop(&local->hw);
 	local->ops->stop(&local->hw);
 	trace_drv_stop(local);
 	trace_drv_stop(local);
 
 
@@ -36,23 +40,33 @@ static inline void drv_stop(struct ieee80211_local *local)
 }
 }
 
 
 static inline int drv_add_interface(struct ieee80211_local *local,
 static inline int drv_add_interface(struct ieee80211_local *local,
-				    struct ieee80211_if_init_conf *conf)
+				    struct ieee80211_vif *vif)
 {
 {
-	int ret = local->ops->add_interface(&local->hw, conf);
-	trace_drv_add_interface(local, vif_to_sdata(conf->vif), ret);
+	int ret;
+
+	might_sleep();
+
+	ret = local->ops->add_interface(&local->hw, vif);
+	trace_drv_add_interface(local, vif_to_sdata(vif), ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static inline void drv_remove_interface(struct ieee80211_local *local,
 static inline void drv_remove_interface(struct ieee80211_local *local,
-					struct ieee80211_if_init_conf *conf)
+					struct ieee80211_vif *vif)
 {
 {
-	local->ops->remove_interface(&local->hw, conf);
-	trace_drv_remove_interface(local, vif_to_sdata(conf->vif));
+	might_sleep();
+
+	local->ops->remove_interface(&local->hw, vif);
+	trace_drv_remove_interface(local, vif_to_sdata(vif));
 }
 }
 
 
 static inline int drv_config(struct ieee80211_local *local, u32 changed)
 static inline int drv_config(struct ieee80211_local *local, u32 changed)
 {
 {
-	int ret = local->ops->config(&local->hw, changed);
+	int ret;
+
+	might_sleep();
+
+	ret = local->ops->config(&local->hw, changed);
 	trace_drv_config(local, changed, ret);
 	trace_drv_config(local, changed, ret);
 	return ret;
 	return ret;
 }
 }
@@ -62,6 +76,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 					struct ieee80211_bss_conf *info,
 					struct ieee80211_bss_conf *info,
 					u32 changed)
 					u32 changed)
 {
 {
+	might_sleep();
+
 	if (local->ops->bss_info_changed)
 	if (local->ops->bss_info_changed)
 		local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
 		local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
 	trace_drv_bss_info_changed(local, sdata, info, changed);
 	trace_drv_bss_info_changed(local, sdata, info, changed);
@@ -111,7 +127,11 @@ static inline int drv_set_key(struct ieee80211_local *local,
 			      struct ieee80211_sta *sta,
 			      struct ieee80211_sta *sta,
 			      struct ieee80211_key_conf *key)
 			      struct ieee80211_key_conf *key)
 {
 {
-	int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
+	int ret;
+
+	might_sleep();
+
+	ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
 	trace_drv_set_key(local, cmd, sdata, sta, key, ret);
 	trace_drv_set_key(local, cmd, sdata, sta, key, ret);
 	return ret;
 	return ret;
 }
 }
@@ -121,6 +141,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
 				       const u8 *address, u32 iv32,
 				       const u8 *address, u32 iv32,
 				       u16 *phase1key)
 				       u16 *phase1key)
 {
 {
+	might_sleep();
+
 	if (local->ops->update_tkip_key)
 	if (local->ops->update_tkip_key)
 		local->ops->update_tkip_key(&local->hw, conf, address,
 		local->ops->update_tkip_key(&local->hw, conf, address,
 					    iv32, phase1key);
 					    iv32, phase1key);
@@ -130,13 +152,19 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
 static inline int drv_hw_scan(struct ieee80211_local *local,
 static inline int drv_hw_scan(struct ieee80211_local *local,
 			      struct cfg80211_scan_request *req)
 			      struct cfg80211_scan_request *req)
 {
 {
-	int ret = local->ops->hw_scan(&local->hw, req);
+	int ret;
+
+	might_sleep();
+
+	ret = local->ops->hw_scan(&local->hw, req);
 	trace_drv_hw_scan(local, req, ret);
 	trace_drv_hw_scan(local, req, ret);
 	return ret;
 	return ret;
 }
 }
 
 
 static inline void drv_sw_scan_start(struct ieee80211_local *local)
 static inline void drv_sw_scan_start(struct ieee80211_local *local)
 {
 {
+	might_sleep();
+
 	if (local->ops->sw_scan_start)
 	if (local->ops->sw_scan_start)
 		local->ops->sw_scan_start(&local->hw);
 		local->ops->sw_scan_start(&local->hw);
 	trace_drv_sw_scan_start(local);
 	trace_drv_sw_scan_start(local);
@@ -144,6 +172,8 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local)
 
 
 static inline void drv_sw_scan_complete(struct ieee80211_local *local)
 static inline void drv_sw_scan_complete(struct ieee80211_local *local)
 {
 {
+	might_sleep();
+
 	if (local->ops->sw_scan_complete)
 	if (local->ops->sw_scan_complete)
 		local->ops->sw_scan_complete(&local->hw);
 		local->ops->sw_scan_complete(&local->hw);
 	trace_drv_sw_scan_complete(local);
 	trace_drv_sw_scan_complete(local);
@@ -154,6 +184,8 @@ static inline int drv_get_stats(struct ieee80211_local *local,
 {
 {
 	int ret = -EOPNOTSUPP;
 	int ret = -EOPNOTSUPP;
 
 
+	might_sleep();
+
 	if (local->ops->get_stats)
 	if (local->ops->get_stats)
 		ret = local->ops->get_stats(&local->hw, stats);
 		ret = local->ops->get_stats(&local->hw, stats);
 	trace_drv_get_stats(local, stats, ret);
 	trace_drv_get_stats(local, stats, ret);
@@ -173,6 +205,9 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
 					u32 value)
 					u32 value)
 {
 {
 	int ret = 0;
 	int ret = 0;
+
+	might_sleep();
+
 	if (local->ops->set_rts_threshold)
 	if (local->ops->set_rts_threshold)
 		ret = local->ops->set_rts_threshold(&local->hw, value);
 		ret = local->ops->set_rts_threshold(&local->hw, value);
 	trace_drv_set_rts_threshold(local, value, ret);
 	trace_drv_set_rts_threshold(local, value, ret);
@@ -193,6 +228,9 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
 			      const struct ieee80211_tx_queue_params *params)
 			      const struct ieee80211_tx_queue_params *params)
 {
 {
 	int ret = -EOPNOTSUPP;
 	int ret = -EOPNOTSUPP;
+
+	might_sleep();
+
 	if (local->ops->conf_tx)
 	if (local->ops->conf_tx)
 		ret = local->ops->conf_tx(&local->hw, queue, params);
 		ret = local->ops->conf_tx(&local->hw, queue, params);
 	trace_drv_conf_tx(local, queue, params, ret);
 	trace_drv_conf_tx(local, queue, params, ret);
@@ -210,6 +248,9 @@ static inline int drv_get_tx_stats(struct ieee80211_local *local,
 static inline u64 drv_get_tsf(struct ieee80211_local *local)
 static inline u64 drv_get_tsf(struct ieee80211_local *local)
 {
 {
 	u64 ret = -1ULL;
 	u64 ret = -1ULL;
+
+	might_sleep();
+
 	if (local->ops->get_tsf)
 	if (local->ops->get_tsf)
 		ret = local->ops->get_tsf(&local->hw);
 		ret = local->ops->get_tsf(&local->hw);
 	trace_drv_get_tsf(local, ret);
 	trace_drv_get_tsf(local, ret);
@@ -218,6 +259,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local)
 
 
 static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
 static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
 {
 {
+	might_sleep();
+
 	if (local->ops->set_tsf)
 	if (local->ops->set_tsf)
 		local->ops->set_tsf(&local->hw, tsf);
 		local->ops->set_tsf(&local->hw, tsf);
 	trace_drv_set_tsf(local, tsf);
 	trace_drv_set_tsf(local, tsf);
@@ -225,6 +268,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
 
 
 static inline void drv_reset_tsf(struct ieee80211_local *local)
 static inline void drv_reset_tsf(struct ieee80211_local *local)
 {
 {
+	might_sleep();
+
 	if (local->ops->reset_tsf)
 	if (local->ops->reset_tsf)
 		local->ops->reset_tsf(&local->hw);
 		local->ops->reset_tsf(&local->hw);
 	trace_drv_reset_tsf(local);
 	trace_drv_reset_tsf(local);
@@ -233,6 +278,9 @@ static inline void drv_reset_tsf(struct ieee80211_local *local)
 static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 {
 {
 	int ret = 1;
 	int ret = 1;
+
+	might_sleep();
+
 	if (local->ops->tx_last_beacon)
 	if (local->ops->tx_last_beacon)
 		ret = local->ops->tx_last_beacon(&local->hw);
 		ret = local->ops->tx_last_beacon(&local->hw);
 	trace_drv_tx_last_beacon(local, ret);
 	trace_drv_tx_last_beacon(local, ret);
@@ -256,7 +304,18 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
 
 
 static inline void drv_rfkill_poll(struct ieee80211_local *local)
 static inline void drv_rfkill_poll(struct ieee80211_local *local)
 {
 {
+	might_sleep();
+
 	if (local->ops->rfkill_poll)
 	if (local->ops->rfkill_poll)
 		local->ops->rfkill_poll(&local->hw);
 		local->ops->rfkill_poll(&local->hw);
 }
 }
+
+static inline void drv_flush(struct ieee80211_local *local, bool drop)
+{
+	might_sleep();
+
+	trace_drv_flush(local, drop);
+	if (local->ops->flush)
+		local->ops->flush(&local->hw, drop);
+}
 #endif /* __MAC80211_DRIVER_OPS */
 #endif /* __MAC80211_DRIVER_OPS */

+ 21 - 0
net/mac80211/driver-trace.h

@@ -690,6 +690,27 @@ TRACE_EVENT(drv_ampdu_action,
 		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
 		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
 	)
 	)
 );
 );
+
+TRACE_EVENT(drv_flush,
+	TP_PROTO(struct ieee80211_local *local, bool drop),
+
+	TP_ARGS(local, drop),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(bool, drop)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->drop = drop;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT " drop:%d",
+		LOCAL_PR_ARG, __entry->drop
+	)
+);
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 
 
 #undef TRACE_INCLUDE_PATH
 #undef TRACE_INCLUDE_PATH

+ 32 - 21
net/mac80211/ibss.c

@@ -187,15 +187,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_bss *bss)
 				    struct ieee80211_bss *bss)
 {
 {
+	struct cfg80211_bss *cbss =
+		container_of((void *)bss, struct cfg80211_bss, priv);
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_supported_band *sband;
 	u32 basic_rates;
 	u32 basic_rates;
 	int i, j;
 	int i, j;
-	u16 beacon_int = bss->cbss.beacon_interval;
+	u16 beacon_int = cbss->beacon_interval;
 
 
 	if (beacon_int < 10)
 	if (beacon_int < 10)
 		beacon_int = 10;
 		beacon_int = 10;
 
 
-	sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band];
+	sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
 
 
 	basic_rates = 0;
 	basic_rates = 0;
 
 
@@ -212,12 +214,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 		}
 		}
 	}
 	}
 
 
-	__ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
+	__ieee80211_sta_join_ibss(sdata, cbss->bssid,
 				  beacon_int,
 				  beacon_int,
-				  bss->cbss.channel,
+				  cbss->channel,
 				  basic_rates,
 				  basic_rates,
-				  bss->cbss.capability,
-				  bss->cbss.tsf);
+				  cbss->capability,
+				  cbss->tsf);
 }
 }
 
 
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -229,6 +231,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 {
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
 	int freq;
 	int freq;
+	struct cfg80211_bss *cbss;
 	struct ieee80211_bss *bss;
 	struct ieee80211_bss *bss;
 	struct sta_info *sta;
 	struct sta_info *sta;
 	struct ieee80211_channel *channel;
 	struct ieee80211_channel *channel;
@@ -283,8 +286,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 	if (!bss)
 	if (!bss)
 		return;
 		return;
 
 
+	cbss = container_of((void *)bss, struct cfg80211_bss, priv);
+
 	/* was just updated in ieee80211_bss_info_update */
 	/* was just updated in ieee80211_bss_info_update */
-	beacon_timestamp = bss->cbss.tsf;
+	beacon_timestamp = cbss->tsf;
 
 
 	/* check if we need to merge IBSS */
 	/* check if we need to merge IBSS */
 
 
@@ -297,11 +302,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 		goto put_bss;
 		goto put_bss;
 
 
 	/* not an IBSS */
 	/* not an IBSS */
-	if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
+	if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
 		goto put_bss;
 		goto put_bss;
 
 
 	/* different channel */
 	/* different channel */
-	if (bss->cbss.channel != local->oper_channel)
+	if (cbss->channel != local->oper_channel)
 		goto put_bss;
 		goto put_bss;
 
 
 	/* different SSID */
 	/* different SSID */
@@ -311,7 +316,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 		goto put_bss;
 		goto put_bss;
 
 
 	/* same BSSID */
 	/* same BSSID */
-	if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
+	if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
 		goto put_bss;
 		goto put_bss;
 
 
 	if (rx_status->flag & RX_FLAG_TSFT) {
 	if (rx_status->flag & RX_FLAG_TSFT) {
@@ -382,6 +387,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 					u8 *bssid,u8 *addr, u32 supp_rates)
 					u8 *bssid,u8 *addr, u32 supp_rates)
 {
 {
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	struct sta_info *sta;
 	int band = local->hw.conf.channel->band;
 	int band = local->hw.conf.channel->band;
@@ -397,6 +403,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 		return NULL;
 		return NULL;
 	}
 	}
 
 
+	if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH)
+		return NULL;
+
 	if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
 	if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
 		return NULL;
 		return NULL;
 
 
@@ -514,7 +523,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 {
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_bss *bss;
+	struct cfg80211_bss *cbss;
 	struct ieee80211_channel *chan = NULL;
 	struct ieee80211_channel *chan = NULL;
 	const u8 *bssid = NULL;
 	const u8 *bssid = NULL;
 	int active_ibss;
 	int active_ibss;
@@ -538,21 +547,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 		chan = ifibss->channel;
 		chan = ifibss->channel;
 	if (!is_zero_ether_addr(ifibss->bssid))
 	if (!is_zero_ether_addr(ifibss->bssid))
 		bssid = ifibss->bssid;
 		bssid = ifibss->bssid;
-	bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid,
-				       ifibss->ssid, ifibss->ssid_len,
-				       WLAN_CAPABILITY_IBSS |
-				       WLAN_CAPABILITY_PRIVACY,
-				       capability);
+	cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
+				ifibss->ssid, ifibss->ssid_len,
+				WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY,
+				capability);
+
+	if (cbss) {
+		struct ieee80211_bss *bss;
 
 
-	if (bss) {
+		bss = (void *)cbss->priv;
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
 		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
-		       "%pM\n", bss->cbss.bssid, ifibss->bssid);
+		       "%pM\n", cbss->bssid, ifibss->bssid);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
 
 		printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
 		printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
 		       " based on configured SSID\n",
 		       " based on configured SSID\n",
-		       sdata->name, bss->cbss.bssid);
+		       sdata->name, cbss->bssid);
 
 
 		ieee80211_sta_join_ibss(sdata, bss);
 		ieee80211_sta_join_ibss(sdata, bss);
 		ieee80211_rx_bss_put(local, bss);
 		ieee80211_rx_bss_put(local, bss);
@@ -744,7 +755,7 @@ static void ieee80211_ibss_work(struct work_struct *work)
 	if (WARN_ON(local->suspended))
 	if (WARN_ON(local->suspended))
 		return;
 		return;
 
 
-	if (!netif_running(sdata->dev))
+	if (!ieee80211_sdata_running(sdata))
 		return;
 		return;
 
 
 	if (local->scanning)
 	if (local->scanning)
@@ -827,7 +838,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
 
 
 	mutex_lock(&local->iflist_mtx);
 	mutex_lock(&local->iflist_mtx);
 	list_for_each_entry(sdata, &local->interfaces, list) {
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
 		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
 			continue;
 			continue;

+ 108 - 33
net/mac80211/ieee80211_i.h

@@ -71,9 +71,6 @@ struct ieee80211_fragment_entry {
 
 
 
 
 struct ieee80211_bss {
 struct ieee80211_bss {
-	/* Yes, this is a hack */
-	struct cfg80211_bss cbss;
-
 	/* don't want to look up all the time */
 	/* don't want to look up all the time */
 	size_t ssid_len;
 	size_t ssid_len;
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -227,31 +224,78 @@ struct mesh_preq_queue {
 	u8 flags;
 	u8 flags;
 };
 };
 
 
-enum ieee80211_mgd_state {
-	IEEE80211_MGD_STATE_IDLE,
-	IEEE80211_MGD_STATE_PROBE,
-	IEEE80211_MGD_STATE_AUTH,
-	IEEE80211_MGD_STATE_ASSOC,
+enum ieee80211_work_type {
+	IEEE80211_WORK_ABORT,
+	IEEE80211_WORK_DIRECT_PROBE,
+	IEEE80211_WORK_AUTH,
+	IEEE80211_WORK_ASSOC,
+	IEEE80211_WORK_REMAIN_ON_CHANNEL,
 };
 };
 
 
-struct ieee80211_mgd_work {
+/**
+ * enum work_done_result - indicates what to do after work was done
+ *
+ * @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
+ * @WORK_DONE_REQUEUE: This work item was reset to be reused, and
+ *	should be requeued.
+ */
+enum work_done_result {
+	WORK_DONE_DESTROY,
+	WORK_DONE_REQUEUE,
+};
+
+struct ieee80211_work {
 	struct list_head list;
 	struct list_head list;
-	struct ieee80211_bss *bss;
-	int ie_len;
-	u8 prev_bssid[ETH_ALEN];
-	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	u8 ssid_len;
+
+	struct rcu_head rcu_head;
+
+	struct ieee80211_sub_if_data *sdata;
+
+	enum work_done_result (*done)(struct ieee80211_work *wk,
+				      struct sk_buff *skb);
+
+	struct ieee80211_channel *chan;
+	enum nl80211_channel_type chan_type;
+
 	unsigned long timeout;
 	unsigned long timeout;
-	enum ieee80211_mgd_state state;
-	u16 auth_alg, auth_transaction;
+	enum ieee80211_work_type type;
 
 
-	int tries;
+	u8 filter_ta[ETH_ALEN];
+
+	bool started;
 
 
-	u8 key[WLAN_KEY_LEN_WEP104];
-	u8 key_len, key_idx;
+	union {
+		struct {
+			int tries;
+			u16 algorithm, transaction;
+			u8 ssid[IEEE80211_MAX_SSID_LEN];
+			u8 ssid_len;
+			u8 key[WLAN_KEY_LEN_WEP104];
+			u8 key_len, key_idx;
+			bool privacy;
+		} probe_auth;
+		struct {
+			struct cfg80211_bss *bss;
+			const u8 *supp_rates;
+			const u8 *ht_information_ie;
+			enum ieee80211_smps_mode smps;
+			int tries;
+			u16 capability;
+			u8 prev_bssid[ETH_ALEN];
+			u8 ssid[IEEE80211_MAX_SSID_LEN];
+			u8 ssid_len;
+			u8 supp_rates_len;
+			bool wmm_used, use_11n;
+		} assoc;
+		struct {
+			u32 duration;
+			bool started;
+		} remain;
+	};
 
 
+	int ie_len;
 	/* must be last */
 	/* must be last */
-	u8 ie[0]; /* for auth or assoc frame, not probe */
+	u8 ie[0];
 };
 };
 
 
 /* flags used in struct ieee80211_if_managed.flags */
 /* flags used in struct ieee80211_if_managed.flags */
@@ -259,17 +303,11 @@ enum ieee80211_sta_flags {
 	IEEE80211_STA_BEACON_POLL	= BIT(0),
 	IEEE80211_STA_BEACON_POLL	= BIT(0),
 	IEEE80211_STA_CONNECTION_POLL	= BIT(1),
 	IEEE80211_STA_CONNECTION_POLL	= BIT(1),
 	IEEE80211_STA_CONTROL_PORT	= BIT(2),
 	IEEE80211_STA_CONTROL_PORT	= BIT(2),
-	IEEE80211_STA_WMM_ENABLED	= BIT(3),
 	IEEE80211_STA_DISABLE_11N	= BIT(4),
 	IEEE80211_STA_DISABLE_11N	= BIT(4),
 	IEEE80211_STA_CSA_RECEIVED	= BIT(5),
 	IEEE80211_STA_CSA_RECEIVED	= BIT(5),
 	IEEE80211_STA_MFP_ENABLED	= BIT(6),
 	IEEE80211_STA_MFP_ENABLED	= BIT(6),
 };
 };
 
 
-/* flags for MLME request */
-enum ieee80211_sta_request {
-	IEEE80211_STA_REQ_SCAN,
-};
-
 struct ieee80211_if_managed {
 struct ieee80211_if_managed {
 	struct timer_list timer;
 	struct timer_list timer;
 	struct timer_list conn_mon_timer;
 	struct timer_list conn_mon_timer;
@@ -284,14 +322,11 @@ struct ieee80211_if_managed {
 	int probe_send_count;
 	int probe_send_count;
 
 
 	struct mutex mtx;
 	struct mutex mtx;
-	struct ieee80211_bss *associated;
-	struct ieee80211_mgd_work *old_associate_work;
-	struct list_head work_list;
+	struct cfg80211_bss *associated;
 
 
 	u8 bssid[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 
 
 	u16 aid;
 	u16 aid;
-	u16 capab;
 
 
 	struct sk_buff_head skb_queue;
 	struct sk_buff_head skb_queue;
 
 
@@ -300,8 +335,6 @@ struct ieee80211_if_managed {
 	enum ieee80211_smps_mode req_smps, /* requested smps mode */
 	enum ieee80211_smps_mode req_smps, /* requested smps mode */
 				 ap_smps; /* smps mode AP thinks we're in */
 				 ap_smps; /* smps mode AP thinks we're in */
 
 
-	unsigned long request;
-
 	unsigned int flags;
 	unsigned int flags;
 
 
 	u32 beacon_crc;
 	u32 beacon_crc;
@@ -567,6 +600,15 @@ struct ieee80211_local {
 
 
 	const struct ieee80211_ops *ops;
 	const struct ieee80211_ops *ops;
 
 
+	/*
+	 * work stuff, potentially off-channel (in the future)
+	 */
+	struct mutex work_mtx;
+	struct list_head work_list;
+	struct timer_list work_timer;
+	struct work_struct work_work;
+	struct sk_buff_head work_skb_queue;
+
 	/*
 	/*
 	 * private workqueue to mac80211. mac80211 makes this accessible
 	 * private workqueue to mac80211. mac80211 makes this accessible
 	 * via ieee80211_queue_work()
 	 * via ieee80211_queue_work()
@@ -695,6 +737,10 @@ struct ieee80211_local {
 	enum nl80211_channel_type oper_channel_type;
 	enum nl80211_channel_type oper_channel_type;
 	struct ieee80211_channel *oper_channel, *csa_channel;
 	struct ieee80211_channel *oper_channel, *csa_channel;
 
 
+	/* Temporary remain-on-channel for off-channel operations */
+	struct ieee80211_channel *tmp_channel;
+	enum nl80211_channel_type tmp_channel_type;
+
 	/* SNMP counters */
 	/* SNMP counters */
 	/* dot11CountersTable */
 	/* dot11CountersTable */
 	u32 dot11TransmittedFragmentCount;
 	u32 dot11TransmittedFragmentCount;
@@ -752,7 +798,7 @@ struct ieee80211_local {
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
 
 	bool pspolling;
 	bool pspolling;
-	bool scan_ps_enabled;
+	bool offchannel_ps_enabled;
 	/*
 	/*
 	 * PS can only be enabled when we have exactly one managed
 	 * PS can only be enabled when we have exactly one managed
 	 * interface (and monitors) in PS, this then points there.
 	 * interface (and monitors) in PS, this then points there.
@@ -947,6 +993,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
 			  struct ieee80211_bss *bss);
 			  struct ieee80211_bss *bss);
 
 
+/* off-channel helpers */
+void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local);
+void ieee80211_offchannel_stop_station(struct ieee80211_local *local);
+void ieee80211_offchannel_return(struct ieee80211_local *local,
+				 bool enable_beaconing);
+
 /* interface handling */
 /* interface handling */
 int ieee80211_iface_init(void);
 int ieee80211_iface_init(void);
 void ieee80211_iface_exit(void);
 void ieee80211_iface_exit(void);
@@ -960,6 +1012,11 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local);
 u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
 u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
 void ieee80211_recalc_idle(struct ieee80211_local *local);
 void ieee80211_recalc_idle(struct ieee80211_local *local);
 
 
+static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
+{
+	return netif_running(sdata->dev);
+}
+
 /* tx handling */
 /* tx handling */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_tx_pending(unsigned long data);
 void ieee80211_tx_pending(unsigned long data);
@@ -1106,6 +1163,24 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
 void ieee80211_recalc_smps(struct ieee80211_local *local,
 void ieee80211_recalc_smps(struct ieee80211_local *local,
 			   struct ieee80211_sub_if_data *forsdata);
 			   struct ieee80211_sub_if_data *forsdata);
 
 
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+			  const u8 *ids, int n_ids, size_t offset);
+size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
+
+/* internal work items */
+void ieee80211_work_init(struct ieee80211_local *local);
+void ieee80211_add_work(struct ieee80211_work *wk);
+void free_work(struct ieee80211_work *wk);
+void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
+ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
+					   struct sk_buff *skb);
+int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
+				   struct ieee80211_channel *chan,
+				   enum nl80211_channel_type channel_type,
+				   unsigned int duration, u64 *cookie);
+int ieee80211_wk_cancel_remain_on_channel(
+	struct ieee80211_sub_if_data *sdata, u64 cookie);
+
 #ifdef CONFIG_MAC80211_NOINLINE
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
 #define debug_noinline noinline
 #else
 #else

+ 19 - 18
net/mac80211/iface.c

@@ -65,7 +65,7 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	int ret;
 	int ret;
 
 
-	if (netif_running(dev))
+	if (ieee80211_sdata_running(sdata))
 		return -EBUSY;
 		return -EBUSY;
 
 
 	ret = eth_mac_addr(dev, addr);
 	ret = eth_mac_addr(dev, addr);
@@ -96,7 +96,6 @@ static int ieee80211_open(struct net_device *dev)
 	struct ieee80211_sub_if_data *nsdata;
 	struct ieee80211_sub_if_data *nsdata;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	struct sta_info *sta;
-	struct ieee80211_if_init_conf conf;
 	u32 changed = 0;
 	u32 changed = 0;
 	int res;
 	int res;
 	u32 hw_reconf_flags = 0;
 	u32 hw_reconf_flags = 0;
@@ -111,7 +110,7 @@ static int ieee80211_open(struct net_device *dev)
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 		struct net_device *ndev = nsdata->dev;
 		struct net_device *ndev = nsdata->dev;
 
 
-		if (ndev != dev && netif_running(ndev)) {
+		if (ndev != dev && ieee80211_sdata_running(nsdata)) {
 			/*
 			/*
 			 * Allow only a single IBSS interface to be up at any
 			 * Allow only a single IBSS interface to be up at any
 			 * time. This is restricted because beacon distribution
 			 * time. This is restricted because beacon distribution
@@ -197,7 +196,7 @@ static int ieee80211_open(struct net_device *dev)
 		struct net_device *ndev = nsdata->dev;
 		struct net_device *ndev = nsdata->dev;
 
 
 		/*
 		/*
-		 * No need to check netif_running since we do not allow
+		 * No need to check running since we do not allow
 		 * it to start up with this invalid address.
 		 * it to start up with this invalid address.
 		 */
 		 */
 		if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
 		if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
@@ -248,10 +247,7 @@ static int ieee80211_open(struct net_device *dev)
 		ieee80211_configure_filter(local);
 		ieee80211_configure_filter(local);
 		break;
 		break;
 	default:
 	default:
-		conf.vif = &sdata->vif;
-		conf.type = sdata->vif.type;
-		conf.mac_addr = sdata->vif.addr;
-		res = drv_add_interface(local, &conf);
+		res = drv_add_interface(local, &sdata->vif);
 		if (res)
 		if (res)
 			goto err_stop;
 			goto err_stop;
 
 
@@ -334,7 +330,7 @@ static int ieee80211_open(struct net_device *dev)
 
 
 	return 0;
 	return 0;
  err_del_interface:
  err_del_interface:
-	drv_remove_interface(local, &conf);
+	drv_remove_interface(local, &sdata->vif);
  err_stop:
  err_stop:
 	if (!local->open_count)
 	if (!local->open_count)
 		drv_stop(local);
 		drv_stop(local);
@@ -349,7 +345,6 @@ static int ieee80211_stop(struct net_device *dev)
 {
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_init_conf conf;
 	struct sta_info *sta;
 	struct sta_info *sta;
 	unsigned long flags;
 	unsigned long flags;
 	struct sk_buff *skb, *tmp;
 	struct sk_buff *skb, *tmp;
@@ -361,6 +356,11 @@ static int ieee80211_stop(struct net_device *dev)
 	 */
 	 */
 	netif_stop_queue(dev);
 	netif_stop_queue(dev);
 
 
+	/*
+	 * Purge work for this interface.
+	 */
+	ieee80211_work_purge(sdata);
+
 	/*
 	/*
 	 * Now delete all active aggregation sessions.
 	 * Now delete all active aggregation sessions.
 	 */
 	 */
@@ -528,12 +528,9 @@ static int ieee80211_stop(struct net_device *dev)
 				BSS_CHANGED_BEACON_ENABLED);
 				BSS_CHANGED_BEACON_ENABLED);
 		}
 		}
 
 
-		conf.vif = &sdata->vif;
-		conf.type = sdata->vif.type;
-		conf.mac_addr = sdata->vif.addr;
 		/* disable all keys for as long as this netdev is down */
 		/* disable all keys for as long as this netdev is down */
 		ieee80211_disable_keys(sdata);
 		ieee80211_disable_keys(sdata);
-		drv_remove_interface(local, &conf);
+		drv_remove_interface(local, &sdata->vif);
 	}
 	}
 
 
 	sdata->bss = NULL;
 	sdata->bss = NULL;
@@ -756,7 +753,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
 	 * and goes into the requested mode.
 	 * and goes into the requested mode.
 	 */
 	 */
 
 
-	if (netif_running(sdata->dev))
+	if (ieee80211_sdata_running(sdata))
 		return -EBUSY;
 		return -EBUSY;
 
 
 	/* Purge and reset type-dependent state. */
 	/* Purge and reset type-dependent state. */
@@ -917,6 +914,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
 	       wiphy_name(local->hw.wiphy));
 	       wiphy_name(local->hw.wiphy));
 #endif
 #endif
 
 
+	drv_flush(local, false);
+
 	local->hw.conf.flags |= IEEE80211_CONF_IDLE;
 	local->hw.conf.flags |= IEEE80211_CONF_IDLE;
 	return IEEE80211_CONF_CHANGE_IDLE;
 	return IEEE80211_CONF_CHANGE_IDLE;
 }
 }
@@ -926,16 +925,18 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
 	int count = 0;
 	int count = 0;
 
 
+	if (!list_empty(&local->work_list))
+		return ieee80211_idle_off(local, "working");
+
 	if (local->scanning)
 	if (local->scanning)
 		return ieee80211_idle_off(local, "scanning");
 		return ieee80211_idle_off(local, "scanning");
 
 
 	list_for_each_entry(sdata, &local->interfaces, list) {
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 		/* do not count disabled managed interfaces */
 		/* do not count disabled managed interfaces */
 		if (sdata->vif.type == NL80211_IFTYPE_STATION &&
 		if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-		    !sdata->u.mgd.associated &&
-		    list_empty(&sdata->u.mgd.work_list))
+		    !sdata->u.mgd.associated)
 			continue;
 			continue;
 		/* do not count unused IBSS interfaces */
 		/* do not count unused IBSS interfaces */
 		if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
 		if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&

+ 2 - 2
net/mac80211/key.c

@@ -443,7 +443,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
 	add_todo(old_key, KEY_FLAG_TODO_DELETE);
 	add_todo(old_key, KEY_FLAG_TODO_DELETE);
 
 
 	add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
 	add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
-	if (netif_running(sdata->dev))
+	if (ieee80211_sdata_running(sdata))
 		add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
 		add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
 
 
 	spin_unlock_irqrestore(&sdata->local->key_lock, flags);
 	spin_unlock_irqrestore(&sdata->local->key_lock, flags);
@@ -509,7 +509,7 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 {
 {
 	ASSERT_RTNL();
 	ASSERT_RTNL();
 
 
-	if (WARN_ON(!netif_running(sdata->dev)))
+	if (WARN_ON(!ieee80211_sdata_running(sdata)))
 		return;
 		return;
 
 
 	ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
 	ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);

+ 7 - 4
net/mac80211/main.c

@@ -107,6 +107,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 	if (scan_chan) {
 	if (scan_chan) {
 		chan = scan_chan;
 		chan = scan_chan;
 		channel_type = NL80211_CHAN_NO_HT;
 		channel_type = NL80211_CHAN_NO_HT;
+	} else if (local->tmp_channel) {
+		chan = scan_chan = local->tmp_channel;
+		channel_type = local->tmp_channel_type;
 	} else {
 	} else {
 		chan = local->oper_channel;
 		chan = local->oper_channel;
 		channel_type = local->oper_channel_type;
 		channel_type = local->oper_channel_type;
@@ -212,7 +215,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 	}
 	}
 
 
 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
-		if (local->quiescing || !netif_running(sdata->dev) ||
+		if (local->quiescing || !ieee80211_sdata_running(sdata) ||
 		    test_bit(SCAN_SW_SCANNING, &local->scanning)) {
 		    test_bit(SCAN_SW_SCANNING, &local->scanning)) {
 			sdata->vif.bss_conf.enable_beacon = false;
 			sdata->vif.bss_conf.enable_beacon = false;
 		} else {
 		} else {
@@ -359,9 +362,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 			WIPHY_FLAG_4ADDR_STATION;
 			WIPHY_FLAG_4ADDR_STATION;
 	wiphy->privid = mac80211_wiphy_privid;
 	wiphy->privid = mac80211_wiphy_privid;
 
 
-	/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
-	wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
-			       sizeof(struct cfg80211_bss);
+	wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
 
 
 	local = wiphy_priv(wiphy);
 	local = wiphy_priv(wiphy);
 
 
@@ -395,6 +396,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
 
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
 
+	ieee80211_work_init(local);
+
 	INIT_WORK(&local->restart_work, ieee80211_restart_work);
 	INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
 
 	INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
 	INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);

+ 1 - 1
net/mac80211/mesh.c

@@ -645,7 +645,7 @@ static void ieee80211_mesh_work(struct work_struct *work)
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 
 
-	if (!netif_running(sdata->dev))
+	if (!ieee80211_sdata_running(sdata))
 		return;
 		return;
 
 
 	if (local->scanning)
 	if (local->scanning)

+ 220 - 861
net/mac80211/mlme.c

@@ -77,12 +77,6 @@ enum rx_mgmt_action {
 
 
 	/* caller must tell cfg80211 about internal error */
 	/* caller must tell cfg80211 about internal error */
 	RX_MGMT_CFG80211_ASSOC_ERROR,
 	RX_MGMT_CFG80211_ASSOC_ERROR,
-
-	/* caller must call cfg80211_auth_timeout() & free work */
-	RX_MGMT_CFG80211_AUTH_TO,
-
-	/* caller must call cfg80211_assoc_timeout() & free work */
-	RX_MGMT_CFG80211_ASSOC_TO,
 };
 };
 
 
 /* utils */
 /* utils */
@@ -125,27 +119,6 @@ static int ecw2cw(int ecw)
 	return (1 << ecw) - 1;
 	return (1 << ecw) - 1;
 }
 }
 
 
-static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
-				      struct ieee80211_supported_band *sband,
-				      u32 *rates)
-{
-	int i, j, count;
-	*rates = 0;
-	count = 0;
-	for (i = 0; i < bss->supp_rates_len; i++) {
-		int rate = (bss->supp_rates[i] & 0x7F) * 5;
-
-		for (j = 0; j < sband->n_bitrates; j++)
-			if (sband->bitrates[j].bitrate == rate) {
-				*rates |= BIT(j);
-				count++;
-				break;
-			}
-	}
-
-	return count;
-}
-
 /*
 /*
  * ieee80211_enable_ht should be called only after the operating band
  * ieee80211_enable_ht should be called only after the operating band
  * has been determined as ht configuration depends on the hw's
  * has been determined as ht configuration depends on the hw's
@@ -231,264 +204,6 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 
 
 /* frame sending functions */
 /* frame sending functions */
 
 
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
-				 struct ieee80211_mgd_work *wk)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	u8 *pos;
-	const u8 *ies, *ht_ie;
-	int i, len, count, rates_len, supp_rates_len;
-	u16 capab;
-	int wmm = 0;
-	struct ieee80211_supported_band *sband;
-	u32 rates = 0;
-
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-			    sizeof(*mgmt) + 200 + wk->ie_len +
-			    wk->ssid_len);
-	if (!skb) {
-		printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
-		       "frame\n", sdata->name);
-		return;
-	}
-	skb_reserve(skb, local->hw.extra_tx_headroom);
-
-	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-	capab = ifmgd->capab;
-
-	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
-		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
-			capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
-		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
-			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
-	}
-
-	if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
-		capab |= WLAN_CAPABILITY_PRIVACY;
-	if (wk->bss->wmm_used)
-		wmm = 1;
-
-	/* get all rates supported by the device and the AP as
-	 * some APs don't like getting a superset of their rates
-	 * in the association request (e.g. D-Link DAP 1353 in
-	 * b-only mode) */
-	rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates);
-
-	if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
-	    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
-		capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
-
-	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN);
-	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
-	memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN);
-
-	if (!is_zero_ether_addr(wk->prev_bssid)) {
-		skb_put(skb, 10);
-		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-						  IEEE80211_STYPE_REASSOC_REQ);
-		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
-		mgmt->u.reassoc_req.listen_interval =
-				cpu_to_le16(local->hw.conf.listen_interval);
-		memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid,
-		       ETH_ALEN);
-	} else {
-		skb_put(skb, 4);
-		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-						  IEEE80211_STYPE_ASSOC_REQ);
-		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
-		mgmt->u.assoc_req.listen_interval =
-				cpu_to_le16(local->hw.conf.listen_interval);
-	}
-
-	/* SSID */
-	ies = pos = skb_put(skb, 2 + wk->ssid_len);
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = wk->ssid_len;
-	memcpy(pos, wk->ssid, wk->ssid_len);
-
-	/* add all rates which were marked to be used above */
-	supp_rates_len = rates_len;
-	if (supp_rates_len > 8)
-		supp_rates_len = 8;
-
-	len = sband->n_bitrates;
-	pos = skb_put(skb, supp_rates_len + 2);
-	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos++ = supp_rates_len;
-
-	count = 0;
-	for (i = 0; i < sband->n_bitrates; i++) {
-		if (BIT(i) & rates) {
-			int rate = sband->bitrates[i].bitrate;
-			*pos++ = (u8) (rate / 5);
-			if (++count == 8)
-				break;
-		}
-	}
-
-	if (rates_len > count) {
-		pos = skb_put(skb, rates_len - count + 2);
-		*pos++ = WLAN_EID_EXT_SUPP_RATES;
-		*pos++ = rates_len - count;
-
-		for (i++; i < sband->n_bitrates; i++) {
-			if (BIT(i) & rates) {
-				int rate = sband->bitrates[i].bitrate;
-				*pos++ = (u8) (rate / 5);
-			}
-		}
-	}
-
-	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
-		/* 1. power capabilities */
-		pos = skb_put(skb, 4);
-		*pos++ = WLAN_EID_PWR_CAPABILITY;
-		*pos++ = 2;
-		*pos++ = 0; /* min tx power */
-		*pos++ = local->hw.conf.channel->max_power; /* max tx power */
-
-		/* 2. supported channels */
-		/* TODO: get this in reg domain format */
-		pos = skb_put(skb, 2 * sband->n_channels + 2);
-		*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
-		*pos++ = 2 * sband->n_channels;
-		for (i = 0; i < sband->n_channels; i++) {
-			*pos++ = ieee80211_frequency_to_channel(
-					sband->channels[i].center_freq);
-			*pos++ = 1; /* one channel in the subband*/
-		}
-	}
-
-	if (wk->ie_len && wk->ie) {
-		pos = skb_put(skb, wk->ie_len);
-		memcpy(pos, wk->ie, wk->ie_len);
-	}
-
-	if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {
-		pos = skb_put(skb, 9);
-		*pos++ = WLAN_EID_VENDOR_SPECIFIC;
-		*pos++ = 7; /* len */
-		*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
-		*pos++ = 0x50;
-		*pos++ = 0xf2;
-		*pos++ = 2; /* WME */
-		*pos++ = 0; /* WME info */
-		*pos++ = 1; /* WME ver */
-		*pos++ = 0;
-	}
-
-	/* wmm support is a must to HT */
-	/*
-	 * IEEE802.11n does not allow TKIP/WEP as pairwise
-	 * ciphers in HT mode. We still associate in non-ht
-	 * mode (11a/b/g) if any one of these ciphers is
-	 * configured as pairwise.
-	 */
-	if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
-	    sband->ht_cap.ht_supported &&
-	    (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) &&
-	    ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
-	    (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) {
-		struct ieee80211_ht_info *ht_info =
-			(struct ieee80211_ht_info *)(ht_ie + 2);
-		u16 cap = sband->ht_cap.cap;
-		__le16 tmp;
-		u32 flags = local->hw.conf.channel->flags;
-
-		/* determine capability flags */
-
-		if (ieee80211_disable_40mhz_24ghz &&
-		    sband->band == IEEE80211_BAND_2GHZ) {
-			cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-			cap &= ~IEEE80211_HT_CAP_SGI_40;
-		}
-
-		switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
-		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-			if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
-				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-				cap &= ~IEEE80211_HT_CAP_SGI_40;
-			}
-			break;
-		case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-			if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
-				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-				cap &= ~IEEE80211_HT_CAP_SGI_40;
-			}
-			break;
-		}
-
-		/* set SM PS mode properly */
-		cap &= ~IEEE80211_HT_CAP_SM_PS;
-		/* new association always uses requested smps mode */
-		if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
-			if (ifmgd->powersave)
-				ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
-			else
-				ifmgd->ap_smps = IEEE80211_SMPS_OFF;
-		} else
-			ifmgd->ap_smps = ifmgd->req_smps;
-
-		switch (ifmgd->ap_smps) {
-		case IEEE80211_SMPS_AUTOMATIC:
-		case IEEE80211_SMPS_NUM_MODES:
-			WARN_ON(1);
-		case IEEE80211_SMPS_OFF:
-			cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
-				IEEE80211_HT_CAP_SM_PS_SHIFT;
-			break;
-		case IEEE80211_SMPS_STATIC:
-			cap |= WLAN_HT_CAP_SM_PS_STATIC <<
-				IEEE80211_HT_CAP_SM_PS_SHIFT;
-			break;
-		case IEEE80211_SMPS_DYNAMIC:
-			cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
-				IEEE80211_HT_CAP_SM_PS_SHIFT;
-			break;
-		}
-
-		/* reserve and fill IE */
-
-		pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
-		*pos++ = WLAN_EID_HT_CAPABILITY;
-		*pos++ = sizeof(struct ieee80211_ht_cap);
-		memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-
-		/* capability flags */
-		tmp = cpu_to_le16(cap);
-		memcpy(pos, &tmp, sizeof(u16));
-		pos += sizeof(u16);
-
-		/* AMPDU parameters */
-		*pos++ = sband->ht_cap.ampdu_factor |
-			 (sband->ht_cap.ampdu_density <<
-				IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
-
-		/* MCS set */
-		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-		pos += sizeof(sband->ht_cap.mcs);
-
-		/* extended capabilities */
-		pos += sizeof(__le16);
-
-		/* BF capabilities */
-		pos += sizeof(__le32);
-
-		/* antenna selection */
-		pos += sizeof(u8);
-	}
-
-	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-	ieee80211_tx_skb(sdata, skb);
-}
-
-
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 					   const u8 *bssid, u16 stype, u16 reason,
 					   const u8 *bssid, u16 stype, u16 reason,
 					   void *cookie)
 					   void *cookie)
@@ -604,7 +319,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
 		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
 
-	if (!netif_running(sdata->dev))
+	if (!ieee80211_sdata_running(sdata))
 		return;
 		return;
 
 
 	mutex_lock(&ifmgd->mtx);
 	mutex_lock(&ifmgd->mtx);
@@ -615,7 +330,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 	ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
 	ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
 
 
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	/* XXX: shouldn't really modify cfg80211-owned data! */
-	ifmgd->associated->cbss.channel = sdata->local->oper_channel;
+	ifmgd->associated->channel = sdata->local->oper_channel;
 
 
 	ieee80211_wake_queues_by_reason(&sdata->local->hw,
 	ieee80211_wake_queues_by_reason(&sdata->local->hw,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
 					IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -642,6 +357,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 				      struct ieee80211_channel_sw_ie *sw_elem,
 				      struct ieee80211_channel_sw_ie *sw_elem,
 				      struct ieee80211_bss *bss)
 				      struct ieee80211_bss *bss)
 {
 {
+	struct cfg80211_bss *cbss =
+		container_of((void *)bss, struct cfg80211_bss, priv);
 	struct ieee80211_channel *new_ch;
 	struct ieee80211_channel *new_ch;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
 	int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
@@ -675,7 +392,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		mod_timer(&ifmgd->chswitch_timer,
 		mod_timer(&ifmgd->chswitch_timer,
 			  jiffies +
 			  jiffies +
 			  msecs_to_jiffies(sw_elem->count *
 			  msecs_to_jiffies(sw_elem->count *
-					   bss->cbss.beacon_interval));
+					   cbss->beacon_interval));
 	}
 	}
 }
 }
 
 
@@ -749,8 +466,13 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 		return;
 		return;
 	}
 	}
 
 
+	if (!list_empty(&local->work_list)) {
+		local->ps_sdata = NULL;
+		goto change;
+	}
+
 	list_for_each_entry(sdata, &local->interfaces, list) {
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 		if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		if (sdata->vif.type != NL80211_IFTYPE_STATION)
 			continue;
 			continue;
@@ -759,7 +481,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 	}
 	}
 
 
 	if (count == 1 && found->u.mgd.powersave &&
 	if (count == 1 && found->u.mgd.powersave &&
-	    found->u.mgd.associated && list_empty(&found->u.mgd.work_list) &&
+	    found->u.mgd.associated &&
 	    !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
 	    !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
 				    IEEE80211_STA_CONNECTION_POLL))) {
 				    IEEE80211_STA_CONNECTION_POLL))) {
 		s32 beaconint_us;
 		s32 beaconint_us;
@@ -787,6 +509,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 		local->ps_sdata = NULL;
 		local->ps_sdata = NULL;
 	}
 	}
 
 
+ change:
 	ieee80211_change_ps(local);
 	ieee80211_change_ps(local);
 }
 }
 
 
@@ -846,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 	int count;
 	int count;
 	u8 *pos;
 	u8 *pos;
 
 
-	if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED))
+	if (local->hw.queues < 4)
 		return;
 		return;
 
 
 	if (!wmm_param)
 	if (!wmm_param)
@@ -949,25 +672,24 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
 }
 }
 
 
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
-				     struct ieee80211_mgd_work *wk,
+				     struct cfg80211_bss *cbss,
 				     u32 bss_info_changed)
 				     u32 bss_info_changed)
 {
 {
+	struct ieee80211_bss *bss = (void *)cbss->priv;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_bss *bss = wk->bss;
 
 
 	bss_info_changed |= BSS_CHANGED_ASSOC;
 	bss_info_changed |= BSS_CHANGED_ASSOC;
 	/* set timing information */
 	/* set timing information */
-	sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
-	sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
+	sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
+	sdata->vif.bss_conf.timestamp = cbss->tsf;
 	sdata->vif.bss_conf.dtim_period = bss->dtim_period;
 	sdata->vif.bss_conf.dtim_period = bss->dtim_period;
 
 
 	bss_info_changed |= BSS_CHANGED_BEACON_INT;
 	bss_info_changed |= BSS_CHANGED_BEACON_INT;
 	bss_info_changed |= ieee80211_handle_bss_capability(sdata,
 	bss_info_changed |= ieee80211_handle_bss_capability(sdata,
-		bss->cbss.capability, bss->has_erp_value, bss->erp_value);
+		cbss->capability, bss->has_erp_value, bss->erp_value);
 
 
-	sdata->u.mgd.associated = bss;
-	sdata->u.mgd.old_associate_work = wk;
-	memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
+	sdata->u.mgd.associated = cbss;
+	memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
 
 
 	/* just to be sure */
 	/* just to be sure */
 	sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
 	sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
@@ -1005,93 +727,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 	netif_carrier_on(sdata->dev);
 	netif_carrier_on(sdata->dev);
 }
 }
 
 
-static enum rx_mgmt_action __must_check
-ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
-		       struct ieee80211_mgd_work *wk)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
-
-	wk->tries++;
-	if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
-		       sdata->name, wk->bss->cbss.bssid);
-
-		/*
-		 * Most likely AP is not in the range so remove the
-		 * bss struct for that AP.
-		 */
-		cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
-
-		/*
-		 * We might have a pending scan which had no chance to run yet
-		 * due to work needing to be done. Hence, queue the STAs work
-		 * again for that.
-		 */
-		ieee80211_queue_work(&local->hw, &ifmgd->work);
-		return RX_MGMT_CFG80211_AUTH_TO;
-	}
-
-	printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n",
-			sdata->name, wk->bss->cbss.bssid,
-			wk->tries);
-
-	/*
-	 * Direct probe is sent to broadcast address as some APs
-	 * will not answer to direct packet in unassociated state.
-	 */
-	ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0);
-
-	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-	run_again(ifmgd, wk->timeout);
-
-	return RX_MGMT_NONE;
-}
-
-
-static enum rx_mgmt_action __must_check
-ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
-		       struct ieee80211_mgd_work *wk)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
-
-	wk->tries++;
-	if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: authentication with AP %pM"
-		       " timed out\n",
-		       sdata->name, wk->bss->cbss.bssid);
-
-		/*
-		 * Most likely AP is not in the range so remove the
-		 * bss struct for that AP.
-		 */
-		cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
-
-		/*
-		 * We might have a pending scan which had no chance to run yet
-		 * due to work needing to be done. Hence, queue the STAs work
-		 * again for that.
-		 */
-		ieee80211_queue_work(&local->hw, &ifmgd->work);
-		return RX_MGMT_CFG80211_AUTH_TO;
-	}
-
-	printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n",
-	       sdata->name, wk->bss->cbss.bssid, wk->tries);
-
-	ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
-			    wk->bss->cbss.bssid, NULL, 0, 0);
-	wk->auth_transaction = 2;
-
-	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-	run_again(ifmgd, wk->timeout);
-
-	return RX_MGMT_NONE;
-}
-
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-				   bool deauth)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
 {
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
@@ -1104,21 +740,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	if (WARN_ON(!ifmgd->associated))
 	if (WARN_ON(!ifmgd->associated))
 		return;
 		return;
 
 
-	memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+	memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
 
 
 	ifmgd->associated = NULL;
 	ifmgd->associated = NULL;
 	memset(ifmgd->bssid, 0, ETH_ALEN);
 	memset(ifmgd->bssid, 0, ETH_ALEN);
 
 
-	if (deauth) {
-		kfree(ifmgd->old_associate_work);
-		ifmgd->old_associate_work = NULL;
-	} else {
-		struct ieee80211_mgd_work *wk = ifmgd->old_associate_work;
-
-		wk->state = IEEE80211_MGD_STATE_IDLE;
-		list_add(&wk->list, &ifmgd->work_list);
-	}
-
 	/*
 	/*
 	 * we need to commit the associated = NULL change because the
 	 * we need to commit the associated = NULL change because the
 	 * scan code uses that to determine whether this iface should
 	 * scan code uses that to determine whether this iface should
@@ -1187,44 +813,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	sta_info_destroy(sta);
 	sta_info_destroy(sta);
 }
 }
 
 
-static enum rx_mgmt_action __must_check
-ieee80211_associate(struct ieee80211_sub_if_data *sdata,
-		    struct ieee80211_mgd_work *wk)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
-
-	wk->tries++;
-	if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: association with AP %pM"
-		       " timed out\n",
-		       sdata->name, wk->bss->cbss.bssid);
-
-		/*
-		 * Most likely AP is not in the range so remove the
-		 * bss struct for that AP.
-		 */
-		cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
-
-		/*
-		 * We might have a pending scan which had no chance to run yet
-		 * due to work needing to be done. Hence, queue the STAs work
-		 * again for that.
-		 */
-		ieee80211_queue_work(&local->hw, &ifmgd->work);
-		return RX_MGMT_CFG80211_ASSOC_TO;
-	}
-
-	printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n",
-	       sdata->name, wk->bss->cbss.bssid, wk->tries);
-	ieee80211_send_assoc(sdata, wk);
-
-	wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
-	run_again(ifmgd, wk->timeout);
-
-	return RX_MGMT_NONE;
-}
-
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
 			     struct ieee80211_hdr *hdr)
 			     struct ieee80211_hdr *hdr)
 {
 {
@@ -1248,8 +836,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	const u8 *ssid;
 	const u8 *ssid;
 
 
-	ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID);
-	ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
+	ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
+	ieee80211_send_probe_req(sdata, ifmgd->associated->bssid,
 				 ssid + 2, ssid[1], NULL, 0);
 				 ssid + 2, ssid[1], NULL, 0);
 
 
 	ifmgd->probe_send_count++;
 	ifmgd->probe_send_count++;
@@ -1263,12 +851,15 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	bool already = false;
 	bool already = false;
 
 
-	if (!netif_running(sdata->dev))
+	if (!ieee80211_sdata_running(sdata))
 		return;
 		return;
 
 
 	if (sdata->local->scanning)
 	if (sdata->local->scanning)
 		return;
 		return;
 
 
+	if (sdata->local->tmp_channel)
+		return;
+
 	mutex_lock(&ifmgd->mtx);
 	mutex_lock(&ifmgd->mtx);
 
 
 	if (!ifmgd->associated)
 	if (!ifmgd->associated)
@@ -1330,88 +921,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
 }
 }
 EXPORT_SYMBOL(ieee80211_beacon_loss);
 EXPORT_SYMBOL(ieee80211_beacon_loss);
 
 
-static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
-				     struct ieee80211_mgd_work *wk)
-{
-	wk->state = IEEE80211_MGD_STATE_IDLE;
-	printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
-}
-
-
-static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
-				     struct ieee80211_mgd_work *wk,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len)
-{
-	u8 *pos;
-	struct ieee802_11_elems elems;
-
-	pos = mgmt->u.auth.variable;
-	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-	if (!elems.challenge)
-		return;
-	ieee80211_send_auth(sdata, 3, wk->auth_alg,
-			    elems.challenge - 2, elems.challenge_len + 2,
-			    wk->bss->cbss.bssid,
-			    wk->key, wk->key_len, wk->key_idx);
-	wk->auth_transaction = 4;
-}
-
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
-		       struct ieee80211_mgd_work *wk,
-		       struct ieee80211_mgmt *mgmt, size_t len)
-{
-	u16 auth_alg, auth_transaction, status_code;
-
-	if (wk->state != IEEE80211_MGD_STATE_AUTH)
-		return RX_MGMT_NONE;
-
-	if (len < 24 + 6)
-		return RX_MGMT_NONE;
-
-	if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
-		return RX_MGMT_NONE;
-
-	if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
-		return RX_MGMT_NONE;
-
-	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
-	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
-	status_code = le16_to_cpu(mgmt->u.auth.status_code);
-
-	if (auth_alg != wk->auth_alg ||
-	    auth_transaction != wk->auth_transaction)
-		return RX_MGMT_NONE;
-
-	if (status_code != WLAN_STATUS_SUCCESS) {
-		list_del(&wk->list);
-		kfree(wk);
-		return RX_MGMT_CFG80211_AUTH;
-	}
-
-	switch (wk->auth_alg) {
-	case WLAN_AUTH_OPEN:
-	case WLAN_AUTH_LEAP:
-	case WLAN_AUTH_FT:
-		ieee80211_auth_completed(sdata, wk);
-		return RX_MGMT_CFG80211_AUTH;
-	case WLAN_AUTH_SHARED_KEY:
-		if (wk->auth_transaction == 4) {
-			ieee80211_auth_completed(sdata, wk);
-			return RX_MGMT_CFG80211_AUTH;
-		} else
-			ieee80211_auth_challenge(sdata, wk, mgmt, len);
-		break;
-	}
-
-	return RX_MGMT_NONE;
-}
-
-
 static enum rx_mgmt_action __must_check
 static enum rx_mgmt_action __must_check
 ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
-			 struct ieee80211_mgd_work *wk,
 			 struct ieee80211_mgmt *mgmt, size_t len)
 			 struct ieee80211_mgmt *mgmt, size_t len)
 {
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1423,23 +934,15 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 
 
 	ASSERT_MGD_MTX(ifmgd);
 	ASSERT_MGD_MTX(ifmgd);
 
 
-	if (wk)
-		bssid = wk->bss->cbss.bssid;
-	else
-		bssid = ifmgd->associated->cbss.bssid;
+	bssid = ifmgd->associated->bssid;
 
 
 	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
 
 	printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
 	printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
 			sdata->name, bssid, reason_code);
 			sdata->name, bssid, reason_code);
 
 
-	if (!wk) {
-		ieee80211_set_disassoc(sdata, true);
-		ieee80211_recalc_idle(sdata->local);
-	} else {
-		list_del(&wk->list);
-		kfree(wk);
-	}
+	ieee80211_set_disassoc(sdata);
+	ieee80211_recalc_idle(sdata->local);
 
 
 	return RX_MGMT_CFG80211_DEAUTH;
 	return RX_MGMT_CFG80211_DEAUTH;
 }
 }
@@ -1460,7 +963,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 	if (WARN_ON(!ifmgd->associated))
 	if (WARN_ON(!ifmgd->associated))
 		return RX_MGMT_NONE;
 		return RX_MGMT_NONE;
 
 
-	if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN)))
+	if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN)))
 		return RX_MGMT_NONE;
 		return RX_MGMT_NONE;
 
 
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
@@ -1468,96 +971,57 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 	printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
 	printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
 			sdata->name, mgmt->sa, reason_code);
 			sdata->name, mgmt->sa, reason_code);
 
 
-	ieee80211_set_disassoc(sdata, false);
+	ieee80211_set_disassoc(sdata);
 	ieee80211_recalc_idle(sdata->local);
 	ieee80211_recalc_idle(sdata->local);
 	return RX_MGMT_CFG80211_DISASSOC;
 	return RX_MGMT_CFG80211_DISASSOC;
 }
 }
 
 
 
 
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
-			     struct ieee80211_mgd_work *wk,
-			     struct ieee80211_mgmt *mgmt, size_t len,
-			     bool reassoc)
+static bool ieee80211_assoc_success(struct ieee80211_work *wk,
+				    struct ieee80211_mgmt *mgmt, size_t len)
 {
 {
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_supported_band *sband;
 	struct sta_info *sta;
 	struct sta_info *sta;
+	struct cfg80211_bss *cbss = wk->assoc.bss;
+	u8 *pos;
 	u32 rates, basic_rates;
 	u32 rates, basic_rates;
-	u16 capab_info, status_code, aid;
+	u16 capab_info, aid;
 	struct ieee802_11_elems elems;
 	struct ieee802_11_elems elems;
 	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
 	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-	u8 *pos;
 	u32 changed = 0;
 	u32 changed = 0;
 	int i, j, err;
 	int i, j, err;
 	bool have_higher_than_11mbit = false;
 	bool have_higher_than_11mbit = false;
 	u16 ap_ht_cap_flags;
 	u16 ap_ht_cap_flags;
 
 
-	/*
-	 * AssocResp and ReassocResp have identical structure, so process both
-	 * of them in this function.
-	 */
-
-	if (len < 24 + 6)
-		return RX_MGMT_NONE;
+	/* AssocResp and ReassocResp have identical structure */
 
 
-	if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
-		return RX_MGMT_NONE;
-
-	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
-	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
 	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
 	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
-
-	printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
-	       "status=%d aid=%d)\n",
-	       sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
-	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
-
-	pos = mgmt->u.assoc_resp.variable;
-	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-
-	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
-	    elems.timeout_int && elems.timeout_int_len == 5 &&
-	    elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
-		u32 tu, ms;
-		tu = get_unaligned_le32(elems.timeout_int + 1);
-		ms = tu * 1024 / 1000;
-		printk(KERN_DEBUG "%s: AP rejected association temporarily; "
-		       "comeback duration %u TU (%u ms)\n",
-		       sdata->name, tu, ms);
-		wk->timeout = jiffies + msecs_to_jiffies(ms);
-		if (ms > IEEE80211_ASSOC_TIMEOUT)
-			run_again(ifmgd, jiffies + msecs_to_jiffies(ms));
-		return RX_MGMT_NONE;
-	}
-
-	if (status_code != WLAN_STATUS_SUCCESS) {
-		printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
-		       sdata->name, status_code);
-		wk->state = IEEE80211_MGD_STATE_IDLE;
-		return RX_MGMT_CFG80211_ASSOC;
-	}
+	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
 
 
 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
 		printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
 		printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
 		       "set\n", sdata->name, aid);
 		       "set\n", sdata->name, aid);
 	aid &= ~(BIT(15) | BIT(14));
 	aid &= ~(BIT(15) | BIT(14));
 
 
+	pos = mgmt->u.assoc_resp.variable;
+	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+
 	if (!elems.supp_rates) {
 	if (!elems.supp_rates) {
 		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
 		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
 		       sdata->name);
 		       sdata->name);
-		return RX_MGMT_NONE;
+		return false;
 	}
 	}
 
 
-	printk(KERN_DEBUG "%s: associated\n", sdata->name);
 	ifmgd->aid = aid;
 	ifmgd->aid = aid;
 
 
-	sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
+	sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
 	if (!sta) {
 	if (!sta) {
 		printk(KERN_DEBUG "%s: failed to alloc STA entry for"
 		printk(KERN_DEBUG "%s: failed to alloc STA entry for"
 		       " the AP\n", sdata->name);
 		       " the AP\n", sdata->name);
-		return RX_MGMT_CFG80211_ASSOC_ERROR;
+		return false;
 	}
 	}
 
 
 	set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
 	set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
@@ -1641,22 +1105,19 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 	else
 	else
 		ieee80211_set_wmm_default(sdata);
 		ieee80211_set_wmm_default(sdata);
 
 
+	local->oper_channel = wk->chan;
+
 	if (elems.ht_info_elem && elems.wmm_param &&
 	if (elems.ht_info_elem && elems.wmm_param &&
-	    (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
+	    (sdata->local->hw.queues >= 4) &&
 	    !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
 	    !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
 		changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
 		changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
-					       wk->bss->cbss.bssid,
-					       ap_ht_cap_flags);
-
-        /* delete work item -- must be before set_associated for PS */
-	list_del(&wk->list);
+					       cbss->bssid, ap_ht_cap_flags);
 
 
 	/* set AID and assoc capability,
 	/* set AID and assoc capability,
 	 * ieee80211_set_associated() will tell the driver */
 	 * ieee80211_set_associated() will tell the driver */
 	bss_conf->aid = aid;
 	bss_conf->aid = aid;
 	bss_conf->assoc_capability = capab_info;
 	bss_conf->assoc_capability = capab_info;
-	/* this will take ownership of wk */
-	ieee80211_set_associated(sdata, wk, changed);
+	ieee80211_set_associated(sdata, cbss, changed);
 
 
 	/*
 	/*
 	 * Start timer to probe the connection to the AP now.
 	 * Start timer to probe the connection to the AP now.
@@ -1665,7 +1126,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 	ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
 	ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
 	mod_beacon_timer(sdata);
 	mod_beacon_timer(sdata);
 
 
-	return RX_MGMT_CFG80211_ASSOC;
+	return true;
 }
 }
 
 
 
 
@@ -1700,7 +1161,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 		return;
 		return;
 
 
 	if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
 	if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
-	    (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid,
+	    (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
 							ETH_ALEN) == 0)) {
 							ETH_ALEN) == 0)) {
 		struct ieee80211_channel_sw_ie *sw_elem =
 		struct ieee80211_channel_sw_ie *sw_elem =
 			(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
 			(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
@@ -1710,12 +1171,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
 
 
 
 static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
-					 struct ieee80211_mgd_work *wk,
-					 struct ieee80211_mgmt *mgmt, size_t len,
-					 struct ieee80211_rx_status *rx_status)
+					 struct sk_buff *skb)
 {
 {
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
 	struct ieee80211_if_managed *ifmgd;
 	struct ieee80211_if_managed *ifmgd;
-	size_t baselen;
+	struct ieee80211_rx_status *rx_status = (void *) skb->cb;
+	size_t baselen, len = skb->len;
 	struct ieee802_11_elems elems;
 	struct ieee802_11_elems elems;
 
 
 	ifmgd = &sdata->u.mgd;
 	ifmgd = &sdata->u.mgd;
@@ -1734,17 +1195,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
 
 	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
 	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
 
 
-	/* direct probe may be part of the association flow */
-	if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
-		printk(KERN_DEBUG "%s: direct probe responded\n",
-		       sdata->name);
-		wk->tries = 0;
-		wk->state = IEEE80211_MGD_STATE_AUTH;
-		WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE);
-	}
-
 	if (ifmgd->associated &&
 	if (ifmgd->associated &&
-	    memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 &&
+	    memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 &&
 	    ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
 	    ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
 			    IEEE80211_STA_CONNECTION_POLL)) {
 			    IEEE80211_STA_CONNECTION_POLL)) {
 		ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
 		ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
@@ -1817,7 +1269,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 	if (!ifmgd->associated)
 	if (!ifmgd->associated)
 		return;
 		return;
 
 
-	bssid = ifmgd->associated->cbss.bssid;
+	bssid = ifmgd->associated->bssid;
 
 
 	/*
 	/*
 	 * And in theory even frames from a different AP we were just
 	 * And in theory even frames from a different AP we were just
@@ -1956,9 +1408,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
 	switch (fc & IEEE80211_FCTL_STYPE) {
 	switch (fc & IEEE80211_FCTL_STYPE) {
 	case IEEE80211_STYPE_PROBE_RESP:
 	case IEEE80211_STYPE_PROBE_RESP:
 	case IEEE80211_STYPE_BEACON:
 	case IEEE80211_STYPE_BEACON:
-	case IEEE80211_STYPE_AUTH:
-	case IEEE80211_STYPE_ASSOC_RESP:
-	case IEEE80211_STYPE_REASSOC_RESP:
 	case IEEE80211_STYPE_DEAUTH:
 	case IEEE80211_STYPE_DEAUTH:
 	case IEEE80211_STYPE_DISASSOC:
 	case IEEE80211_STYPE_DISASSOC:
 	case IEEE80211_STYPE_ACTION:
 	case IEEE80211_STYPE_ACTION:
@@ -1976,7 +1425,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_rx_status *rx_status;
 	struct ieee80211_rx_status *rx_status;
 	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_mgmt *mgmt;
-	struct ieee80211_mgd_work *wk;
 	enum rx_mgmt_action rma = RX_MGMT_NONE;
 	enum rx_mgmt_action rma = RX_MGMT_NONE;
 	u16 fc;
 	u16 fc;
 
 
@@ -1987,20 +1435,17 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 	mutex_lock(&ifmgd->mtx);
 	mutex_lock(&ifmgd->mtx);
 
 
 	if (ifmgd->associated &&
 	if (ifmgd->associated &&
-	    memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid,
-							ETH_ALEN) == 0) {
+	    memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) {
 		switch (fc & IEEE80211_FCTL_STYPE) {
 		switch (fc & IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_BEACON:
 		case IEEE80211_STYPE_BEACON:
 			ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
 			ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
 						 rx_status);
 						 rx_status);
 			break;
 			break;
 		case IEEE80211_STYPE_PROBE_RESP:
 		case IEEE80211_STYPE_PROBE_RESP:
-			ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt,
-						     skb->len, rx_status);
+			ieee80211_rx_mgmt_probe_resp(sdata, skb);
 			break;
 			break;
 		case IEEE80211_STYPE_DEAUTH:
 		case IEEE80211_STYPE_DEAUTH:
-			rma = ieee80211_rx_mgmt_deauth(sdata, NULL,
-						       mgmt, skb->len);
+			rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
 			break;
 			break;
 		case IEEE80211_STYPE_DISASSOC:
 		case IEEE80211_STYPE_DISASSOC:
 			rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
 			rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
@@ -2009,7 +1454,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 			/* XXX: differentiate, can only happen for CSA now! */
 			/* XXX: differentiate, can only happen for CSA now! */
 			ieee80211_sta_process_chanswitch(sdata,
 			ieee80211_sta_process_chanswitch(sdata,
 					&mgmt->u.action.u.chan_switch.sw_elem,
 					&mgmt->u.action.u.chan_switch.sw_elem,
-					ifmgd->associated);
+					(void *)ifmgd->associated->priv);
 			break;
 			break;
 		}
 		}
 		mutex_unlock(&ifmgd->mtx);
 		mutex_unlock(&ifmgd->mtx);
@@ -2030,62 +1475,11 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	list_for_each_entry(wk, &ifmgd->work_list, list) {
-		if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
-			continue;
-
-		switch (fc & IEEE80211_FCTL_STYPE) {
-		case IEEE80211_STYPE_PROBE_RESP:
-			ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len,
-						     rx_status);
-			break;
-		case IEEE80211_STYPE_AUTH:
-			rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len);
-			break;
-		case IEEE80211_STYPE_ASSOC_RESP:
-			rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
-							   skb->len, false);
-			break;
-		case IEEE80211_STYPE_REASSOC_RESP:
-			rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
-							   skb->len, true);
-			break;
-		case IEEE80211_STYPE_DEAUTH:
-			rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt,
-						       skb->len);
-			break;
-		}
-		/*
-		 * We've processed this frame for that work, so it can't
-		 * belong to another work struct.
-		 * NB: this is also required for correctness because the
-		 * called functions can free 'wk', and for 'rma'!
-		 */
-		break;
-	}
-
 	mutex_unlock(&ifmgd->mtx);
 	mutex_unlock(&ifmgd->mtx);
 
 
-	switch (rma) {
-	case RX_MGMT_NONE:
-		/* no action */
-		break;
-	case RX_MGMT_CFG80211_AUTH:
-		cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len);
-		break;
-	case RX_MGMT_CFG80211_ASSOC:
-		cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
-		break;
-	case RX_MGMT_CFG80211_DEAUTH:
+	if (skb->len >= 24 + 2 /* mgmt + deauth reason */ &&
+	    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH)
 		cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
 		cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
-		break;
-	case RX_MGMT_CFG80211_ASSOC_ERROR:
-		/* an internal error -- pretend timeout for now */
-		cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
-		break;
-	default:
-		WARN(1, "unexpected: %d", rma);
-	}
 
 
  out:
  out:
 	kfree_skb(skb);
 	kfree_skb(skb);
@@ -2113,12 +1507,8 @@ static void ieee80211_sta_work(struct work_struct *work)
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd;
 	struct ieee80211_if_managed *ifmgd;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
-	struct ieee80211_mgd_work *wk, *tmp;
-	LIST_HEAD(free_work);
-	enum rx_mgmt_action rma;
-	bool anybusy = false;
 
 
-	if (!netif_running(sdata->dev))
+	if (!ieee80211_sdata_running(sdata))
 		return;
 		return;
 
 
 	if (local->scanning)
 	if (local->scanning)
@@ -2149,7 +1539,7 @@ static void ieee80211_sta_work(struct work_struct *work)
 	    ifmgd->associated) {
 	    ifmgd->associated) {
 		u8 bssid[ETH_ALEN];
 		u8 bssid[ETH_ALEN];
 
 
-		memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+		memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
 		if (time_is_after_jiffies(ifmgd->probe_timeout))
 		if (time_is_after_jiffies(ifmgd->probe_timeout))
 			run_again(ifmgd, ifmgd->probe_timeout);
 			run_again(ifmgd, ifmgd->probe_timeout);
 
 
@@ -2171,7 +1561,7 @@ static void ieee80211_sta_work(struct work_struct *work)
 			printk(KERN_DEBUG "No probe response from AP %pM"
 			printk(KERN_DEBUG "No probe response from AP %pM"
 				" after %dms, disconnecting.\n",
 				" after %dms, disconnecting.\n",
 				bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
 				bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
-			ieee80211_set_disassoc(sdata, true);
+			ieee80211_set_disassoc(sdata);
 			ieee80211_recalc_idle(local);
 			ieee80211_recalc_idle(local);
 			mutex_unlock(&ifmgd->mtx);
 			mutex_unlock(&ifmgd->mtx);
 			/*
 			/*
@@ -2186,87 +1576,7 @@ static void ieee80211_sta_work(struct work_struct *work)
 		}
 		}
 	}
 	}
 
 
-
-	ieee80211_recalc_idle(local);
-
-	list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
-		if (time_is_after_jiffies(wk->timeout)) {
-			/*
-			 * This work item isn't supposed to be worked on
-			 * right now, but take care to adjust the timer
-			 * properly.
-			 */
-			run_again(ifmgd, wk->timeout);
-			continue;
-		}
-
-		switch (wk->state) {
-		default:
-			WARN_ON(1);
-			/* fall through */
-		case IEEE80211_MGD_STATE_IDLE:
-			/* nothing */
-			rma = RX_MGMT_NONE;
-			break;
-		case IEEE80211_MGD_STATE_PROBE:
-			rma = ieee80211_direct_probe(sdata, wk);
-			break;
-		case IEEE80211_MGD_STATE_AUTH:
-			rma = ieee80211_authenticate(sdata, wk);
-			break;
-		case IEEE80211_MGD_STATE_ASSOC:
-			rma = ieee80211_associate(sdata, wk);
-			break;
-		}
-
-		switch (rma) {
-		case RX_MGMT_NONE:
-			/* no action required */
-			break;
-		case RX_MGMT_CFG80211_AUTH_TO:
-		case RX_MGMT_CFG80211_ASSOC_TO:
-			list_del(&wk->list);
-			list_add(&wk->list, &free_work);
-			wk->tries = rma; /* small abuse but only local */
-			break;
-		default:
-			WARN(1, "unexpected: %d", rma);
-		}
-	}
-
-	list_for_each_entry(wk, &ifmgd->work_list, list) {
-		if (wk->state != IEEE80211_MGD_STATE_IDLE) {
-			anybusy = true;
-			break;
-		}
-	}
-	if (!anybusy &&
-	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
-		ieee80211_queue_delayed_work(&local->hw,
-					     &local->scan_work,
-					     round_jiffies_relative(0));
-
 	mutex_unlock(&ifmgd->mtx);
 	mutex_unlock(&ifmgd->mtx);
-
-	list_for_each_entry_safe(wk, tmp, &free_work, list) {
-		switch (wk->tries) {
-		case RX_MGMT_CFG80211_AUTH_TO:
-			cfg80211_send_auth_timeout(sdata->dev,
-						   wk->bss->cbss.bssid);
-			break;
-		case RX_MGMT_CFG80211_ASSOC_TO:
-			cfg80211_send_assoc_timeout(sdata->dev,
-						    wk->bss->cbss.bssid);
-			break;
-		default:
-			WARN(1, "unexpected: %d", wk->tries);
-		}
-
-		list_del(&wk->list);
-		kfree(wk);
-	}
-
-	ieee80211_recalc_idle(local);
 }
 }
 
 
 static void ieee80211_sta_bcn_mon_timer(unsigned long data)
 static void ieee80211_sta_bcn_mon_timer(unsigned long data)
@@ -2375,12 +1685,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 		    (unsigned long) sdata);
 		    (unsigned long) sdata);
 	skb_queue_head_init(&ifmgd->skb_queue);
 	skb_queue_head_init(&ifmgd->skb_queue);
 
 
-	INIT_LIST_HEAD(&ifmgd->work_list);
-
-	ifmgd->capab = WLAN_CAPABILITY_ESS;
 	ifmgd->flags = 0;
 	ifmgd->flags = 0;
-	if (sdata->local->hw.queues >= 4)
-		ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
 
 
 	mutex_init(&ifmgd->mtx);
 	mutex_init(&ifmgd->mtx);
 
 
@@ -2418,12 +1723,34 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
 }
 }
 
 
 /* config hooks */
 /* config hooks */
+static enum work_done_result
+ieee80211_probe_auth_done(struct ieee80211_work *wk,
+			  struct sk_buff *skb)
+{
+	if (!skb) {
+		cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta);
+		return WORK_DONE_DESTROY;
+	}
+
+	if (wk->type == IEEE80211_WORK_AUTH) {
+		cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len);
+		return WORK_DONE_DESTROY;
+	}
+
+	mutex_lock(&wk->sdata->u.mgd.mtx);
+	ieee80211_rx_mgmt_probe_resp(wk->sdata, skb);
+	mutex_unlock(&wk->sdata->u.mgd.mtx);
+
+	wk->type = IEEE80211_WORK_AUTH;
+	wk->probe_auth.tries = 0;
+	return WORK_DONE_REQUEUE;
+}
+
 int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 		       struct cfg80211_auth_request *req)
 		       struct cfg80211_auth_request *req)
 {
 {
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	const u8 *ssid;
 	const u8 *ssid;
-	struct ieee80211_mgd_work *wk;
+	struct ieee80211_work *wk;
 	u16 auth_alg;
 	u16 auth_alg;
 
 
 	switch (req->auth_type) {
 	switch (req->auth_type) {
@@ -2447,7 +1774,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 	if (!wk)
 	if (!wk)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	wk->bss = (void *)req->bss;
+	memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);;
 
 
 	if (req->ie && req->ie_len) {
 	if (req->ie && req->ie_len) {
 		memcpy(wk->ie, req->ie, req->ie_len);
 		memcpy(wk->ie, req->ie, req->ie_len);
@@ -2455,66 +1782,76 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 	}
 	}
 
 
 	if (req->key && req->key_len) {
 	if (req->key && req->key_len) {
-		wk->key_len = req->key_len;
-		wk->key_idx = req->key_idx;
-		memcpy(wk->key, req->key, req->key_len);
+		wk->probe_auth.key_len = req->key_len;
+		wk->probe_auth.key_idx = req->key_idx;
+		memcpy(wk->probe_auth.key, req->key, req->key_len);
 	}
 	}
 
 
 	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
 	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
-	memcpy(wk->ssid, ssid + 2, ssid[1]);
-	wk->ssid_len = ssid[1];
+	memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]);
+	wk->probe_auth.ssid_len = ssid[1];
 
 
-	wk->state = IEEE80211_MGD_STATE_PROBE;
-	wk->auth_alg = auth_alg;
-	wk->timeout = jiffies; /* run right away */
+	wk->probe_auth.algorithm = auth_alg;
+	wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY;
 
 
-	/*
-	 * XXX: if still associated need to tell AP that we're going
-	 *	to sleep and then change channel etc.
-	 */
-	sdata->local->oper_channel = req->bss->channel;
-	ieee80211_hw_config(sdata->local, 0);
+	wk->type = IEEE80211_WORK_DIRECT_PROBE;
+	wk->chan = req->bss->channel;
+	wk->sdata = sdata;
+	wk->done = ieee80211_probe_auth_done;
 
 
-	mutex_lock(&ifmgd->mtx);
-	list_add(&wk->list, &sdata->u.mgd.work_list);
-	mutex_unlock(&ifmgd->mtx);
-
-	ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
+	ieee80211_add_work(wk);
 	return 0;
 	return 0;
 }
 }
 
 
-int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
-			struct cfg80211_assoc_request *req)
+static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
+						  struct sk_buff *skb)
 {
 {
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_mgd_work *wk, *found = NULL;
-	int i, err;
+	struct ieee80211_mgmt *mgmt;
+	u16 status;
 
 
-	mutex_lock(&ifmgd->mtx);
+	if (!skb) {
+		cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta);
+		return WORK_DONE_DESTROY;
+	}
 
 
-	list_for_each_entry(wk, &ifmgd->work_list, list) {
-		if (&wk->bss->cbss == req->bss &&
-		    wk->state == IEEE80211_MGD_STATE_IDLE) {
-			found = wk;
-			break;
+	mgmt = (void *)skb->data;
+	status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+
+	if (status == WLAN_STATUS_SUCCESS) {
+		mutex_lock(&wk->sdata->u.mgd.mtx);
+		if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {
+			mutex_unlock(&wk->sdata->u.mgd.mtx);
+			/* oops -- internal error -- send timeout for now */
+			cfg80211_send_assoc_timeout(wk->sdata->dev,
+						    wk->filter_ta);
+			return WORK_DONE_DESTROY;
 		}
 		}
+		mutex_unlock(&wk->sdata->u.mgd.mtx);
 	}
 	}
 
 
-	if (!found) {
-		err = -ENOLINK;
-		goto out;
-	}
+	cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
+	return WORK_DONE_DESTROY;
+}
 
 
-	list_del(&found->list);
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+			struct cfg80211_assoc_request *req)
+{
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	struct ieee80211_bss *bss = (void *)req->bss->priv;
+	struct ieee80211_work *wk;
+	const u8 *ssid;
+	int i;
 
 
-	wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL);
-	if (!wk) {
-		list_add(&found->list, &ifmgd->work_list);
-		err = -ENOMEM;
-		goto out;
+	mutex_lock(&ifmgd->mtx);
+	if (ifmgd->associated) {
+		mutex_unlock(&ifmgd->mtx);
+		return -EALREADY;
 	}
 	}
+	mutex_unlock(&ifmgd->mtx);
 
 
-	list_add(&wk->list, &ifmgd->work_list);
+	wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL);
+	if (!wk)
+		return -ENOMEM;
 
 
 	ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
 	ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
 
 
@@ -2524,8 +1861,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
 		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
 			ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 			ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 
 
-	sdata->local->oper_channel = req->bss->channel;
-	ieee80211_hw_config(sdata->local, 0);
 
 
 	if (req->ie && req->ie_len) {
 	if (req->ie && req->ie_len) {
 		memcpy(wk->ie, req->ie, req->ie_len);
 		memcpy(wk->ie, req->ie, req->ie_len);
@@ -2533,12 +1868,46 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	} else
 	} else
 		wk->ie_len = 0;
 		wk->ie_len = 0;
 
 
+	wk->assoc.bss = req->bss;
+
+	memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);
+
+	/* new association always uses requested smps mode */
+	if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
+		if (ifmgd->powersave)
+			ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
+		else
+			ifmgd->ap_smps = IEEE80211_SMPS_OFF;
+	} else
+		ifmgd->ap_smps = ifmgd->req_smps;
+
+	wk->assoc.smps = ifmgd->ap_smps;
+	/*
+	 * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
+	 * We still associate in non-HT mode (11a/b/g) if any one of these
+	 * ciphers is configured as pairwise.
+	 * We can set this to true for non-11n hardware, that'll be checked
+	 * separately along with the peer capabilities.
+	 */
+	wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N);
+	wk->assoc.capability = req->bss->capability;
+	wk->assoc.wmm_used = bss->wmm_used;
+	wk->assoc.supp_rates = bss->supp_rates;
+	wk->assoc.supp_rates_len = bss->supp_rates_len;
+	wk->assoc.ht_information_ie =
+		ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION);
+
+	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
+	memcpy(wk->assoc.ssid, ssid + 2, ssid[1]);
+	wk->assoc.ssid_len = ssid[1];
+
 	if (req->prev_bssid)
 	if (req->prev_bssid)
-		memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN);
+		memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN);
 
 
-	wk->state = IEEE80211_MGD_STATE_ASSOC;
-	wk->tries = 0;
-	wk->timeout = jiffies; /* run right away */
+	wk->type = IEEE80211_WORK_ASSOC;
+	wk->chan = req->bss->channel;
+	wk->sdata = sdata;
+	wk->done = ieee80211_assoc_done;
 
 
 	if (req->use_mfp) {
 	if (req->use_mfp) {
 		ifmgd->mfp = IEEE80211_MFP_REQUIRED;
 		ifmgd->mfp = IEEE80211_MFP_REQUIRED;
@@ -2553,67 +1922,57 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	else
 	else
 		ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
 		ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
 
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
-
-	err = 0;
-
- out:
-	mutex_unlock(&ifmgd->mtx);
-	return err;
+	ieee80211_add_work(wk);
+	return 0;
 }
 }
 
 
 int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 			 struct cfg80211_deauth_request *req,
 			 struct cfg80211_deauth_request *req,
 			 void *cookie)
 			 void *cookie)
 {
 {
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_mgd_work *wk;
-	const u8 *bssid = NULL;
-	bool not_auth_yet = false;
+	struct ieee80211_work *wk;
+	const u8 *bssid = req->bss->bssid;
 
 
 	mutex_lock(&ifmgd->mtx);
 	mutex_lock(&ifmgd->mtx);
 
 
-	if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
+	if (ifmgd->associated == req->bss) {
 		bssid = req->bss->bssid;
 		bssid = req->bss->bssid;
-		ieee80211_set_disassoc(sdata, true);
-	} else list_for_each_entry(wk, &ifmgd->work_list, list) {
-		if (&wk->bss->cbss == req->bss) {
-			bssid = req->bss->bssid;
-			if (wk->state == IEEE80211_MGD_STATE_PROBE)
-				not_auth_yet = true;
+		ieee80211_set_disassoc(sdata);
+		mutex_unlock(&ifmgd->mtx);
+	} else {
+		bool not_auth_yet = false;
+
+		mutex_unlock(&ifmgd->mtx);
+
+		mutex_lock(&local->work_mtx);
+		list_for_each_entry(wk, &local->work_list, list) {
+			if (wk->type != IEEE80211_WORK_DIRECT_PROBE)
+				continue;
+			if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN))
+				continue;
+			not_auth_yet = true;
 			list_del(&wk->list);
 			list_del(&wk->list);
-			kfree(wk);
+			free_work(wk);
 			break;
 			break;
 		}
 		}
-	}
+		mutex_unlock(&local->work_mtx);
 
 
-	/*
-	 * If somebody requests authentication and we haven't
-	 * sent out an auth frame yet there's no need to send
-	 * out a deauth frame either. If the state was PROBE,
-	 * then this is the case. If it's AUTH we have sent a
-	 * frame, and if it's IDLE we have completed the auth
-	 * process already.
-	 */
-	if (not_auth_yet) {
-		mutex_unlock(&ifmgd->mtx);
-		__cfg80211_auth_canceled(sdata->dev, bssid);
-		return 0;
-	}
-
-	/*
-	 * cfg80211 should catch this ... but it's racy since
-	 * we can receive a deauth frame, process it, hand it
-	 * to cfg80211 while that's in a locked section already
-	 * trying to tell us that the user wants to disconnect.
-	 */
-	if (!bssid) {
-		mutex_unlock(&ifmgd->mtx);
-		return -ENOLINK;
+		/*
+		 * If somebody requests authentication and we haven't
+		 * sent out an auth frame yet there's no need to send
+		 * out a deauth frame either. If the state was PROBE,
+		 * then this is the case. If it's AUTH we have sent a
+		 * frame, and if it's IDLE we have completed the auth
+		 * process already.
+		 */
+		if (not_auth_yet) {
+			__cfg80211_auth_canceled(sdata->dev, bssid);
+			return 0;
+		}
 	}
 	}
 
 
-	mutex_unlock(&ifmgd->mtx);
-
 	printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
 	printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
 	       sdata->name, bssid, req->reason_code);
 	       sdata->name, bssid, req->reason_code);
 
 
@@ -2640,7 +1999,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
 	 * to cfg80211 while that's in a locked section already
 	 * to cfg80211 while that's in a locked section already
 	 * trying to tell us that the user wants to disconnect.
 	 * trying to tell us that the user wants to disconnect.
 	 */
 	 */
-	if (&ifmgd->associated->cbss != req->bss) {
+	if (ifmgd->associated != req->bss) {
 		mutex_unlock(&ifmgd->mtx);
 		mutex_unlock(&ifmgd->mtx);
 		return -ENOLINK;
 		return -ENOLINK;
 	}
 	}
@@ -2648,7 +2007,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
 	printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
 	printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
 	       sdata->name, req->bss->bssid, req->reason_code);
 	       sdata->name, req->bss->bssid, req->reason_code);
 
 
-	ieee80211_set_disassoc(sdata, false);
+	ieee80211_set_disassoc(sdata);
 
 
 	mutex_unlock(&ifmgd->mtx);
 	mutex_unlock(&ifmgd->mtx);
 
 

+ 168 - 0
net/mac80211/offchannel.c

@@ -0,0 +1,168 @@
+/*
+ * Off-channel operation helpers
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+/*
+ * inform AP that we will go to sleep so that it will buffer the frames
+ * while we scan
+ */
+static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+
+	local->offchannel_ps_enabled = false;
+
+	/* FIXME: what to do when local->pspolling is true? */
+
+	del_timer_sync(&local->dynamic_ps_timer);
+	cancel_work_sync(&local->dynamic_ps_enable_work);
+
+	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+		local->offchannel_ps_enabled = true;
+		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+	}
+
+	if (!(local->offchannel_ps_enabled) ||
+	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
+		/*
+		 * If power save was enabled, no need to send a nullfunc
+		 * frame because AP knows that we are sleeping. But if the
+		 * hardware is creating the nullfunc frame for power save
+		 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
+		 * enabled) and power save was enabled, the firmware just
+		 * sent a null frame with power save disabled. So we need
+		 * to send a new nullfunc frame to inform the AP that we
+		 * are again sleeping.
+		 */
+		ieee80211_send_nullfunc(local, sdata, 1);
+}
+
+/* inform AP that we are awake again, unless power save is enabled */
+static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+
+	if (!local->ps_sdata)
+		ieee80211_send_nullfunc(local, sdata, 0);
+	else if (local->offchannel_ps_enabled) {
+		/*
+		 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
+		 * will send a nullfunc frame with the powersave bit set
+		 * even though the AP already knows that we are sleeping.
+		 * This could be avoided by sending a null frame with power
+		 * save bit disabled before enabling the power save, but
+		 * this doesn't gain anything.
+		 *
+		 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
+		 * to send a nullfunc frame because AP already knows that
+		 * we are sleeping, let's just enable power save mode in
+		 * hardware.
+		 */
+		local->hw.conf.flags |= IEEE80211_CONF_PS;
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+	} else if (local->hw.conf.dynamic_ps_timeout > 0) {
+		/*
+		 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
+		 * had been running before leaving the operating channel,
+		 * restart the timer now and send a nullfunc frame to inform
+		 * the AP that we are awake.
+		 */
+		ieee80211_send_nullfunc(local, sdata, 0);
+		mod_timer(&local->dynamic_ps_timer, jiffies +
+			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+	}
+}
+
+void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (!ieee80211_sdata_running(sdata))
+			continue;
+
+		/* disable beaconing */
+		if (sdata->vif.type == NL80211_IFTYPE_AP ||
+		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+			ieee80211_bss_info_change_notify(
+				sdata, BSS_CHANGED_BEACON_ENABLED);
+
+		/*
+		 * only handle non-STA interfaces here, STA interfaces
+		 * are handled in ieee80211_offchannel_stop_station(),
+		 * e.g., from the background scan state machine.
+		 *
+		 * In addition, do not stop monitor interface to allow it to be
+		 * used from user space controlled off-channel operations.
+		 */
+		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+		    sdata->vif.type != NL80211_IFTYPE_MONITOR)
+			netif_stop_queue(sdata->dev);
+	}
+	mutex_unlock(&local->iflist_mtx);
+}
+
+void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	/*
+	 * notify the AP about us leaving the channel and stop all STA interfaces
+	 */
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (!ieee80211_sdata_running(sdata))
+			continue;
+
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+			netif_stop_queue(sdata->dev);
+			if (sdata->u.mgd.associated)
+				ieee80211_offchannel_ps_enable(sdata);
+		}
+	}
+	mutex_unlock(&local->iflist_mtx);
+}
+
+void ieee80211_offchannel_return(struct ieee80211_local *local,
+				 bool enable_beaconing)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (!ieee80211_sdata_running(sdata))
+			continue;
+
+		/* Tell AP we're back */
+		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+			if (sdata->u.mgd.associated)
+				ieee80211_offchannel_ps_disable(sdata);
+			netif_wake_queue(sdata->dev);
+		}
+
+		/* re-enable beaconing */
+		if (enable_beaconing &&
+		    (sdata->vif.type == NL80211_IFTYPE_AP ||
+		     sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+		     sdata->vif.type == NL80211_IFTYPE_MESH_POINT))
+			ieee80211_bss_info_change_notify(
+				sdata, BSS_CHANGED_BEACON_ENABLED);
+	}
+	mutex_unlock(&local->iflist_mtx);
+}

+ 2 - 6
net/mac80211/pm.c

@@ -10,7 +10,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 {
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_if_init_conf conf;
 	struct sta_info *sta;
 	struct sta_info *sta;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -93,17 +92,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 			break;
 			break;
 		}
 		}
 
 
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 
 
 		/* disable beaconing */
 		/* disable beaconing */
 		ieee80211_bss_info_change_notify(sdata,
 		ieee80211_bss_info_change_notify(sdata,
 			BSS_CHANGED_BEACON_ENABLED);
 			BSS_CHANGED_BEACON_ENABLED);
 
 
-		conf.vif = &sdata->vif;
-		conf.type = sdata->vif.type;
-		conf.mac_addr = sdata->vif.addr;
-		drv_remove_interface(local, &conf);
+		drv_remove_interface(local, &sdata->vif);
 	}
 	}
 
 
 	/* stop hardware - this must stop RX */
 	/* stop hardware - this must stop RX */

+ 8 - 3
net/mac80211/rx.c

@@ -289,7 +289,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
 		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
 			continue;
 			continue;
 
 
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 
 
 		if (prev_dev) {
 		if (prev_dev) {
@@ -1945,6 +1945,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
 {
 	struct ieee80211_sub_if_data *sdata = rx->sdata;
 	struct ieee80211_sub_if_data *sdata = rx->sdata;
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+	ieee80211_rx_result rxs;
 
 
 	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
 	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
 		return RX_DROP_MONITOR;
 		return RX_DROP_MONITOR;
@@ -1952,6 +1953,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 	if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
 	if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
 		return RX_DROP_MONITOR;
 		return RX_DROP_MONITOR;
 
 
+	rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
+	if (rxs != RX_CONTINUE)
+		return rxs;
+
 	if (ieee80211_vif_is_mesh(&sdata->vif))
 	if (ieee80211_vif_is_mesh(&sdata->vif))
 		return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
 		return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
 
 
@@ -2056,7 +2061,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
 	skb->protocol = htons(ETH_P_802_2);
 	skb->protocol = htons(ETH_P_802_2);
 
 
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 
 
 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
@@ -2318,7 +2323,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 	}
 	}
 	if (!found_sta) {
 	if (!found_sta) {
 		list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-			if (!netif_running(sdata->dev))
+			if (!ieee80211_sdata_running(sdata))
 				continue;
 				continue;
 
 
 			if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
 			if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||

+ 38 - 170
net/mac80211/scan.c

@@ -29,16 +29,19 @@ struct ieee80211_bss *
 ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
 ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
 		     u8 *ssid, u8 ssid_len)
 		     u8 *ssid, u8 ssid_len)
 {
 {
-	return (void *)cfg80211_get_bss(local->hw.wiphy,
-					ieee80211_get_channel(local->hw.wiphy,
-							      freq),
-					bssid, ssid, ssid_len,
-					0, 0);
+	struct cfg80211_bss *cbss;
+
+	cbss = cfg80211_get_bss(local->hw.wiphy,
+				ieee80211_get_channel(local->hw.wiphy, freq),
+				bssid, ssid, ssid_len, 0, 0);
+	if (!cbss)
+		return NULL;
+	return (void *)cbss->priv;
 }
 }
 
 
 static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
 static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
 {
 {
-	struct ieee80211_bss *bss = (void *)cbss;
+	struct ieee80211_bss *bss = (void *)cbss->priv;
 
 
 	kfree(bss_mesh_id(bss));
 	kfree(bss_mesh_id(bss));
 	kfree(bss_mesh_cfg(bss));
 	kfree(bss_mesh_cfg(bss));
@@ -47,7 +50,9 @@ static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
 			  struct ieee80211_bss *bss)
 			  struct ieee80211_bss *bss)
 {
 {
-	cfg80211_put_bss((struct cfg80211_bss *)bss);
+	if (!bss)
+		return;
+	cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv));
 }
 }
 
 
 struct ieee80211_bss *
 struct ieee80211_bss *
@@ -59,6 +64,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 			  struct ieee80211_channel *channel,
 			  struct ieee80211_channel *channel,
 			  bool beacon)
 			  bool beacon)
 {
 {
+	struct cfg80211_bss *cbss;
 	struct ieee80211_bss *bss;
 	struct ieee80211_bss *bss;
 	int clen;
 	int clen;
 	s32 signal = 0;
 	s32 signal = 0;
@@ -68,13 +74,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
 	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
 		signal = (rx_status->signal * 100) / local->hw.max_signal;
 		signal = (rx_status->signal * 100) / local->hw.max_signal;
 
 
-	bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
-						mgmt, len, signal, GFP_ATOMIC);
+	cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
+					 mgmt, len, signal, GFP_ATOMIC);
 
 
-	if (!bss)
+	if (!cbss)
 		return NULL;
 		return NULL;
 
 
-	bss->cbss.free_priv = ieee80211_rx_bss_free;
+	cbss->free_priv = ieee80211_rx_bss_free;
+	bss = (void *)cbss->priv;
 
 
 	/* save the ERP value so that it is available at association time */
 	/* save the ERP value so that it is available at association time */
 	if (elems->erp_info && elems->erp_info_len >= 1) {
 	if (elems->erp_info && elems->erp_info_len >= 1) {
@@ -220,82 +227,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
 	return true;
 	return true;
 }
 }
 
 
-/*
- * inform AP that we will go to sleep so that it will buffer the frames
- * while we scan
- */
-static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_local *local = sdata->local;
-
-	local->scan_ps_enabled = false;
-
-	/* FIXME: what to do when local->pspolling is true? */
-
-	del_timer_sync(&local->dynamic_ps_timer);
-	cancel_work_sync(&local->dynamic_ps_enable_work);
-
-	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-		local->scan_ps_enabled = true;
-		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
-		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-	}
-
-	if (!(local->scan_ps_enabled) ||
-	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
-		/*
-		 * If power save was enabled, no need to send a nullfunc
-		 * frame because AP knows that we are sleeping. But if the
-		 * hardware is creating the nullfunc frame for power save
-		 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
-		 * enabled) and power save was enabled, the firmware just
-		 * sent a null frame with power save disabled. So we need
-		 * to send a new nullfunc frame to inform the AP that we
-		 * are again sleeping.
-		 */
-		ieee80211_send_nullfunc(local, sdata, 1);
-}
-
-/* inform AP that we are awake again, unless power save is enabled */
-static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_local *local = sdata->local;
-
-	if (!local->ps_sdata)
-		ieee80211_send_nullfunc(local, sdata, 0);
-	else if (local->scan_ps_enabled) {
-		/*
-		 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
-		 * will send a nullfunc frame with the powersave bit set
-		 * even though the AP already knows that we are sleeping.
-		 * This could be avoided by sending a null frame with power
-		 * save bit disabled before enabling the power save, but
-		 * this doesn't gain anything.
-		 *
-		 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
-		 * to send a nullfunc frame because AP already knows that
-		 * we are sleeping, let's just enable power save mode in
-		 * hardware.
-		 */
-		local->hw.conf.flags |= IEEE80211_CONF_PS;
-		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-	} else if (local->hw.conf.dynamic_ps_timeout > 0) {
-		/*
-		 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
-		 * had been running before leaving the operating channel,
-		 * restart the timer now and send a nullfunc frame to inform
-		 * the AP that we are awake.
-		 */
-		ieee80211_send_nullfunc(local, sdata, 0);
-		mod_timer(&local->dynamic_ps_timer, jiffies +
-			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
-	}
-}
-
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_sub_if_data *sdata;
 	bool was_hw_scan;
 	bool was_hw_scan;
 
 
 	mutex_lock(&local->scan_mtx);
 	mutex_lock(&local->scan_mtx);
@@ -344,28 +278,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
 
 	drv_sw_scan_complete(local);
 	drv_sw_scan_complete(local);
 
 
-	mutex_lock(&local->iflist_mtx);
-	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
-			continue;
-
-		/* Tell AP we're back */
-		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-			if (sdata->u.mgd.associated) {
-				ieee80211_scan_ps_disable(sdata);
-				netif_wake_queue(sdata->dev);
-			}
-		} else
-			netif_wake_queue(sdata->dev);
-
-		/* re-enable beaconing */
-		if (sdata->vif.type == NL80211_IFTYPE_AP ||
-		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
-			ieee80211_bss_info_change_notify(
-				sdata, BSS_CHANGED_BEACON_ENABLED);
-	}
-	mutex_unlock(&local->iflist_mtx);
+	ieee80211_offchannel_return(local, true);
 
 
  done:
  done:
 	ieee80211_recalc_idle(local);
 	ieee80211_recalc_idle(local);
@@ -377,8 +290,6 @@ EXPORT_SYMBOL(ieee80211_scan_completed);
 
 
 static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 {
 {
-	struct ieee80211_sub_if_data *sdata;
-
 	/*
 	/*
 	 * Hardware/driver doesn't support hw_scan, so use software
 	 * Hardware/driver doesn't support hw_scan, so use software
 	 * scanning instead. First send a nullfunc frame with power save
 	 * scanning instead. First send a nullfunc frame with power save
@@ -394,33 +305,15 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 	 */
 	 */
 	drv_sw_scan_start(local);
 	drv_sw_scan_start(local);
 
 
-	mutex_lock(&local->iflist_mtx);
-	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
-			continue;
-
-		/* disable beaconing */
-		if (sdata->vif.type == NL80211_IFTYPE_AP ||
-		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
-			ieee80211_bss_info_change_notify(
-				sdata, BSS_CHANGED_BEACON_ENABLED);
-
-		/*
-		 * only handle non-STA interfaces here, STA interfaces
-		 * are handled in the scan state machine
-		 */
-		if (sdata->vif.type != NL80211_IFTYPE_STATION)
-			netif_stop_queue(sdata->dev);
-	}
-	mutex_unlock(&local->iflist_mtx);
+	ieee80211_offchannel_stop_beaconing(local);
 
 
 	local->next_scan_state = SCAN_DECISION;
 	local->next_scan_state = SCAN_DECISION;
 	local->scan_channel_idx = 0;
 	local->scan_channel_idx = 0;
 
 
+	drv_flush(local, false);
+
 	ieee80211_configure_filter(local);
 	ieee80211_configure_filter(local);
 
 
-	/* TODO: start scan as soon as all nullfunc frames are ACKed */
 	ieee80211_queue_delayed_work(&local->hw,
 	ieee80211_queue_delayed_work(&local->hw,
 				     &local->scan_work,
 				     &local->scan_work,
 				     IEEE80211_CHANNEL_TIME);
 				     IEEE80211_CHANNEL_TIME);
@@ -433,7 +326,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 				  struct cfg80211_scan_request *req)
 				  struct cfg80211_scan_request *req)
 {
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	int rc;
 	int rc;
 
 
 	if (local->scan_req)
 	if (local->scan_req)
@@ -463,11 +355,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 	local->scan_req = req;
 	local->scan_req = req;
 	local->scan_sdata = sdata;
 	local->scan_sdata = sdata;
 
 
-	if (req != local->int_scan_req &&
-	    sdata->vif.type == NL80211_IFTYPE_STATION &&
-	    !list_empty(&ifmgd->work_list)) {
-		/* actually wait for the work it's doing to finish/time out */
-		set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
+	if (!list_empty(&local->work_list)) {
+		/* wait for the work to finish/time out */
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -526,7 +415,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
 	/* check if at least one STA interface is associated */
 	/* check if at least one STA interface is associated */
 	mutex_lock(&local->iflist_mtx);
 	mutex_lock(&local->iflist_mtx);
 	list_for_each_entry(sdata, &local->interfaces, list) {
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 
 
 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
@@ -564,56 +453,35 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
 static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
 static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
 						    unsigned long *next_delay)
 						    unsigned long *next_delay)
 {
 {
-	struct ieee80211_sub_if_data *sdata;
+	ieee80211_offchannel_stop_station(local);
+
+	__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
 
 
 	/*
 	/*
-	 * notify the AP about us leaving the channel and stop all STA interfaces
+	 * What if the nullfunc frames didn't arrive?
 	 */
 	 */
-	mutex_lock(&local->iflist_mtx);
-	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
-			continue;
-
-		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-			netif_stop_queue(sdata->dev);
-			if (sdata->u.mgd.associated)
-				ieee80211_scan_ps_enable(sdata);
-		}
-	}
-	mutex_unlock(&local->iflist_mtx);
-
-	__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
+	drv_flush(local, false);
+	if (local->ops->flush)
+		*next_delay = 0;
+	else
+		*next_delay = HZ / 10;
 
 
 	/* advance to the next channel to be scanned */
 	/* advance to the next channel to be scanned */
-	*next_delay = HZ / 10;
 	local->next_scan_state = SCAN_SET_CHANNEL;
 	local->next_scan_state = SCAN_SET_CHANNEL;
 }
 }
 
 
 static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
 static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
 						    unsigned long *next_delay)
 						    unsigned long *next_delay)
 {
 {
-	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-
 	/* switch back to the operating channel */
 	/* switch back to the operating channel */
 	local->scan_channel = NULL;
 	local->scan_channel = NULL;
 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
 
 	/*
 	/*
-	 * notify the AP about us being back and restart all STA interfaces
+	 * Only re-enable station mode interface now; beaconing will be
+	 * re-enabled once the full scan has been completed.
 	 */
 	 */
-	mutex_lock(&local->iflist_mtx);
-	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
-			continue;
-
-		/* Tell AP we're back */
-		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-			if (sdata->u.mgd.associated)
-				ieee80211_scan_ps_disable(sdata);
-			netif_wake_queue(sdata->dev);
-		}
-	}
-	mutex_unlock(&local->iflist_mtx);
+	ieee80211_offchannel_return(local, false);
 
 
 	__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
 	__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
 
 
@@ -727,7 +595,7 @@ void ieee80211_scan_work(struct work_struct *work)
 	/*
 	/*
 	 * Avoid re-scheduling when the sdata is going away.
 	 * Avoid re-scheduling when the sdata is going away.
 	 */
 	 */
-	if (!netif_running(sdata->dev)) {
+	if (!ieee80211_sdata_running(sdata)) {
 		ieee80211_scan_completed(&local->hw, true);
 		ieee80211_scan_completed(&local->hw, true);
 		return;
 		return;
 	}
 	}

+ 6 - 1
net/mac80211/sta_info.c

@@ -359,6 +359,7 @@ int sta_info_insert(struct sta_info *sta)
 {
 {
 	struct ieee80211_local *local = sta->local;
 	struct ieee80211_local *local = sta->local;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct station_info sinfo;
 	unsigned long flags;
 	unsigned long flags;
 	int err = 0;
 	int err = 0;
 
 
@@ -367,7 +368,7 @@ int sta_info_insert(struct sta_info *sta)
 	 * something inserts a STA (on one CPU) without holding the RTNL
 	 * something inserts a STA (on one CPU) without holding the RTNL
 	 * and another CPU turns off the net device.
 	 * and another CPU turns off the net device.
 	 */
 	 */
-	if (unlikely(!netif_running(sdata->dev))) {
+	if (unlikely(!ieee80211_sdata_running(sdata))) {
 		err = -ENETDOWN;
 		err = -ENETDOWN;
 		goto out_free;
 		goto out_free;
 	}
 	}
@@ -408,6 +409,10 @@ int sta_info_insert(struct sta_info *sta)
 
 
 	spin_unlock_irqrestore(&local->sta_lock, flags);
 	spin_unlock_irqrestore(&local->sta_lock, flags);
 
 
+	sinfo.filled = 0;
+	sinfo.generation = local->sta_generation;
+	cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC);
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 #ifdef CONFIG_MAC80211_DEBUGFS
 	/*
 	/*
 	 * Debugfs entry adding might sleep, so schedule process
 	 * Debugfs entry adding might sleep, so schedule process

+ 1 - 1
net/mac80211/status.c

@@ -351,7 +351,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 	rcu_read_lock();
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
-			if (!netif_running(sdata->dev))
+			if (!ieee80211_sdata_running(sdata))
 				continue;
 				continue;
 
 
 			if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
 			if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&

+ 5 - 1
net/mac80211/tx.c

@@ -1418,6 +1418,10 @@ static bool need_dynamic_ps(struct ieee80211_local *local)
 	if (!local->ps_sdata)
 	if (!local->ps_sdata)
 		return false;
 		return false;
 
 
+	/* No point if we're going to suspend */
+	if (local->quiescing)
+		return false;
+
 	return true;
 	return true;
 }
 }
 
 
@@ -1469,7 +1473,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
 
 			list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
 			list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
 						list) {
 						list) {
-				if (!netif_running(tmp_sdata->dev))
+				if (!ieee80211_sdata_running(tmp_sdata))
 					continue;
 					continue;
 				if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
 				if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
 					continue;
 					continue;

+ 132 - 31
net/mac80211/util.c

@@ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces(
 		case NL80211_IFTYPE_MESH_POINT:
 		case NL80211_IFTYPE_MESH_POINT:
 			break;
 			break;
 		}
 		}
-		if (netif_running(sdata->dev))
+		if (ieee80211_sdata_running(sdata))
 			iterator(data, sdata->vif.addr,
 			iterator(data, sdata->vif.addr,
 				 &sdata->vif);
 				 &sdata->vif);
 	}
 	}
@@ -502,7 +502,7 @@ void ieee80211_iterate_active_interfaces_atomic(
 		case NL80211_IFTYPE_MESH_POINT:
 		case NL80211_IFTYPE_MESH_POINT:
 			break;
 			break;
 		}
 		}
-		if (netif_running(sdata->dev))
+		if (ieee80211_sdata_running(sdata))
 			iterator(data, sdata->vif.addr,
 			iterator(data, sdata->vif.addr,
 				 &sdata->vif);
 				 &sdata->vif);
 	}
 	}
@@ -881,30 +881,66 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
 			     enum ieee80211_band band)
 			     enum ieee80211_band band)
 {
 {
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_supported_band *sband;
-	u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
-	int i;
+	u8 *pos;
+	size_t offset = 0, noffset;
+	int supp_rates_len, i;
 
 
 	sband = local->hw.wiphy->bands[band];
 	sband = local->hw.wiphy->bands[band];
 
 
 	pos = buffer;
 	pos = buffer;
 
 
+	supp_rates_len = min_t(int, sband->n_bitrates, 8);
+
 	*pos++ = WLAN_EID_SUPP_RATES;
 	*pos++ = WLAN_EID_SUPP_RATES;
-	supp_rates_len = pos;
-	*pos++ = 0;
-
-	for (i = 0; i < sband->n_bitrates; i++) {
-		struct ieee80211_rate *rate = &sband->bitrates[i];
-
-		if (esupp_rates_len) {
-			*esupp_rates_len += 1;
-		} else if (*supp_rates_len == 8) {
-			*pos++ = WLAN_EID_EXT_SUPP_RATES;
-			esupp_rates_len = pos;
-			*pos++ = 1;
-		} else
-			*supp_rates_len += 1;
+	*pos++ = supp_rates_len;
+
+	for (i = 0; i < supp_rates_len; i++) {
+		int rate = sband->bitrates[i].bitrate;
+		*pos++ = (u8) (rate / 5);
+	}
+
+	/* insert "request information" if in custom IEs */
+	if (ie && ie_len) {
+		static const u8 before_extrates[] = {
+			WLAN_EID_SSID,
+			WLAN_EID_SUPP_RATES,
+			WLAN_EID_REQUEST,
+		};
+		noffset = ieee80211_ie_split(ie, ie_len,
+					     before_extrates,
+					     ARRAY_SIZE(before_extrates),
+					     offset);
+		memcpy(pos, ie + offset, noffset - offset);
+		pos += noffset - offset;
+		offset = noffset;
+	}
 
 
-		*pos++ = rate->bitrate / 5;
+	if (sband->n_bitrates > i) {
+		*pos++ = WLAN_EID_EXT_SUPP_RATES;
+		*pos++ = sband->n_bitrates - i;
+
+		for (; i < sband->n_bitrates; i++) {
+			int rate = sband->bitrates[i].bitrate;
+			*pos++ = (u8) (rate / 5);
+		}
+	}
+
+	/* insert custom IEs that go before HT */
+	if (ie && ie_len) {
+		static const u8 before_ht[] = {
+			WLAN_EID_SSID,
+			WLAN_EID_SUPP_RATES,
+			WLAN_EID_REQUEST,
+			WLAN_EID_EXT_SUPP_RATES,
+			WLAN_EID_DS_PARAMS,
+			WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+		};
+		noffset = ieee80211_ie_split(ie, ie_len,
+					     before_ht, ARRAY_SIZE(before_ht),
+					     offset);
+		memcpy(pos, ie + offset, noffset - offset);
+		pos += noffset - offset;
+		offset = noffset;
 	}
 	}
 
 
 	if (sband->ht_cap.ht_supported) {
 	if (sband->ht_cap.ht_supported) {
@@ -936,9 +972,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
 	 * that calculates local->scan_ies_len.
 	 * that calculates local->scan_ies_len.
 	 */
 	 */
 
 
-	if (ie) {
-		memcpy(pos, ie, ie_len);
-		pos += ie_len;
+	/* add any remaining custom IEs */
+	if (ie && ie_len) {
+		noffset = ie_len;
+		memcpy(pos, ie + offset, noffset - offset);
+		pos += noffset - offset;
 	}
 	}
 
 
 	return pos - buffer;
 	return pos - buffer;
@@ -1037,7 +1075,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 {
 {
 	struct ieee80211_hw *hw = &local->hw;
 	struct ieee80211_hw *hw = &local->hw;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_if_init_conf conf;
 	struct sta_info *sta;
 	struct sta_info *sta;
 	unsigned long flags;
 	unsigned long flags;
 	int res;
 	int res;
@@ -1047,7 +1084,19 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
 
 	/* restart hardware */
 	/* restart hardware */
 	if (local->open_count) {
 	if (local->open_count) {
+		/*
+		 * Upon resume hardware can sometimes be goofy due to
+		 * various platform / driver / bus issues, so restarting
+		 * the device may at times not work immediately. Propagate
+		 * the error.
+		 */
 		res = drv_start(local);
 		res = drv_start(local);
+		if (res) {
+			WARN(local->suspended, "Harware became unavailable "
+			     "upon resume. This is could be a software issue"
+			     "prior to suspend or a harware issue\n");
+			return res;
+		}
 
 
 		ieee80211_led_radio(local, true);
 		ieee80211_led_radio(local, true);
 	}
 	}
@@ -1056,12 +1105,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 	list_for_each_entry(sdata, &local->interfaces, list) {
 	list_for_each_entry(sdata, &local->interfaces, list) {
 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
 		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
 		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-		    netif_running(sdata->dev)) {
-			conf.vif = &sdata->vif;
-			conf.type = sdata->vif.type;
-			conf.mac_addr = sdata->vif.addr;
-			res = drv_add_interface(local, &conf);
-		}
+		    ieee80211_sdata_running(sdata))
+			res = drv_add_interface(local, &sdata->vif);
 	}
 	}
 
 
 	/* add STAs back */
 	/* add STAs back */
@@ -1103,7 +1148,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 	/* Finally also reconfigure all the BSS information */
 	/* Finally also reconfigure all the BSS information */
 	list_for_each_entry(sdata, &local->interfaces, list) {
 	list_for_each_entry(sdata, &local->interfaces, list) {
 		u32 changed = ~0;
 		u32 changed = ~0;
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 			continue;
 		switch (sdata->vif.type) {
 		switch (sdata->vif.type) {
 		case NL80211_IFTYPE_STATION:
 		case NL80211_IFTYPE_STATION:
@@ -1131,7 +1176,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
 
 	/* add back keys */
 	/* add back keys */
 	list_for_each_entry(sdata, &local->interfaces, list)
 	list_for_each_entry(sdata, &local->interfaces, list)
-		if (netif_running(sdata->dev))
+		if (ieee80211_sdata_running(sdata))
 			ieee80211_enable_keys(sdata);
 			ieee80211_enable_keys(sdata);
 
 
 	ieee80211_wake_queues_by_reason(hw,
 	ieee80211_wake_queues_by_reason(hw,
@@ -1252,3 +1297,59 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
 	/* changed flag is auto-detected for this */
 	/* changed flag is auto-detected for this */
 	ieee80211_hw_config(local, 0);
 	ieee80211_hw_config(local, 0);
 }
 }
+
+static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
+{
+	int i;
+
+	for (i = 0; i < n_ids; i++)
+		if (ids[i] == id)
+			return true;
+	return false;
+}
+
+/**
+ * ieee80211_ie_split - split an IE buffer according to ordering
+ *
+ * @ies: the IE buffer
+ * @ielen: the length of the IE buffer
+ * @ids: an array with element IDs that are allowed before
+ *	the split
+ * @n_ids: the size of the element ID array
+ * @offset: offset where to start splitting in the buffer
+ *
+ * This function splits an IE buffer by updating the @offset
+ * variable to point to the location where the buffer should be
+ * split.
+ *
+ * It assumes that the given IE buffer is well-formed, this
+ * has to be guaranteed by the caller!
+ *
+ * It also assumes that the IEs in the buffer are ordered
+ * correctly, if not the result of using this function will not
+ * be ordered correctly either, i.e. it does no reordering.
+ *
+ * The function returns the offset where the next part of the
+ * buffer starts, which may be @ielen if the entire (remainder)
+ * of the buffer should be used.
+ */
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+			  const u8 *ids, int n_ids, size_t offset)
+{
+	size_t pos = offset;
+
+	while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
+		pos += 2 + ies[pos + 1];
+
+	return pos;
+}
+
+size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
+{
+	size_t pos = offset;
+
+	while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
+		pos += 2 + ies[pos + 1];
+
+	return pos;
+}

+ 1086 - 0
net/mac80211/work.c

@@ -0,0 +1,1086 @@
+/*
+ * mac80211 work implementation
+ *
+ * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "rate.h"
+
+#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
+#define IEEE80211_AUTH_MAX_TRIES 3
+#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
+#define IEEE80211_ASSOC_MAX_TRIES 3
+#define IEEE80211_MAX_PROBE_TRIES 5
+
+enum work_action {
+	WORK_ACT_NONE,
+	WORK_ACT_TIMEOUT,
+	WORK_ACT_DONE,
+};
+
+
+/* utils */
+static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
+{
+	WARN_ON(!mutex_is_locked(&local->work_mtx));
+}
+
+/*
+ * We can have multiple work items (and connection probing)
+ * scheduling this timer, but we need to take care to only
+ * reschedule it when it should fire _earlier_ than it was
+ * asked for before, or if it's not pending right now. This
+ * function ensures that. Note that it then is required to
+ * run this function for all timeouts after the first one
+ * has happened -- the work that runs from this timer will
+ * do that.
+ */
+static void run_again(struct ieee80211_local *local,
+		      unsigned long timeout)
+{
+	ASSERT_WORK_MTX(local);
+
+	if (!timer_pending(&local->work_timer) ||
+	    time_before(timeout, local->work_timer.expires))
+		mod_timer(&local->work_timer, timeout);
+}
+
+static void work_free_rcu(struct rcu_head *head)
+{
+	struct ieee80211_work *wk =
+		container_of(head, struct ieee80211_work, rcu_head);
+
+	kfree(wk);
+}
+
+void free_work(struct ieee80211_work *wk)
+{
+	call_rcu(&wk->rcu_head, work_free_rcu);
+}
+
+static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
+				      struct ieee80211_supported_band *sband,
+				      u32 *rates)
+{
+	int i, j, count;
+	*rates = 0;
+	count = 0;
+	for (i = 0; i < supp_rates_len; i++) {
+		int rate = (supp_rates[i] & 0x7F) * 5;
+
+		for (j = 0; j < sband->n_bitrates; j++)
+			if (sband->bitrates[j].bitrate == rate) {
+				*rates |= BIT(j);
+				count++;
+				break;
+			}
+	}
+
+	return count;
+}
+
+/* frame sending functions */
+
+static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
+				struct ieee80211_supported_band *sband,
+				struct ieee80211_channel *channel,
+				enum ieee80211_smps_mode smps)
+{
+	struct ieee80211_ht_info *ht_info;
+	u8 *pos;
+	u32 flags = channel->flags;
+	u16 cap = sband->ht_cap.cap;
+	__le16 tmp;
+
+	if (!sband->ht_cap.ht_supported)
+		return;
+
+	if (!ht_info_ie)
+		return;
+
+	if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
+		return;
+
+	ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
+
+	/* determine capability flags */
+
+	if (ieee80211_disable_40mhz_24ghz &&
+	    sband->band == IEEE80211_BAND_2GHZ) {
+		cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		cap &= ~IEEE80211_HT_CAP_SGI_40;
+	}
+
+	switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+		if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
+			cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			cap &= ~IEEE80211_HT_CAP_SGI_40;
+		}
+		break;
+	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+		if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
+			cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			cap &= ~IEEE80211_HT_CAP_SGI_40;
+		}
+		break;
+	}
+
+	/* set SM PS mode properly */
+	cap &= ~IEEE80211_HT_CAP_SM_PS;
+	switch (smps) {
+	case IEEE80211_SMPS_AUTOMATIC:
+	case IEEE80211_SMPS_NUM_MODES:
+		WARN_ON(1);
+	case IEEE80211_SMPS_OFF:
+		cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
+			IEEE80211_HT_CAP_SM_PS_SHIFT;
+		break;
+	case IEEE80211_SMPS_STATIC:
+		cap |= WLAN_HT_CAP_SM_PS_STATIC <<
+			IEEE80211_HT_CAP_SM_PS_SHIFT;
+		break;
+	case IEEE80211_SMPS_DYNAMIC:
+		cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
+			IEEE80211_HT_CAP_SM_PS_SHIFT;
+		break;
+	}
+
+	/* reserve and fill IE */
+
+	pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
+	*pos++ = WLAN_EID_HT_CAPABILITY;
+	*pos++ = sizeof(struct ieee80211_ht_cap);
+	memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+
+	/* capability flags */
+	tmp = cpu_to_le16(cap);
+	memcpy(pos, &tmp, sizeof(u16));
+	pos += sizeof(u16);
+
+	/* AMPDU parameters */
+	*pos++ = sband->ht_cap.ampdu_factor |
+		 (sband->ht_cap.ampdu_density <<
+			IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+
+	/* MCS set */
+	memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+	pos += sizeof(sband->ht_cap.mcs);
+
+	/* extended capabilities */
+	pos += sizeof(__le16);
+
+	/* BF capabilities */
+	pos += sizeof(__le32);
+
+	/* antenna selection */
+	pos += sizeof(u8);
+}
+
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+				 struct ieee80211_work *wk)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u8 *pos;
+	const u8 *ies;
+	size_t offset = 0, noffset;
+	int i, len, count, rates_len, supp_rates_len;
+	u16 capab;
+	struct ieee80211_supported_band *sband;
+	u32 rates = 0;
+
+	sband = local->hw.wiphy->bands[wk->chan->band];
+
+	/*
+	 * Get all rates supported by the device and the AP as
+	 * some APs don't like getting a superset of their rates
+	 * in the association request (e.g. D-Link DAP 1353 in
+	 * b-only mode)...
+	 */
+	rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
+					       wk->assoc.supp_rates_len,
+					       sband, &rates);
+
+	skb = alloc_skb(local->hw.extra_tx_headroom +
+			sizeof(*mgmt) + /* bit too much but doesn't matter */
+			2 + wk->assoc.ssid_len + /* SSID */
+			4 + rates_len + /* (extended) rates */
+			4 + /* power capability */
+			2 + 2 * sband->n_channels + /* supported channels */
+			2 + sizeof(struct ieee80211_ht_cap) + /* HT */
+			wk->ie_len + /* extra IEs */
+			9, /* WMM */
+			GFP_KERNEL);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
+		       "frame\n", sdata->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	capab = WLAN_CAPABILITY_ESS;
+
+	if (sband->band == IEEE80211_BAND_2GHZ) {
+		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+			capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+	}
+
+	if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY)
+		capab |= WLAN_CAPABILITY_PRIVACY;
+
+	if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+	    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+		capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, wk->filter_ta, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+	memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN);
+
+	if (!is_zero_ether_addr(wk->assoc.prev_bssid)) {
+		skb_put(skb, 10);
+		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						  IEEE80211_STYPE_REASSOC_REQ);
+		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
+		mgmt->u.reassoc_req.listen_interval =
+				cpu_to_le16(local->hw.conf.listen_interval);
+		memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid,
+		       ETH_ALEN);
+	} else {
+		skb_put(skb, 4);
+		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						  IEEE80211_STYPE_ASSOC_REQ);
+		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
+		mgmt->u.assoc_req.listen_interval =
+				cpu_to_le16(local->hw.conf.listen_interval);
+	}
+
+	/* SSID */
+	ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = wk->assoc.ssid_len;
+	memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
+
+	/* add all rates which were marked to be used above */
+	supp_rates_len = rates_len;
+	if (supp_rates_len > 8)
+		supp_rates_len = 8;
+
+	len = sband->n_bitrates;
+	pos = skb_put(skb, supp_rates_len + 2);
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos++ = supp_rates_len;
+
+	count = 0;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		if (BIT(i) & rates) {
+			int rate = sband->bitrates[i].bitrate;
+			*pos++ = (u8) (rate / 5);
+			if (++count == 8)
+				break;
+		}
+	}
+
+	if (rates_len > count) {
+		pos = skb_put(skb, rates_len - count + 2);
+		*pos++ = WLAN_EID_EXT_SUPP_RATES;
+		*pos++ = rates_len - count;
+
+		for (i++; i < sband->n_bitrates; i++) {
+			if (BIT(i) & rates) {
+				int rate = sband->bitrates[i].bitrate;
+				*pos++ = (u8) (rate / 5);
+			}
+		}
+	}
+
+	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
+		/* 1. power capabilities */
+		pos = skb_put(skb, 4);
+		*pos++ = WLAN_EID_PWR_CAPABILITY;
+		*pos++ = 2;
+		*pos++ = 0; /* min tx power */
+		*pos++ = wk->chan->max_power; /* max tx power */
+
+		/* 2. supported channels */
+		/* TODO: get this in reg domain format */
+		pos = skb_put(skb, 2 * sband->n_channels + 2);
+		*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
+		*pos++ = 2 * sband->n_channels;
+		for (i = 0; i < sband->n_channels; i++) {
+			*pos++ = ieee80211_frequency_to_channel(
+					sband->channels[i].center_freq);
+			*pos++ = 1; /* one channel in the subband*/
+		}
+	}
+
+	/* if present, add any custom IEs that go before HT */
+	if (wk->ie_len && wk->ie) {
+		static const u8 before_ht[] = {
+			WLAN_EID_SSID,
+			WLAN_EID_SUPP_RATES,
+			WLAN_EID_EXT_SUPP_RATES,
+			WLAN_EID_PWR_CAPABILITY,
+			WLAN_EID_SUPPORTED_CHANNELS,
+			WLAN_EID_RSN,
+			WLAN_EID_QOS_CAPA,
+			WLAN_EID_RRM_ENABLED_CAPABILITIES,
+			WLAN_EID_MOBILITY_DOMAIN,
+			WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+		};
+		noffset = ieee80211_ie_split(wk->ie, wk->ie_len,
+					     before_ht, ARRAY_SIZE(before_ht),
+					     offset);
+		pos = skb_put(skb, noffset - offset);
+		memcpy(pos, wk->ie + offset, noffset - offset);
+		offset = noffset;
+	}
+
+	if (wk->assoc.use_11n && wk->assoc.wmm_used &&
+	    local->hw.queues >= 4)
+		ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie,
+				    sband, wk->chan, wk->assoc.smps);
+
+	/* if present, add any custom non-vendor IEs that go after HT */
+	if (wk->ie_len && wk->ie) {
+		noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len,
+						    offset);
+		pos = skb_put(skb, noffset - offset);
+		memcpy(pos, wk->ie + offset, noffset - offset);
+		offset = noffset;
+	}
+
+	if (wk->assoc.wmm_used && local->hw.queues >= 4) {
+		pos = skb_put(skb, 9);
+		*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+		*pos++ = 7; /* len */
+		*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+		*pos++ = 0x50;
+		*pos++ = 0xf2;
+		*pos++ = 2; /* WME */
+		*pos++ = 0; /* WME info */
+		*pos++ = 1; /* WME ver */
+		*pos++ = 0;
+	}
+
+	/* add any remaining custom (i.e. vendor specific here) IEs */
+	if (wk->ie_len && wk->ie) {
+		noffset = wk->ie_len;
+		pos = skb_put(skb, noffset - offset);
+		memcpy(pos, wk->ie + offset, noffset - offset);
+	}
+
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
+}
+
+static void ieee80211_remove_auth_bss(struct ieee80211_local *local,
+				      struct ieee80211_work *wk)
+{
+	struct cfg80211_bss *cbss;
+	u16 capa_val = WLAN_CAPABILITY_ESS;
+
+	if (wk->probe_auth.privacy)
+		capa_val |= WLAN_CAPABILITY_PRIVACY;
+
+	cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta,
+				wk->probe_auth.ssid, wk->probe_auth.ssid_len,
+				WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
+				capa_val);
+	if (!cbss)
+		return;
+
+	cfg80211_unlink_bss(local->hw.wiphy, cbss);
+	cfg80211_put_bss(cbss);
+}
+
+static enum work_action __must_check
+ieee80211_direct_probe(struct ieee80211_work *wk)
+{
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
+	struct ieee80211_local *local = sdata->local;
+
+	wk->probe_auth.tries++;
+	if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
+		printk(KERN_DEBUG "%s: direct probe to %pM timed out\n",
+		       sdata->name, wk->filter_ta);
+
+		/*
+		 * Most likely AP is not in the range so remove the
+		 * bss struct for that AP.
+		 */
+		ieee80211_remove_auth_bss(local, wk);
+
+		return WORK_ACT_TIMEOUT;
+	}
+
+	printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n",
+			sdata->name, wk->filter_ta, wk->probe_auth.tries);
+
+	/*
+	 * Direct probe is sent to broadcast address as some APs
+	 * will not answer to direct packet in unassociated state.
+	 */
+	ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid,
+				 wk->probe_auth.ssid_len, NULL, 0);
+
+	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+	run_again(local, wk->timeout);
+
+	return WORK_ACT_NONE;
+}
+
+
+static enum work_action __must_check
+ieee80211_authenticate(struct ieee80211_work *wk)
+{
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
+	struct ieee80211_local *local = sdata->local;
+
+	wk->probe_auth.tries++;
+	if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
+		printk(KERN_DEBUG "%s: authentication with %pM"
+		       " timed out\n", sdata->name, wk->filter_ta);
+
+		/*
+		 * Most likely AP is not in the range so remove the
+		 * bss struct for that AP.
+		 */
+		ieee80211_remove_auth_bss(local, wk);
+
+		return WORK_ACT_TIMEOUT;
+	}
+
+	printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n",
+	       sdata->name, wk->filter_ta, wk->probe_auth.tries);
+
+	ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie,
+			    wk->ie_len, wk->filter_ta, NULL, 0, 0);
+	wk->probe_auth.transaction = 2;
+
+	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+	run_again(local, wk->timeout);
+
+	return WORK_ACT_NONE;
+}
+
+static enum work_action __must_check
+ieee80211_associate(struct ieee80211_work *wk)
+{
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
+	struct ieee80211_local *local = sdata->local;
+
+	wk->assoc.tries++;
+	if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) {
+		printk(KERN_DEBUG "%s: association with %pM"
+		       " timed out\n",
+		       sdata->name, wk->filter_ta);
+
+		/*
+		 * Most likely AP is not in the range so remove the
+		 * bss struct for that AP.
+		 */
+		if (wk->assoc.bss)
+			cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss);
+
+		return WORK_ACT_TIMEOUT;
+	}
+
+	printk(KERN_DEBUG "%s: associate with %pM (try %d)\n",
+	       sdata->name, wk->filter_ta, wk->assoc.tries);
+	ieee80211_send_assoc(sdata, wk);
+
+	wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
+	run_again(local, wk->timeout);
+
+	return WORK_ACT_NONE;
+}
+
+static enum work_action __must_check
+ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
+{
+	/*
+	 * First time we run, do nothing -- the generic code will
+	 * have switched to the right channel etc.
+	 */
+	if (!wk->remain.started) {
+		wk->remain.started = true;
+		wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
+
+		cfg80211_ready_on_channel(wk->sdata->dev, (u64)wk, wk->chan,
+					  wk->chan_type, wk->remain.duration,
+					  GFP_KERNEL);
+
+		return WORK_ACT_NONE;
+	}
+
+	return WORK_ACT_TIMEOUT;
+}
+
+static void ieee80211_auth_challenge(struct ieee80211_work *wk,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len)
+{
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
+	u8 *pos;
+	struct ieee802_11_elems elems;
+
+	pos = mgmt->u.auth.variable;
+	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+	if (!elems.challenge)
+		return;
+	ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm,
+			    elems.challenge - 2, elems.challenge_len + 2,
+			    wk->filter_ta, wk->probe_auth.key,
+			    wk->probe_auth.key_len, wk->probe_auth.key_idx);
+	wk->probe_auth.transaction = 4;
+}
+
+static enum work_action __must_check
+ieee80211_rx_mgmt_auth(struct ieee80211_work *wk,
+		       struct ieee80211_mgmt *mgmt, size_t len)
+{
+	u16 auth_alg, auth_transaction, status_code;
+
+	if (wk->type != IEEE80211_WORK_AUTH)
+		return WORK_ACT_NONE;
+
+	if (len < 24 + 6)
+		return WORK_ACT_NONE;
+
+	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+	status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+	if (auth_alg != wk->probe_auth.algorithm ||
+	    auth_transaction != wk->probe_auth.transaction)
+		return WORK_ACT_NONE;
+
+	if (status_code != WLAN_STATUS_SUCCESS) {
+		printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
+		       wk->sdata->name, mgmt->sa, status_code);
+		return WORK_ACT_DONE;
+	}
+
+	switch (wk->probe_auth.algorithm) {
+	case WLAN_AUTH_OPEN:
+	case WLAN_AUTH_LEAP:
+	case WLAN_AUTH_FT:
+		break;
+	case WLAN_AUTH_SHARED_KEY:
+		if (wk->probe_auth.transaction != 4) {
+			ieee80211_auth_challenge(wk, mgmt, len);
+			/* need another frame */
+			return WORK_ACT_NONE;
+		}
+		break;
+	default:
+		WARN_ON(1);
+		return WORK_ACT_NONE;
+	}
+
+	printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name);
+	return WORK_ACT_DONE;
+}
+
+static enum work_action __must_check
+ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk,
+			     struct ieee80211_mgmt *mgmt, size_t len,
+			     bool reassoc)
+{
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
+	struct ieee80211_local *local = sdata->local;
+	u16 capab_info, status_code, aid;
+	struct ieee802_11_elems elems;
+	u8 *pos;
+
+	/*
+	 * AssocResp and ReassocResp have identical structure, so process both
+	 * of them in this function.
+	 */
+
+	if (len < 24 + 6)
+		return WORK_ACT_NONE;
+
+	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
+	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
+
+	printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
+	       "status=%d aid=%d)\n",
+	       sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
+	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
+
+	pos = mgmt->u.assoc_resp.variable;
+	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+
+	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
+	    elems.timeout_int && elems.timeout_int_len == 5 &&
+	    elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
+		u32 tu, ms;
+		tu = get_unaligned_le32(elems.timeout_int + 1);
+		ms = tu * 1024 / 1000;
+		printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
+		       "comeback duration %u TU (%u ms)\n",
+		       sdata->name, mgmt->sa, tu, ms);
+		wk->timeout = jiffies + msecs_to_jiffies(ms);
+		if (ms > IEEE80211_ASSOC_TIMEOUT)
+			run_again(local, wk->timeout);
+		return WORK_ACT_NONE;
+	}
+
+	if (status_code != WLAN_STATUS_SUCCESS)
+		printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
+		       sdata->name, mgmt->sa, status_code);
+	else
+		printk(KERN_DEBUG "%s: associated\n", sdata->name);
+
+	return WORK_ACT_DONE;
+}
+
+static enum work_action __must_check
+ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
+			     struct ieee80211_mgmt *mgmt, size_t len,
+			     struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_sub_if_data *sdata = wk->sdata;
+	struct ieee80211_local *local = sdata->local;
+	size_t baselen;
+
+	ASSERT_WORK_MTX(local);
+
+	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+	if (baselen > len)
+		return WORK_ACT_NONE;
+
+	printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
+	return WORK_ACT_DONE;
+}
+
+static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
+					  struct sk_buff *skb)
+{
+	struct ieee80211_rx_status *rx_status;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_work *wk;
+	enum work_action rma = WORK_ACT_NONE;
+	u16 fc;
+
+	rx_status = (struct ieee80211_rx_status *) skb->cb;
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	fc = le16_to_cpu(mgmt->frame_control);
+
+	mutex_lock(&local->work_mtx);
+
+	list_for_each_entry(wk, &local->work_list, list) {
+		const u8 *bssid = NULL;
+
+		switch (wk->type) {
+		case IEEE80211_WORK_DIRECT_PROBE:
+		case IEEE80211_WORK_AUTH:
+		case IEEE80211_WORK_ASSOC:
+			bssid = wk->filter_ta;
+			break;
+		default:
+			continue;
+		}
+
+		/*
+		 * Before queuing, we already verified mgmt->sa,
+		 * so this is needed just for matching.
+		 */
+		if (compare_ether_addr(bssid, mgmt->bssid))
+			continue;
+
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PROBE_RESP:
+			rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
+							   rx_status);
+			break;
+		case IEEE80211_STYPE_AUTH:
+			rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len);
+			break;
+		case IEEE80211_STYPE_ASSOC_RESP:
+			rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
+							   skb->len, false);
+			break;
+		case IEEE80211_STYPE_REASSOC_RESP:
+			rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
+							   skb->len, true);
+			break;
+		default:
+			WARN_ON(1);
+		}
+		/*
+		 * We've processed this frame for that work, so it can't
+		 * belong to another work struct.
+		 * NB: this is also required for correctness for 'rma'!
+		 */
+		break;
+	}
+
+	switch (rma) {
+	case WORK_ACT_NONE:
+		break;
+	case WORK_ACT_DONE:
+		list_del_rcu(&wk->list);
+		break;
+	default:
+		WARN(1, "unexpected: %d", rma);
+	}
+
+	mutex_unlock(&local->work_mtx);
+
+	if (rma != WORK_ACT_DONE)
+		goto out;
+
+	switch (wk->done(wk, skb)) {
+	case WORK_DONE_DESTROY:
+		free_work(wk);
+		break;
+	case WORK_DONE_REQUEUE:
+		synchronize_rcu();
+		wk->started = false; /* restart */
+		mutex_lock(&local->work_mtx);
+		list_add_tail(&wk->list, &local->work_list);
+		mutex_unlock(&local->work_mtx);
+	}
+
+ out:
+	kfree_skb(skb);
+}
+
+static void ieee80211_work_timer(unsigned long data)
+{
+	struct ieee80211_local *local = (void *) data;
+
+	if (local->quiescing)
+		return;
+
+	ieee80211_queue_work(&local->hw, &local->work_work);
+}
+
+static void ieee80211_work_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local, work_work);
+	struct sk_buff *skb;
+	struct ieee80211_work *wk, *tmp;
+	LIST_HEAD(free_work);
+	enum work_action rma;
+	bool remain_off_channel = false;
+
+	if (local->scanning)
+		return;
+
+	/*
+	 * ieee80211_queue_work() should have picked up most cases,
+	 * here we'll pick the the rest.
+	 */
+	if (WARN(local->suspended, "work scheduled while going to suspend\n"))
+		return;
+
+	/* first process frames to avoid timing out while a frame is pending */
+	while ((skb = skb_dequeue(&local->work_skb_queue)))
+		ieee80211_work_rx_queued_mgmt(local, skb);
+
+	ieee80211_recalc_idle(local);
+
+	mutex_lock(&local->work_mtx);
+
+	list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
+		/* mark work as started if it's on the current off-channel */
+		if (!wk->started && local->tmp_channel &&
+		    wk->chan == local->tmp_channel &&
+		    wk->chan_type == local->tmp_channel_type) {
+			wk->started = true;
+		}
+
+		if (!wk->started && !local->tmp_channel) {
+			/*
+			 * TODO: could optimize this by leaving the
+			 *	 station vifs in awake mode if they
+			 *	 happen to be on the same channel as
+			 *	 the requested channel
+			 */
+			ieee80211_offchannel_stop_beaconing(local);
+			ieee80211_offchannel_stop_station(local);
+
+			local->tmp_channel = wk->chan;
+			local->tmp_channel_type = wk->chan_type;
+			ieee80211_hw_config(local, 0);
+			wk->started = true;
+			wk->timeout = jiffies;
+		}
+
+		/* don't try to work with items that aren't started */
+		if (!wk->started)
+			continue;
+
+		if (time_is_after_jiffies(wk->timeout)) {
+			/*
+			 * This work item isn't supposed to be worked on
+			 * right now, but take care to adjust the timer
+			 * properly.
+			 */
+			run_again(local, wk->timeout);
+			continue;
+		}
+
+		switch (wk->type) {
+		default:
+			WARN_ON(1);
+			/* nothing */
+			rma = WORK_ACT_NONE;
+			break;
+		case IEEE80211_WORK_ABORT:
+			rma = WORK_ACT_TIMEOUT;
+		case IEEE80211_WORK_DIRECT_PROBE:
+			rma = ieee80211_direct_probe(wk);
+			break;
+		case IEEE80211_WORK_AUTH:
+			rma = ieee80211_authenticate(wk);
+			break;
+		case IEEE80211_WORK_ASSOC:
+			rma = ieee80211_associate(wk);
+			break;
+		case IEEE80211_WORK_REMAIN_ON_CHANNEL:
+			rma = ieee80211_remain_on_channel_timeout(wk);
+			break;
+		}
+
+		switch (rma) {
+		case WORK_ACT_NONE:
+			/* might have changed the timeout */
+			run_again(local, wk->timeout);
+			break;
+		case WORK_ACT_TIMEOUT:
+			list_del_rcu(&wk->list);
+			synchronize_rcu();
+			list_add(&wk->list, &free_work);
+			break;
+		default:
+			WARN(1, "unexpected: %d", rma);
+		}
+	}
+
+	list_for_each_entry(wk, &local->work_list, list) {
+		if (!wk->started)
+			continue;
+		if (wk->chan != local->tmp_channel)
+			continue;
+		if (wk->chan_type != local->tmp_channel_type)
+			continue;
+		remain_off_channel = true;
+	}
+
+	if (!remain_off_channel && local->tmp_channel) {
+		local->tmp_channel = NULL;
+		ieee80211_hw_config(local, 0);
+		ieee80211_offchannel_return(local, true);
+		/* give connection some time to breathe */
+		run_again(local, jiffies + HZ/2);
+	}
+
+	if (list_empty(&local->work_list) && local->scan_req)
+		ieee80211_queue_delayed_work(&local->hw,
+					     &local->scan_work,
+					     round_jiffies_relative(0));
+
+	mutex_unlock(&local->work_mtx);
+
+	ieee80211_recalc_idle(local);
+
+	list_for_each_entry_safe(wk, tmp, &free_work, list) {
+		wk->done(wk, NULL);
+		list_del(&wk->list);
+		kfree(wk);
+	}
+}
+
+void ieee80211_add_work(struct ieee80211_work *wk)
+{
+	struct ieee80211_local *local;
+
+	if (WARN_ON(!wk->chan))
+		return;
+
+	if (WARN_ON(!wk->sdata))
+		return;
+
+	if (WARN_ON(!wk->done))
+		return;
+
+	wk->started = false;
+
+	local = wk->sdata->local;
+	mutex_lock(&local->work_mtx);
+	list_add_tail(&wk->list, &local->work_list);
+	mutex_unlock(&local->work_mtx);
+
+	ieee80211_queue_work(&local->hw, &local->work_work);
+}
+
+void ieee80211_work_init(struct ieee80211_local *local)
+{
+	mutex_init(&local->work_mtx);
+	INIT_LIST_HEAD(&local->work_list);
+	setup_timer(&local->work_timer, ieee80211_work_timer,
+		    (unsigned long)local);
+	INIT_WORK(&local->work_work, ieee80211_work_work);
+	skb_queue_head_init(&local->work_skb_queue);
+}
+
+void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_work *wk;
+
+	mutex_lock(&local->work_mtx);
+	list_for_each_entry(wk, &local->work_list, list) {
+		if (wk->sdata != sdata)
+			continue;
+		wk->type = IEEE80211_WORK_ABORT;
+		wk->started = true;
+		wk->timeout = jiffies;
+	}
+	mutex_unlock(&local->work_mtx);
+
+	/* run cleanups etc. */
+	ieee80211_work_work(&local->work_work);
+
+	mutex_lock(&local->work_mtx);
+	list_for_each_entry(wk, &local->work_list, list) {
+		if (wk->sdata != sdata)
+			continue;
+		WARN_ON(1);
+		break;
+	}
+	mutex_unlock(&local->work_mtx);
+}
+
+ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
+					   struct sk_buff *skb)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_work *wk;
+	u16 fc;
+
+	if (skb->len < 24)
+		return RX_DROP_MONITOR;
+
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	fc = le16_to_cpu(mgmt->frame_control);
+
+	list_for_each_entry_rcu(wk, &local->work_list, list) {
+		if (sdata != wk->sdata)
+			continue;
+		if (compare_ether_addr(wk->filter_ta, mgmt->sa))
+			continue;
+		if (compare_ether_addr(wk->filter_ta, mgmt->bssid))
+			continue;
+
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_AUTH:
+		case IEEE80211_STYPE_PROBE_RESP:
+		case IEEE80211_STYPE_ASSOC_RESP:
+		case IEEE80211_STYPE_REASSOC_RESP:
+		case IEEE80211_STYPE_DEAUTH:
+		case IEEE80211_STYPE_DISASSOC:
+			skb_queue_tail(&local->work_skb_queue, skb);
+			ieee80211_queue_work(&local->hw, &local->work_work);
+			return RX_QUEUED;
+		}
+	}
+
+	return RX_CONTINUE;
+}
+
+static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
+						   struct sk_buff *skb)
+{
+	/*
+	 * We are done serving the remain-on-channel command.
+	 */
+	cfg80211_remain_on_channel_expired(wk->sdata->dev, (u64)wk,
+					   wk->chan, wk->chan_type,
+					   GFP_KERNEL);
+
+	return WORK_DONE_DESTROY;
+}
+
+int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
+				   struct ieee80211_channel *chan,
+				   enum nl80211_channel_type channel_type,
+				   unsigned int duration, u64 *cookie)
+{
+	struct ieee80211_work *wk;
+
+	wk = kzalloc(sizeof(*wk), GFP_KERNEL);
+	if (!wk)
+		return -ENOMEM;
+
+	wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
+	wk->chan = chan;
+	wk->chan_type = channel_type;
+	wk->sdata = sdata;
+	wk->done = ieee80211_remain_done;
+
+	wk->remain.duration = duration;
+
+	*cookie = (u64)wk;
+
+	ieee80211_add_work(wk);
+
+	return 0;
+}
+
+int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
+					  u64 cookie)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_work *wk, *tmp;
+	bool found = false;
+
+	mutex_lock(&local->work_mtx);
+	list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
+		if ((u64)wk == cookie) {
+			wk->timeout = jiffies;
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&local->work_mtx);
+
+	if (!found)
+		return -ENOENT;
+
+	ieee80211_queue_work(&local->hw, &local->work_work);
+
+	return 0;
+}

+ 0 - 15
net/wireless/Kconfig

@@ -94,21 +94,6 @@ config CFG80211_DEBUGFS
 
 
 	  If unsure, say N.
 	  If unsure, say N.
 
 
-config WIRELESS_OLD_REGULATORY
-	bool "Old wireless static regulatory definitions"
-	default n
-	depends on CFG80211
-	---help---
-	  This option enables the old static regulatory information
-	  and uses it within the new framework. This option is available
-	  for historical reasons and it is advised to leave it off.
-
-	  For details see:
-
-	  http://wireless.kernel.org/en/developers/Regulatory
-
-	  Say N and if you say Y, please tell us why. The default is N.
-
 config CFG80211_INTERNAL_REGDB
 config CFG80211_INTERNAL_REGDB
 	bool "use statically compiled regulatory rules database" if EMBEDDED
 	bool "use statically compiled regulatory rules database" if EMBEDDED
 	default n
 	default n

+ 27 - 14
net/wireless/chan.c

@@ -41,44 +41,57 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev,
 	return result;
 	return result;
 }
 }
 
 
-int rdev_set_freq(struct cfg80211_registered_device *rdev,
-		  struct wireless_dev *for_wdev,
+struct ieee80211_channel *
+rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
 		  int freq, enum nl80211_channel_type channel_type)
 		  int freq, enum nl80211_channel_type channel_type)
 {
 {
 	struct ieee80211_channel *chan;
 	struct ieee80211_channel *chan;
 	struct ieee80211_sta_ht_cap *ht_cap;
 	struct ieee80211_sta_ht_cap *ht_cap;
-	int result;
-
-	if (rdev_fixed_channel(rdev, for_wdev))
-		return -EBUSY;
-
-	if (!rdev->ops->set_channel)
-		return -EOPNOTSUPP;
 
 
 	chan = ieee80211_get_channel(&rdev->wiphy, freq);
 	chan = ieee80211_get_channel(&rdev->wiphy, freq);
 
 
 	/* Primary channel not allowed */
 	/* Primary channel not allowed */
 	if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
 	if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
-		return -EINVAL;
+		return NULL;
 
 
 	if (channel_type == NL80211_CHAN_HT40MINUS &&
 	if (channel_type == NL80211_CHAN_HT40MINUS &&
 	    chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
 	    chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
-		return -EINVAL;
+		return NULL;
 	else if (channel_type == NL80211_CHAN_HT40PLUS &&
 	else if (channel_type == NL80211_CHAN_HT40PLUS &&
 		 chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
 		 chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
-		return -EINVAL;
+		return NULL;
 
 
 	ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
 	ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
 
 
 	if (channel_type != NL80211_CHAN_NO_HT) {
 	if (channel_type != NL80211_CHAN_NO_HT) {
 		if (!ht_cap->ht_supported)
 		if (!ht_cap->ht_supported)
-			return -EINVAL;
+			return NULL;
 
 
 		if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
 		if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
 		    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
 		    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
-			return -EINVAL;
+			return NULL;
 	}
 	}
 
 
+	return chan;
+}
+
+int rdev_set_freq(struct cfg80211_registered_device *rdev,
+		  struct wireless_dev *for_wdev,
+		  int freq, enum nl80211_channel_type channel_type)
+{
+	struct ieee80211_channel *chan;
+	int result;
+
+	if (rdev_fixed_channel(rdev, for_wdev))
+		return -EBUSY;
+
+	if (!rdev->ops->set_channel)
+		return -EOPNOTSUPP;
+
+	chan = rdev_freq_to_chan(rdev, freq, channel_type);
+	if (!chan)
+		return -EINVAL;
+
 	result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
 	result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
 	if (result)
 	if (result)
 		return result;
 		return result;

+ 3 - 0
net/wireless/core.h

@@ -374,6 +374,9 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
 struct ieee80211_channel *
 struct ieee80211_channel *
 rdev_fixed_channel(struct cfg80211_registered_device *rdev,
 rdev_fixed_channel(struct cfg80211_registered_device *rdev,
 		   struct wireless_dev *for_wdev);
 		   struct wireless_dev *for_wdev);
+struct ieee80211_channel *
+rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
+		  int freq, enum nl80211_channel_type channel_type);
 int rdev_set_freq(struct cfg80211_registered_device *rdev,
 int rdev_set_freq(struct cfg80211_registered_device *rdev,
 		  struct wireless_dev *for_wdev,
 		  struct wireless_dev *for_wdev,
 		  int freq, enum nl80211_channel_type channel_type);
 		  int freq, enum nl80211_channel_type channel_type);

+ 49 - 1
net/wireless/mlme.c

@@ -93,7 +93,18 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
 			}
 			}
 		}
 		}
 
 
-		WARN_ON(!bss);
+		/*
+		 * We might be coming here because the driver reported
+		 * a successful association at the same time as the
+		 * user requested a deauth. In that case, we will have
+		 * removed the BSS from the auth_bsses list due to the
+		 * deauth request when the assoc response makes it. If
+		 * the two code paths acquire the lock the other way
+		 * around, that's just the standard situation of a
+		 * deauth being requested while connected.
+		 */
+		if (!bss)
+			goto out;
 	} else if (wdev->conn) {
 	} else if (wdev->conn) {
 		cfg80211_sme_failed_assoc(wdev);
 		cfg80211_sme_failed_assoc(wdev);
 		/*
 		/*
@@ -680,3 +691,40 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
 		}
 		}
 	}
 	}
 }
 }
+
+void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
+			       struct ieee80211_channel *chan,
+			       enum nl80211_channel_type channel_type,
+			       unsigned int duration, gfp_t gfp)
+{
+	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
+				       duration, gfp);
+}
+EXPORT_SYMBOL(cfg80211_ready_on_channel);
+
+void cfg80211_remain_on_channel_expired(struct net_device *dev,
+					u64 cookie,
+					struct ieee80211_channel *chan,
+					enum nl80211_channel_type channel_type,
+					gfp_t gfp)
+{
+	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
+					      channel_type, gfp);
+}
+EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
+
+void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
+		      struct station_info *sinfo, gfp_t gfp)
+{
+	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
+}
+EXPORT_SYMBOL(cfg80211_new_sta);

+ 237 - 8
net/wireless/nl80211.c

@@ -141,6 +141,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
 	[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
 	[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
 	[NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
 	[NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
 				 .len = WLAN_PMKID_LEN },
 				 .len = WLAN_PMKID_LEN },
+	[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
+	[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
 };
 };
 
 
 /* policy for the attributes */
 /* policy for the attributes */
@@ -569,6 +571,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 	CMD(set_pmksa, SET_PMKSA);
 	CMD(set_pmksa, SET_PMKSA);
 	CMD(del_pmksa, DEL_PMKSA);
 	CMD(del_pmksa, DEL_PMKSA);
 	CMD(flush_pmksa, FLUSH_PMKSA);
 	CMD(flush_pmksa, FLUSH_PMKSA);
+	CMD(remain_on_channel, REMAIN_ON_CHANNEL);
 	if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
 	if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
 		i++;
 		i++;
 		NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
 		NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -1639,7 +1642,7 @@ static int parse_station_flags(struct genl_info *info,
 
 
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 				int flags, struct net_device *dev,
 				int flags, struct net_device *dev,
-				u8 *mac_addr, struct station_info *sinfo)
+				const u8 *mac_addr, struct station_info *sinfo)
 {
 {
 	void *hdr;
 	void *hdr;
 	struct nlattr *sinfoattr, *txrate;
 	struct nlattr *sinfoattr, *txrate;
@@ -2550,12 +2553,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 
 
 	data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
 	data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
 
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-	/* We ignore world regdom requests with the old regdom setup */
-	if (is_world_regdom(data))
-		return -EINVAL;
-#endif
-
 	r = regulatory_hint_user(data);
 	r = regulatory_hint_user(data);
 
 
 	return r;
 	return r;
@@ -4289,6 +4286,143 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
 
 
 }
 }
 
 
+static int nl80211_remain_on_channel(struct sk_buff *skb,
+				     struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev;
+	struct net_device *dev;
+	struct ieee80211_channel *chan;
+	struct sk_buff *msg;
+	void *hdr;
+	u64 cookie;
+	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+	u32 freq, duration;
+	int err;
+
+	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
+	    !info->attrs[NL80211_ATTR_DURATION])
+		return -EINVAL;
+
+	duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+
+	/*
+	 * We should be on that channel for at least one jiffie,
+	 * and more than 5 seconds seems excessive.
+	 */
+	if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
+		return -EINVAL;
+
+	rtnl_lock();
+
+	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+	if (err)
+		goto unlock_rtnl;
+
+	if (!rdev->ops->remain_on_channel) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (!netif_running(dev)) {
+		err = -ENETDOWN;
+		goto out;
+	}
+
+	if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+		channel_type = nla_get_u32(
+			info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+		if (channel_type != NL80211_CHAN_NO_HT &&
+		    channel_type != NL80211_CHAN_HT20 &&
+		    channel_type != NL80211_CHAN_HT40PLUS &&
+		    channel_type != NL80211_CHAN_HT40MINUS)
+			err = -EINVAL;
+			goto out;
+	}
+
+	freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+	chan = rdev_freq_to_chan(rdev, freq, channel_type);
+	if (chan == NULL) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+			     NL80211_CMD_REMAIN_ON_CHANNEL);
+
+	if (IS_ERR(hdr)) {
+		err = PTR_ERR(hdr);
+		goto free_msg;
+	}
+
+	err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan,
+					   channel_type, duration, &cookie);
+
+	if (err)
+		goto free_msg;
+
+	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+	genlmsg_end(msg, hdr);
+	err = genlmsg_reply(msg, info);
+	goto out;
+
+ nla_put_failure:
+	err = -ENOBUFS;
+ free_msg:
+	nlmsg_free(msg);
+ out:
+	cfg80211_unlock_rdev(rdev);
+	dev_put(dev);
+ unlock_rtnl:
+	rtnl_unlock();
+	return err;
+}
+
+static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
+					    struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev;
+	struct net_device *dev;
+	u64 cookie;
+	int err;
+
+	if (!info->attrs[NL80211_ATTR_COOKIE])
+		return -EINVAL;
+
+	rtnl_lock();
+
+	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+	if (err)
+		goto unlock_rtnl;
+
+	if (!rdev->ops->cancel_remain_on_channel) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (!netif_running(dev)) {
+		err = -ENETDOWN;
+		goto out;
+	}
+
+	cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
+
+	err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
+
+ out:
+	cfg80211_unlock_rdev(rdev);
+	dev_put(dev);
+ unlock_rtnl:
+	rtnl_unlock();
+	return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
 static struct genl_ops nl80211_ops[] = {
 	{
 	{
 		.cmd = NL80211_CMD_GET_WIPHY,
 		.cmd = NL80211_CMD_GET_WIPHY,
@@ -4551,8 +4685,20 @@ static struct genl_ops nl80211_ops[] = {
 		.policy = nl80211_policy,
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 		.flags = GENL_ADMIN_PERM,
 	},
 	},
-
+	{
+		.cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
+		.doit = nl80211_remain_on_channel,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+		.doit = nl80211_cancel_remain_on_channel,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
 };
 };
+
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
 	.name = "mlme",
 	.name = "mlme",
 };
 };
@@ -5140,6 +5286,89 @@ nla_put_failure:
 	nlmsg_free(msg);
 	nlmsg_free(msg);
 }
 }
 
 
+static void nl80211_send_remain_on_chan_event(
+	int cmd, struct cfg80211_registered_device *rdev,
+	struct net_device *netdev, u64 cookie,
+	struct ieee80211_channel *chan,
+	enum nl80211_channel_type channel_type,
+	unsigned int duration, gfp_t gfp)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type);
+	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+	if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
+		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, gfp);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
+void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
+				    struct net_device *netdev, u64 cookie,
+				    struct ieee80211_channel *chan,
+				    enum nl80211_channel_type channel_type,
+				    unsigned int duration, gfp_t gfp)
+{
+	nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
+					  rdev, netdev, cookie, chan,
+					  channel_type, duration, gfp);
+}
+
+void nl80211_send_remain_on_channel_cancel(
+	struct cfg80211_registered_device *rdev, struct net_device *netdev,
+	u64 cookie, struct ieee80211_channel *chan,
+	enum nl80211_channel_type channel_type, gfp_t gfp)
+{
+	nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+					  rdev, netdev, cookie, chan,
+					  channel_type, 0, gfp);
+}
+
+void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
+			    struct net_device *dev, const u8 *mac_addr,
+			    struct station_info *sinfo, gfp_t gfp)
+{
+	struct sk_buff *msg;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+	if (!msg)
+		return;
+
+	if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, gfp);
+}
+
 /* initialisation/exit functions */
 /* initialisation/exit functions */
 
 
 int nl80211_init(void)
 int nl80211_init(void)

+ 15 - 0
net/wireless/nl80211.h

@@ -59,4 +59,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev, const u8 *bssid,
 			     struct net_device *netdev, const u8 *bssid,
 			     gfp_t gfp);
 			     gfp_t gfp);
 
 
+void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
+				    struct net_device *netdev,
+				    u64 cookie,
+				    struct ieee80211_channel *chan,
+				    enum nl80211_channel_type channel_type,
+				    unsigned int duration, gfp_t gfp);
+void nl80211_send_remain_on_channel_cancel(
+	struct cfg80211_registered_device *rdev, struct net_device *netdev,
+	u64 cookie, struct ieee80211_channel *chan,
+	enum nl80211_channel_type channel_type, gfp_t gfp);
+
+void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
+			    struct net_device *dev, const u8 *mac_addr,
+			    struct station_info *sinfo, gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */
 #endif /* __NET_WIRELESS_NL80211_H */

+ 2 - 87
net/wireless/reg.c

@@ -129,78 +129,6 @@ static char *ieee80211_regdom = "00";
 module_param(ieee80211_regdom, charp, 0444);
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-/*
- * We assume 40 MHz bandwidth for the old regulatory work.
- * We make emphasis we are using the exact same frequencies
- * as before
- */
-
-static const struct ieee80211_regdomain us_regdom = {
-	.n_reg_rules = 6,
-	.alpha2 =  "US",
-	.reg_rules = {
-		/* IEEE 802.11b/g, channels 1..11 */
-		REG_RULE(2412-10, 2462+10, 40, 6, 27, 0),
-		/* IEEE 802.11a, channel 36..48 */
-		REG_RULE(5180-10, 5240+10, 40, 6, 17, 0),
-		/* IEEE 802.11a, channels 48..64 */
-		REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS),
-		/* IEEE 802.11a, channels 100..124 */
-		REG_RULE(5500-10, 5590+10, 40, 6, 20, NL80211_RRF_DFS),
-		/* IEEE 802.11a, channels 132..144 */
-		REG_RULE(5660-10, 5700+10, 40, 6, 20, NL80211_RRF_DFS),
-		/* IEEE 802.11a, channels 149..165, outdoor */
-		REG_RULE(5745-10, 5825+10, 40, 6, 30, 0),
-	}
-};
-
-static const struct ieee80211_regdomain jp_regdom = {
-	.n_reg_rules = 6,
-	.alpha2 =  "JP",
-	.reg_rules = {
-		/* IEEE 802.11b/g, channels 1..11 */
-		REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
-		/* IEEE 802.11b/g, channels 12..13 */
-		REG_RULE(2467-10, 2472+10, 20, 6, 20, 0),
-		/* IEEE 802.11b/g, channel 14 */
-		REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_OFDM),
-		/* IEEE 802.11a, channels 36..48 */
-		REG_RULE(5180-10, 5240+10, 40, 6, 20, 0),
-		/* IEEE 802.11a, channels 52..64 */
-		REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS),
-		/* IEEE 802.11a, channels 100..144 */
-		REG_RULE(5500-10, 5700+10, 40, 6, 23, NL80211_RRF_DFS),
-	}
-};
-
-static const struct ieee80211_regdomain *static_regdom(char *alpha2)
-{
-	if (alpha2[0] == 'U' && alpha2[1] == 'S')
-		return &us_regdom;
-	if (alpha2[0] == 'J' && alpha2[1] == 'P')
-		return &jp_regdom;
-	/* Use world roaming rules for "EU", since it was a pseudo
-	   domain anyway... */
-	if (alpha2[0] == 'E' && alpha2[1] == 'U')
-		return &world_regdom;
-	/* Default, world roaming rules */
-	return &world_regdom;
-}
-
-static bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
-{
-	if (rd == &us_regdom || rd == &jp_regdom || rd == &world_regdom)
-		return true;
-	return false;
-}
-#else
-static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
-{
-	return false;
-}
-#endif
-
 static void reset_regdomains(void)
 static void reset_regdomains(void)
 {
 {
 	/* avoid freeing static information or freeing something twice */
 	/* avoid freeing static information or freeing something twice */
@@ -210,8 +138,6 @@ static void reset_regdomains(void)
 		cfg80211_world_regdom = NULL;
 		cfg80211_world_regdom = NULL;
 	if (cfg80211_regdomain == &world_regdom)
 	if (cfg80211_regdomain == &world_regdom)
 		cfg80211_regdomain = NULL;
 		cfg80211_regdomain = NULL;
-	if (is_old_static_regdom(cfg80211_regdomain))
-		cfg80211_regdomain = NULL;
 
 
 	kfree(cfg80211_regdomain);
 	kfree(cfg80211_regdomain);
 	kfree(cfg80211_world_regdom);
 	kfree(cfg80211_world_regdom);
@@ -1490,8 +1416,6 @@ static int ignore_request(struct wiphy *wiphy,
 		return REG_INTERSECT;
 		return REG_INTERSECT;
 	case NL80211_REGDOM_SET_BY_DRIVER:
 	case NL80211_REGDOM_SET_BY_DRIVER:
 		if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
 		if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
-			if (is_old_static_regdom(cfg80211_regdomain))
-				return 0;
 			if (regdom_changes(pending_request->alpha2))
 			if (regdom_changes(pending_request->alpha2))
 				return 0;
 				return 0;
 			return -EALREADY;
 			return -EALREADY;
@@ -1528,8 +1452,7 @@ static int ignore_request(struct wiphy *wiphy,
 				return -EAGAIN;
 				return -EAGAIN;
 		}
 		}
 
 
-		if (!is_old_static_regdom(cfg80211_regdomain) &&
-		    !regdom_changes(pending_request->alpha2))
+		if (!regdom_changes(pending_request->alpha2))
 			return -EALREADY;
 			return -EALREADY;
 
 
 		return 0;
 		return 0;
@@ -2111,8 +2034,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 		 * If someone else asked us to change the rd lets only bother
 		 * If someone else asked us to change the rd lets only bother
 		 * checking if the alpha2 changes if CRDA was already called
 		 * checking if the alpha2 changes if CRDA was already called
 		 */
 		 */
-		if (!is_old_static_regdom(cfg80211_regdomain) &&
-		    !regdom_changes(rd->alpha2))
+		if (!regdom_changes(rd->alpha2))
 			return -EINVAL;
 			return -EINVAL;
 	}
 	}
 
 
@@ -2311,15 +2233,8 @@ int regulatory_init(void)
 	spin_lock_init(&reg_requests_lock);
 	spin_lock_init(&reg_requests_lock);
 	spin_lock_init(&reg_pending_beacons_lock);
 	spin_lock_init(&reg_pending_beacons_lock);
 
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-	cfg80211_regdomain = static_regdom(ieee80211_regdom);
-
-	printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
-	print_regdomain_info(cfg80211_regdomain);
-#else
 	cfg80211_regdomain = cfg80211_world_regdom;
 	cfg80211_regdomain = cfg80211_world_regdom;
 
 
-#endif
 	/* We always try to get an update for the static regdomain */
 	/* We always try to get an update for the static regdomain */
 	err = regulatory_hint_core(cfg80211_regdomain->alpha2);
 	err = regulatory_hint_core(cfg80211_regdomain->alpha2);
 	if (err) {
 	if (err) {

+ 9 - 4
net/wireless/scan.c

@@ -601,7 +601,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
 	struct cfg80211_registered_device *rdev;
 	struct cfg80211_registered_device *rdev;
 	struct wiphy *wiphy;
 	struct wiphy *wiphy;
 	struct iw_scan_req *wreq = NULL;
 	struct iw_scan_req *wreq = NULL;
-	struct cfg80211_scan_request *creq;
+	struct cfg80211_scan_request *creq = NULL;
 	int i, err, n_channels = 0;
 	int i, err, n_channels = 0;
 	enum ieee80211_band band;
 	enum ieee80211_band band;
 
 
@@ -694,8 +694,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
 	/* translate "Scan for SSID" request */
 	/* translate "Scan for SSID" request */
 	if (wreq) {
 	if (wreq) {
 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-			if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
-				return -EINVAL;
+			if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
+				err = -EINVAL;
+				goto out;
+			}
 			memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
 			memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
 			creq->ssids[0].ssid_len = wreq->essid_len;
 			creq->ssids[0].ssid_len = wreq->essid_len;
 		}
 		}
@@ -707,12 +709,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
 	err = rdev->ops->scan(wiphy, dev, creq);
 	err = rdev->ops->scan(wiphy, dev, creq);
 	if (err) {
 	if (err) {
 		rdev->scan_req = NULL;
 		rdev->scan_req = NULL;
-		kfree(creq);
+		/* creq will be freed below */
 	} else {
 	} else {
 		nl80211_send_scan_start(rdev, dev);
 		nl80211_send_scan_start(rdev, dev);
+		/* creq now owned by driver */
+		creq = NULL;
 		dev_hold(dev);
 		dev_hold(dev);
 	}
 	}
  out:
  out:
+	kfree(creq);
 	cfg80211_unlock_rdev(rdev);
 	cfg80211_unlock_rdev(rdev);
 	return err;
 	return err;
 }
 }