فهرست منبع

Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next

Johannes Berg 13 سال پیش
والد
کامیت
94d2f0ba05
100فایلهای تغییر یافته به همراه6504 افزوده شده و 1150 حذف شده
  1. 5 5
      arch/arm/mach-omap2/board-omap3evm.c
  2. 2 2
      drivers/bcma/driver_chipcommon_nflash.c
  3. 2 2
      drivers/bcma/driver_chipcommon_sflash.c
  4. 4 0
      drivers/net/wireless/ath/ath5k/phy.c
  5. 2 0
      drivers/net/wireless/ath/ath5k/reset.c
  6. 2 2
      drivers/net/wireless/ath/ath6kl/cfg80211.c
  7. 1 0
      drivers/net/wireless/ath/ath9k/Kconfig
  8. 7 4
      drivers/net/wireless/ath/ath9k/ath9k.h
  9. 87 26
      drivers/net/wireless/ath/ath9k/beacon.c
  10. 1 1
      drivers/net/wireless/ath/ath9k/init.c
  11. 5 8
      drivers/net/wireless/ath/ath9k/main.c
  12. 0 2
      drivers/net/wireless/ath/ath9k/mci.c
  13. 29 6
      drivers/net/wireless/ath/ath9k/recv.c
  14. 2 3
      drivers/net/wireless/ath/ath9k/xmit.c
  15. 1 1
      drivers/net/wireless/ath/carl9170/main.c
  16. 2 1
      drivers/net/wireless/brcm80211/brcmfmac/Makefile
  17. 48 9
      drivers/net/wireless/brcm80211/brcmfmac/dhd.h
  18. 4 15
      drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
  19. 8 0
      drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
  20. 190 121
      drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
  21. 5 20
      drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
  22. 5 6
      drivers/net/wireless/brcm80211/brcmfmac/fweh.c
  23. 5 1
      drivers/net/wireless/brcm80211/brcmfmac/fweh.h
  24. 5 2
      drivers/net/wireless/brcm80211/brcmfmac/fwil.c
  25. 66 0
      drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
  26. 2277 0
      drivers/net/wireless/brcm80211/brcmfmac/p2p.c
  27. 183 0
      drivers/net/wireless/brcm80211/brcmfmac/p2p.h
  28. 3 8
      drivers/net/wireless/brcm80211/brcmfmac/usb.c
  29. 997 374
      drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
  30. 111 2
      drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
  31. 8 5
      drivers/net/wireless/brcm80211/brcmsmac/main.c
  32. 27 12
      drivers/net/wireless/iwlegacy/3945-mac.c
  33. 39 17
      drivers/net/wireless/iwlegacy/4965-mac.c
  34. 1 0
      drivers/net/wireless/iwlegacy/commands.h
  35. 1 0
      drivers/net/wireless/iwlegacy/common.h
  36. 1 1
      drivers/net/wireless/iwlwifi/dvm/mac80211.c
  37. 1 1
      drivers/net/wireless/iwlwifi/mvm/mac80211.c
  38. 0 39
      drivers/net/wireless/mwifiex/11n.c
  39. 0 2
      drivers/net/wireless/mwifiex/11n.h
  40. 2 2
      drivers/net/wireless/mwifiex/Kconfig
  41. 0 1
      drivers/net/wireless/mwifiex/README
  42. 0 2
      drivers/net/wireless/mwifiex/debugfs.c
  43. 0 1
      drivers/net/wireless/mwifiex/init.c
  44. 0 1
      drivers/net/wireless/mwifiex/ioctl.h
  45. 0 2
      drivers/net/wireless/mwifiex/join.c
  46. 0 1
      drivers/net/wireless/mwifiex/main.h
  47. 479 260
      drivers/net/wireless/mwifiex/pcie.c
  48. 178 34
      drivers/net/wireless/mwifiex/pcie.h
  49. 2 3
      drivers/net/wireless/mwifiex/sta_cmdresp.c
  50. 1 1
      drivers/net/wireless/mwifiex/util.c
  51. 2 2
      drivers/net/wireless/mwl8k.c
  52. 1 1
      drivers/net/wireless/p54/p54usb.c
  53. 1 0
      drivers/net/wireless/rt2x00/rt2800pci.c
  54. 30 5
      drivers/net/wireless/rt2x00/rt2800usb.c
  55. 2 1
      drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
  56. 1 1
      drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
  57. 1 1
      drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
  58. 9 2
      drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
  59. 2 2
      drivers/net/wireless/rtlwifi/rtl8192de/dm.c
  60. 0 2
      drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
  61. 0 2
      drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
  62. 2 6
      drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
  63. 2 18
      drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
  64. 0 2
      drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
  65. 3 6
      drivers/net/wireless/rtlwifi/usb.c
  66. 2 1
      drivers/net/wireless/rtlwifi/usb.h
  67. 1 1
      drivers/net/wireless/rtlwifi/wifi.h
  68. 9 0
      drivers/net/wireless/ti/Kconfig
  69. 3 1
      drivers/net/wireless/ti/Makefile
  70. 0 0
      drivers/net/wireless/ti/wilink_platform_data.c
  71. 2 1
      drivers/net/wireless/ti/wl12xx/main.c
  72. 4 3
      drivers/net/wireless/ti/wl18xx/conf.h
  73. 5 0
      drivers/net/wireless/ti/wl18xx/main.c
  74. 0 5
      drivers/net/wireless/ti/wlcore/Kconfig
  75. 0 3
      drivers/net/wireless/ti/wlcore/Makefile
  76. 2 2
      drivers/net/wireless/ti/wlcore/boot.c
  77. 5 3
      drivers/net/wireless/ti/wlcore/cmd.c
  78. 7 10
      drivers/net/wireless/ti/wlcore/main.c
  79. 19 12
      drivers/net/wireless/ti/wlcore/sdio.c
  80. 18 8
      drivers/net/wireless/ti/wlcore/spi.c
  81. 0 1
      drivers/net/wireless/ti/wlcore/wlcore.h
  82. 5 0
      drivers/net/wireless/ti/wlcore/wlcore_i.h
  83. 1 0
      drivers/nfc/Kconfig
  84. 1 0
      drivers/nfc/Makefile
  85. 35 0
      drivers/nfc/microread/Kconfig
  86. 10 0
      drivers/nfc/microread/Makefile
  87. 340 0
      drivers/nfc/microread/i2c.c
  88. 246 0
      drivers/nfc/microread/mei.c
  89. 728 0
      drivers/nfc/microread/microread.c
  90. 33 0
      drivers/nfc/microread/microread.h
  91. 3 5
      drivers/nfc/pn533.c
  92. 1 1
      include/linux/bcma/bcma_driver_chipcommon.h
  93. 8 0
      include/linux/ieee80211.h
  94. 35 0
      include/linux/platform_data/microread.h
  95. 11 5
      include/linux/wl12xx.h
  96. 1 0
      include/net/bluetooth/hci_core.h
  97. 49 11
      include/net/cfg80211.h
  98. 27 13
      include/net/mac80211.h
  99. 35 0
      include/uapi/linux/nl80211.h
  100. 3 7
      net/bluetooth/hci_core.c

+ 5 - 5
arch/arm/mach-omap2/board-omap3evm.c

@@ -309,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] = {
 		.gpio_wp	= 63,
 		.gpio_wp	= 63,
 		.deferred	= true,
 		.deferred	= true,
 	},
 	},
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
 	{
 	{
 		.name		= "wl1271",
 		.name		= "wl1271",
 		.mmc		= 2,
 		.mmc		= 2,
@@ -450,7 +450,7 @@ static struct regulator_init_data omap3evm_vio = {
 	.consumer_supplies	= omap3evm_vio_supply,
 	.consumer_supplies	= omap3evm_vio_supply,
 };
 };
 
 
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
 
 
 #define OMAP3EVM_WLAN_PMENA_GPIO	(150)
 #define OMAP3EVM_WLAN_PMENA_GPIO	(150)
 #define OMAP3EVM_WLAN_IRQ_GPIO		(149)
 #define OMAP3EVM_WLAN_IRQ_GPIO		(149)
@@ -563,7 +563,7 @@ static struct omap_board_mux omap35x_board_mux[] __initdata = {
 				OMAP_PIN_OFF_NONE),
 				OMAP_PIN_OFF_NONE),
 	OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
 	OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
 				OMAP_PIN_OFF_NONE),
 				OMAP_PIN_OFF_NONE),
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
 	/* WLAN IRQ - GPIO 149 */
 	/* WLAN IRQ - GPIO 149 */
 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
 
 
@@ -601,7 +601,7 @@ static struct omap_board_mux omap36x_board_mux[] __initdata = {
 	OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
 	OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
 	OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
 	OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
 	OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
 	OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
 	/* WLAN IRQ - GPIO 149 */
 	/* WLAN IRQ - GPIO 149 */
 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
 
 
@@ -637,7 +637,7 @@ static struct gpio omap3_evm_ehci_gpios[] __initdata = {
 
 
 static void __init omap3_evm_wl12xx_init(void)
 static void __init omap3_evm_wl12xx_init(void)
 {
 {
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
 	int ret;
 	int ret;
 
 
 	/* WL12xx WLAN Init */
 	/* WL12xx WLAN Init */

+ 2 - 2
drivers/bcma/driver_chipcommon_nflash.c

@@ -5,11 +5,11 @@
  * Licensed under the GNU/GPL. See COPYING for details.
  * Licensed under the GNU/GPL. See COPYING for details.
  */
  */
 
 
+#include "bcma_private.h"
+
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 #include <linux/bcma/bcma.h>
 
 
-#include "bcma_private.h"
-
 struct platform_device bcma_nflash_dev = {
 struct platform_device bcma_nflash_dev = {
 	.name		= "bcma_nflash",
 	.name		= "bcma_nflash",
 	.num_resources	= 0,
 	.num_resources	= 0,

+ 2 - 2
drivers/bcma/driver_chipcommon_sflash.c

@@ -5,11 +5,11 @@
  * Licensed under the GNU/GPL. See COPYING for details.
  * Licensed under the GNU/GPL. See COPYING for details.
  */
  */
 
 
+#include "bcma_private.h"
+
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 #include <linux/bcma/bcma.h>
 
 
-#include "bcma_private.h"
-
 static struct resource bcma_sflash_resource = {
 static struct resource bcma_sflash_resource = {
 	.name	= "bcma_sflash",
 	.name	= "bcma_sflash",
 	.start	= BCMA_SOC_FLASH2,
 	.start	= BCMA_SOC_FLASH2,

+ 4 - 0
drivers/net/wireless/ath/ath5k/phy.c

@@ -1613,6 +1613,10 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
 	ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
 	ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
 
 
 	ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
 	ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
+	if (WARN_ON(ee_mode < 0)) {
+		ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF;
+		return;
+	}
 
 
 	/* completed NF calibration, test threshold */
 	/* completed NF calibration, test threshold */
 	nf = ath5k_hw_read_measured_noise_floor(ah);
 	nf = ath5k_hw_read_measured_noise_floor(ah);

+ 2 - 0
drivers/net/wireless/ath/ath5k/reset.c

@@ -985,6 +985,8 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
 		return;
 		return;
 
 
 	ee_mode = ath5k_eeprom_mode_from_channel(channel);
 	ee_mode = ath5k_eeprom_mode_from_channel(channel);
+	if (WARN_ON(ee_mode < 0))
+		return;
 
 
 	/* Adjust power delta for channel 14 */
 	/* Adjust power delta for channel 14 */
 	if (channel->center_freq == 2484)
 	if (channel->center_freq == 2484)

+ 2 - 2
drivers/net/wireless/ath/ath6kl/cfg80211.c

@@ -1778,14 +1778,14 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
 
 
 	if (vif->target_stats.rx_byte) {
 	if (vif->target_stats.rx_byte) {
 		sinfo->rx_bytes = vif->target_stats.rx_byte;
 		sinfo->rx_bytes = vif->target_stats.rx_byte;
-		sinfo->filled |= STATION_INFO_RX_BYTES;
+		sinfo->filled |= STATION_INFO_RX_BYTES64;
 		sinfo->rx_packets = vif->target_stats.rx_pkt;
 		sinfo->rx_packets = vif->target_stats.rx_pkt;
 		sinfo->filled |= STATION_INFO_RX_PACKETS;
 		sinfo->filled |= STATION_INFO_RX_PACKETS;
 	}
 	}
 
 
 	if (vif->target_stats.tx_byte) {
 	if (vif->target_stats.tx_byte) {
 		sinfo->tx_bytes = vif->target_stats.tx_byte;
 		sinfo->tx_bytes = vif->target_stats.tx_byte;
-		sinfo->filled |= STATION_INFO_TX_BYTES;
+		sinfo->filled |= STATION_INFO_TX_BYTES64;
 		sinfo->tx_packets = vif->target_stats.tx_pkt;
 		sinfo->tx_packets = vif->target_stats.tx_pkt;
 		sinfo->filled |= STATION_INFO_TX_PACKETS;
 		sinfo->filled |= STATION_INFO_TX_PACKETS;
 	}
 	}

+ 1 - 0
drivers/net/wireless/ath/ath9k/Kconfig

@@ -58,6 +58,7 @@ config ATH9K_DEBUGFS
 	bool "Atheros ath9k debugging"
 	bool "Atheros ath9k debugging"
 	depends on ATH9K
 	depends on ATH9K
 	select MAC80211_DEBUGFS
 	select MAC80211_DEBUGFS
+	select RELAY
 	---help---
 	---help---
 	  Say Y, if you need access to ath9k's statistics for
 	  Say Y, if you need access to ath9k's statistics for
 	  interrupts, rate control, etc.
 	  interrupts, rate control, etc.

+ 7 - 4
drivers/net/wireless/ath/ath9k/ath9k.h

@@ -319,6 +319,8 @@ struct ath_rx {
 	struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
 	struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
 
 
 	struct sk_buff *frag;
 	struct sk_buff *frag;
+
+	u32 ampdu_ref;
 };
 };
 
 
 int ath_startrecv(struct ath_softc *sc);
 int ath_startrecv(struct ath_softc *sc);
@@ -387,6 +389,7 @@ struct ath_beacon_config {
 	u16 bmiss_timeout;
 	u16 bmiss_timeout;
 	u8 dtim_count;
 	u8 dtim_count;
 	bool enable_beacon;
 	bool enable_beacon;
+	bool ibss_creator;
 };
 };
 
 
 struct ath_beacon {
 struct ath_beacon {
@@ -869,7 +872,7 @@ enum ath_fft_sample_type {
 
 
 struct fft_sample_tlv {
 struct fft_sample_tlv {
 	u8 type;	/* see ath_fft_sample */
 	u8 type;	/* see ath_fft_sample */
-	u16 length;
+	__be16 length;
 	/* type dependent data follows */
 	/* type dependent data follows */
 } __packed;
 } __packed;
 
 
@@ -878,15 +881,15 @@ struct fft_sample_ht20 {
 
 
 	u8 max_exp;
 	u8 max_exp;
 
 
-	u16 freq;
+	__be16 freq;
 	s8 rssi;
 	s8 rssi;
 	s8 noise;
 	s8 noise;
 
 
-	u16 max_magnitude;
+	__be16 max_magnitude;
 	u8 max_index;
 	u8 max_index;
 	u8 bitmap_weight;
 	u8 bitmap_weight;
 
 
-	u64 tsf;
+	__be64 tsf;
 
 
 	u8 data[SPECTRAL_HT20_NUM_BINS];
 	u8 data[SPECTRAL_HT20_NUM_BINS];
 } __packed;
 } __packed;

+ 87 - 26
drivers/net/wireless/ath/ath9k/beacon.c

@@ -407,12 +407,17 @@ void ath9k_beacon_tasklet(unsigned long data)
 	}
 	}
 }
 }
 
 
-static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
+/*
+ * Both nexttbtt and intval have to be in usecs.
+ */
+static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
+			      u32 intval, bool reset_tsf)
 {
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_hw *ah = sc->sc_ah;
 
 
 	ath9k_hw_disable_interrupts(ah);
 	ath9k_hw_disable_interrupts(ah);
-	ath9k_hw_reset_tsf(ah);
+	if (reset_tsf)
+		ath9k_hw_reset_tsf(ah);
 	ath9k_beaconq_config(sc);
 	ath9k_beaconq_config(sc);
 	ath9k_hw_beaconinit(ah, nexttbtt, intval);
 	ath9k_hw_beaconinit(ah, nexttbtt, intval);
 	sc->beacon.bmisscnt = 0;
 	sc->beacon.bmisscnt = 0;
@@ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
 	else
 	else
 		ah->imask &= ~ATH9K_INT_SWBA;
 		ah->imask &= ~ATH9K_INT_SWBA;
 
 
-	ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
+	ath_dbg(common, BEACON,
+		"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+		(conf->enable_beacon) ? "Enable" : "Disable",
 		nexttbtt, intval, conf->beacon_interval);
 		nexttbtt, intval, conf->beacon_interval);
 
 
-	ath9k_beacon_init(sc, nexttbtt, intval);
+	ath9k_beacon_init(sc, nexttbtt, intval, true);
 }
 }
 
 
 /*
 /*
@@ -586,17 +593,45 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
 	ath9k_reset_beacon_status(sc);
 	ath9k_reset_beacon_status(sc);
 
 
 	intval = TU_TO_USEC(conf->beacon_interval);
 	intval = TU_TO_USEC(conf->beacon_interval);
-	nexttbtt = intval;
+
+	if (conf->ibss_creator) {
+		nexttbtt = intval;
+	} else {
+		u32 tbtt, offset, tsftu;
+		u64 tsf;
+
+		/*
+		 * Pull nexttbtt forward to reflect the current
+		 * sync'd TSF.
+		 */
+		tsf = ath9k_hw_gettsf64(ah);
+		tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
+		offset = tsftu % conf->beacon_interval;
+		tbtt = tsftu - offset;
+		if (offset)
+			tbtt += conf->beacon_interval;
+
+		nexttbtt = TU_TO_USEC(tbtt);
+	}
 
 
 	if (conf->enable_beacon)
 	if (conf->enable_beacon)
 		ah->imask |= ATH9K_INT_SWBA;
 		ah->imask |= ATH9K_INT_SWBA;
 	else
 	else
 		ah->imask &= ~ATH9K_INT_SWBA;
 		ah->imask &= ~ATH9K_INT_SWBA;
 
 
-	ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
+	ath_dbg(common, BEACON,
+		"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+		(conf->enable_beacon) ? "Enable" : "Disable",
 		nexttbtt, intval, conf->beacon_interval);
 		nexttbtt, intval, conf->beacon_interval);
 
 
-	ath9k_beacon_init(sc, nexttbtt, intval);
+	ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator);
+
+	/*
+	 * Set the global 'beacon has been configured' flag for the
+	 * joiner case in IBSS mode.
+	 */
+	if (!conf->ibss_creator && conf->enable_beacon)
+		set_bit(SC_OP_BEACONS, &sc->sc_flags);
 }
 }
 
 
 bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
 bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
@@ -639,6 +674,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
 	cur_conf->dtim_period = bss_conf->dtim_period;
 	cur_conf->dtim_period = bss_conf->dtim_period;
 	cur_conf->listen_interval = 1;
 	cur_conf->listen_interval = 1;
 	cur_conf->dtim_count = 1;
 	cur_conf->dtim_count = 1;
+	cur_conf->ibss_creator = bss_conf->ibss_creator;
 	cur_conf->bmiss_timeout =
 	cur_conf->bmiss_timeout =
 		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
 		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
 
 
@@ -666,34 +702,59 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
 {
 {
 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
 	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+	unsigned long flags;
+	bool skip_beacon = false;
 
 
 	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
 	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
 		ath9k_cache_beacon_config(sc, bss_conf);
 		ath9k_cache_beacon_config(sc, bss_conf);
 		ath9k_set_beacon(sc);
 		ath9k_set_beacon(sc);
 		set_bit(SC_OP_BEACONS, &sc->sc_flags);
 		set_bit(SC_OP_BEACONS, &sc->sc_flags);
-	} else {
-		/*
-		 * Take care of multiple interfaces when
-		 * enabling/disabling SWBA.
-		 */
-		if (changed & BSS_CHANGED_BEACON_ENABLED) {
-			if (!bss_conf->enable_beacon &&
-			    (sc->nbcnvifs <= 1)) {
-				cur_conf->enable_beacon = false;
-			} else if (bss_conf->enable_beacon) {
-				cur_conf->enable_beacon = true;
-				ath9k_cache_beacon_config(sc, bss_conf);
-			}
+		return;
+
+	}
+
+	/*
+	 * Take care of multiple interfaces when
+	 * enabling/disabling SWBA.
+	 */
+	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+		if (!bss_conf->enable_beacon &&
+		    (sc->nbcnvifs <= 1)) {
+			cur_conf->enable_beacon = false;
+		} else if (bss_conf->enable_beacon) {
+			cur_conf->enable_beacon = true;
+			ath9k_cache_beacon_config(sc, bss_conf);
 		}
 		}
+	}
 
 
-		if (cur_conf->beacon_interval) {
+	/*
+	 * Configure the HW beacon registers only when we have a valid
+	 * beacon interval.
+	 */
+	if (cur_conf->beacon_interval) {
+		/*
+		 * If we are joining an existing IBSS network, start beaconing
+		 * only after a TSF-sync has taken place. Ensure that this
+		 * happens by setting the appropriate flags.
+		 */
+		if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
+		    bss_conf->enable_beacon) {
+			spin_lock_irqsave(&sc->sc_pm_lock, flags);
+			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+			spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+			skip_beacon = true;
+		} else {
 			ath9k_set_beacon(sc);
 			ath9k_set_beacon(sc);
-
-			if (cur_conf->enable_beacon)
-				set_bit(SC_OP_BEACONS, &sc->sc_flags);
-			else
-				clear_bit(SC_OP_BEACONS, &sc->sc_flags);
 		}
 		}
+
+		/*
+		 * Do not set the SC_OP_BEACONS flag for IBSS joiner mode
+		 * here, it is done in ath9k_beacon_config_adhoc().
+		 */
+		if (cur_conf->enable_beacon && !skip_beacon)
+			set_bit(SC_OP_BEACONS, &sc->sc_flags);
+		else
+			clear_bit(SC_OP_BEACONS, &sc->sc_flags);
 	}
 	}
 }
 }
 
 

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

@@ -922,7 +922,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 
 
 	ath9k_eeprom_release(sc);
 	ath9k_eeprom_release(sc);
 
 
-	if (sc->rfs_chan_spec_scan) {
+	if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
 		relay_close(sc->rfs_chan_spec_scan);
 		relay_close(sc->rfs_chan_spec_scan);
 		sc->rfs_chan_spec_scan = NULL;
 		sc->rfs_chan_spec_scan = NULL;
 	}
 	}

+ 5 - 8
drivers/net/wireless/ath/ath9k/main.c

@@ -320,28 +320,25 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
 			    struct ieee80211_vif *vif)
 			    struct ieee80211_vif *vif)
 {
 {
 	struct ath_node *an;
 	struct ath_node *an;
-	u8 density;
 	an = (struct ath_node *)sta->drv_priv;
 	an = (struct ath_node *)sta->drv_priv;
 
 
 	an->sc = sc;
 	an->sc = sc;
 	an->sta = sta;
 	an->sta = sta;
 	an->vif = vif;
 	an->vif = vif;
 
 
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
-		ath_tx_node_init(sc, an);
+	ath_tx_node_init(sc, an);
+
+	if (sta->ht_cap.ht_supported) {
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 				     sta->ht_cap.ampdu_factor);
 				     sta->ht_cap.ampdu_factor);
-		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
-		an->mpdudensity = density;
+		an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
 	}
 	}
 }
 }
 
 
 static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
 {
 	struct ath_node *an = (struct ath_node *)sta->drv_priv;
 	struct ath_node *an = (struct ath_node *)sta->drv_priv;
-
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
-		ath_tx_node_cleanup(sc, an);
+	ath_tx_node_cleanup(sc, an);
 }
 }
 
 
 void ath9k_tasklet(unsigned long data)
 void ath9k_tasklet(unsigned long data)

+ 0 - 2
drivers/net/wireless/ath/ath9k/mci.c

@@ -474,8 +474,6 @@ void ath_mci_cleanup(struct ath_softc *sc)
 {
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_hw *ah = sc->sc_ah;
-	struct ath_mci_coex *mci = &sc->mci_coex;
-	struct ath_mci_buf *buf = &mci->sched_buf;
 
 
 	ar9003_mci_cleanup(ah);
 	ar9003_mci_cleanup(ah);
 
 

+ 29 - 6
drivers/net/wireless/ath/ath9k/recv.c

@@ -533,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
 	if (sc->ps_flags & PS_BEACON_SYNC) {
 	if (sc->ps_flags & PS_BEACON_SYNC) {
 		sc->ps_flags &= ~PS_BEACON_SYNC;
 		sc->ps_flags &= ~PS_BEACON_SYNC;
 		ath_dbg(common, PS,
 		ath_dbg(common, PS,
-			"Reconfigure Beacon timers based on timestamp from the AP\n");
+			"Reconfigure beacon timers based on synchronized timestamp\n");
 		ath9k_set_beacon(sc);
 		ath9k_set_beacon(sc);
 	}
 	}
 
 
@@ -1016,18 +1016,20 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
 		rxs->flag &= ~RX_FLAG_DECRYPTED;
 		rxs->flag &= ~RX_FLAG_DECRYPTED;
 }
 }
 
 
+#ifdef CONFIG_ATH9K_DEBUGFS
 static s8 fix_rssi_inv_only(u8 rssi_val)
 static s8 fix_rssi_inv_only(u8 rssi_val)
 {
 {
 	if (rssi_val == 128)
 	if (rssi_val == 128)
 		rssi_val = 0;
 		rssi_val = 0;
 	return (s8) rssi_val;
 	return (s8) rssi_val;
 }
 }
+#endif
 
 
 /* returns 1 if this was a spectral frame, even if not handled. */
 /* returns 1 if this was a spectral frame, even if not handled. */
 static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 			   struct ath_rx_status *rs, u64 tsf)
 			   struct ath_rx_status *rs, u64 tsf)
 {
 {
-#ifdef CONFIG_ATH_DEBUG
+#ifdef CONFIG_ATH9K_DEBUGFS
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_hw *ah = sc->sc_ah;
 	u8 bins[SPECTRAL_HT20_NUM_BINS];
 	u8 bins[SPECTRAL_HT20_NUM_BINS];
 	u8 *vdata = (u8 *)hdr;
 	u8 *vdata = (u8 *)hdr;
@@ -1036,6 +1038,7 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 	struct ath_ht20_mag_info *mag_info;
 	struct ath_ht20_mag_info *mag_info;
 	int len = rs->rs_datalen;
 	int len = rs->rs_datalen;
 	int dc_pos;
 	int dc_pos;
+	u16 length, max_magnitude;
 
 
 	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
 	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
 	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
 	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
@@ -1063,8 +1066,8 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 		return 1;
 		return 1;
 
 
 	fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
 	fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
-	fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
-	fft_sample.tlv.length = __cpu_to_be16(fft_sample.tlv.length);
+	length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
+	fft_sample.tlv.length = __cpu_to_be16(length);
 
 
 	fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
 	fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
 	fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
 	fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
@@ -1110,8 +1113,8 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 	memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS);
 	memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS);
 	fft_sample.max_exp = mag_info->max_exp & 0xf;
 	fft_sample.max_exp = mag_info->max_exp & 0xf;
 
 
-	fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins);
-	fft_sample.max_magnitude = __cpu_to_be16(fft_sample.max_magnitude);
+	max_magnitude = spectral_max_magnitude(mag_info->all_bins);
+	fft_sample.max_magnitude = __cpu_to_be16(max_magnitude);
 	fft_sample.max_index = spectral_max_index(mag_info->all_bins);
 	fft_sample.max_index = spectral_max_index(mag_info->all_bins);
 	fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
 	fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
 	fft_sample.tsf = __cpu_to_be64(tsf);
 	fft_sample.tsf = __cpu_to_be64(tsf);
@@ -1123,6 +1126,24 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
 #endif
 #endif
 }
 }
 
 
+static void ath9k_apply_ampdu_details(struct ath_softc *sc,
+	struct ath_rx_status *rs, struct ieee80211_rx_status *rxs)
+{
+	if (rs->rs_isaggr) {
+		rxs->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN;
+
+		rxs->ampdu_reference = sc->rx.ampdu_ref;
+
+		if (!rs->rs_moreaggr) {
+			rxs->flag |= RX_FLAG_AMPDU_IS_LAST;
+			sc->rx.ampdu_ref++;
+		}
+
+		if (rs->rs_flags & ATH9K_RX_DELIM_CRC_PRE)
+			rxs->flag |= RX_FLAG_AMPDU_DELIM_CRC_ERROR;
+	}
+}
+
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
 {
 	struct ath_buf *bf;
 	struct ath_buf *bf;
@@ -1329,6 +1350,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 		if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
 		if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
 			ath_ant_comb_scan(sc, &rs);
 			ath_ant_comb_scan(sc, &rs);
 
 
+		ath9k_apply_ampdu_details(sc, &rs, rxs);
+
 		ieee80211_rx(hw, skb);
 		ieee80211_rx(hw, skb);
 
 
 requeue_drop_frag:
 requeue_drop_frag:

+ 2 - 3
drivers/net/wireless/ath/ath9k/xmit.c

@@ -1233,7 +1233,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 	 * in HT IBSS when a beacon with HT-info is received after the station
 	 * in HT IBSS when a beacon with HT-info is received after the station
 	 * has already been added.
 	 * has already been added.
 	 */
 	 */
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+	if (sta->ht_cap.ht_supported) {
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 				     sta->ht_cap.ampdu_factor);
 				     sta->ht_cap.ampdu_factor);
 		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
 		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
@@ -1904,8 +1904,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
 	struct ath_buf *bf;
 	struct ath_buf *bf;
 	u8 tidno;
 	u8 tidno;
 
 
-	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an &&
-		ieee80211_is_data_qos(hdr->frame_control)) {
+	if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
 		tidno = ieee80211_get_qos_ctl(hdr)[0] &
 		tidno = ieee80211_get_qos_ctl(hdr)[0] &
 			IEEE80211_QOS_CTL_TID_MASK;
 			IEEE80211_QOS_CTL_TID_MASK;
 		tid = ATH_AN_2_TID(txctl->an, tidno);
 		tid = ATH_AN_2_TID(txctl->an, tidno);

+ 1 - 1
drivers/net/wireless/ath/carl9170/main.c

@@ -1853,7 +1853,7 @@ void *carl9170_alloc(size_t priv_size)
 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		     IEEE80211_HW_SUPPORTS_PS |
 		     IEEE80211_HW_SUPPORTS_PS |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
-		     IEEE80211_HW_NEED_DTIM_PERIOD |
+		     IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
 		     IEEE80211_HW_SIGNAL_DBM;
 		     IEEE80211_HW_SIGNAL_DBM;
 
 
 	if (!modparam_noht) {
 	if (!modparam_noht) {

+ 2 - 1
drivers/net/wireless/brcm80211/brcmfmac/Makefile

@@ -26,6 +26,7 @@ brcmfmac-objs += \
 		wl_cfg80211.o \
 		wl_cfg80211.o \
 		fwil.o \
 		fwil.o \
 		fweh.o \
 		fweh.o \
+		p2p.o \
 		dhd_cdc.o \
 		dhd_cdc.o \
 		dhd_common.o \
 		dhd_common.o \
 		dhd_linux.o
 		dhd_linux.o
@@ -37,4 +38,4 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
 		usb.o
 		usb.o
 brcmfmac-$(CONFIG_BRCMDBG) += \
 brcmfmac-$(CONFIG_BRCMDBG) += \
-		dhd_dbg.o
+		dhd_dbg.o

+ 48 - 9
drivers/net/wireless/brcm80211/brcmfmac/dhd.h

@@ -72,6 +72,7 @@
 #define BRCMF_C_SET_WSEC			134
 #define BRCMF_C_SET_WSEC			134
 #define BRCMF_C_GET_PHY_NOISE			135
 #define BRCMF_C_GET_PHY_NOISE			135
 #define BRCMF_C_GET_BSS_INFO			136
 #define BRCMF_C_GET_BSS_INFO			136
+#define BRCMF_C_SET_SCB_TIMEOUT			158
 #define BRCMF_C_GET_PHYLIST			180
 #define BRCMF_C_GET_PHYLIST			180
 #define BRCMF_C_SET_SCAN_CHANNEL_TIME		185
 #define BRCMF_C_SET_SCAN_CHANNEL_TIME		185
 #define BRCMF_C_SET_SCAN_UNASSOC_TIME		187
 #define BRCMF_C_SET_SCAN_UNASSOC_TIME		187
@@ -149,6 +150,7 @@
 #define BRCMF_E_REASON_MINTXRATE		9
 #define BRCMF_E_REASON_MINTXRATE		9
 #define BRCMF_E_REASON_TXFAIL			10
 #define BRCMF_E_REASON_TXFAIL			10
 
 
+#define BRCMF_E_REASON_LINK_BSSCFG_DIS		4
 #define BRCMF_E_REASON_FAST_ROAM_FAILED		5
 #define BRCMF_E_REASON_FAST_ROAM_FAILED		5
 #define BRCMF_E_REASON_DIRECTED_ROAM		6
 #define BRCMF_E_REASON_DIRECTED_ROAM		6
 #define BRCMF_E_REASON_TSPEC_REJECTED		7
 #define BRCMF_E_REASON_TSPEC_REJECTED		7
@@ -375,6 +377,28 @@ struct brcmf_join_params {
 	struct brcmf_assoc_params_le params_le;
 	struct brcmf_assoc_params_le params_le;
 };
 };
 
 
+/* scan params for extended join */
+struct brcmf_join_scan_params_le {
+	u8 scan_type;		/* 0 use default, active or passive scan */
+	__le32 nprobes;		/* -1 use default, nr of probes per channel */
+	__le32 active_time;	/* -1 use default, dwell time per channel for
+				 * active scanning
+				 */
+	__le32 passive_time;	/* -1 use default, dwell time per channel
+				 * for passive scanning
+				 */
+	__le32 home_time;	/* -1 use default, dwell time for the home
+				 * channel between channel scans
+				 */
+};
+
+/* extended join params */
+struct brcmf_ext_join_params_le {
+	struct brcmf_ssid_le ssid_le;	/* {0, ""}: wildcard scan */
+	struct brcmf_join_scan_params_le scan_le;
+	struct brcmf_assoc_params_le assoc_le;
+};
+
 struct brcmf_wsec_key {
 struct brcmf_wsec_key {
 	u32 index;		/* key index */
 	u32 index;		/* key index */
 	u32 len;		/* key length */
 	u32 len;		/* key length */
@@ -451,6 +475,19 @@ struct brcmf_sta_info_le {
 	__le32	rx_decrypt_failures;	/* # of packet decrypted failed */
 	__le32	rx_decrypt_failures;	/* # of packet decrypted failed */
 };
 };
 
 
+/*
+ * WLC_E_PROBRESP_MSG
+ * WLC_E_P2P_PROBREQ_MSG
+ * WLC_E_ACTION_FRAME_RX
+ */
+struct brcmf_rx_mgmt_data {
+	__be16	version;
+	__be16	chanspec;
+	__be32	rssi;
+	__be32	mactime;
+	__be32	rate;
+};
+
 /* Bus independent dongle command */
 /* Bus independent dongle command */
 struct brcmf_dcmd {
 struct brcmf_dcmd {
 	uint cmd;		/* common dongle cmd definition */
 	uint cmd;		/* common dongle cmd definition */
@@ -489,9 +526,6 @@ struct brcmf_pub {
 	struct mutex proto_block;
 	struct mutex proto_block;
 	unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 	unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 
 
-	atomic_t pend_8021x_cnt;
-	wait_queue_head_t pend_8021x_wait;
-
 	struct brcmf_fweh_info fweh;
 	struct brcmf_fweh_info fweh;
 #ifdef DEBUG
 #ifdef DEBUG
 	struct dentry *dbgfs_dir;
 	struct dentry *dbgfs_dir;
@@ -515,9 +549,11 @@ struct brcmf_cfg80211_vif;
  * @vif: points to cfg80211 specific interface information.
  * @vif: points to cfg80211 specific interface information.
  * @ndev: associated network device.
  * @ndev: associated network device.
  * @stats: interface specific network statistics.
  * @stats: interface specific network statistics.
- * @idx: interface index in device firmware.
+ * @ifidx: interface index in device firmware.
  * @bssidx: index of bss associated with this interface.
  * @bssidx: index of bss associated with this interface.
  * @mac_addr: assigned mac address.
  * @mac_addr: assigned mac address.
+ * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
+ * @pend_8021x_wait: used for signalling change in count.
  */
  */
 struct brcmf_if {
 struct brcmf_if {
 	struct brcmf_pub *drvr;
 	struct brcmf_pub *drvr;
@@ -526,9 +562,11 @@ struct brcmf_if {
 	struct net_device_stats stats;
 	struct net_device_stats stats;
 	struct work_struct setmacaddr_work;
 	struct work_struct setmacaddr_work;
 	struct work_struct multicast_work;
 	struct work_struct multicast_work;
-	int idx;
+	int ifidx;
 	s32 bssidx;
 	s32 bssidx;
 	u8 mac_addr[ETH_ALEN];
 	u8 mac_addr[ETH_ALEN];
+	atomic_t pend_8021x_cnt;
+	wait_queue_head_t pend_8021x_wait;
 };
 };
 
 
 
 
@@ -547,9 +585,10 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
 extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
 extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
 			       struct sk_buff *rxp);
 			       struct sk_buff *rxp);
 
 
-extern int brcmf_net_attach(struct brcmf_if *ifp);
-extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx,
-				     s32 bssidx, char *name, u8 *mac_addr);
-extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx);
+extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
+extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx,
+				     s32 ifidx, char *name, u8 *mac_addr);
+extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
+extern u32 brcmf_get_chip_info(struct brcmf_if *ifp);
 
 
 #endif				/* _BRCMF_H_ */
 #endif				/* _BRCMF_H_ */

+ 4 - 15
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h

@@ -24,18 +24,6 @@ enum brcmf_bus_state {
 	BRCMF_BUS_DATA		/* Ready for frame transfers */
 	BRCMF_BUS_DATA		/* Ready for frame transfers */
 };
 };
 
 
-struct dngl_stats {
-	unsigned long rx_packets;	/* total packets received */
-	unsigned long tx_packets;	/* total packets transmitted */
-	unsigned long rx_bytes;	/* total bytes received */
-	unsigned long tx_bytes;	/* total bytes transmitted */
-	unsigned long rx_errors;	/* bad packets received */
-	unsigned long tx_errors;	/* packet transmit problems */
-	unsigned long rx_dropped;	/* packets dropped by dongle */
-	unsigned long tx_dropped;	/* packets dropped by dongle */
-	unsigned long multicast;	/* multicast packets received */
-};
-
 struct brcmf_bus_dcmd {
 struct brcmf_bus_dcmd {
 	char *name;
 	char *name;
 	char *param;
 	char *param;
@@ -72,11 +60,12 @@ struct brcmf_bus_ops {
  * @drvr: public driver information.
  * @drvr: public driver information.
  * @state: operational state of the bus interface.
  * @state: operational state of the bus interface.
  * @maxctl: maximum size for rxctl request message.
  * @maxctl: maximum size for rxctl request message.
- * @drvr_up: indicates driver up/down status.
  * @tx_realloc: number of tx packets realloced for headroom.
  * @tx_realloc: number of tx packets realloced for headroom.
  * @dstats: dongle-based statistical data.
  * @dstats: dongle-based statistical data.
  * @align: alignment requirement for the bus.
  * @align: alignment requirement for the bus.
  * @dcmd_list: bus/device specific dongle initialization commands.
  * @dcmd_list: bus/device specific dongle initialization commands.
+ * @chip: device identifier of the dongle chip.
+ * @chiprev: revision of the dongle chip.
  */
  */
 struct brcmf_bus {
 struct brcmf_bus {
 	union {
 	union {
@@ -87,10 +76,10 @@ struct brcmf_bus {
 	struct brcmf_pub *drvr;
 	struct brcmf_pub *drvr;
 	enum brcmf_bus_state state;
 	enum brcmf_bus_state state;
 	uint maxctl;
 	uint maxctl;
-	bool drvr_up;
 	unsigned long tx_realloc;
 	unsigned long tx_realloc;
-	struct dngl_stats dstats;
 	u8 align;
 	u8 align;
+	u32 chip;
+	u32 chiprev;
 	struct list_head dcmd_list;
 	struct list_head dcmd_list;
 
 
 	struct brcmf_bus_ops *ops;
 	struct brcmf_bus_ops *ops;

+ 8 - 0
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c

@@ -303,6 +303,14 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
 		brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
 		brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
 		return -EBADE;
 		return -EBADE;
 	}
 	}
+	/* The ifidx is the idx to map to matching netdev/ifp. When receiving
+	 * events this is easy because it contains the bssidx which maps
+	 * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+	 * bssidx 1 is used for p2p0 and no data can be received or
+	 * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+	 */
+	if (*ifidx)
+		(*ifidx)++;
 
 
 	if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
 	if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
 	    BDC_PROTO_VER) {
 	    BDC_PROTO_VER) {

+ 190 - 121
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c

@@ -26,6 +26,8 @@
 #include "dhd_bus.h"
 #include "dhd_bus.h"
 #include "dhd_proto.h"
 #include "dhd_proto.h"
 #include "dhd_dbg.h"
 #include "dhd_dbg.h"
+#include "fwil_types.h"
+#include "p2p.h"
 #include "wl_cfg80211.h"
 #include "wl_cfg80211.h"
 #include "fwil.h"
 #include "fwil.h"
 
 
@@ -40,6 +42,12 @@ MODULE_LICENSE("Dual BSD/GPL");
 int brcmf_msg_level;
 int brcmf_msg_level;
 module_param(brcmf_msg_level, int, 0);
 module_param(brcmf_msg_level, int, 0);
 
 
+/* P2P0 enable */
+static int brcmf_p2p_enable;
+#ifdef CONFIG_BRCMDBG
+module_param_named(p2pon, brcmf_p2p_enable, int, 0);
+MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
+#endif
 
 
 char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
 char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
 {
 {
@@ -70,9 +78,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
 	u32 buflen;
 	u32 buflen;
 	s32 err;
 	s32 err;
 
 
-	brcmf_dbg(TRACE, "enter\n");
-
 	ifp = container_of(work, struct brcmf_if, multicast_work);
 	ifp = container_of(work, struct brcmf_if, multicast_work);
+
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
 	ndev = ifp->ndev;
 	ndev = ifp->ndev;
 
 
 	/* Determine initial value of allmulti flag */
 	/* Determine initial value of allmulti flag */
@@ -129,9 +138,10 @@ _brcmf_set_mac_address(struct work_struct *work)
 	struct brcmf_if *ifp;
 	struct brcmf_if *ifp;
 	s32 err;
 	s32 err;
 
 
-	brcmf_dbg(TRACE, "enter\n");
-
 	ifp = container_of(work, struct brcmf_if, setmacaddr_work);
 	ifp = container_of(work, struct brcmf_if, setmacaddr_work);
+
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
 	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
 	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
 				       ETH_ALEN);
 				       ETH_ALEN);
 	if (err < 0) {
 	if (err < 0) {
@@ -168,7 +178,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct ethhdr *eh;
 	struct ethhdr *eh;
 
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 
 	/* Can the device send data? */
 	/* Can the device send data? */
 	if (drvr->bus_if->state != BRCMF_BUS_DATA) {
 	if (drvr->bus_if->state != BRCMF_BUS_DATA) {
@@ -179,8 +189,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
 		goto done;
 		goto done;
 	}
 	}
 
 
-	if (!drvr->iflist[ifp->idx]) {
-		brcmf_err("bad ifidx %d\n", ifp->idx);
+	if (!drvr->iflist[ifp->bssidx]) {
+		brcmf_err("bad ifidx %d\n", ifp->bssidx);
 		netif_stop_queue(ndev);
 		netif_stop_queue(ndev);
 		dev_kfree_skb(skb);
 		dev_kfree_skb(skb);
 		ret = -ENODEV;
 		ret = -ENODEV;
@@ -192,14 +202,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
 		struct sk_buff *skb2;
 		struct sk_buff *skb2;
 
 
 		brcmf_dbg(INFO, "%s: insufficient headroom\n",
 		brcmf_dbg(INFO, "%s: insufficient headroom\n",
-			  brcmf_ifname(drvr, ifp->idx));
+			  brcmf_ifname(drvr, ifp->bssidx));
 		drvr->bus_if->tx_realloc++;
 		drvr->bus_if->tx_realloc++;
 		skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
 		skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
 		dev_kfree_skb(skb);
 		dev_kfree_skb(skb);
 		skb = skb2;
 		skb = skb2;
 		if (skb == NULL) {
 		if (skb == NULL) {
 			brcmf_err("%s: skb_realloc_headroom failed\n",
 			brcmf_err("%s: skb_realloc_headroom failed\n",
-				  brcmf_ifname(drvr, ifp->idx));
+				  brcmf_ifname(drvr, ifp->bssidx));
 			ret = -ENOMEM;
 			ret = -ENOMEM;
 			goto done;
 			goto done;
 		}
 		}
@@ -217,19 +227,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
 	if (is_multicast_ether_addr(eh->h_dest))
 	if (is_multicast_ether_addr(eh->h_dest))
 		drvr->tx_multicast++;
 		drvr->tx_multicast++;
 	if (ntohs(eh->h_proto) == ETH_P_PAE)
 	if (ntohs(eh->h_proto) == ETH_P_PAE)
-		atomic_inc(&drvr->pend_8021x_cnt);
+		atomic_inc(&ifp->pend_8021x_cnt);
 
 
 	/* If the protocol uses a data header, apply it */
 	/* If the protocol uses a data header, apply it */
-	brcmf_proto_hdrpush(drvr, ifp->idx, skb);
+	brcmf_proto_hdrpush(drvr, ifp->ifidx, skb);
 
 
 	/* Use bus module to send data frame */
 	/* Use bus module to send data frame */
 	ret =  brcmf_bus_txdata(drvr->bus_if, skb);
 	ret =  brcmf_bus_txdata(drvr->bus_if, skb);
 
 
 done:
 done:
-	if (ret)
-		drvr->bus_if->dstats.tx_dropped++;
-	else
-		drvr->bus_if->dstats.tx_packets++;
+	if (ret) {
+		ifp->stats.tx_dropped++;
+	} else {
+		ifp->stats.tx_packets++;
+		ifp->stats.tx_bytes += skb->len;
+	}
 
 
 	/* Return ok: we always eat the packet */
 	/* Return ok: we always eat the packet */
 	return NETDEV_TX_OK;
 	return NETDEV_TX_OK;
@@ -270,12 +282,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 	skb_queue_walk_safe(skb_list, skb, pnext) {
 	skb_queue_walk_safe(skb_list, skb, pnext) {
 		skb_unlink(skb, skb_list);
 		skb_unlink(skb, skb_list);
 
 
-		/* process and remove protocol-specific header
-		 */
+		/* process and remove protocol-specific header */
 		ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
 		ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
-		if (ret < 0) {
-			if (ret != -ENODATA)
-				bus_if->dstats.rx_errors++;
+		ifp = drvr->iflist[ifidx];
+
+		if (ret || !ifp || !ifp->ndev) {
+			if ((ret != -ENODATA) && ifp)
+				ifp->stats.rx_errors++;
 			brcmu_pkt_buf_free_skb(skb);
 			brcmu_pkt_buf_free_skb(skb);
 			continue;
 			continue;
 		}
 		}
@@ -295,21 +308,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 		eth = skb->data;
 		eth = skb->data;
 		len = skb->len;
 		len = skb->len;
 
 
-		ifp = drvr->iflist[ifidx];
-		if (ifp == NULL)
-			ifp = drvr->iflist[0];
-
-		if (!ifp || !ifp->ndev ||
-		    ifp->ndev->reg_state != NETREG_REGISTERED) {
-			brcmu_pkt_buf_free_skb(skb);
-			continue;
-		}
-
 		skb->dev = ifp->ndev;
 		skb->dev = ifp->ndev;
 		skb->protocol = eth_type_trans(skb, skb->dev);
 		skb->protocol = eth_type_trans(skb, skb->dev);
 
 
 		if (skb->pkt_type == PACKET_MULTICAST)
 		if (skb->pkt_type == PACKET_MULTICAST)
-			bus_if->dstats.multicast++;
+			ifp->stats.multicast++;
 
 
 		skb->data = eth;
 		skb->data = eth;
 		skb->len = len;
 		skb->len = len;
@@ -325,8 +328,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 			ifp->ndev->last_rx = jiffies;
 			ifp->ndev->last_rx = jiffies;
 		}
 		}
 
 
-		bus_if->dstats.rx_bytes += skb->len;
-		bus_if->dstats.rx_packets++;	/* Local count */
+		if (!(ifp->ndev->flags & IFF_UP)) {
+			brcmu_pkt_buf_free_skb(skb);
+			continue;
+		}
+
+		ifp->stats.rx_bytes += skb->len;
+		ifp->stats.rx_packets++;
 
 
 		if (in_interrupt())
 		if (in_interrupt())
 			netif_rx(skb);
 			netif_rx(skb);
@@ -348,36 +356,31 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
 	u16 type;
 	u16 type;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
 	struct brcmf_pub *drvr = bus_if->drvr;
+	struct brcmf_if *ifp;
 
 
 	brcmf_proto_hdrpull(drvr, &ifidx, txp);
 	brcmf_proto_hdrpull(drvr, &ifidx, txp);
 
 
+	ifp = drvr->iflist[ifidx];
+	if (!ifp)
+		return;
+
 	eh = (struct ethhdr *)(txp->data);
 	eh = (struct ethhdr *)(txp->data);
 	type = ntohs(eh->h_proto);
 	type = ntohs(eh->h_proto);
 
 
 	if (type == ETH_P_PAE) {
 	if (type == ETH_P_PAE) {
-		atomic_dec(&drvr->pend_8021x_cnt);
-		if (waitqueue_active(&drvr->pend_8021x_wait))
-			wake_up(&drvr->pend_8021x_wait);
+		atomic_dec(&ifp->pend_8021x_cnt);
+		if (waitqueue_active(&ifp->pend_8021x_wait))
+			wake_up(&ifp->pend_8021x_wait);
 	}
 	}
+	if (!success)
+		ifp->stats.tx_errors++;
 }
 }
 
 
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
 {
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcmf_bus *bus_if = ifp->drvr->bus_if;
-
-	brcmf_dbg(TRACE, "Enter\n");
 
 
-	/* Copy dongle stats to net device stats */
-	ifp->stats.rx_packets = bus_if->dstats.rx_packets;
-	ifp->stats.tx_packets = bus_if->dstats.tx_packets;
-	ifp->stats.rx_bytes = bus_if->dstats.rx_bytes;
-	ifp->stats.tx_bytes = bus_if->dstats.tx_bytes;
-	ifp->stats.rx_errors = bus_if->dstats.rx_errors;
-	ifp->stats.tx_errors = bus_if->dstats.tx_errors;
-	ifp->stats.rx_dropped = bus_if->dstats.rx_dropped;
-	ifp->stats.tx_dropped = bus_if->dstats.tx_dropped;
-	ifp->stats.multicast = bus_if->dstats.multicast;
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 
 	return &ifp->stats;
 	return &ifp->stats;
 }
 }
@@ -429,7 +432,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
 	u32 toe_cmpnt, csum_dir;
 	u32 toe_cmpnt, csum_dir;
 	int ret;
 	int ret;
 
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 
 	/* all ethtool calls start with a cmd word */
 	/* all ethtool calls start with a cmd word */
 	if (copy_from_user(&cmd, uaddr, sizeof(u32)))
 	if (copy_from_user(&cmd, uaddr, sizeof(u32)))
@@ -452,13 +455,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
 			sprintf(info.driver, "dhd");
 			sprintf(info.driver, "dhd");
 			strcpy(info.version, BRCMF_VERSION_STR);
 			strcpy(info.version, BRCMF_VERSION_STR);
 		}
 		}
-
-		/* otherwise, require dongle to be up */
-		else if (!drvr->bus_if->drvr_up) {
-			brcmf_err("dongle is not up\n");
-			return -ENODEV;
-		}
-		/* finally, report dongle driver type */
+		/* report dongle driver type */
 		else
 		else
 			sprintf(info.driver, "wl");
 			sprintf(info.driver, "wl");
 
 
@@ -532,9 +529,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct brcmf_pub *drvr = ifp->drvr;
 
 
-	brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
+	brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd);
 
 
-	if (!drvr->iflist[ifp->idx])
+	if (!drvr->iflist[ifp->bssidx])
 		return -1;
 		return -1;
 
 
 	if (cmd == SIOCETHTOOL)
 	if (cmd == SIOCETHTOOL)
@@ -546,17 +543,12 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
 static int brcmf_netdev_stop(struct net_device *ndev)
 static int brcmf_netdev_stop(struct net_device *ndev)
 {
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcmf_pub *drvr = ifp->drvr;
-
-	brcmf_dbg(TRACE, "Enter\n");
 
 
-	if (drvr->bus_if->drvr_up == 0)
-		return 0;
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 
 	brcmf_cfg80211_down(ndev);
 	brcmf_cfg80211_down(ndev);
 
 
 	/* Set state and stop OS transmissions */
 	/* Set state and stop OS transmissions */
-	drvr->bus_if->drvr_up = false;
 	netif_stop_queue(ndev);
 	netif_stop_queue(ndev);
 
 
 	return 0;
 	return 0;
@@ -570,7 +562,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
 	u32 toe_ol;
 	u32 toe_ol;
 	s32 ret = 0;
 	s32 ret = 0;
 
 
-	brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 
 	/* If bus is not ready, can't continue */
 	/* If bus is not ready, can't continue */
 	if (bus_if->state != BRCMF_BUS_DATA) {
 	if (bus_if->state != BRCMF_BUS_DATA) {
@@ -578,9 +570,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
 
 
-	atomic_set(&drvr->pend_8021x_cnt, 0);
-
-	memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
+	atomic_set(&ifp->pend_8021x_cnt, 0);
 
 
 	/* Get current TOE mode from dongle */
 	/* Get current TOE mode from dongle */
 	if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
 	if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
@@ -591,7 +581,6 @@ static int brcmf_netdev_open(struct net_device *ndev)
 
 
 	/* Allow transmit calls */
 	/* Allow transmit calls */
 	netif_start_queue(ndev);
 	netif_start_queue(ndev);
-	drvr->bus_if->drvr_up = true;
 	if (brcmf_cfg80211_up(ndev)) {
 	if (brcmf_cfg80211_up(ndev)) {
 		brcmf_err("failed to bring up cfg80211\n");
 		brcmf_err("failed to bring up cfg80211\n");
 		return -1;
 		return -1;
@@ -610,29 +599,18 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
 	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
 	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
 };
 };
 
 
-static const struct net_device_ops brcmf_netdev_ops_virt = {
-	.ndo_open = brcmf_cfg80211_up,
-	.ndo_stop = brcmf_cfg80211_down,
-	.ndo_get_stats = brcmf_netdev_get_stats,
-	.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
-	.ndo_start_xmit = brcmf_netdev_start_xmit,
-	.ndo_set_mac_address = brcmf_netdev_set_mac_address,
-	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
-};
-
-int brcmf_net_attach(struct brcmf_if *ifp)
+int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
 {
 {
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct net_device *ndev;
 	struct net_device *ndev;
+	s32 err;
 
 
-	brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
+	brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+		  ifp->mac_addr);
 	ndev = ifp->ndev;
 	ndev = ifp->ndev;
 
 
 	/* set appropriate operations */
 	/* set appropriate operations */
-	if (!ifp->idx)
-		ndev->netdev_ops = &brcmf_netdev_ops_pri;
-	else
-		ndev->netdev_ops = &brcmf_netdev_ops_virt;
+	ndev->netdev_ops = &brcmf_netdev_ops_pri;
 
 
 	ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
 	ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
 	ndev->ethtool_ops = &brcmf_ethtool_ops;
 	ndev->ethtool_ops = &brcmf_ethtool_ops;
@@ -643,7 +621,14 @@ int brcmf_net_attach(struct brcmf_if *ifp)
 	/* set the mac address */
 	/* set the mac address */
 	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
 	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
 
 
-	if (register_netdev(ndev) != 0) {
+	INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
+	INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
+
+	if (rtnl_locked)
+		err = register_netdevice(ndev);
+	else
+		err = register_netdev(ndev);
+	if (err != 0) {
 		brcmf_err("couldn't register the net device\n");
 		brcmf_err("couldn't register the net device\n");
 		goto fail;
 		goto fail;
 	}
 	}
@@ -657,16 +642,78 @@ fail:
 	return -EBADE;
 	return -EBADE;
 }
 }
 
 
-struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
-			      char *name, u8 *addr_mask)
+static int brcmf_net_p2p_open(struct net_device *ndev)
+{
+	brcmf_dbg(TRACE, "Enter\n");
+
+	return brcmf_cfg80211_up(ndev);
+}
+
+static int brcmf_net_p2p_stop(struct net_device *ndev)
+{
+	brcmf_dbg(TRACE, "Enter\n");
+
+	return brcmf_cfg80211_down(ndev);
+}
+
+static int brcmf_net_p2p_do_ioctl(struct net_device *ndev,
+				  struct ifreq *ifr, int cmd)
+{
+	brcmf_dbg(TRACE, "Enter\n");
+	return 0;
+}
+
+static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
+					    struct net_device *ndev)
+{
+	if (skb)
+		dev_kfree_skb_any(skb);
+
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops brcmf_netdev_ops_p2p = {
+	.ndo_open = brcmf_net_p2p_open,
+	.ndo_stop = brcmf_net_p2p_stop,
+	.ndo_do_ioctl = brcmf_net_p2p_do_ioctl,
+	.ndo_start_xmit = brcmf_net_p2p_start_xmit
+};
+
+static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
+{
+	struct net_device *ndev;
+
+	brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+		  ifp->mac_addr);
+	ndev = ifp->ndev;
+
+	ndev->netdev_ops = &brcmf_netdev_ops_p2p;
+
+	/* set the mac address */
+	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+
+	if (register_netdev(ndev) != 0) {
+		brcmf_err("couldn't register the p2p net device\n");
+		goto fail;
+	}
+
+	brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
+
+	return 0;
+
+fail:
+	return -EBADE;
+}
+
+struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+			      char *name, u8 *mac_addr)
 {
 {
 	struct brcmf_if *ifp;
 	struct brcmf_if *ifp;
 	struct net_device *ndev;
 	struct net_device *ndev;
-	int i;
 
 
-	brcmf_dbg(TRACE, "idx %d\n", ifidx);
+	brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx);
 
 
-	ifp = drvr->iflist[ifidx];
+	ifp = drvr->iflist[bssidx];
 	/*
 	/*
 	 * Delete the existing interface before overwriting it
 	 * Delete the existing interface before overwriting it
 	 * in case we missed the BRCMF_E_IF_DEL event.
 	 * in case we missed the BRCMF_E_IF_DEL event.
@@ -678,7 +725,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
 			netif_stop_queue(ifp->ndev);
 			netif_stop_queue(ifp->ndev);
 			unregister_netdev(ifp->ndev);
 			unregister_netdev(ifp->ndev);
 			free_netdev(ifp->ndev);
 			free_netdev(ifp->ndev);
-			drvr->iflist[ifidx] = NULL;
+			drvr->iflist[bssidx] = NULL;
 		} else {
 		} else {
 			brcmf_err("ignore IF event\n");
 			brcmf_err("ignore IF event\n");
 			return ERR_PTR(-EINVAL);
 			return ERR_PTR(-EINVAL);
@@ -695,16 +742,15 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
 	ifp = netdev_priv(ndev);
 	ifp = netdev_priv(ndev);
 	ifp->ndev = ndev;
 	ifp->ndev = ndev;
 	ifp->drvr = drvr;
 	ifp->drvr = drvr;
-	drvr->iflist[ifidx] = ifp;
-	ifp->idx = ifidx;
+	drvr->iflist[bssidx] = ifp;
+	ifp->ifidx = ifidx;
 	ifp->bssidx = bssidx;
 	ifp->bssidx = bssidx;
 
 
-	INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
-	INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
 
 
-	if (addr_mask != NULL)
-		for (i = 0; i < ETH_ALEN; i++)
-			ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i];
+	init_waitqueue_head(&ifp->pend_8021x_wait);
+
+	if (mac_addr != NULL)
+		memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
 
 
 	brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
 	brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
 		  current->pid, ifp->ndev->name, ifp->mac_addr);
 		  current->pid, ifp->ndev->name, ifp->mac_addr);
@@ -712,19 +758,18 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
 	return ifp;
 	return ifp;
 }
 }
 
 
-void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
+void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
 {
 {
 	struct brcmf_if *ifp;
 	struct brcmf_if *ifp;
 
 
-	brcmf_dbg(TRACE, "idx %d\n", ifidx);
-
-	ifp = drvr->iflist[ifidx];
+	ifp = drvr->iflist[bssidx];
 	if (!ifp) {
 	if (!ifp) {
-		brcmf_err("Null interface\n");
+		brcmf_err("Null interface, idx=%d\n", bssidx);
 		return;
 		return;
 	}
 	}
+	brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
 	if (ifp->ndev) {
 	if (ifp->ndev) {
-		if (ifidx == 0) {
+		if (bssidx == 0) {
 			if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
 			if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
 				rtnl_lock();
 				rtnl_lock();
 				brcmf_netdev_stop(ifp->ndev);
 				brcmf_netdev_stop(ifp->ndev);
@@ -734,12 +779,14 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
 			netif_stop_queue(ifp->ndev);
 			netif_stop_queue(ifp->ndev);
 		}
 		}
 
 
-		cancel_work_sync(&ifp->setmacaddr_work);
-		cancel_work_sync(&ifp->multicast_work);
+		if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+			cancel_work_sync(&ifp->setmacaddr_work);
+			cancel_work_sync(&ifp->multicast_work);
+		}
 
 
 		unregister_netdev(ifp->ndev);
 		unregister_netdev(ifp->ndev);
-		drvr->iflist[ifidx] = NULL;
-		if (ifidx == 0)
+		drvr->iflist[bssidx] = NULL;
+		if (bssidx == 0)
 			brcmf_cfg80211_detach(drvr->config);
 			brcmf_cfg80211_detach(drvr->config);
 		free_netdev(ifp->ndev);
 		free_netdev(ifp->ndev);
 	}
 	}
@@ -779,8 +826,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
 
 
 	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
 	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
 
 
-	init_waitqueue_head(&drvr->pend_8021x_wait);
-
 	return ret;
 	return ret;
 
 
 fail:
 fail:
@@ -795,6 +840,7 @@ int brcmf_bus_start(struct device *dev)
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
 	struct brcmf_pub *drvr = bus_if->drvr;
 	struct brcmf_if *ifp;
 	struct brcmf_if *ifp;
+	struct brcmf_if *p2p_ifp;
 
 
 	brcmf_dbg(TRACE, "\n");
 	brcmf_dbg(TRACE, "\n");
 
 
@@ -810,6 +856,13 @@ int brcmf_bus_start(struct device *dev)
 	if (IS_ERR(ifp))
 	if (IS_ERR(ifp))
 		return PTR_ERR(ifp);
 		return PTR_ERR(ifp);
 
 
+	if (brcmf_p2p_enable)
+		p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
+	else
+		p2p_ifp = NULL;
+	if (IS_ERR(p2p_ifp))
+		p2p_ifp = NULL;
+
 	/* signal bus ready */
 	/* signal bus ready */
 	bus_if->state = BRCMF_BUS_DATA;
 	bus_if->state = BRCMF_BUS_DATA;
 
 
@@ -828,16 +881,22 @@ int brcmf_bus_start(struct device *dev)
 	if (ret < 0)
 	if (ret < 0)
 		goto fail;
 		goto fail;
 
 
-	ret = brcmf_net_attach(ifp);
+	ret = brcmf_net_attach(ifp, false);
 fail:
 fail:
 	if (ret < 0) {
 	if (ret < 0) {
 		brcmf_err("failed: %d\n", ret);
 		brcmf_err("failed: %d\n", ret);
 		if (drvr->config)
 		if (drvr->config)
 			brcmf_cfg80211_detach(drvr->config);
 			brcmf_cfg80211_detach(drvr->config);
-		free_netdev(drvr->iflist[0]->ndev);
+		free_netdev(ifp->ndev);
 		drvr->iflist[0] = NULL;
 		drvr->iflist[0] = NULL;
+		if (p2p_ifp) {
+			free_netdev(p2p_ifp->ndev);
+			drvr->iflist[1] = NULL;
+		}
 		return ret;
 		return ret;
 	}
 	}
+	if ((brcmf_p2p_enable) && (p2p_ifp))
+		brcmf_net_p2p_attach(p2p_ifp);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -863,12 +922,13 @@ void brcmf_dev_reset(struct device *dev)
 	if (drvr == NULL)
 	if (drvr == NULL)
 		return;
 		return;
 
 
-	brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
+	if (drvr->iflist[0])
+		brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
 }
 }
 
 
 void brcmf_detach(struct device *dev)
 void brcmf_detach(struct device *dev)
 {
 {
-	int i;
+	s32 i;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
 	struct brcmf_pub *drvr = bus_if->drvr;
 
 
@@ -895,19 +955,18 @@ void brcmf_detach(struct device *dev)
 	kfree(drvr);
 	kfree(drvr);
 }
 }
 
 
-static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
+static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
 {
 {
-	return atomic_read(&drvr->pend_8021x_cnt);
+	return atomic_read(&ifp->pend_8021x_cnt);
 }
 }
 
 
 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 {
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcmf_pub *drvr = ifp->drvr;
 	int err;
 	int err;
 
 
-	err = wait_event_timeout(drvr->pend_8021x_wait,
-				 !brcmf_get_pend_8021x_cnt(drvr),
+	err = wait_event_timeout(ifp->pend_8021x_wait,
+				 !brcmf_get_pend_8021x_cnt(ifp),
 				 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
 				 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
 
 
 	WARN_ON(!err);
 	WARN_ON(!err);
@@ -915,6 +974,16 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 	return !err;
 	return !err;
 }
 }
 
 
+/*
+ * return chip id and rev of the device encoded in u32.
+ */
+u32 brcmf_get_chip_info(struct brcmf_if *ifp)
+{
+	struct brcmf_bus *bus = ifp->drvr->bus_if;
+
+	return bus->chip << 4 | bus->chiprev;
+}
+
 static void brcmf_driver_init(struct work_struct *work)
 static void brcmf_driver_init(struct work_struct *work)
 {
 {
 	brcmf_debugfs_init();
 	brcmf_debugfs_init();

+ 5 - 20
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c

@@ -1096,7 +1096,6 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
 	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
 	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
 	    type != BRCMF_SDIO_FT_SUPER) {
 	    type != BRCMF_SDIO_FT_SUPER) {
 		brcmf_err("HW header length too long\n");
 		brcmf_err("HW header length too long\n");
-		bus->sdiodev->bus_if->dstats.rx_errors++;
 		bus->sdcnt.rx_toolong++;
 		bus->sdcnt.rx_toolong++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		rd->len = 0;
 		rd->len = 0;
@@ -1298,7 +1297,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 		if (errcode < 0) {
 		if (errcode < 0) {
 			brcmf_err("glom read of %d bytes failed: %d\n",
 			brcmf_err("glom read of %d bytes failed: %d\n",
 				  dlen, errcode);
 				  dlen, errcode);
-			bus->sdiodev->bus_if->dstats.rx_errors++;
 
 
 			sdio_claim_host(bus->sdiodev->func[1]);
 			sdio_claim_host(bus->sdiodev->func[1]);
 			if (bus->glomerr++ < 3) {
 			if (bus->glomerr++ < 3) {
@@ -1478,7 +1476,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
 	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
 		brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
 		brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
 			  rdlen, bus->sdiodev->bus_if->maxctl);
 			  rdlen, bus->sdiodev->bus_if->maxctl);
-		bus->sdiodev->bus_if->dstats.rx_errors++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto done;
 		goto done;
 	}
 	}
@@ -1486,7 +1483,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 	if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
 	if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
 		brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
 		brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
 			  len, len - doff, bus->sdiodev->bus_if->maxctl);
 			  len, len - doff, bus->sdiodev->bus_if->maxctl);
-		bus->sdiodev->bus_if->dstats.rx_errors++;
 		bus->sdcnt.rx_toolong++;
 		bus->sdcnt.rx_toolong++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto done;
 		goto done;
@@ -1634,7 +1630,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 		if (!pkt) {
 		if (!pkt) {
 			/* Give up on data, request rtx of events */
 			/* Give up on data, request rtx of events */
 			brcmf_err("brcmu_pkt_buf_get_skb failed\n");
 			brcmf_err("brcmu_pkt_buf_get_skb failed\n");
-			bus->sdiodev->bus_if->dstats.rx_dropped++;
 			brcmf_sdbrcm_rxfail(bus, false,
 			brcmf_sdbrcm_rxfail(bus, false,
 					    RETRYCHAN(rd->channel));
 					    RETRYCHAN(rd->channel));
 			sdio_release_host(bus->sdiodev->func[1]);
 			sdio_release_host(bus->sdiodev->func[1]);
@@ -1652,7 +1647,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 			brcmf_err("read %d bytes from channel %d failed: %d\n",
 			brcmf_err("read %d bytes from channel %d failed: %d\n",
 				  rd->len, rd->channel, sdret);
 				  rd->len, rd->channel, sdret);
 			brcmu_pkt_buf_free_skb(pkt);
 			brcmu_pkt_buf_free_skb(pkt);
-			bus->sdiodev->bus_if->dstats.rx_errors++;
 			sdio_claim_host(bus->sdiodev->func[1]);
 			sdio_claim_host(bus->sdiodev->func[1]);
 			brcmf_sdbrcm_rxfail(bus, true,
 			brcmf_sdbrcm_rxfail(bus, true,
 					    RETRYCHAN(rd->channel));
 					    RETRYCHAN(rd->channel));
@@ -1940,10 +1934,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 		datalen = pkt->len - SDPCM_HDRLEN;
 		datalen = pkt->len - SDPCM_HDRLEN;
 
 
 		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
 		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
-		if (ret)
-			bus->sdiodev->bus_if->dstats.tx_errors++;
-		else
-			bus->sdiodev->bus_if->dstats.tx_bytes += datalen;
 
 
 		/* In poll mode, need to check for other events */
 		/* In poll mode, need to check for other events */
 		if (!bus->intr && cnt) {
 		if (!bus->intr && cnt) {
@@ -1962,8 +1952,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 	}
 	}
 
 
 	/* Deflow-control stack if needed */
 	/* Deflow-control stack if needed */
-	if (bus->sdiodev->bus_if->drvr_up &&
-	    (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
+	if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
 	    bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
 	    bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
 		bus->txoff = false;
 		bus->txoff = false;
 		brcmf_txflowblock(bus->sdiodev->dev, false);
 		brcmf_txflowblock(bus->sdiodev->dev, false);
@@ -2710,9 +2699,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
 	 * address of sdpcm_shared structure
 	 * address of sdpcm_shared structure
 	 */
 	 */
 	sdio_claim_host(bus->sdiodev->func[1]);
 	sdio_claim_host(bus->sdiodev->func[1]);
+	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
 	rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
 	rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
 				   (u8 *)&addr_le, 4);
 				   (u8 *)&addr_le, 4);
-	sdio_claim_host(bus->sdiodev->func[1]);
+	sdio_release_host(bus->sdiodev->func[1]);
 	if (rv < 0)
 	if (rv < 0)
 		return rv;
 		return rv;
 
 
@@ -2731,10 +2721,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
 	}
 	}
 
 
 	/* Read hndrte_shared structure */
 	/* Read hndrte_shared structure */
-	sdio_claim_host(bus->sdiodev->func[1]);
 	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
 	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
 				   sizeof(struct sdpcm_shared_le));
 				   sizeof(struct sdpcm_shared_le));
-	sdio_release_host(bus->sdiodev->func[1]);
 	if (rv < 0)
 	if (rv < 0)
 		return rv;
 		return rv;
 
 
@@ -2836,14 +2824,12 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
 	if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
 	if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
 		return 0;
 		return 0;
 
 
-	sdio_claim_host(bus->sdiodev->func[1]);
 	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
 	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
 				      sizeof(struct brcmf_trap_info));
 				      sizeof(struct brcmf_trap_info));
 	if (error < 0)
 	if (error < 0)
 		return error;
 		return error;
 
 
 	nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
 	nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
-	sdio_release_host(bus->sdiodev->func[1]);
 	if (nbytes < 0)
 	if (nbytes < 0)
 		return nbytes;
 		return nbytes;
 
 
@@ -3308,9 +3294,6 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
 {
 {
 	int ret;
 	int ret;
 
 
-	if (bus->sdiodev->bus_if->drvr_up)
-		return -EISCONN;
-
 	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
 	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
 			       &bus->sdiodev->func[2]->dev);
 			       &bus->sdiodev->func[2]->dev);
 	if (ret) {
 	if (ret) {
@@ -3941,6 +3924,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 	/* Assign bus interface call back */
 	/* Assign bus interface call back */
 	bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
 	bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
 	bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
 	bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
+	bus->sdiodev->bus_if->chip = bus->ci->chip;
+	bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
 
 
 	/* Attach to the brcmf/OS/network interface */
 	/* Attach to the brcmf/OS/network interface */
 	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
 	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);

+ 5 - 6
drivers/net/wireless/brcm80211/brcmfmac/fweh.c

@@ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
 		return;
 		return;
 	}
 	}
 
 
-	ifp = drvr->iflist[ifevent->ifidx];
+	ifp = drvr->iflist[ifevent->bssidx];
 
 
 	if (ifevent->action == BRCMF_E_IF_ADD) {
 	if (ifevent->action == BRCMF_E_IF_ADD) {
 		brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
 		brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
 			  emsg->addr);
 			  emsg->addr);
-		ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx,
+		ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
 				   emsg->ifname, emsg->addr);
 				   emsg->ifname, emsg->addr);
 		if (IS_ERR(ifp))
 		if (IS_ERR(ifp))
 			return;
 			return;
 
 
 		if (!drvr->fweh.evt_handler[BRCMF_E_IF])
 		if (!drvr->fweh.evt_handler[BRCMF_E_IF])
-			err = brcmf_net_attach(ifp);
+			err = brcmf_net_attach(ifp, false);
 	}
 	}
 
 
 	err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
 	err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
 
 
 	if (ifevent->action == BRCMF_E_IF_DEL)
 	if (ifevent->action == BRCMF_E_IF_DEL)
-		brcmf_del_if(drvr, ifevent->ifidx);
+		brcmf_del_if(drvr, ifevent->bssidx);
 }
 }
 
 
 /**
 /**
@@ -250,8 +250,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
 	drvr = container_of(fweh, struct brcmf_pub, fweh);
 	drvr = container_of(fweh, struct brcmf_pub, fweh);
 
 
 	while ((event = brcmf_fweh_dequeue_event(fweh))) {
 	while ((event = brcmf_fweh_dequeue_event(fweh))) {
-		ifp = drvr->iflist[event->ifidx];
-
 		brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
 		brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
 			  brcmf_fweh_event_name(event->code), event->code,
 			  brcmf_fweh_event_name(event->code), event->code,
 			  event->emsg.ifidx, event->emsg.bsscfgidx,
 			  event->emsg.ifidx, event->emsg.bsscfgidx,
@@ -283,6 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
 			goto event_free;
 			goto event_free;
 		}
 		}
 
 
+		ifp = drvr->iflist[emsg.bsscfgidx];
 		err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
 		err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
 						    event->data);
 						    event->data);
 		if (err) {
 		if (err) {

+ 5 - 1
drivers/net/wireless/brcm80211/brcmfmac/fweh.h

@@ -83,6 +83,7 @@ struct brcmf_event;
 	BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \
 	BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \
 	BRCMF_ENUM_DEF(TRACE, 52) \
 	BRCMF_ENUM_DEF(TRACE, 52) \
 	BRCMF_ENUM_DEF(IF, 54) \
 	BRCMF_ENUM_DEF(IF, 54) \
+	BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
 	BRCMF_ENUM_DEF(RSSI, 56) \
 	BRCMF_ENUM_DEF(RSSI, 56) \
 	BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
 	BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
 	BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
 	BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
@@ -96,8 +97,11 @@ struct brcmf_event;
 	BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \
 	BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \
 	BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \
 	BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \
 	BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \
 	BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \
+	BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \
+	BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \
 	BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
 	BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
-	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74)
+	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
+	BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75)
 
 
 #define BRCMF_ENUM_DEF(id, val) \
 #define BRCMF_ENUM_DEF(id, val) \
 	BRCMF_E_##id = (val),
 	BRCMF_E_##id = (val),

+ 5 - 2
drivers/net/wireless/brcm80211/brcmfmac/fwil.c

@@ -45,9 +45,10 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
 	if (data != NULL)
 	if (data != NULL)
 		len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
 		len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
 	if (set)
 	if (set)
-		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len);
+		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
+					       len);
 	else
 	else
-		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data,
+		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
 						 len);
 						 len);
 
 
 	if (err >= 0)
 	if (err >= 0)
@@ -100,6 +101,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
 	__le32 data_le = cpu_to_le32(data);
 	__le32 data_le = cpu_to_le32(data);
 
 
 	mutex_lock(&ifp->drvr->proto_block);
 	mutex_lock(&ifp->drvr->proto_block);
+	brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data);
 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
 	mutex_unlock(&ifp->drvr->proto_block);
 	mutex_unlock(&ifp->drvr->proto_block);
 
 
@@ -116,6 +118,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
 	mutex_unlock(&ifp->drvr->proto_block);
 	mutex_unlock(&ifp->drvr->proto_block);
 	*data = le32_to_cpu(data_le);
 	*data = le32_to_cpu(data_le);
+	brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data);
 
 
 	return err;
 	return err;
 }
 }

+ 66 - 0
drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h

@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef FWIL_TYPES_H_
+#define FWIL_TYPES_H_
+
+#include <linux/if_ether.h>
+
+
+#define BRCMF_FIL_ACTION_FRAME_SIZE	1800
+
+
+enum brcmf_fil_p2p_if_types {
+	BRCMF_FIL_P2P_IF_CLIENT,
+	BRCMF_FIL_P2P_IF_GO,
+	BRCMF_FIL_P2P_IF_DYNBCN_GO,
+	BRCMF_FIL_P2P_IF_DEV,
+};
+
+struct brcmf_fil_p2p_if_le {
+	u8 addr[ETH_ALEN];
+	__le16 type;
+	__le16 chspec;
+};
+
+struct brcmf_fil_chan_info_le {
+	__le32 hw_channel;
+	__le32 target_channel;
+	__le32 scan_channel;
+};
+
+struct brcmf_fil_action_frame_le {
+	u8	da[ETH_ALEN];
+	__le16	len;
+	__le32	packet_id;
+	u8	data[BRCMF_FIL_ACTION_FRAME_SIZE];
+};
+
+struct brcmf_fil_af_params_le {
+	__le32					channel;
+	__le32					dwell_time;
+	u8					bssid[ETH_ALEN];
+	u8					pad[2];
+	struct brcmf_fil_action_frame_le	action_frame;
+};
+
+struct brcmf_fil_bss_enable_le {
+	__le32 bsscfg_idx;
+	__le32 enable;
+};
+
+#endif /* FWIL_TYPES_H_ */

+ 2277 - 0
drivers/net/wireless/brcm80211/brcmfmac/p2p.c

@@ -0,0 +1,2277 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <defs.h>
+#include <dhd.h>
+#include <dhd_dbg.h>
+#include "fwil.h"
+#include "fwil_types.h"
+#include "p2p.h"
+#include "wl_cfg80211.h"
+
+/* parameters used for p2p escan */
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 80
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
+#define P2PAPI_SCAN_HOME_TIME_MS 60
+#define P2PAPI_SCAN_NPROBS_TIME_MS 30
+#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
+#define WL_SCAN_CONNECT_DWELL_TIME_MS 200
+#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
+
+#define BRCMF_P2P_WILDCARD_SSID		"DIRECT-"
+#define BRCMF_P2P_WILDCARD_SSID_LEN	(sizeof(BRCMF_P2P_WILDCARD_SSID) - 1)
+
+#define SOCIAL_CHAN_1		1
+#define SOCIAL_CHAN_2		6
+#define SOCIAL_CHAN_3		11
+#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
+					 (channel == SOCIAL_CHAN_2) || \
+					 (channel == SOCIAL_CHAN_3))
+#define SOCIAL_CHAN_CNT		3
+#define AF_PEER_SEARCH_CNT	2
+
+#define BRCMF_SCB_TIMEOUT_VALUE	20
+
+#define P2P_VER			9	/* P2P version: 9=WiFi P2P v1.0 */
+#define P2P_PUB_AF_CATEGORY	0x04
+#define P2P_PUB_AF_ACTION	0x09
+#define P2P_AF_CATEGORY		0x7f
+#define P2P_OUI			"\x50\x6F\x9A"	/* P2P OUI */
+#define P2P_OUI_LEN		3		/* P2P OUI length */
+
+/* Action Frame Constants */
+#define DOT11_ACTION_HDR_LEN	2	/* action frame category + action */
+#define DOT11_ACTION_CAT_OFF	0	/* category offset */
+#define DOT11_ACTION_ACT_OFF	1	/* action offset */
+
+#define P2P_AF_DWELL_TIME		200
+#define P2P_AF_MIN_DWELL_TIME		100
+#define P2P_AF_MED_DWELL_TIME		400
+#define P2P_AF_LONG_DWELL_TIME		1000
+#define P2P_AF_TX_MAX_RETRY		1
+#define P2P_AF_MAX_WAIT_TIME		2000
+#define P2P_INVALID_CHANNEL		-1
+#define P2P_CHANNEL_SYNC_RETRY		5
+#define P2P_AF_FRM_SCAN_MAX_WAIT	1500
+#define P2P_DEFAULT_SLEEP_TIME_VSDB	200
+
+/* WiFi P2P Public Action Frame OUI Subtypes */
+#define P2P_PAF_GON_REQ		0	/* Group Owner Negotiation Req */
+#define P2P_PAF_GON_RSP		1	/* Group Owner Negotiation Rsp */
+#define P2P_PAF_GON_CONF	2	/* Group Owner Negotiation Confirm */
+#define P2P_PAF_INVITE_REQ	3	/* P2P Invitation Request */
+#define P2P_PAF_INVITE_RSP	4	/* P2P Invitation Response */
+#define P2P_PAF_DEVDIS_REQ	5	/* Device Discoverability Request */
+#define P2P_PAF_DEVDIS_RSP	6	/* Device Discoverability Response */
+#define P2P_PAF_PROVDIS_REQ	7	/* Provision Discovery Request */
+#define P2P_PAF_PROVDIS_RSP	8	/* Provision Discovery Response */
+#define P2P_PAF_SUBTYPE_INVALID	255	/* Invalid Subtype */
+
+/* WiFi P2P Action Frame OUI Subtypes */
+#define P2P_AF_NOTICE_OF_ABSENCE	0	/* Notice of Absence */
+#define P2P_AF_PRESENCE_REQ		1	/* P2P Presence Request */
+#define P2P_AF_PRESENCE_RSP		2	/* P2P Presence Response */
+#define P2P_AF_GO_DISC_REQ		3	/* GO Discoverability Request */
+
+/* P2P Service Discovery related */
+#define P2PSD_ACTION_CATEGORY		0x04	/* Public action frame */
+#define P2PSD_ACTION_ID_GAS_IREQ	0x0a	/* GAS Initial Request AF */
+#define P2PSD_ACTION_ID_GAS_IRESP	0x0b	/* GAS Initial Response AF */
+#define P2PSD_ACTION_ID_GAS_CREQ	0x0c	/* GAS Comback Request AF */
+#define P2PSD_ACTION_ID_GAS_CRESP	0x0d	/* GAS Comback Response AF */
+
+/**
+ * struct brcmf_p2p_disc_st_le - set discovery state in firmware.
+ *
+ * @state: requested discovery state (see enum brcmf_p2p_disc_state).
+ * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state.
+ * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state.
+ */
+struct brcmf_p2p_disc_st_le {
+	u8 state;
+	__le16 chspec;
+	__le16 dwell;
+};
+
+/**
+ * enum brcmf_p2p_disc_state - P2P discovery state values
+ *
+ * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE.
+ * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time.
+ * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE.
+ */
+enum brcmf_p2p_disc_state {
+	WL_P2P_DISC_ST_SCAN,
+	WL_P2P_DISC_ST_LISTEN,
+	WL_P2P_DISC_ST_SEARCH
+};
+
+/**
+ * struct brcmf_p2p_scan_le - P2P specific scan request.
+ *
+ * @type: type of scan method requested (values: 'E' or 'S').
+ * @reserved: reserved (ignored).
+ * @eparams: parameters used for type 'E'.
+ * @sparams: parameters used for type 'S'.
+ */
+struct brcmf_p2p_scan_le {
+	u8 type;
+	u8 reserved[3];
+	union {
+		struct brcmf_escan_params_le eparams;
+		struct brcmf_scan_params_le sparams;
+	};
+};
+
+/**
+ * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame
+ *
+ * @category: P2P_PUB_AF_CATEGORY
+ * @action: P2P_PUB_AF_ACTION
+ * @oui[3]: P2P_OUI
+ * @oui_type: OUI type - P2P_VER
+ * @subtype: OUI subtype - P2P_TYPE_*
+ * @dialog_token: nonzero, identifies req/rsp transaction
+ * @elts[1]: Variable length information elements.
+ */
+struct brcmf_p2p_pub_act_frame {
+	u8	category;
+	u8	action;
+	u8	oui[3];
+	u8	oui_type;
+	u8	subtype;
+	u8	dialog_token;
+	u8	elts[1];
+};
+
+/**
+ * struct brcmf_p2p_action_frame - WiFi P2P Action Frame
+ *
+ * @category: P2P_AF_CATEGORY
+ * @OUI[3]: OUI - P2P_OUI
+ * @type: OUI Type - P2P_VER
+ * @subtype: OUI Subtype - P2P_AF_*
+ * @dialog_token: nonzero, identifies req/resp tranaction
+ * @elts[1]: Variable length information elements.
+ */
+struct brcmf_p2p_action_frame {
+	u8	category;
+	u8	oui[3];
+	u8	type;
+	u8	subtype;
+	u8	dialog_token;
+	u8	elts[1];
+};
+
+/**
+ * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame
+ *
+ * @category: 0x04 Public Action Frame
+ * @action: 0x6c Advertisement Protocol
+ * @dialog_token: nonzero, identifies req/rsp transaction
+ * @query_data[1]: Query Data. SD gas ireq SD gas iresp
+ */
+struct brcmf_p2psd_gas_pub_act_frame {
+	u8	category;
+	u8	action;
+	u8	dialog_token;
+	u8	query_data[1];
+};
+
+/**
+ * struct brcmf_config_af_params - Action Frame Parameters for tx.
+ *
+ * @mpc_onoff: To make sure to send successfully action frame, we have to
+ *             turn off mpc  0: off, 1: on,  (-1): do nothing
+ * @search_channel: 1: search peer's channel to send af
+ * extra_listen: keep the dwell time to get af response frame.
+ */
+struct brcmf_config_af_params {
+	s32 mpc_onoff;
+	bool search_channel;
+	bool extra_listen;
+};
+
+/**
+ * brcmf_p2p_is_pub_action() - true if p2p public type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p public action type
+ */
+static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
+{
+	struct brcmf_p2p_pub_act_frame *pact_frm;
+
+	if (frame == NULL)
+		return false;
+
+	pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+	if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1)
+		return false;
+
+	if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
+	    pact_frm->action == P2P_PUB_AF_ACTION &&
+	    pact_frm->oui_type == P2P_VER &&
+	    memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
+		return true;
+
+	return false;
+}
+
+/**
+ * brcmf_p2p_is_p2p_action() - true if p2p action type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p action type
+ */
+static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)
+{
+	struct brcmf_p2p_action_frame *act_frm;
+
+	if (frame == NULL)
+		return false;
+
+	act_frm = (struct brcmf_p2p_action_frame *)frame;
+	if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1)
+		return false;
+
+	if (act_frm->category == P2P_AF_CATEGORY &&
+	    act_frm->type  == P2P_VER &&
+	    memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
+		return true;
+
+	return false;
+}
+
+/**
+ * brcmf_p2p_is_gas_action() - true if p2p gas action type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p gas action type
+ */
+static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len)
+{
+	struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+
+	if (frame == NULL)
+		return false;
+
+	sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+	if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1)
+		return false;
+
+	if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+		return false;
+
+	if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+	    sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
+	    sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
+	    sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+		return true;
+
+	return false;
+}
+
+/**
+ * brcmf_p2p_print_actframe() - debug print routine.
+ *
+ * @tx: Received or to be transmitted
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Print information about the p2p action frame
+ */
+
+#ifdef DEBUG
+
+static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+	struct brcmf_p2p_pub_act_frame *pact_frm;
+	struct brcmf_p2p_action_frame *act_frm;
+	struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+
+	if (!frame || frame_len <= 2)
+		return;
+
+	if (brcmf_p2p_is_pub_action(frame, frame_len)) {
+		pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+		switch (pact_frm->subtype) {
+		case P2P_PAF_GON_REQ:
+			brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_GON_RSP:
+			brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_GON_CONF:
+			brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_INVITE_REQ:
+			brcmf_dbg(TRACE, "%s P2P Invitation Request  Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_INVITE_RSP:
+			brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_DEVDIS_REQ:
+			brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_DEVDIS_RSP:
+			brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_PROVDIS_REQ:
+			brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_PROVDIS_RSP:
+			brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		default:
+			brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		}
+	} else if (brcmf_p2p_is_p2p_action(frame, frame_len)) {
+		act_frm = (struct brcmf_p2p_action_frame *)frame;
+		switch (act_frm->subtype) {
+		case P2P_AF_NOTICE_OF_ABSENCE:
+			brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_AF_PRESENCE_REQ:
+			brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_AF_PRESENCE_RSP:
+			brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_AF_GO_DISC_REQ:
+			brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		default:
+			brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n",
+				  (tx) ? "TX" : "RX");
+		}
+
+	} else if (brcmf_p2p_is_gas_action(frame, frame_len)) {
+		sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+		switch (sd_act_frm->action) {
+		case P2PSD_ACTION_ID_GAS_IREQ:
+			brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2PSD_ACTION_ID_GAS_IRESP:
+			brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2PSD_ACTION_ID_GAS_CREQ:
+			brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2PSD_ACTION_ID_GAS_CRESP:
+			brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		default:
+			brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		}
+	}
+}
+
+#else
+
+static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+}
+
+#endif
+
+
+/**
+ * brcmf_p2p_chnr_to_chspec() - convert channel number to chanspec.
+ *
+ * @channel: channel number
+ */
+static u16 brcmf_p2p_chnr_to_chspec(u16 channel)
+{
+	u16 chanspec;
+
+	chanspec = channel & WL_CHANSPEC_CHAN_MASK;
+
+	if (channel <= CH_MAX_2G_CHANNEL)
+		chanspec |= WL_CHANSPEC_BAND_2G;
+	else
+		chanspec |= WL_CHANSPEC_BAND_5G;
+
+	chanspec |= WL_CHANSPEC_BW_20;
+	chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+	return chanspec;
+}
+
+
+/**
+ * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.
+ *
+ * @ifp: ifp to use for iovars (primary).
+ * @p2p_mac: mac address to configure for p2p_da_override
+ */
+static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
+{
+	s32 ret = 0;
+
+	brcmf_fil_iovar_int_set(ifp, "apsta", 1);
+
+	/* In case of COB type, firmware has default mac address
+	 * After Initializing firmware, we have to set current mac address to
+	 * firmware for P2P device address
+	 */
+	ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac,
+				       ETH_ALEN);
+	if (ret)
+		brcmf_err("failed to update device address ret %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.
+ *
+ * @p2p: P2P specific data.
+ *
+ * P2P needs mac addresses for P2P device and interface. These are
+ * derived from the primary net device, ie. the permanent ethernet
+ * address of the device.
+ */
+static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+	struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+
+	/* Generate the P2P Device Address.  This consists of the device's
+	 * primary MAC address with the locally administered bit set.
+	 */
+	memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN);
+	p2p->dev_addr[0] |= 0x02;
+	memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+
+	/* Generate the P2P Interface Address.  If the discovery and connection
+	 * BSSCFGs need to simultaneously co-exist, then this address must be
+	 * different from the P2P Device Address, but also locally administered.
+	 */
+	memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN);
+	p2p->int_addr[4] ^= 0x80;
+}
+
+/**
+ * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan.
+ *
+ * @request: the scan request as received from cfg80211.
+ *
+ * returns true if one of the ssids in the request matches the
+ * P2P wildcard ssid; otherwise returns false.
+ */
+static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request)
+{
+	struct cfg80211_ssid *ssids = request->ssids;
+	int i;
+
+	for (i = 0; i < request->n_ssids; i++) {
+		if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN)
+			continue;
+
+		brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid);
+		if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid,
+			    BRCMF_P2P_WILDCARD_SSID_LEN))
+			return true;
+	}
+	return false;
+}
+
+/**
+ * brcmf_p2p_set_discover_state - set discover state in firmware.
+ *
+ * @ifp: low-level interface object.
+ * @state: discover state to set.
+ * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only).
+ * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only).
+ */
+static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state,
+					u16 chanspec, u16 listen_ms)
+{
+	struct brcmf_p2p_disc_st_le discover_state;
+	s32 ret = 0;
+	brcmf_dbg(TRACE, "enter\n");
+
+	discover_state.state = state;
+	discover_state.chspec = cpu_to_le16(chanspec);
+	discover_state.dwell = cpu_to_le16(listen_ms);
+	ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state,
+					sizeof(discover_state));
+	return ret;
+}
+
+/**
+ * brcmf_p2p_deinit_discovery() - disable P2P device discovery.
+ *
+ * @p2p: P2P specific data.
+ *
+ * Resets the discovery state and disables it in firmware.
+ */
+static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_cfg80211_vif *vif;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	/* Set the discovery state to SCAN */
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	(void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+
+	/* Disable P2P discovery in the firmware */
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+	(void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0);
+
+	return 0;
+}
+
+/**
+ * brcmf_p2p_enable_discovery() - initialize and configure discovery.
+ *
+ * @p2p: P2P specific data.
+ *
+ * Initializes the discovery device and configure the virtual interface.
+ */
+static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_cfg80211_vif *vif;
+	s32 ret = 0;
+
+	brcmf_dbg(TRACE, "enter\n");
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (!vif) {
+		brcmf_err("P2P config device not available\n");
+		ret = -EPERM;
+		goto exit;
+	}
+
+	if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) {
+		brcmf_dbg(INFO, "P2P config device already configured\n");
+		goto exit;
+	}
+
+	/* Re-initialize P2P Discovery in the firmware */
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+	ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1);
+	if (ret < 0) {
+		brcmf_err("set p2p_disc error\n");
+		goto exit;
+	}
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+	if (ret < 0) {
+		brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n");
+		goto exit;
+	}
+
+	/*
+	 * Set wsec to any non-zero value in the discovery bsscfg
+	 * to ensure our P2P probe responses have the privacy bit
+	 * set in the 802.11 WPA IE. Some peer devices may not
+	 * initiate WPS with us if this bit is not set.
+	 */
+	ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED);
+	if (ret < 0) {
+		brcmf_err("wsec error %d\n", ret);
+		goto exit;
+	}
+
+	set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status);
+exit:
+	return ret;
+}
+
+/**
+ * brcmf_p2p_escan() - initiate a P2P scan.
+ *
+ * @p2p: P2P specific data.
+ * @num_chans: number of channels to scan.
+ * @chanspecs: channel parameters for @num_chans channels.
+ * @search_state: P2P discover state to use.
+ * @action: scan action to pass to firmware.
+ * @bss_type: type of P2P bss.
+ */
+static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
+			   u16 chanspecs[], s32 search_state, u16 action,
+			   enum p2p_bss_type bss_type)
+{
+	s32 ret = 0;
+	s32 memsize = offsetof(struct brcmf_p2p_scan_le,
+			       eparams.params_le.channel_list);
+	s32 nprobes;
+	s32 active;
+	u32 i;
+	u8 *memblk;
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_p2p_scan_le *p2p_params;
+	struct brcmf_scan_params_le *sparams;
+	struct brcmf_ssid ssid;
+
+	memsize += num_chans * sizeof(__le16);
+	memblk = kzalloc(memsize, GFP_KERNEL);
+	if (!memblk)
+		return -ENOMEM;
+
+	vif = p2p->bss_idx[bss_type].vif;
+	if (vif == NULL) {
+		brcmf_err("no vif for bss type %d\n", bss_type);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	switch (search_state) {
+	case WL_P2P_DISC_ST_SEARCH:
+		/*
+		 * If we in SEARCH STATE, we don't need to set SSID explictly
+		 * because dongle use P2P WILDCARD internally by default
+		 */
+		/* use null ssid */
+		ssid.SSID_len = 0;
+		memset(ssid.SSID, 0, sizeof(ssid.SSID));
+		break;
+	case WL_P2P_DISC_ST_SCAN:
+		/*
+		 * wpa_supplicant has p2p_find command with type social or
+		 * progressive. For progressive, we need to set the ssid to
+		 * P2P WILDCARD because we just do broadcast scan unless
+		 * setting SSID.
+		 */
+		ssid.SSID_len = BRCMF_P2P_WILDCARD_SSID_LEN;
+		memcpy(ssid.SSID, BRCMF_P2P_WILDCARD_SSID, ssid.SSID_len);
+		break;
+	default:
+		brcmf_err(" invalid search state %d\n", search_state);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0);
+
+	/*
+	 * set p2p scan parameters.
+	 */
+	p2p_params = (struct brcmf_p2p_scan_le *)memblk;
+	p2p_params->type = 'E';
+
+	/* determine the scan engine parameters */
+	sparams = &p2p_params->eparams.params_le;
+	sparams->bss_type = DOT11_BSSTYPE_ANY;
+	if (p2p->cfg->active_scan)
+		sparams->scan_type = 0;
+	else
+		sparams->scan_type = 1;
+
+	memset(&sparams->bssid, 0xFF, ETH_ALEN);
+	if (ssid.SSID_len)
+		memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len);
+	sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
+	sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS);
+
+	/*
+	 * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan
+	 * supported by the supplicant.
+	 */
+	if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1))
+		active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;
+	else if (num_chans == AF_PEER_SEARCH_CNT)
+		active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS;
+	else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
+		active = -1;
+	else
+		active = P2PAPI_SCAN_DWELL_TIME_MS;
+
+	/* Override scan params to find a peer for a connection */
+	if (num_chans == 1) {
+		active = WL_SCAN_CONNECT_DWELL_TIME_MS;
+		/* WAR to sync with presence period of VSDB GO.
+		 * send probe request more frequently
+		 */
+		nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;
+	} else {
+		nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;
+	}
+
+	if (nprobes <= 0)
+		nprobes = 1;
+
+	brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active);
+	sparams->active_time = cpu_to_le32(active);
+	sparams->nprobes = cpu_to_le32(nprobes);
+	sparams->passive_time = cpu_to_le32(-1);
+	sparams->channel_num = cpu_to_le32(num_chans &
+					   BRCMF_SCAN_PARAMS_COUNT_MASK);
+	for (i = 0; i < num_chans; i++)
+		sparams->channel_list[i] = cpu_to_le16(chanspecs[i]);
+
+	/* set the escan specific parameters */
+	p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+	p2p_params->eparams.action =  cpu_to_le16(action);
+	p2p_params->eparams.sync_id = cpu_to_le16(0x1234);
+	/* perform p2p scan on primary device */
+	ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize);
+	if (!ret)
+		set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status);
+exit:
+	kfree(memblk);
+	return ret;
+}
+
+/**
+ * brcmf_p2p_run_escan() - escan callback for peer-to-peer.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @ndev: net device for which scan is requested.
+ * @request: scan request from cfg80211.
+ * @action: scan action.
+ *
+ * Determines the P2P discovery state based to scan request parameters and
+ * validates the channels in the request.
+ */
+static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
+			       struct net_device *ndev,
+			       struct cfg80211_scan_request *request,
+			       u16 action)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	s32 err = 0;
+	s32 search_state = WL_P2P_DISC_ST_SCAN;
+	struct brcmf_cfg80211_vif *vif;
+	struct net_device *dev = NULL;
+	int i, num_nodfs = 0;
+	u16 *chanspecs;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	if (!request) {
+		err = -EINVAL;
+		goto exit;
+	}
+
+	if (request->n_channels) {
+		chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs),
+				    GFP_KERNEL);
+		if (!chanspecs) {
+			err = -ENOMEM;
+			goto exit;
+		}
+		vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
+		if (vif)
+			dev = vif->wdev.netdev;
+		if (request->n_channels == 3 &&
+		    request->channels[0]->hw_value == SOCIAL_CHAN_1 &&
+		    request->channels[1]->hw_value == SOCIAL_CHAN_2 &&
+		    request->channels[2]->hw_value == SOCIAL_CHAN_3) {
+			/* SOCIAL CHANNELS 1, 6, 11 */
+			search_state = WL_P2P_DISC_ST_SEARCH;
+			brcmf_dbg(INFO, "P2P SEARCH PHASE START\n");
+		} else if (dev != NULL && vif->mode == WL_MODE_AP) {
+			/* If you are already a GO, then do SEARCH only */
+			brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");
+			search_state = WL_P2P_DISC_ST_SEARCH;
+		} else {
+			brcmf_dbg(INFO, "P2P SCAN STATE START\n");
+		}
+
+		/*
+		 * no P2P scanning on passive or DFS channels.
+		 */
+		for (i = 0; i < request->n_channels; i++) {
+			struct ieee80211_channel *chan = request->channels[i];
+
+			if (chan->flags & (IEEE80211_CHAN_RADAR |
+					   IEEE80211_CHAN_PASSIVE_SCAN))
+				continue;
+
+			chanspecs[i] = channel_to_chanspec(chan);
+			brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n",
+				  num_nodfs, chan->hw_value, chanspecs[i]);
+			num_nodfs++;
+		}
+		err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state,
+				      action, P2PAPI_BSSCFG_DEVICE);
+	}
+exit:
+	if (err)
+		brcmf_err("error (%d)\n", err);
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_find_listen_channel() - find listen channel in ie string.
+ *
+ * @ie: string of information elements.
+ * @ie_len: length of string.
+ *
+ * Scan ie for p2p ie and look for attribute 6 channel. If available determine
+ * channel and return it.
+ */
+static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len)
+{
+	u8 channel_ie[5];
+	s32 listen_channel;
+	s32 err;
+
+	err = cfg80211_get_p2p_attr(ie, ie_len,
+				    IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
+				    channel_ie, sizeof(channel_ie));
+	if (err < 0)
+		return err;
+
+	/* listen channel subel length format:     */
+	/* 3(country) + 1(op. class) + 1(chan num) */
+	listen_channel = (s32)channel_ie[3 + 1];
+
+	if (listen_channel == SOCIAL_CHAN_1 ||
+	    listen_channel == SOCIAL_CHAN_2 ||
+	    listen_channel == SOCIAL_CHAN_3) {
+		brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel);
+		return listen_channel;
+	}
+
+	return -EPERM;
+}
+
+
+/**
+ * brcmf_p2p_scan_prep() - prepare scan based on request.
+ *
+ * @wiphy: wiphy device.
+ * @request: scan request from cfg80211.
+ * @vif: vif on which scan request is to be executed.
+ *
+ * Prepare the scan appropriately for type of scan requested. Overrides the
+ * escan .run() callback for peer-to-peer scanning.
+ */
+int brcmf_p2p_scan_prep(struct wiphy *wiphy,
+			struct cfg80211_scan_request *request,
+			struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	int err = 0;
+
+	if (brcmf_p2p_scan_is_p2p_request(request)) {
+		/* find my listen channel */
+		err = brcmf_p2p_find_listen_channel(request->ie,
+						    request->ie_len);
+		if (err < 0)
+			return err;
+
+		p2p->afx_hdl.my_listen_chan = err;
+
+		clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
+
+		err = brcmf_p2p_enable_discovery(p2p);
+		if (err)
+			return err;
+
+		vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+
+		/* override .run_escan() callback. */
+		cfg->escan_info.run = brcmf_p2p_run_escan;
+	}
+	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
+				    request->ie, request->ie_len);
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_discover_listen() - set firmware to discover listen state.
+ *
+ * @p2p: p2p device.
+ * @channel: channel nr for discover listen.
+ * @duration: time in ms to stay on channel.
+ *
+ */
+static s32
+brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
+{
+	struct brcmf_cfg80211_vif *vif;
+	s32 err = 0;
+	u16 chanspec;
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (!vif) {
+		brcmf_err("Discovery is not set, so we have nothing to do\n");
+		err = -EPERM;
+		goto exit;
+	}
+
+	if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) {
+		brcmf_err("Previous LISTEN is not completed yet\n");
+		/* WAR: prevent cookie mismatch in wpa_supplicant return OK */
+		goto exit;
+	}
+
+	chanspec = brcmf_p2p_chnr_to_chspec(channel);
+	err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
+					   chanspec, (u16)duration);
+	if (!err) {
+		set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status);
+		p2p->remain_on_channel_cookie++;
+	}
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_remain_on_channel() - put device on channel and stay there.
+ *
+ * @wiphy: wiphy device.
+ * @channel: channel to stay on.
+ * @duration: time in ms to remain on channel.
+ *
+ */
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+				struct ieee80211_channel *channel,
+				unsigned int duration, u64 *cookie)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	s32 err;
+	u16 channel_nr;
+
+	channel_nr = ieee80211_frequency_to_channel(channel->center_freq);
+	brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr,
+		  duration);
+
+	err = brcmf_p2p_enable_discovery(p2p);
+	if (err)
+		goto exit;
+	err = brcmf_p2p_discover_listen(p2p, channel_nr, duration);
+	if (err)
+		goto exit;
+
+	memcpy(&p2p->remain_on_channel, channel, sizeof(*channel));
+	*cookie = p2p->remain_on_channel_cookie;
+	cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
+
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_notify_listen_complete() - p2p listen has completed.
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: payload of message. Not used.
+ *
+ */
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+
+	brcmf_dbg(TRACE, "Enter\n");
+	if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN,
+			       &p2p->status)) {
+		if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+				       &p2p->status)) {
+			clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+				  &p2p->status);
+			brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n");
+			complete(&p2p->wait_next_af);
+		}
+
+		cfg80211_remain_on_channel_expired(&ifp->vif->wdev,
+						   p2p->remain_on_channel_cookie,
+						   &p2p->remain_on_channel,
+						   GFP_KERNEL);
+	}
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.
+ *
+ * @ifp: interfac control.
+ *
+ */
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
+{
+	if (!ifp)
+		return;
+	brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+	brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);
+}
+
+
+/**
+ * brcmf_p2p_act_frm_search() - search function for action frame.
+ *
+ * @p2p: p2p device.
+ * channel: channel on which action frame is to be trasmitted.
+ *
+ * search function to reach at common channel to send action frame. When
+ * channel is 0 then all social channels will be used to send af
+ */
+static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel)
+{
+	s32 err;
+	u32 channel_cnt;
+	u16 *default_chan_list;
+	u32 i;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	if (channel)
+		channel_cnt = AF_PEER_SEARCH_CNT;
+	else
+		channel_cnt = SOCIAL_CHAN_CNT;
+	default_chan_list = kzalloc(channel_cnt * sizeof(*default_chan_list),
+				    GFP_KERNEL);
+	if (default_chan_list == NULL) {
+		brcmf_err("channel list allocation failed\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+	if (channel) {
+		/* insert same channel to the chan_list */
+		for (i = 0; i < channel_cnt; i++)
+			default_chan_list[i] =
+					brcmf_p2p_chnr_to_chspec(channel);
+	} else {
+		default_chan_list[0] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_1);
+		default_chan_list[1] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_2);
+		default_chan_list[2] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_3);
+	}
+	err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list,
+			      WL_P2P_DISC_ST_SEARCH, WL_ESCAN_ACTION_START,
+			      P2PAPI_BSSCFG_DEVICE);
+	kfree(default_chan_list);
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_afx_handler() - afx worker thread.
+ *
+ * @work:
+ *
+ */
+static void brcmf_p2p_afx_handler(struct work_struct *work)
+{
+	struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work);
+	struct brcmf_p2p_info *p2p = container_of(afx_hdl,
+						  struct brcmf_p2p_info,
+						  afx_hdl);
+	s32 err;
+
+	if (!afx_hdl->is_active)
+		return;
+
+	if (afx_hdl->is_listen && afx_hdl->my_listen_chan)
+		/* 100ms ~ 300ms */
+		err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan,
+						100 * (1 + (random32() % 3)));
+	else
+		err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan);
+
+	if (err) {
+		brcmf_err("ERROR occurred! value is (%d)\n", err);
+		if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+			     &p2p->status))
+			complete(&afx_hdl->act_frm_scan);
+	}
+}
+
+
+/**
+ * brcmf_p2p_af_searching_channel() - search channel.
+ *
+ * @p2p: p2p device info struct.
+ *
+ */
+static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
+{
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	struct brcmf_cfg80211_vif *pri_vif;
+	unsigned long duration;
+	s32 retry;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+
+	INIT_COMPLETION(afx_hdl->act_frm_scan);
+	set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
+	afx_hdl->is_active = true;
+	afx_hdl->peer_chan = P2P_INVALID_CHANNEL;
+
+	/* Loop to wait until we find a peer's channel or the
+	 * pending action frame tx is cancelled.
+	 */
+	retry = 0;
+	duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT);
+	while ((retry < P2P_CHANNEL_SYNC_RETRY) &&
+	       (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {
+		afx_hdl->is_listen = false;
+		brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n",
+			  retry);
+		/* search peer on peer's listen channel */
+		schedule_work(&afx_hdl->afx_work);
+		wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration);
+		if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
+		    (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+			       &p2p->status)))
+			break;
+
+		if (afx_hdl->my_listen_chan) {
+			brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n",
+				  afx_hdl->my_listen_chan);
+			/* listen on my listen channel */
+			afx_hdl->is_listen = true;
+			schedule_work(&afx_hdl->afx_work);
+			wait_for_completion_timeout(&afx_hdl->act_frm_scan,
+						    duration);
+		}
+		if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
+		    (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+			       &p2p->status)))
+			break;
+		retry++;
+
+		/* if sta is connected or connecting, sleep for a while before
+		 * retry af tx or finding a peer
+		 */
+		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) ||
+		    test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state))
+			msleep(P2P_DEFAULT_SLEEP_TIME_VSDB);
+	}
+
+	brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n",
+		  afx_hdl->peer_chan);
+	afx_hdl->is_active = false;
+
+	clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
+
+	return afx_hdl->peer_chan;
+}
+
+
+/**
+ * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel
+ *
+ * @cfg: common configuration struct.
+ * @bi: bss info struct, result from scan.
+ *
+ */
+bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
+					   struct brcmf_bss_info_le *bi)
+
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	u8 *ie;
+	s32 err;
+	u8 p2p_dev_addr[ETH_ALEN];
+
+	if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status))
+		return false;
+
+	if (bi == NULL) {
+		brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n");
+		if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)
+			complete(&afx_hdl->act_frm_scan);
+		return true;
+	}
+
+	ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
+	memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr));
+	err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
+				    IEEE80211_P2P_ATTR_DEVICE_INFO,
+				    p2p_dev_addr, sizeof(p2p_dev_addr));
+	if (err < 0)
+		err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
+					    IEEE80211_P2P_ATTR_DEVICE_ID,
+					    p2p_dev_addr, sizeof(p2p_dev_addr));
+	if ((err >= 0) &&
+	    (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) {
+		afx_hdl->peer_chan = bi->ctl_ch ? bi->ctl_ch :
+				      CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+		brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n",
+			  afx_hdl->tx_dst_addr, afx_hdl->peer_chan);
+		complete(&afx_hdl->act_frm_scan);
+	}
+	return true;
+}
+
+/**
+ * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete.
+ *
+ * @cfg: common configuration struct.
+ *
+ */
+static void
+brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct net_device *ndev = cfg->escan_info.ndev;
+
+	if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
+	    (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
+	     test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) {
+		brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n");
+		/* if channel is not zero, "actfame" uses off channel scan.
+		 * So abort scan for off channel completion.
+		 */
+		if (p2p->af_sent_channel)
+			brcmf_notify_escan_complete(cfg, ndev, true, true);
+	} else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+			    &p2p->status)) {
+		brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n");
+		/* So abort scan to cancel listen */
+		brcmf_notify_escan_complete(cfg, ndev, true, true);
+	}
+}
+
+
+/**
+ * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission
+ *
+ * @p2p: p2p device info struct.
+ *
+ * return true if recevied action frame is to be dropped.
+ */
+static bool
+brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)
+{
+	struct brcmf_cfg80211_info *cfg = p2p->cfg;
+	struct brcmf_if *ifp;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) ||
+	    !p2p->gon_req_action)
+		return false;
+
+	brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n");
+	/* if sa(peer) addr is less than da(my) addr, then this device
+	 * process peer's gon request and block to send gon req.
+	 * if not (sa addr > da addr),
+	 * this device will process gon request and drop gon req of peer.
+	 */
+	ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+	if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {
+		brcmf_dbg(INFO, "Block transmit gon req !!!\n");
+		p2p->block_gon_req_tx = true;
+		/* if we are finding a common channel for sending af,
+		 * do not scan more to block to send current gon req
+		 */
+		if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+				       &p2p->status))
+			complete(&p2p->afx_hdl.act_frm_scan);
+		if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+				       &p2p->status))
+			brcmf_p2p_stop_wait_next_action_frame(cfg);
+		return false;
+	}
+
+	/* drop gon request of peer to process gon request by this device. */
+	brcmf_dbg(INFO, "Drop received gon req !!!\n");
+
+	return true;
+}
+
+
+/**
+ * brcmf_p2p_notify_action_frame_rx() - received action frame.
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: payload of message, containing action frame data.
+ *
+ */
+int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	struct wireless_dev *wdev;
+	u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
+	struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
+	u8 *frame = (u8 *)(rxframe + 1);
+	struct brcmf_p2p_pub_act_frame *act_frm;
+	struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+	u16 chanspec = be16_to_cpu(rxframe->chanspec);
+	struct ieee80211_mgmt *mgmt_frame;
+	s32 freq;
+	u16 mgmt_type;
+	u8 action;
+
+	/* Check if wpa_supplicant has registered for this frame */
+	brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg);
+	mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4;
+	if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
+		return 0;
+
+	brcmf_p2p_print_actframe(false, frame, mgmt_frame_len);
+
+	action = P2P_PAF_SUBTYPE_INVALID;
+	if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) {
+		act_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+		action = act_frm->subtype;
+		if ((action == P2P_PAF_GON_REQ) &&
+		    (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) {
+			if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+				     &p2p->status) &&
+			    (memcmp(afx_hdl->tx_dst_addr, e->addr,
+				    ETH_ALEN) == 0)) {
+				afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+				brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",
+					  afx_hdl->peer_chan);
+				complete(&afx_hdl->act_frm_scan);
+			}
+			return 0;
+		}
+		/* After complete GO Negotiation, roll back to mpc mode */
+		if ((action == P2P_PAF_GON_CONF) ||
+		    (action == P2P_PAF_PROVDIS_RSP))
+			brcmf_set_mpc(ifp->ndev, 1);
+		if (action == P2P_PAF_GON_CONF) {
+			brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
+			clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		}
+	} else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) {
+		sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+		action = sd_act_frm->action;
+	}
+
+	if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
+	    (p2p->next_af_subtype == action)) {
+		brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action);
+		clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+			  &p2p->status);
+		/* Stop waiting for next AF. */
+		brcmf_p2p_stop_wait_next_action_frame(cfg);
+	}
+
+	mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) +
+			     mgmt_frame_len, GFP_KERNEL);
+	if (!mgmt_frame) {
+		brcmf_err("No memory available for action frame\n");
+		return -ENOMEM;
+	}
+	memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);
+	brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,
+			       ETH_ALEN);
+	memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);
+	mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
+	memcpy(&mgmt_frame->u, frame, mgmt_frame_len);
+	mgmt_frame_len += offsetof(struct ieee80211_mgmt, u);
+
+	freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
+					      CHSPEC_IS2G(chanspec) ?
+					      IEEE80211_BAND_2GHZ :
+					      IEEE80211_BAND_5GHZ);
+	wdev = ifp->ndev->ieee80211_ptr;
+	cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
+			 GFP_ATOMIC);
+
+	kfree(mgmt_frame);
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_notify_action_tx_complete() - transmit action frame complete
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: not used.
+ *
+ */
+int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
+					const struct brcmf_event_msg *e,
+					void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+
+	brcmf_dbg(INFO, "Enter: event %s, status=%d\n",
+		  e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ?
+		  "ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE",
+		  e->status);
+
+	if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status))
+		return 0;
+
+	if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {
+		if (e->status == BRCMF_E_STATUS_SUCCESS)
+			set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
+				&p2p->status);
+		else {
+			set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+			/* If there is no ack, we don't need to wait for
+			 * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
+			 */
+			brcmf_p2p_stop_wait_next_action_frame(cfg);
+		}
+
+	} else {
+		complete(&p2p->send_af_done);
+	}
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_tx_action_frame() - send action frame over fil.
+ *
+ * @p2p: p2p info struct for vif.
+ * @af_params: action frame data/info.
+ *
+ * Send an action frame immediately without doing channel synchronization.
+ *
+ * This function waits for a completion event before returning.
+ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
+ * frame is transmitted.
+ */
+static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
+				     struct brcmf_fil_af_params_le *af_params)
+{
+	struct brcmf_cfg80211_vif *vif;
+	s32 err = 0;
+	s32 timeout = 0;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	INIT_COMPLETION(p2p->send_af_done);
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
+					sizeof(*af_params));
+	if (err) {
+		brcmf_err(" sending action frame has failed\n");
+		goto exit;
+	}
+
+	p2p->af_sent_channel = le32_to_cpu(af_params->channel);
+	p2p->af_tx_sent_jiffies = jiffies;
+
+	timeout = wait_for_completion_timeout(&p2p->send_af_done,
+					msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME));
+
+	if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) {
+		brcmf_dbg(TRACE, "TX action frame operation is success\n");
+	} else {
+		err = -EIO;
+		brcmf_dbg(TRACE, "TX action frame operation has failed\n");
+	}
+	/* clear status bit for action tx */
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_pub_af_tx() - public action frame tx routine.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @af_params: action frame data/info.
+ * @config_af_params: configuration data for action frame.
+ *
+ * routine which transmits ation frame public type.
+ */
+static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg,
+			       struct brcmf_fil_af_params_le *af_params,
+			       struct brcmf_config_af_params *config_af_params)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_fil_action_frame_le *action_frame;
+	struct brcmf_p2p_pub_act_frame *act_frm;
+	s32 err = 0;
+	u16 ie_len;
+
+	action_frame = &af_params->action_frame;
+	act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data);
+
+	config_af_params->extra_listen = true;
+
+	switch (act_frm->subtype) {
+	case P2P_PAF_GON_REQ:
+		brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n");
+		set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		config_af_params->mpc_onoff = 0;
+		config_af_params->search_channel = true;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		p2p->gon_req_action = true;
+		/* increase dwell time to wait for RESP frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_GON_RSP:
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* increase dwell time to wait for CONF frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_GON_CONF:
+		/* If we reached till GO Neg confirmation reset the filter */
+		brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
+		clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		/* turn on mpc again if go nego is done */
+		config_af_params->mpc_onoff = 1;
+		/* minimize dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	case P2P_PAF_INVITE_REQ:
+		config_af_params->search_channel = true;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* increase dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_INVITE_RSP:
+		/* minimize dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	case P2P_PAF_DEVDIS_REQ:
+		config_af_params->search_channel = true;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* maximize dwell time to wait for RESP frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME);
+		break;
+	case P2P_PAF_DEVDIS_RSP:
+		/* minimize dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	case P2P_PAF_PROVDIS_REQ:
+		ie_len = le16_to_cpu(action_frame->len) -
+			 offsetof(struct brcmf_p2p_pub_act_frame, elts);
+		if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len,
+					  IEEE80211_P2P_ATTR_GROUP_ID,
+					  NULL, 0) < 0)
+			config_af_params->search_channel = true;
+		config_af_params->mpc_onoff = 0;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* increase dwell time to wait for RESP frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_PROVDIS_RSP:
+		/* wpa_supplicant send go nego req right after prov disc */
+		p2p->next_af_subtype = P2P_PAF_GON_REQ;
+		/* increase dwell time to MED level */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	default:
+		brcmf_err("Unknown p2p pub act frame subtype: %d\n",
+			  act_frm->subtype);
+		err = -EINVAL;
+	}
+	return err;
+}
+
+/**
+ * brcmf_p2p_send_action_frame() - send action frame .
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @ndev: net device to transmit on.
+ * @af_params: configuration data for action frame.
+ */
+bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
+				 struct net_device *ndev,
+				 struct brcmf_fil_af_params_le *af_params)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_fil_action_frame_le *action_frame;
+	struct brcmf_config_af_params config_af_params;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	u16 action_frame_len;
+	bool ack = false;
+	u8 category;
+	u8 action;
+	s32 tx_retry;
+	s32 extra_listen_time;
+	uint delta_ms;
+
+	action_frame = &af_params->action_frame;
+	action_frame_len = le16_to_cpu(action_frame->len);
+
+	brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len);
+
+	/* Add the default dwell time. Dwell time to stay off-channel */
+	/* to wait for a response action frame after transmitting an  */
+	/* GO Negotiation action frame                                */
+	af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME);
+
+	category = action_frame->data[DOT11_ACTION_CAT_OFF];
+	action = action_frame->data[DOT11_ACTION_ACT_OFF];
+
+	/* initialize variables */
+	p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
+	p2p->gon_req_action = false;
+
+	/* config parameters */
+	config_af_params.mpc_onoff = -1;
+	config_af_params.search_channel = false;
+	config_af_params.extra_listen = false;
+
+	if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) {
+		/* p2p public action frame process */
+		if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) {
+			/* Just send unknown subtype frame with */
+			/* default parameters.                  */
+			brcmf_err("P2P Public action frame, unknown subtype.\n");
+		}
+	} else if (brcmf_p2p_is_gas_action(action_frame->data,
+					   action_frame_len)) {
+		/* service discovery process */
+		if (action == P2PSD_ACTION_ID_GAS_IREQ ||
+		    action == P2PSD_ACTION_ID_GAS_CREQ) {
+			/* configure service discovery query frame */
+			config_af_params.search_channel = true;
+
+			/* save next af suptype to cancel */
+			/* remaining dwell time           */
+			p2p->next_af_subtype = action + 1;
+
+			af_params->dwell_time =
+				cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		} else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
+			   action == P2PSD_ACTION_ID_GAS_CRESP) {
+			/* configure service discovery response frame */
+			af_params->dwell_time =
+				cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		} else {
+			brcmf_err("Unknown action type: %d\n", action);
+			goto exit;
+		}
+	} else if (brcmf_p2p_is_p2p_action(action_frame->data,
+					   action_frame_len)) {
+		/* do not configure anything. it will be */
+		/* sent with a default configuration     */
+	} else {
+		brcmf_err("Unknown Frame: category 0x%x, action 0x%x\n",
+			  category, action);
+		return false;
+	}
+
+	/* if connecting on primary iface, sleep for a while before sending
+	 * af tx for VSDB
+	 */
+	if (test_bit(BRCMF_VIF_STATUS_CONNECTING,
+		     &p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state))
+		msleep(50);
+
+	/* if scan is ongoing, abort current scan. */
+	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+		brcmf_abort_scanning(cfg);
+
+	memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN);
+
+	/* To make sure to send successfully action frame, turn off mpc */
+	if (config_af_params.mpc_onoff == 0)
+		brcmf_set_mpc(ndev, 0);
+
+	/* set status and destination address before sending af */
+	if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
+		/* set status to cancel the remained dwell time in rx process */
+		set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
+	}
+
+	p2p->af_sent_channel = 0;
+	set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
+	/* validate channel and p2p ies */
+	if (config_af_params.search_channel &&
+	    IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) &&
+	    p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) {
+		afx_hdl = &p2p->afx_hdl;
+		afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel);
+
+		if (brcmf_p2p_af_searching_channel(p2p) ==
+							P2P_INVALID_CHANNEL) {
+			brcmf_err("Couldn't find peer's channel.\n");
+			goto exit;
+		}
+
+		/* Abort scan even for VSDB scenarios. Scan gets aborted in
+		 * firmware but after the check of piggyback algorithm. To take
+		 * care of current piggback algo, lets abort the scan here
+		 * itself.
+		 */
+		brcmf_notify_escan_complete(cfg, ndev, true, true);
+
+		/* update channel */
+		af_params->channel = cpu_to_le32(afx_hdl->peer_chan);
+	}
+
+	tx_retry = 0;
+	while (!p2p->block_gon_req_tx &&
+	       (ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) {
+		ack = !brcmf_p2p_tx_action_frame(p2p, af_params);
+		tx_retry++;
+	}
+	if (ack == false) {
+		brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry);
+		clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+	}
+
+exit:
+	clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
+
+	/* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
+	 * if we coundn't get the next action response frame and dongle does
+	 * not keep the dwell time, go to listen state again to get next action
+	 * response frame.
+	 */
+	if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx &&
+	    test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
+	    p2p->af_sent_channel == afx_hdl->my_listen_chan) {
+		delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies);
+		if (le32_to_cpu(af_params->dwell_time) > delta_ms)
+			extra_listen_time = le32_to_cpu(af_params->dwell_time) -
+					    delta_ms;
+		else
+			extra_listen_time = 0;
+		if (extra_listen_time > 50) {
+			set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+				&p2p->status);
+			brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n",
+				  le32_to_cpu(af_params->dwell_time),
+				  extra_listen_time);
+			extra_listen_time += 100;
+			if (!brcmf_p2p_discover_listen(p2p,
+						       p2p->af_sent_channel,
+						       extra_listen_time)) {
+				unsigned long duration;
+
+				extra_listen_time += 100;
+				duration = msecs_to_jiffies(extra_listen_time);
+				wait_for_completion_timeout(&p2p->wait_next_af,
+							    duration);
+			}
+			clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+				  &p2p->status);
+		}
+	}
+
+	if (p2p->block_gon_req_tx) {
+		/* if ack is true, supplicant will wait more time(100ms).
+		 * so we will return it as a success to get more time .
+		 */
+		p2p->block_gon_req_tx = false;
+		ack = true;
+	}
+
+	clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
+	/* if all done, turn mpc on again */
+	if (config_af_params.mpc_onoff == 1)
+		brcmf_set_mpc(ndev, 1);
+
+	return ack;
+}
+
+/**
+ * brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req.
+ *
+ * @ifp: interface pointer for which event was received.
+ * @e: even message.
+ * @data: payload of event message (probe request).
+ */
+s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
+					  const struct brcmf_event_msg *e,
+					  void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	struct wireless_dev *wdev;
+	struct brcmf_cfg80211_vif *vif = ifp->vif;
+	struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
+	u16 chanspec = be16_to_cpu(rxframe->chanspec);
+	u8 *mgmt_frame;
+	u32 mgmt_frame_len;
+	s32 freq;
+	u16 mgmt_type;
+
+	brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
+		  e->reason);
+
+	if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) &&
+	    (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) {
+		afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+		brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",
+			  afx_hdl->peer_chan);
+		complete(&afx_hdl->act_frm_scan);
+	}
+
+	/* Firmware sends us two proberesponses for each idx one. At the */
+	/* moment anything but bsscfgidx 0 is passed up to supplicant    */
+	if (e->bsscfgidx == 0)
+		return 0;
+
+	/* Filter any P2P probe reqs arriving during the GO-NEG Phase */
+	if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) {
+		brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n");
+		return 0;
+	}
+
+	/* Check if wpa_supplicant has registered for this frame */
+	brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
+	mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
+	if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
+		return 0;
+
+	mgmt_frame = (u8 *)(rxframe + 1);
+	mgmt_frame_len = e->datalen - sizeof(*rxframe);
+	freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
+					      CHSPEC_IS2G(chanspec) ?
+					      IEEE80211_BAND_2GHZ :
+					      IEEE80211_BAND_5GHZ);
+	wdev = ifp->ndev->ieee80211_ptr;
+	cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+
+	brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
+		  mgmt_frame_len, e->datalen, chanspec, freq);
+
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_attach() - attach for P2P.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ */
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_if *pri_ifp;
+	struct brcmf_if *p2p_ifp;
+	struct brcmf_cfg80211_vif *p2p_vif;
+	struct brcmf_p2p_info *p2p;
+	struct brcmf_pub *drvr;
+	s32 bssidx;
+	s32 err = 0;
+
+	p2p = &cfg->p2p;
+	p2p->cfg = cfg;
+
+	drvr = cfg->pub;
+
+	pri_ifp = drvr->iflist[0];
+	p2p_ifp = drvr->iflist[1];
+
+	p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
+	if (p2p_ifp) {
+		p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+					  false);
+		if (IS_ERR(p2p_vif)) {
+			brcmf_err("could not create discovery vif\n");
+			err = -ENOMEM;
+			goto exit;
+		}
+
+		p2p_vif->ifp = p2p_ifp;
+		p2p_ifp->vif = p2p_vif;
+		p2p_vif->wdev.netdev = p2p_ifp->ndev;
+		p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
+		SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
+
+		p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+
+		brcmf_p2p_generate_bss_mac(p2p);
+		brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+		/* Initialize P2P Discovery in the firmware */
+		err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+		if (err < 0) {
+			brcmf_err("set p2p_disc error\n");
+			brcmf_free_vif(p2p_vif);
+			goto exit;
+		}
+		/* obtain bsscfg index for P2P discovery */
+		err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+		if (err < 0) {
+			brcmf_err("retrieving discover bsscfg index failed\n");
+			brcmf_free_vif(p2p_vif);
+			goto exit;
+		}
+		/* Verify that firmware uses same bssidx as driver !! */
+		if (p2p_ifp->bssidx != bssidx) {
+			brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
+				  bssidx, p2p_ifp->bssidx);
+			brcmf_free_vif(p2p_vif);
+			goto exit;
+		}
+
+		init_completion(&p2p->send_af_done);
+		INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+		init_completion(&p2p->afx_hdl.act_frm_scan);
+		init_completion(&p2p->wait_next_af);
+	}
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_detach() - detach P2P.
+ *
+ * @p2p: P2P specific data.
+ */
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_cfg80211_vif *vif;
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (vif != NULL) {
+		brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+		brcmf_p2p_deinit_discovery(p2p);
+		/* remove discovery interface */
+		brcmf_free_vif(vif);
+		p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+	}
+	/* just set it all to zero */
+	memset(p2p, 0, sizeof(*p2p));
+}
+
+/**
+ * brcmf_p2p_get_current_chanspec() - Get current operation channel.
+ *
+ * @p2p: P2P specific data.
+ * @chanspec: chanspec to be returned.
+ */
+static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
+					   u16 *chanspec)
+{
+	struct brcmf_if *ifp;
+	struct brcmf_fil_chan_info_le ci;
+	s32 err;
+
+	ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+
+	*chanspec = 11 & WL_CHANSPEC_CHAN_MASK;
+
+	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci));
+	if (!err) {
+		*chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
+		if (*chanspec < CH_MAX_2G_CHANNEL)
+			*chanspec |= WL_CHANSPEC_BAND_2G;
+		else
+			*chanspec |= WL_CHANSPEC_BAND_5G;
+	}
+	*chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
+}
+
+/**
+ * Change a P2P Role.
+ * Parameters:
+ * @mac: MAC address of the BSS to change a role
+ * Returns 0 if success.
+ */
+int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
+		       enum brcmf_fil_p2p_if_types if_type)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_fil_p2p_if_le if_request;
+	s32 err;
+	u16 chanspec;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+	if (!vif) {
+		brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");
+		return -EPERM;
+	}
+	brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true);
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
+	if (!vif) {
+		brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");
+		return -EPERM;
+	}
+	brcmf_set_mpc(vif->ifp->ndev, 0);
+
+	/* In concurrency case, STA may be already associated in a particular */
+	/* channel. so retrieve the current channel of primary interface and  */
+	/* then start the virtual interface on that.                          */
+	brcmf_p2p_get_current_chanspec(p2p, &chanspec);
+
+	if_request.type = cpu_to_le16((u16)if_type);
+	if_request.chspec = cpu_to_le16(chanspec);
+	memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr));
+
+	brcmf_cfg80211_arm_vif_event(cfg, vif);
+	err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request,
+				       sizeof(if_request));
+	if (err) {
+		brcmf_err("p2p_ifupd FAILED, err=%d\n", err);
+		brcmf_cfg80211_arm_vif_event(cfg, NULL);
+		return err;
+	}
+	err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
+						    msecs_to_jiffies(1500));
+	brcmf_cfg80211_arm_vif_event(cfg, NULL);
+	if (!err)  {
+		brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
+		return -EIO;
+	}
+
+	err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT,
+				    BRCMF_SCB_TIMEOUT_VALUE);
+
+	return err;
+}
+
+static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p,
+				    struct brcmf_if *ifp, u8 ea[ETH_ALEN],
+				    enum brcmf_fil_p2p_if_types iftype)
+{
+	struct brcmf_fil_p2p_if_le if_request;
+	int err;
+	u16 chanspec;
+
+	/* we need a default channel */
+	brcmf_p2p_get_current_chanspec(p2p, &chanspec);
+
+	/* fill the firmware request */
+	memcpy(if_request.addr, ea, ETH_ALEN);
+	if_request.type = cpu_to_le16((u16)iftype);
+	if_request.chspec = cpu_to_le16(chanspec);
+
+	err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request,
+				       sizeof(if_request));
+	if (err)
+		return err;
+
+	return err;
+}
+
+static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
+	struct net_device *pri_ndev = cfg_to_ndev(cfg);
+	struct brcmf_if *ifp = netdev_priv(pri_ndev);
+	u8 *addr = vif->wdev.netdev->dev_addr;
+
+	return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN);
+}
+
+static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
+	struct net_device *pri_ndev = cfg_to_ndev(cfg);
+	struct brcmf_if *ifp = netdev_priv(pri_ndev);
+	u8 *addr = vif->wdev.netdev->dev_addr;
+
+	return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN);
+}
+
+/**
+ * brcmf_p2p_add_vif() - create a new P2P virtual interface.
+ *
+ * @wiphy: wiphy device of new interface.
+ * @name: name of the new interface.
+ * @type: nl80211 interface type.
+ * @flags: TBD
+ * @params: TBD
+ */
+struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+				       enum nl80211_iftype type, u32 *flags,
+				       struct vif_params *params)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+	struct brcmf_cfg80211_vif *vif;
+	enum brcmf_fil_p2p_if_types iftype;
+	enum wl_mode mode;
+	int err;
+
+	if (brcmf_cfg80211_vif_event_armed(cfg))
+		return ERR_PTR(-EBUSY);
+
+	brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type);
+
+	switch (type) {
+	case NL80211_IFTYPE_P2P_CLIENT:
+		iftype = BRCMF_FIL_P2P_IF_CLIENT;
+		mode = WL_MODE_BSS;
+		break;
+	case NL80211_IFTYPE_P2P_GO:
+		iftype = BRCMF_FIL_P2P_IF_GO;
+		mode = WL_MODE_AP;
+		break;
+	default:
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+
+	vif = brcmf_alloc_vif(cfg, type, false);
+	if (IS_ERR(vif))
+		return (struct wireless_dev *)vif;
+	brcmf_cfg80211_arm_vif_event(cfg, vif);
+
+	err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr,
+				       iftype);
+	if (err) {
+		brcmf_cfg80211_arm_vif_event(cfg, NULL);
+		goto fail;
+	}
+
+	/* wait for firmware event */
+	err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
+						    msecs_to_jiffies(1500));
+	brcmf_cfg80211_arm_vif_event(cfg, NULL);
+	if (!err) {
+		brcmf_err("timeout occurred\n");
+		err = -EIO;
+		goto fail;
+	}
+
+	/* interface created in firmware */
+	ifp = vif->ifp;
+	if (!ifp) {
+		brcmf_err("no if pointer provided\n");
+		err = -ENOENT;
+		goto fail;
+	}
+
+	strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
+	err = brcmf_net_attach(ifp, true);
+	if (err) {
+		brcmf_err("Registering netdevice failed\n");
+		goto fail;
+	}
+	cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
+	/* Disable firmware roaming for P2P interface  */
+	brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
+	if (iftype == BRCMF_FIL_P2P_IF_GO) {
+		/* set station timeout for p2p */
+		brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT,
+				      BRCMF_SCB_TIMEOUT_VALUE);
+	}
+	return &ifp->vif->wdev;
+
+fail:
+	brcmf_free_vif(vif);
+	return ERR_PTR(err);
+}
+
+/**
+ * brcmf_p2p_del_vif() - delete a P2P virtual interface.
+ *
+ * @wiphy: wiphy device of interface.
+ * @wdev: wireless device of interface.
+ *
+ * TODO: not yet supported.
+ */
+int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_cfg80211_vif *vif;
+	unsigned long jiffie_timeout = msecs_to_jiffies(1500);
+	bool wait_for_disable = false;
+	int err;
+
+	brcmf_dbg(TRACE, "delete P2P vif\n");
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+	switch (vif->wdev.iftype) {
+	case NL80211_IFTYPE_P2P_CLIENT:
+		if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
+			wait_for_disable = true;
+		break;
+
+	case NL80211_IFTYPE_P2P_GO:
+		if (!brcmf_p2p_disable_p2p_if(vif))
+			wait_for_disable = true;
+		break;
+
+	case NL80211_IFTYPE_P2P_DEVICE:
+	default:
+		return -ENOTSUPP;
+		break;
+	}
+
+	clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+	brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
+
+	if (wait_for_disable)
+		wait_for_completion_timeout(&cfg->vif_disabled,
+					    msecs_to_jiffies(500));
+
+	brcmf_vif_clear_mgmt_ies(vif);
+
+	brcmf_cfg80211_arm_vif_event(cfg, vif);
+	err = brcmf_p2p_release_p2p_if(vif);
+	if (!err) {
+		/* wait for firmware event */
+		err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
+							    jiffie_timeout);
+		if (!err)
+			err = -EIO;
+		else
+			err = 0;
+	}
+	brcmf_cfg80211_arm_vif_event(cfg, NULL);
+	brcmf_free_vif(vif);
+	p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
+
+	return err;
+}

+ 183 - 0
drivers/net/wireless/brcm80211/brcmfmac/p2p.h

@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef WL_CFGP2P_H_
+#define WL_CFGP2P_H_
+
+#include <net/cfg80211.h>
+
+struct brcmf_cfg80211_info;
+
+/**
+ * enum p2p_bss_type - different type of BSS configurations.
+ *
+ * @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg.
+ * @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg.
+ * @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg.
+ * @P2PAPI_BSSCFG_MAX: used for range checking.
+ */
+enum p2p_bss_type {
+	P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
+	P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
+	P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */
+	P2PAPI_BSSCFG_MAX
+};
+
+/**
+ * struct p2p_bss - peer-to-peer bss related information.
+ *
+ * @vif: virtual interface of this P2P bss.
+ * @private_data: TBD
+ */
+struct p2p_bss {
+	struct brcmf_cfg80211_vif *vif;
+	void *private_data;
+};
+
+/**
+ * enum brcmf_p2p_status - P2P specific dongle status.
+ *
+ * @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_DEL: NOT-USED?
+ * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle.
+ * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed.
+ * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked.
+ * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing.
+ * @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel.
+ * @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame.
+ * @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx.
+ * @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response.
+ * @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active.
+ */
+enum brcmf_p2p_status {
+	BRCMF_P2P_STATUS_ENABLED,
+	BRCMF_P2P_STATUS_IF_ADD,
+	BRCMF_P2P_STATUS_IF_DEL,
+	BRCMF_P2P_STATUS_IF_DELETING,
+	BRCMF_P2P_STATUS_IF_CHANGING,
+	BRCMF_P2P_STATUS_IF_CHANGED,
+	BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
+	BRCMF_P2P_STATUS_ACTION_TX_NOACK,
+	BRCMF_P2P_STATUS_GO_NEG_PHASE,
+	BRCMF_P2P_STATUS_DISCOVER_LISTEN,
+	BRCMF_P2P_STATUS_SENDING_ACT_FRAME,
+	BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+	BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+	BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL
+};
+
+/**
+ * struct afx_hdl - action frame off channel storage.
+ *
+ * @afx_work: worker thread for searching channel
+ * @act_frm_scan: thread synchronizing struct.
+ * @is_active: channel searching active.
+ * @peer_chan: current channel.
+ * @is_listen: sets mode for afx worker.
+ * @my_listen_chan: this peers listen channel.
+ * @peer_listen_chan: remote peers listen channel.
+ * @tx_dst_addr: mac address where tx af should be sent to.
+ */
+struct afx_hdl {
+	struct work_struct afx_work;
+	struct completion act_frm_scan;
+	bool is_active;
+	s32 peer_chan;
+	bool is_listen;
+	u16 my_listen_chan;
+	u16 peer_listen_chan;
+	u8 tx_dst_addr[ETH_ALEN];
+};
+
+/**
+ * struct brcmf_p2p_info - p2p specific driver information.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @status: status of P2P (see enum brcmf_p2p_status).
+ * @dev_addr: P2P device address.
+ * @int_addr: P2P interface address.
+ * @bss_idx: informate for P2P bss types.
+ * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state.
+ * @ssid: ssid for P2P GO.
+ * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state.
+ * @remain_on_channel: contains copy of struct used by cfg80211.
+ * @remain_on_channel_cookie: cookie counter for remain on channel cmd
+ * @next_af_subtype: expected action frame subtype.
+ * @send_af_done: indication that action frame tx is complete.
+ * @afx_hdl: action frame search handler info.
+ * @af_sent_channel: channel action frame is sent.
+ * @af_tx_sent_jiffies: jiffies time when af tx was transmitted.
+ * @wait_next_af: thread synchronizing struct.
+ * @gon_req_action: about to send go negotiation requets frame.
+ * @block_gon_req_tx: drop tx go negotiation requets frame.
+ */
+struct brcmf_p2p_info {
+	struct brcmf_cfg80211_info *cfg;
+	unsigned long status;
+	u8 dev_addr[ETH_ALEN];
+	u8 int_addr[ETH_ALEN];
+	struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX];
+	struct timer_list listen_timer;
+	struct brcmf_ssid ssid;
+	u8 listen_channel;
+	struct ieee80211_channel remain_on_channel;
+	u32 remain_on_channel_cookie;
+	u8 next_af_subtype;
+	struct completion send_af_done;
+	struct afx_hdl afx_hdl;
+	u32 af_sent_channel;
+	unsigned long af_tx_sent_jiffies;
+	struct completion wait_next_af;
+	bool gon_req_action;
+	bool block_gon_req_tx;
+};
+
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
+struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+				       enum nl80211_iftype type, u32 *flags,
+				       struct vif_params *params);
+int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
+int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
+		       enum brcmf_fil_p2p_if_types if_type);
+int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+int brcmf_p2p_scan_prep(struct wiphy *wiphy,
+			struct cfg80211_scan_request *request,
+			struct brcmf_cfg80211_vif *vif);
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+				struct ieee80211_channel *channel,
+				unsigned int duration, u64 *cookie);
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data);
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp);
+int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data);
+int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
+					const struct brcmf_event_msg *e,
+					void *data);
+bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
+				 struct net_device *ndev,
+				 struct brcmf_fil_af_params_le *af_params);
+bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
+					   struct brcmf_bss_info_le *bi);
+s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
+					  const struct brcmf_event_msg *e,
+					  void *data);
+#endif /* WL_CFGP2P_H_ */

+ 3 - 8
drivers/net/wireless/brcm80211/brcmfmac/usb.c

@@ -421,10 +421,6 @@ static void brcmf_usb_tx_complete(struct urb *urb)
 	brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
 	brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
 		  req->skb);
 		  req->skb);
 	brcmf_usb_del_fromq(devinfo, req);
 	brcmf_usb_del_fromq(devinfo, req);
-	if (urb->status == 0)
-		devinfo->bus_pub.bus->dstats.tx_packets++;
-	else
-		devinfo->bus_pub.bus->dstats.tx_errors++;
 
 
 	brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
 	brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
 
 
@@ -451,10 +447,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
 	req->skb = NULL;
 	req->skb = NULL;
 
 
 	/* zero lenght packets indicate usb "failure". Do not refill */
 	/* zero lenght packets indicate usb "failure". Do not refill */
-	if (urb->status == 0 && urb->actual_length) {
-		devinfo->bus_pub.bus->dstats.rx_packets++;
-	} else {
-		devinfo->bus_pub.bus->dstats.rx_errors++;
+	if (urb->status != 0 || !urb->actual_length) {
 		brcmu_pkt_buf_free_skb(skb);
 		brcmu_pkt_buf_free_skb(skb);
 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
 		return;
 		return;
@@ -1257,6 +1250,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
 	bus->bus_priv.usb = bus_pub;
 	bus->bus_priv.usb = bus_pub;
 	dev_set_drvdata(dev, bus);
 	dev_set_drvdata(dev, bus);
 	bus->ops = &brcmf_usb_bus_ops;
 	bus->ops = &brcmf_usb_bus_ops;
+	bus->chip = bus_pub->devid;
+	bus->chiprev = bus_pub->chiprev;
 
 
 	/* Attach to the common driver interface */
 	/* Attach to the common driver interface */
 	ret = brcmf_attach(0, dev);
 	ret = brcmf_attach(0, dev);

+ 997 - 374
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c

@@ -26,6 +26,8 @@
 #include <brcmu_wifi.h>
 #include <brcmu_wifi.h>
 #include "dhd.h"
 #include "dhd.h"
 #include "dhd_dbg.h"
 #include "dhd_dbg.h"
+#include "fwil_types.h"
+#include "p2p.h"
 #include "wl_cfg80211.h"
 #include "wl_cfg80211.h"
 #include "fwil.h"
 #include "fwil.h"
 
 
@@ -41,16 +43,13 @@
 #define BRCMF_PNO_SCAN_COMPLETE		1
 #define BRCMF_PNO_SCAN_COMPLETE		1
 #define BRCMF_PNO_SCAN_INCOMPLETE	0
 #define BRCMF_PNO_SCAN_INCOMPLETE	0
 
 
-#define BRCMF_IFACE_MAX_CNT		2
+#define BRCMF_IFACE_MAX_CNT		3
 
 
-#define TLV_LEN_OFF			1	/* length offset */
-#define TLV_HDR_LEN			2	/* header length */
-#define TLV_BODY_OFF			2	/* body offset */
-#define TLV_OUI_LEN			3	/* oui id length */
 #define WPA_OUI				"\x00\x50\xF2"	/* WPA OUI */
 #define WPA_OUI				"\x00\x50\xF2"	/* WPA OUI */
 #define WPA_OUI_TYPE			1
 #define WPA_OUI_TYPE			1
 #define RSN_OUI				"\x00\x0F\xAC"	/* RSN OUI */
 #define RSN_OUI				"\x00\x0F\xAC"	/* RSN OUI */
 #define	WME_OUI_TYPE			2
 #define	WME_OUI_TYPE			2
+#define WPS_OUI_TYPE			4
 
 
 #define VS_IE_FIXED_HDR_LEN		6
 #define VS_IE_FIXED_HDR_LEN		6
 #define WPA_IE_VERSION_LEN		2
 #define WPA_IE_VERSION_LEN		2
@@ -76,13 +75,15 @@
 #define VNDR_IE_PKTFLAG_OFFSET		8
 #define VNDR_IE_PKTFLAG_OFFSET		8
 #define VNDR_IE_VSIE_OFFSET		12
 #define VNDR_IE_VSIE_OFFSET		12
 #define VNDR_IE_HDR_SIZE		12
 #define VNDR_IE_HDR_SIZE		12
-#define VNDR_IE_BEACON_FLAG		0x1
-#define VNDR_IE_PRBRSP_FLAG		0x2
-#define MAX_VNDR_IE_NUMBER		5
+#define VNDR_IE_PARSE_LIMIT		5
 
 
 #define	DOT11_MGMT_HDR_LEN		24	/* d11 management header len */
 #define	DOT11_MGMT_HDR_LEN		24	/* d11 management header len */
 #define	DOT11_BCN_PRB_FIXED_LEN		12	/* beacon/probe fixed length */
 #define	DOT11_BCN_PRB_FIXED_LEN		12	/* beacon/probe fixed length */
 
 
+#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS	320
+#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS	400
+#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS	20
+
 #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
 #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
 	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
 	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
 
 
@@ -271,13 +272,6 @@ static const u32 __wl_cipher_suites[] = {
 	WLAN_CIPHER_SUITE_AES_CMAC,
 	WLAN_CIPHER_SUITE_AES_CMAC,
 };
 };
 
 
-/* tag_ID/length/value_buffer tuple */
-struct brcmf_tlv {
-	u8 id;
-	u8 len;
-	u8 data[1];
-};
-
 /* Vendor specific ie. id = 221, oui and type defines exact ie */
 /* Vendor specific ie. id = 221, oui and type defines exact ie */
 struct brcmf_vs_tlv {
 struct brcmf_vs_tlv {
 	u8 id;
 	u8 id;
@@ -294,7 +288,7 @@ struct parsed_vndr_ie_info {
 
 
 struct parsed_vndr_ies {
 struct parsed_vndr_ies {
 	u32 count;
 	u32 count;
-	struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
+	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 };
 };
 
 
 /* Quarter dBm units to mW
 /* Quarter dBm units to mW
@@ -381,7 +375,7 @@ static u8 brcmf_mw_to_qdbm(u16 mw)
 	return qdbm;
 	return qdbm;
 }
 }
 
 
-static u16 channel_to_chanspec(struct ieee80211_channel *ch)
+u16 channel_to_chanspec(struct ieee80211_channel *ch)
 {
 {
 	u16 chanspec;
 	u16 chanspec;
 
 
@@ -393,19 +387,92 @@ static u16 channel_to_chanspec(struct ieee80211_channel *ch)
 	else
 	else
 		chanspec |= WL_CHANSPEC_BAND_5G;
 		chanspec |= WL_CHANSPEC_BAND_5G;
 
 
-	if (ch->flags & IEEE80211_CHAN_NO_HT40) {
-		chanspec |= WL_CHANSPEC_BW_20;
-		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-	} else {
-		chanspec |= WL_CHANSPEC_BW_40;
-		if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS)
-			chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
-		else
-			chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
-	}
+	chanspec |= WL_CHANSPEC_BW_20;
+	chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
 	return chanspec;
 	return chanspec;
 }
 }
 
 
+/* Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+{
+	struct brcmf_tlv *elt;
+	int totlen;
+
+	elt = (struct brcmf_tlv *)buf;
+	totlen = buflen;
+
+	/* find tagged parameter */
+	while (totlen >= TLV_HDR_LEN) {
+		int len = elt->len;
+
+		/* validate remaining totlen */
+		if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
+			return elt;
+
+		elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
+		totlen -= (len + TLV_HDR_LEN);
+	}
+
+	return NULL;
+}
+
+/* Is any of the tlvs the expected entry? If
+ * not update the tlvs buffer pointer/length.
+ */
+static bool
+brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
+		 u8 *oui, u32 oui_len, u8 type)
+{
+	/* If the contents match the OUI and the type */
+	if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
+	    !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
+	    type == ie[TLV_BODY_OFF + oui_len]) {
+		return true;
+	}
+
+	if (tlvs == NULL)
+		return false;
+	/* point to the next ie */
+	ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
+	/* calculate the length of the rest of the buffer */
+	*tlvs_len -= (int)(ie - *tlvs);
+	/* update the pointer to the start of the buffer */
+	*tlvs = ie;
+
+	return false;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpaie(u8 *parse, u32 len)
+{
+	struct brcmf_tlv *ie;
+
+	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
+			return (struct brcmf_vs_tlv *)ie;
+	}
+	return NULL;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpsie(u8 *parse, u32 len)
+{
+	struct brcmf_tlv *ie;
+
+	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+				     WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
+			return (struct brcmf_vs_tlv *)ie;
+	}
+	return NULL;
+}
+
+
 static void convert_key_from_CPU(struct brcmf_wsec_key *key,
 static void convert_key_from_CPU(struct brcmf_wsec_key *key,
 				 struct brcmf_wsec_key_le *key_le)
 				 struct brcmf_wsec_key_le *key_le)
 {
 {
@@ -438,11 +505,153 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
 	return err;
 	return err;
 }
 }
 
 
+static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
+						     const char *name,
+						     enum nl80211_iftype type,
+						     u32 *flags,
+						     struct vif_params *params)
+{
+	brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
+	switch (type) {
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_MESH_POINT:
+		return ERR_PTR(-EOPNOTSUPP);
+	case NL80211_IFTYPE_P2P_CLIENT:
+	case NL80211_IFTYPE_P2P_GO:
+		return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NL80211_IFTYPE_P2P_DEVICE:
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+void brcmf_set_mpc(struct net_device *ndev, int mpc)
+{
+	struct brcmf_if *ifp = netdev_priv(ndev);
+	s32 err = 0;
+
+	if (check_vif_up(ifp->vif)) {
+		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
+		if (err) {
+			brcmf_err("fail to set mpc\n");
+			return;
+		}
+		brcmf_dbg(INFO, "MPC : %d\n", mpc);
+	}
+}
+
+s32
+brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+			    struct net_device *ndev,
+			    bool aborted, bool fw_abort)
+{
+	struct brcmf_scan_params_le params_le;
+	struct cfg80211_scan_request *scan_request;
+	s32 err = 0;
+
+	brcmf_dbg(SCAN, "Enter\n");
+
+	/* clear scan request, because the FW abort can cause a second call */
+	/* to this functon and might cause a double cfg80211_scan_done      */
+	scan_request = cfg->scan_request;
+	cfg->scan_request = NULL;
+
+	if (timer_pending(&cfg->escan_timeout))
+		del_timer_sync(&cfg->escan_timeout);
+
+	if (fw_abort) {
+		/* Do a scan abort to stop the driver's scan engine */
+		brcmf_dbg(SCAN, "ABORT scan in firmware\n");
+		memset(&params_le, 0, sizeof(params_le));
+		memset(params_le.bssid, 0xFF, ETH_ALEN);
+		params_le.bss_type = DOT11_BSSTYPE_ANY;
+		params_le.scan_type = 0;
+		params_le.channel_num = cpu_to_le32(1);
+		params_le.nprobes = cpu_to_le32(1);
+		params_le.active_time = cpu_to_le32(-1);
+		params_le.passive_time = cpu_to_le32(-1);
+		params_le.home_time = cpu_to_le32(-1);
+		/* Scan is aborted by setting channel_list[0] to -1 */
+		params_le.channel_list[0] = cpu_to_le16(-1);
+		/* E-Scan (or anyother type) can be aborted by SCAN */
+		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
+					     &params_le, sizeof(params_le));
+		if (err)
+			brcmf_err("Scan abort  failed\n");
+	}
+	/*
+	 * e-scan can be initiated by scheduled scan
+	 * which takes precedence.
+	 */
+	if (cfg->sched_escan) {
+		brcmf_dbg(SCAN, "scheduled scan completed\n");
+		cfg->sched_escan = false;
+		if (!aborted)
+			cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
+		brcmf_set_mpc(ndev, 1);
+	} else if (scan_request) {
+		brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
+			  aborted ? "Aborted" : "Done");
+		cfg80211_scan_done(scan_request, aborted);
+		brcmf_set_mpc(ndev, 1);
+	}
+	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+		brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
+
+	return err;
+}
+
+static
+int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+	struct net_device *ndev = wdev->netdev;
+
+	/* vif event pending in firmware */
+	if (brcmf_cfg80211_vif_event_armed(cfg))
+		return -EBUSY;
+
+	if (ndev) {
+		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
+		    cfg->escan_info.ndev == ndev)
+			brcmf_notify_escan_complete(cfg, ndev, true,
+						    true);
+
+		brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
+	}
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_MESH_POINT:
+		return -EOPNOTSUPP;
+	case NL80211_IFTYPE_P2P_CLIENT:
+	case NL80211_IFTYPE_P2P_GO:
+		return brcmf_p2p_del_vif(wiphy, wdev);
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NL80211_IFTYPE_P2P_DEVICE:
+	default:
+		return -EINVAL;
+	}
+	return -EOPNOTSUPP;
+}
+
 static s32
 static s32
 brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
 brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
 			 enum nl80211_iftype type, u32 *flags,
 			 enum nl80211_iftype type, u32 *flags,
 			 struct vif_params *params)
 			 struct vif_params *params)
 {
 {
+	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_cfg80211_vif *vif = ifp->vif;
 	struct brcmf_cfg80211_vif *vif = ifp->vif;
 	s32 infra = 0;
 	s32 infra = 0;
@@ -462,10 +671,23 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
 		infra = 0;
 		infra = 0;
 		break;
 		break;
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_STATION:
+		/* Ignore change for p2p IF. Unclear why supplicant does this */
+		if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
+		    (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
+			brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
+			/* WAR: It is unexpected to get a change of VIF for P2P
+			 * IF, but it happens. The request can not be handled
+			 * but returning EPERM causes a crash. Returning 0
+			 * without setting ieee80211_ptr->iftype causes trace
+			 * (WARN_ON) but it works with wpa_supplicant
+			 */
+			return 0;
+		}
 		vif->mode = WL_MODE_BSS;
 		vif->mode = WL_MODE_BSS;
 		infra = 1;
 		infra = 1;
 		break;
 		break;
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
 		vif->mode = WL_MODE_AP;
 		vif->mode = WL_MODE_AP;
 		ap = 1;
 		ap = 1;
 		break;
 		break;
@@ -475,8 +697,14 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
 	}
 	}
 
 
 	if (ap) {
 	if (ap) {
-		set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
-		brcmf_dbg(INFO, "IF Type = AP\n");
+		if (type == NL80211_IFTYPE_P2P_GO) {
+			brcmf_dbg(INFO, "IF Type = P2P GO\n");
+			err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
+		}
+		if (!err) {
+			set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
+			brcmf_dbg(INFO, "IF Type = AP\n");
+		}
 	} else {
 	} else {
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
 		if (err) {
 		if (err) {
@@ -495,21 +723,6 @@ done:
 	return err;
 	return err;
 }
 }
 
 
-static void brcmf_set_mpc(struct net_device *ndev, int mpc)
-{
-	struct brcmf_if *ifp = netdev_priv(ndev);
-	s32 err = 0;
-
-	if (check_vif_up(ifp->vif)) {
-		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
-		if (err) {
-			brcmf_err("fail to set mpc\n");
-			return;
-		}
-		brcmf_dbg(INFO, "MPC : %d\n", mpc);
-	}
-}
-
 static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
 static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
 			     struct cfg80211_scan_request *request)
 			     struct cfg80211_scan_request *request)
 {
 {
@@ -589,69 +802,6 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
 			(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
 			(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
 }
 }
 
 
-static s32
-brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
-			    struct net_device *ndev,
-			    bool aborted, bool fw_abort)
-{
-	struct brcmf_scan_params_le params_le;
-	struct cfg80211_scan_request *scan_request;
-	s32 err = 0;
-
-	brcmf_dbg(SCAN, "Enter\n");
-
-	/* clear scan request, because the FW abort can cause a second call */
-	/* to this functon and might cause a double cfg80211_scan_done      */
-	scan_request = cfg->scan_request;
-	cfg->scan_request = NULL;
-
-	if (timer_pending(&cfg->escan_timeout))
-		del_timer_sync(&cfg->escan_timeout);
-
-	if (fw_abort) {
-		/* Do a scan abort to stop the driver's scan engine */
-		brcmf_dbg(SCAN, "ABORT scan in firmware\n");
-		memset(&params_le, 0, sizeof(params_le));
-		memset(params_le.bssid, 0xFF, ETH_ALEN);
-		params_le.bss_type = DOT11_BSSTYPE_ANY;
-		params_le.scan_type = 0;
-		params_le.channel_num = cpu_to_le32(1);
-		params_le.nprobes = cpu_to_le32(1);
-		params_le.active_time = cpu_to_le32(-1);
-		params_le.passive_time = cpu_to_le32(-1);
-		params_le.home_time = cpu_to_le32(-1);
-		/* Scan is aborted by setting channel_list[0] to -1 */
-		params_le.channel_list[0] = cpu_to_le16(-1);
-		/* E-Scan (or anyother type) can be aborted by SCAN */
-		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
-					     &params_le, sizeof(params_le));
-		if (err)
-			brcmf_err("Scan abort  failed\n");
-	}
-	/*
-	 * e-scan can be initiated by scheduled scan
-	 * which takes precedence.
-	 */
-	if (cfg->sched_escan) {
-		brcmf_dbg(SCAN, "scheduled scan completed\n");
-		cfg->sched_escan = false;
-		if (!aborted)
-			cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
-		brcmf_set_mpc(ndev, 1);
-	} else if (scan_request) {
-		brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
-			  aborted ? "Aborted" : "Done");
-		cfg80211_scan_done(scan_request, aborted);
-		brcmf_set_mpc(ndev, 1);
-	}
-	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-		brcmf_err("Scan complete while device not scanning\n");
-		return -EPERM;
-	}
-
-	return err;
-}
-
 static s32
 static s32
 brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
 brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
 		struct cfg80211_scan_request *request, u16 action)
 		struct cfg80211_scan_request *request, u16 action)
@@ -703,11 +853,12 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
 	s32 err;
 	s32 err;
 	u32 passive_scan;
 	u32 passive_scan;
 	struct brcmf_scan_results *results;
 	struct brcmf_scan_results *results;
+	struct escan_info *escan = &cfg->escan_info;
 
 
 	brcmf_dbg(SCAN, "Enter\n");
 	brcmf_dbg(SCAN, "Enter\n");
-	cfg->escan_info.ndev = ndev;
-	cfg->escan_info.wiphy = wiphy;
-	cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
+	escan->ndev = ndev;
+	escan->wiphy = wiphy;
+	escan->escan_state = WL_ESCAN_STATE_SCANNING;
 	passive_scan = cfg->active_scan ? 0 : 1;
 	passive_scan = cfg->active_scan ? 0 : 1;
 	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
 	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
 				    passive_scan);
 				    passive_scan);
@@ -721,7 +872,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
 	results->count = 0;
 	results->count = 0;
 	results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
 	results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
 
 
-	err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
+	err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
 	if (err)
 	if (err)
 		brcmf_set_mpc(ndev, 1);
 		brcmf_set_mpc(ndev, 1);
 	return err;
 	return err;
@@ -758,6 +909,12 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
 
 
+	/* If scan req comes for p2p0, send it over primary I/F */
+	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
+		ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+		ndev = ifp->ndev;
+	}
+
 	/* Arm scan timeout timer */
 	/* Arm scan timeout timer */
 	mod_timer(&cfg->escan_timeout, jiffies +
 	mod_timer(&cfg->escan_timeout, jiffies +
 			WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
 			WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
@@ -776,6 +933,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
 	cfg->scan_request = request;
 	cfg->scan_request = request;
 	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
 	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
 	if (escan_req) {
 	if (escan_req) {
+		cfg->escan_info.run = brcmf_run_escan;
+		err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);
+		if (err)
+			goto scan_out;
+
 		err = brcmf_do_escan(cfg, wiphy, ndev, request);
 		err = brcmf_do_escan(cfg, wiphy, ndev, request);
 		if (err)
 		if (err)
 			goto scan_out;
 			goto scan_out;
@@ -933,31 +1095,6 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
 	memset(prof, 0, sizeof(*prof));
 	memset(prof, 0, sizeof(*prof));
 }
 }
 
 
-static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
-	size_t *join_params_size)
-{
-	u16 chanspec = 0;
-
-	if (ch != 0) {
-		if (ch <= CH_MAX_2G_CHANNEL)
-			chanspec |= WL_CHANSPEC_BAND_2G;
-		else
-			chanspec |= WL_CHANSPEC_BAND_5G;
-
-		chanspec |= WL_CHANSPEC_BW_20;
-		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-
-		*join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
-				     sizeof(u16);
-
-		chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
-		join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
-		join_params->params_le.chanspec_num = cpu_to_le32(1);
-
-		brcmf_dbg(CONN, "channel %d, chanspec %#X\n", ch, chanspec);
-	}
-}
-
 static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
 static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
 {
 {
 	s32 err = 0;
 	s32 err = 0;
@@ -988,6 +1125,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
 	s32 err = 0;
 	s32 err = 0;
 	s32 wsec = 0;
 	s32 wsec = 0;
 	s32 bcnprd;
 	s32 bcnprd;
+	u16 chanspec;
 
 
 	brcmf_dbg(TRACE, "Enter\n");
 	brcmf_dbg(TRACE, "Enter\n");
 	if (!check_vif_up(ifp->vif))
 	if (!check_vif_up(ifp->vif))
@@ -1091,8 +1229,11 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
 				params->chandef.chan->center_freq);
 				params->chandef.chan->center_freq);
 		if (params->channel_fixed) {
 		if (params->channel_fixed) {
 			/* adding chanspec */
 			/* adding chanspec */
-			brcmf_ch_to_chanspec(cfg->channel,
-				&join_params, &join_params_size);
+			chanspec = channel_to_chanspec(params->chandef.chan);
+			join_params.params_le.chanspec_list[0] =
+				cpu_to_le16(chanspec);
+			join_params.params_le.chanspec_num = cpu_to_le32(1);
+			join_params_size += sizeof(join_params.params_le);
 		}
 		}
 
 
 		/* set channel for starter */
 		/* set channel for starter */
@@ -1155,7 +1296,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
 	else
 	else
 		val = WPA_AUTH_DISABLED;
 		val = WPA_AUTH_DISABLED;
 	brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
 	brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
-	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
+	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
 	if (err) {
 	if (err) {
 		brcmf_err("set wpa_auth failed (%d)\n", err);
 		brcmf_err("set wpa_auth failed (%d)\n", err);
 		return err;
 		return err;
@@ -1194,7 +1335,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
 		break;
 		break;
 	}
 	}
 
 
-	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
+	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
 	if (err) {
 	if (err) {
 		brcmf_err("set auth failed (%d)\n", err);
 		brcmf_err("set auth failed (%d)\n", err);
 		return err;
 		return err;
@@ -1258,7 +1399,12 @@ brcmf_set_set_cipher(struct net_device *ndev,
 	}
 	}
 
 
 	brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
 	brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
-	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
+	/* In case of privacy, but no security and WPS then simulate */
+	/* setting AES. WPS-2.0 allows no security                   */
+	if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
+	    sme->privacy)
+		pval = AES_ENABLED;
+	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
 	if (err) {
 	if (err) {
 		brcmf_err("error (%d)\n", err);
 		brcmf_err("error (%d)\n", err);
 		return err;
 		return err;
@@ -1280,8 +1426,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
 	s32 err = 0;
 	s32 err = 0;
 
 
 	if (sme->crypto.n_akm_suites) {
 	if (sme->crypto.n_akm_suites) {
-		err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
-					      "wpa_auth", &val);
+		err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
+					       "wpa_auth", &val);
 		if (err) {
 		if (err) {
 			brcmf_err("could not get wpa_auth (%d)\n", err);
 			brcmf_err("could not get wpa_auth (%d)\n", err);
 			return err;
 			return err;
@@ -1315,8 +1461,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
 		}
 		}
 
 
 		brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
 		brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
-		err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
-					      "wpa_auth", val);
+		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
+					       "wpa_auth", val);
 		if (err) {
 		if (err) {
 			brcmf_err("could not set wpa_auth (%d)\n", err);
 			brcmf_err("could not set wpa_auth (%d)\n", err);
 			return err;
 			return err;
@@ -1393,9 +1539,28 @@ brcmf_set_sharedkey(struct net_device *ndev,
 	return err;
 	return err;
 }
 }
 
 
+static
+enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
+					   enum nl80211_auth_type type)
+{
+	u32 ci;
+	if (type == NL80211_AUTHTYPE_AUTOMATIC) {
+		/* shift to ignore chip revision */
+		ci = brcmf_get_chip_info(ifp) >> 4;
+		switch (ci) {
+		case 43236:
+			brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
+			return NL80211_AUTHTYPE_OPEN_SYSTEM;
+		default:
+			break;
+		}
+	}
+	return type;
+}
+
 static s32
 static s32
 brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
-		    struct cfg80211_connect_params *sme)
+		       struct cfg80211_connect_params *sme)
 {
 {
 	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
@@ -1403,7 +1568,12 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 	struct ieee80211_channel *chan = sme->channel;
 	struct ieee80211_channel *chan = sme->channel;
 	struct brcmf_join_params join_params;
 	struct brcmf_join_params join_params;
 	size_t join_params_size;
 	size_t join_params_size;
-	struct brcmf_ssid ssid;
+	struct brcmf_tlv *rsn_ie;
+	struct brcmf_vs_tlv *wpa_ie;
+	void *ie;
+	u32 ie_len;
+	struct brcmf_ext_join_params_le *ext_join_params;
+	u16 chanspec;
 
 
 	s32 err = 0;
 	s32 err = 0;
 
 
@@ -1416,15 +1586,46 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	}
 	}
 
 
+	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
+		/* A normal (non P2P) connection request setup. */
+		ie = NULL;
+		ie_len = 0;
+		/* find the WPA_IE */
+		wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
+		if (wpa_ie) {
+			ie = wpa_ie;
+			ie_len = wpa_ie->len + TLV_HDR_LEN;
+		} else {
+			/* find the RSN_IE */
+			rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+						  WLAN_EID_RSN);
+			if (rsn_ie) {
+				ie = rsn_ie;
+				ie_len = rsn_ie->len + TLV_HDR_LEN;
+			}
+		}
+		brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
+	}
+
+	err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
+				    sme->ie, sme->ie_len);
+	if (err)
+		brcmf_err("Set Assoc REQ IE Failed\n");
+	else
+		brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
+
 	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
 	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
 
 
 	if (chan) {
 	if (chan) {
 		cfg->channel =
 		cfg->channel =
 			ieee80211_frequency_to_channel(chan->center_freq);
 			ieee80211_frequency_to_channel(chan->center_freq);
-		brcmf_dbg(CONN, "channel (%d), center_req (%d)\n",
-			  cfg->channel, chan->center_freq);
-	} else
+		chanspec = channel_to_chanspec(chan);
+		brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
+			  cfg->channel, chan->center_freq, chanspec);
+	} else {
 		cfg->channel = 0;
 		cfg->channel = 0;
+		chanspec = 0;
+	}
 
 
 	brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
 	brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
 
 
@@ -1434,6 +1635,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 		goto done;
 		goto done;
 	}
 	}
 
 
+	sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
 	err = brcmf_set_auth_type(ndev, sme);
 	err = brcmf_set_auth_type(ndev, sme);
 	if (err) {
 	if (err) {
 		brcmf_err("wl_set_auth_type failed (%d)\n", err);
 		brcmf_err("wl_set_auth_type failed (%d)\n", err);
@@ -1458,27 +1660,88 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 		goto done;
 		goto done;
 	}
 	}
 
 
+	profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
+				       (u32)sme->ssid_len);
+	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
+	if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+		profile->ssid.SSID[profile->ssid.SSID_len] = 0;
+		brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
+			  profile->ssid.SSID_len);
+	}
+
+	/* Join with specific BSSID and cached SSID
+	 * If SSID is zero join based on BSSID only
+	 */
+	join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
+		offsetof(struct brcmf_assoc_params_le, chanspec_list);
+	if (cfg->channel)
+		join_params_size += sizeof(u16);
+	ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
+	if (ext_join_params == NULL) {
+		err = -ENOMEM;
+		goto done;
+	}
+	ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
+	memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
+	       profile->ssid.SSID_len);
+	/*increase dwell time to receive probe response or detect Beacon
+	 * from target AP at a noisy air only during connect command
+	 */
+	ext_join_params->scan_le.active_time =
+		cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
+	ext_join_params->scan_le.passive_time =
+		cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
+	/* Set up join scan parameters */
+	ext_join_params->scan_le.scan_type = -1;
+	/* to sync with presence period of VSDB GO.
+	 * Send probe request more frequently. Probe request will be stopped
+	 * when it gets probe response from target AP/GO.
+	 */
+	ext_join_params->scan_le.nprobes =
+		cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
+			    BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
+	ext_join_params->scan_le.home_time = cpu_to_le32(-1);
+
+	if (sme->bssid)
+		memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
+	else
+		memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
+
+	if (cfg->channel) {
+		ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
+
+		ext_join_params->assoc_le.chanspec_list[0] =
+			cpu_to_le16(chanspec);
+	}
+
+	err  = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
+					 join_params_size);
+	kfree(ext_join_params);
+	if (!err)
+		/* This is it. join command worked, we are done */
+		goto done;
+
+	/* join command failed, fallback to set ssid */
 	memset(&join_params, 0, sizeof(join_params));
 	memset(&join_params, 0, sizeof(join_params));
 	join_params_size = sizeof(join_params.ssid_le);
 	join_params_size = sizeof(join_params.ssid_le);
 
 
-	profile->ssid.SSID_len = min_t(u32,
-				       sizeof(ssid.SSID), (u32)sme->ssid_len);
 	memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
 	memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
-	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
 	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
 	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
 
 
-	memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
-
-	if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
-		brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
-			  ssid.SSID, ssid.SSID_len);
+	if (sme->bssid)
+		memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
+	else
+		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
 
 
-	brcmf_ch_to_chanspec(cfg->channel,
-			     &join_params, &join_params_size);
+	if (cfg->channel) {
+		join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
+		join_params.params_le.chanspec_num = cpu_to_le32(1);
+		join_params_size += sizeof(join_params.params_le);
+	}
 	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
 	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
 				     &join_params, join_params_size);
 				     &join_params, join_params_size);
 	if (err)
 	if (err)
-		brcmf_err("WLC_SET_SSID failed (%d)\n", err);
+		brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
 
 
 done:
 done:
 	if (err)
 	if (err)
@@ -1937,7 +2200,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
 			goto done;
 			goto done;
 		}
 		}
 		/* Report the current tx rate */
 		/* Report the current tx rate */
-	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
+		err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
 		if (err) {
 		if (err) {
 			brcmf_err("Could not get rate (%d)\n", err);
 			brcmf_err("Could not get rate (%d)\n", err);
 			goto done;
 			goto done;
@@ -2182,78 +2445,10 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
 	return vif->mode == WL_MODE_IBSS;
 	return vif->mode == WL_MODE_IBSS;
 }
 }
 
 
-/*
- * Traverse a string of 1-byte tag/1-byte length/variable-length value
- * triples, returning a pointer to the substring whose first element
- * matches tag
- */
-static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
-{
-	struct brcmf_tlv *elt;
-	int totlen;
-
-	elt = (struct brcmf_tlv *) buf;
-	totlen = buflen;
-
-	/* find tagged parameter */
-	while (totlen >= TLV_HDR_LEN) {
-		int len = elt->len;
-
-		/* validate remaining totlen */
-		if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
-			return elt;
-
-		elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
-		totlen -= (len + TLV_HDR_LEN);
-	}
-
-	return NULL;
-}
-
-/* Is any of the tlvs the expected entry? If
- * not update the tlvs buffer pointer/length.
- */
-static bool
-brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
-		 u8 *oui, u32 oui_len, u8 type)
-{
-	/* If the contents match the OUI and the type */
-	if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
-	    !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
-	    type == ie[TLV_BODY_OFF + oui_len]) {
-		return true;
-	}
-
-	if (tlvs == NULL)
-		return false;
-	/* point to the next ie */
-	ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
-	/* calculate the length of the rest of the buffer */
-	*tlvs_len -= (int)(ie - *tlvs);
-	/* update the pointer to the start of the buffer */
-	*tlvs = ie;
-
-	return false;
-}
-
-static struct brcmf_vs_tlv *
-brcmf_find_wpaie(u8 *parse, u32 len)
+static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
+				 struct brcmf_if *ifp)
 {
 {
-	struct brcmf_tlv *ie;
-
-	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
-		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
-				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
-			return (struct brcmf_vs_tlv *)ie;
-	}
-	return NULL;
-}
-
-static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
-{
-	struct net_device *ndev = cfg_to_ndev(cfg);
-	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
-	struct brcmf_if *ifp = netdev_priv(ndev);
+	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
 	struct brcmf_bss_info_le *bi;
 	struct brcmf_bss_info_le *bi;
 	struct brcmf_ssid *ssid;
 	struct brcmf_ssid *ssid;
 	struct brcmf_tlv *tim;
 	struct brcmf_tlv *tim;
@@ -2309,7 +2504,7 @@ update_bss_info_out:
 	return err;
 	return err;
 }
 }
 
 
-static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
 {
 {
 	struct escan_info *escan = &cfg->escan_info;
 	struct escan_info *escan = &cfg->escan_info;
 
 
@@ -2328,8 +2523,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
 			container_of(work, struct brcmf_cfg80211_info,
 			container_of(work, struct brcmf_cfg80211_info,
 				     escan_timeout_work);
 				     escan_timeout_work);
 
 
-	brcmf_notify_escan_complete(cfg,
-		cfg->escan_info.ndev, true, true);
+	brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
 }
 }
 
 
 static void brcmf_escan_timeout(unsigned long data)
 static void brcmf_escan_timeout(unsigned long data)
@@ -2401,16 +2595,11 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
 
 
 	if (status == BRCMF_E_STATUS_PARTIAL) {
 	if (status == BRCMF_E_STATUS_PARTIAL) {
 		brcmf_dbg(SCAN, "ESCAN Partial result\n");
 		brcmf_dbg(SCAN, "ESCAN Partial result\n");
-		escan_result_le = (struct brcmf_escan_result_le *) data;
-		if (!escan_result_le) {
-			brcmf_err("Invalid escan result (NULL pointer)\n");
-			goto exit;
-		}
-		if (!cfg->scan_request) {
-			brcmf_dbg(SCAN, "result without cfg80211 request\n");
+		escan_result_le = (struct brcmf_escan_result_le *) data;
+		if (!escan_result_le) {
+			brcmf_err("Invalid escan result (NULL pointer)\n");
 			goto exit;
 			goto exit;
 		}
 		}
-
 		if (le16_to_cpu(escan_result_le->bss_count) != 1) {
 		if (le16_to_cpu(escan_result_le->bss_count) != 1) {
 			brcmf_err("Invalid bss_count %d: ignoring\n",
 			brcmf_err("Invalid bss_count %d: ignoring\n",
 				  escan_result_le->bss_count);
 				  escan_result_le->bss_count);
@@ -2418,6 +2607,14 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
 		}
 		}
 		bss_info_le = &escan_result_le->bss_info_le;
 		bss_info_le = &escan_result_le->bss_info_le;
 
 
+		if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
+			goto exit;
+
+		if (!cfg->scan_request) {
+			brcmf_dbg(SCAN, "result without cfg80211 request\n");
+			goto exit;
+		}
+
 		bi_length = le32_to_cpu(bss_info_le->length);
 		bi_length = le32_to_cpu(bss_info_le->length);
 		if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
 		if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
 					WL_ESCAN_RESULTS_FIXED_SIZE)) {
 					WL_ESCAN_RESULTS_FIXED_SIZE)) {
@@ -2456,6 +2653,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
 		list->count++;
 		list->count++;
 	} else {
 	} else {
 		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
 		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+		if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
+			goto exit;
 		if (cfg->scan_request) {
 		if (cfg->scan_request) {
 			cfg->bss_list = (struct brcmf_scan_results *)
 			cfg->bss_list = (struct brcmf_scan_results *)
 				cfg->escan_info.escan_buf;
 				cfg->escan_info.escan_buf;
@@ -2464,7 +2663,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
 			brcmf_notify_escan_complete(cfg, ndev, aborted,
 			brcmf_notify_escan_complete(cfg, ndev, aborted,
 						    false);
 						    false);
 		} else
 		} else
-			brcmf_err("Unexpected scan result 0x%x\n", status);
+			brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
+				  status);
 	}
 	}
 exit:
 exit:
 	return err;
 	return err;
@@ -2968,9 +3168,8 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
 }
 }
 #endif
 #endif
 
 
-static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
+static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
 {
 {
-	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err;
 	s32 err;
 
 
 	/* set auth */
 	/* set auth */
@@ -3229,7 +3428,7 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
 			  parsed_info->vndrie.oui[2],
 			  parsed_info->vndrie.oui[2],
 			  parsed_info->vndrie.oui_type);
 			  parsed_info->vndrie.oui_type);
 
 
-		if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
+		if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
 			break;
 			break;
 next:
 next:
 		remaining_len -= (ie->len + TLV_HDR_LEN);
 		remaining_len -= (ie->len + TLV_HDR_LEN);
@@ -3263,7 +3462,6 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
 	return ie_len + VNDR_IE_HDR_SIZE;
 	return ie_len + VNDR_IE_HDR_SIZE;
 }
 }
 
 
-static
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 			  const u8 *vndr_ie_buf, u32 vndr_ie_len)
 			  const u8 *vndr_ie_buf, u32 vndr_ie_len)
 {
 {
@@ -3295,24 +3493,28 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 	if (!iovar_ie_buf)
 	if (!iovar_ie_buf)
 		return -ENOMEM;
 		return -ENOMEM;
 	curr_ie_buf = iovar_ie_buf;
 	curr_ie_buf = iovar_ie_buf;
-	if (ifp->vif->mode == WL_MODE_AP) {
-		switch (pktflag) {
-		case VNDR_IE_PRBRSP_FLAG:
-			mgmt_ie_buf = saved_ie->probe_res_ie;
-			mgmt_ie_len = &saved_ie->probe_res_ie_len;
-			mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
-			break;
-		case VNDR_IE_BEACON_FLAG:
-			mgmt_ie_buf = saved_ie->beacon_ie;
-			mgmt_ie_len = &saved_ie->beacon_ie_len;
-			mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
-			break;
-		default:
-			err = -EPERM;
-			brcmf_err("not suitable type\n");
-			goto exit;
-		}
-	} else {
+	switch (pktflag) {
+	case BRCMF_VNDR_IE_PRBREQ_FLAG:
+		mgmt_ie_buf = saved_ie->probe_req_ie;
+		mgmt_ie_len = &saved_ie->probe_req_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
+		break;
+	case BRCMF_VNDR_IE_PRBRSP_FLAG:
+		mgmt_ie_buf = saved_ie->probe_res_ie;
+		mgmt_ie_len = &saved_ie->probe_res_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
+		break;
+	case BRCMF_VNDR_IE_BEACON_FLAG:
+		mgmt_ie_buf = saved_ie->beacon_ie;
+		mgmt_ie_len = &saved_ie->beacon_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
+		break;
+	case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
+		mgmt_ie_buf = saved_ie->assoc_req_ie;
+		mgmt_ie_len = &saved_ie->assoc_req_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
+		break;
+	default:
 		err = -EPERM;
 		err = -EPERM;
 		brcmf_err("not suitable type\n");
 		brcmf_err("not suitable type\n");
 		goto exit;
 		goto exit;
@@ -3421,6 +3623,49 @@ exit:
 	return err;
 	return err;
 }
 }
 
 
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
+{
+	s32 pktflags[] = {
+		BRCMF_VNDR_IE_PRBREQ_FLAG,
+		BRCMF_VNDR_IE_PRBRSP_FLAG,
+		BRCMF_VNDR_IE_BEACON_FLAG
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pktflags); i++)
+		brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
+
+	memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
+	return 0;
+}
+
+static s32
+brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
+			struct cfg80211_beacon_data *beacon)
+{
+	s32 err;
+
+	/* Set Beacon IEs to FW */
+	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
+				    beacon->tail, beacon->tail_len);
+	if (err) {
+		brcmf_err("Set Beacon IE Failed\n");
+		return err;
+	}
+	brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
+
+	/* Set Probe Response IEs to FW */
+	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
+				    beacon->proberesp_ies,
+				    beacon->proberesp_ies_len);
+	if (err)
+		brcmf_err("Set Probe Resp IE Failed\n");
+	else
+		brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
+
+	return err;
+}
+
 static s32
 static s32
 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 			struct cfg80211_ap_settings *settings)
 			struct cfg80211_ap_settings *settings)
@@ -3433,7 +3678,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 	struct brcmf_tlv *rsn_ie;
 	struct brcmf_tlv *rsn_ie;
 	struct brcmf_vs_tlv *wpa_ie;
 	struct brcmf_vs_tlv *wpa_ie;
 	struct brcmf_join_params join_params;
 	struct brcmf_join_params join_params;
-	s32 bssidx = 0;
+	enum nl80211_iftype dev_role;
+	struct brcmf_fil_bss_enable_le bss_enable;
 
 
 	brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
 	brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
 		  cfg80211_get_chandef_type(&settings->chandef),
 		  cfg80211_get_chandef_type(&settings->chandef),
@@ -3443,10 +3689,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 		  settings->ssid, settings->ssid_len, settings->auth_type,
 		  settings->ssid, settings->ssid_len, settings->auth_type,
 		  settings->inactivity_timeout);
 		  settings->inactivity_timeout);
 
 
-	if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
-		brcmf_err("Not in AP creation mode\n");
-		return -EPERM;
-	}
+	dev_role = ifp->vif->wdev.iftype;
 
 
 	memset(&ssid_le, 0, sizeof(ssid_le));
 	memset(&ssid_le, 0, sizeof(ssid_le));
 	if (settings->ssid == NULL || settings->ssid_len == 0) {
 	if (settings->ssid == NULL || settings->ssid_len == 0) {
@@ -3467,21 +3710,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 	}
 	}
 
 
 	brcmf_set_mpc(ndev, 0);
 	brcmf_set_mpc(ndev, 0);
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
-	if (err < 0) {
-		brcmf_err("BRCMF_C_DOWN error %d\n", err);
-		goto exit;
-	}
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
-	if (err < 0) {
-		brcmf_err("SET INFRA error %d\n", err);
-		goto exit;
-	}
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
-	if (err < 0) {
-		brcmf_err("setting AP mode failed %d\n", err);
-		goto exit;
-	}
 
 
 	/* find the RSN_IE */
 	/* find the RSN_IE */
 	rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
 	rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
@@ -3507,27 +3735,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 		}
 		}
 	} else {
 	} else {
 		brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
 		brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
-		brcmf_configure_opensecurity(ndev, bssidx);
+		brcmf_configure_opensecurity(ifp);
 	}
 	}
-	/* Set Beacon IEs to FW */
-	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
-				    VNDR_IE_BEACON_FLAG,
-				    settings->beacon.tail,
-				    settings->beacon.tail_len);
-	if (err)
-		brcmf_err("Set Beacon IE Failed\n");
-	else
-		brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
 
 
-	/* Set Probe Response IEs to FW */
-	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
-				    VNDR_IE_PRBRSP_FLAG,
-				    settings->beacon.proberesp_ies,
-				    settings->beacon.proberesp_ies_len);
-	if (err)
-		brcmf_err("Set Probe Resp IE Failed\n");
-	else
-		brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
+	brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
 
 
 	if (settings->beacon_interval) {
 	if (settings->beacon_interval) {
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
@@ -3545,22 +3756,62 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 			goto exit;
 			goto exit;
 		}
 		}
 	}
 	}
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
-	if (err < 0) {
-		brcmf_err("BRCMF_C_UP error (%d)\n", err);
-		goto exit;
+
+	if (dev_role == NL80211_IFTYPE_AP) {
+		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
+		if (err < 0) {
+			brcmf_err("BRCMF_C_DOWN error %d\n", err);
+			goto exit;
+		}
+		brcmf_fil_iovar_int_set(ifp, "apsta", 0);
 	}
 	}
 
 
-	memset(&join_params, 0, sizeof(join_params));
-	/* join parameters starts with ssid */
-	memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
-	/* create softap */
-	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
-				     &join_params, sizeof(join_params));
+	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
 	if (err < 0) {
 	if (err < 0) {
-		brcmf_err("SET SSID error (%d)\n", err);
+		brcmf_err("SET INFRA error %d\n", err);
 		goto exit;
 		goto exit;
 	}
 	}
+	if (dev_role == NL80211_IFTYPE_AP) {
+		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
+		if (err < 0) {
+			brcmf_err("setting AP mode failed %d\n", err);
+			goto exit;
+		}
+		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
+		if (err < 0) {
+			brcmf_err("BRCMF_C_UP error (%d)\n", err);
+			goto exit;
+		}
+
+		memset(&join_params, 0, sizeof(join_params));
+		/* join parameters starts with ssid */
+		memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
+		/* create softap */
+		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+					     &join_params, sizeof(join_params));
+		if (err < 0) {
+			brcmf_err("SET SSID error (%d)\n", err);
+			goto exit;
+		}
+		brcmf_dbg(TRACE, "AP mode configuration complete\n");
+	} else {
+		err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
+						sizeof(ssid_le));
+		if (err < 0) {
+			brcmf_err("setting ssid failed %d\n", err);
+			goto exit;
+		}
+		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+		bss_enable.enable = cpu_to_le32(1);
+		err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+					       sizeof(bss_enable));
+		if (err < 0) {
+			brcmf_err("bss_enable config failed %d\n", err);
+			goto exit;
+		}
+
+		brcmf_dbg(TRACE, "GO mode configuration complete\n");
+	}
 	clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
 	clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
 	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
 	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
 
 
@@ -3574,10 +3825,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
 {
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err = -EPERM;
 	s32 err = -EPERM;
+	struct brcmf_fil_bss_enable_le bss_enable;
 
 
 	brcmf_dbg(TRACE, "Enter\n");
 	brcmf_dbg(TRACE, "Enter\n");
 
 
-	if (ifp->vif->mode == WL_MODE_AP) {
+	if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
 		/* Due to most likely deauths outstanding we sleep */
 		/* Due to most likely deauths outstanding we sleep */
 		/* first to make sure they get processed by fw. */
 		/* first to make sure they get processed by fw. */
 		msleep(400);
 		msleep(400);
@@ -3591,18 +3843,41 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
 			brcmf_err("BRCMF_C_UP error %d\n", err);
 			brcmf_err("BRCMF_C_UP error %d\n", err);
 			goto exit;
 			goto exit;
 		}
 		}
-		brcmf_set_mpc(ndev, 1);
-		clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
-		clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+	} else {
+		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+		bss_enable.enable = cpu_to_le32(0);
+		err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+					       sizeof(bss_enable));
+		if (err < 0)
+			brcmf_err("bss_enable config failed %d\n", err);
 	}
 	}
+	brcmf_set_mpc(ndev, 1);
+	set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+	clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+
 exit:
 exit:
 	return err;
 	return err;
 }
 }
 
 
+static s32
+brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
+			     struct cfg80211_beacon_data *info)
+{
+	struct brcmf_if *ifp = netdev_priv(ndev);
+	s32 err;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
+
+	return err;
+}
+
 static int
 static int
 brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
 brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
 			   u8 *mac)
 			   u8 *mac)
 {
 {
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 	struct brcmf_scb_val_le scbval;
 	struct brcmf_scb_val_le scbval;
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err;
 	s32 err;
@@ -3612,6 +3887,8 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
 
 
 	brcmf_dbg(TRACE, "Enter %pM\n", mac);
 	brcmf_dbg(TRACE, "Enter %pM\n", mac);
 
 
+	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+		ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
 	if (!check_vif_up(ifp->vif))
 	if (!check_vif_up(ifp->vif))
 		return -EIO;
 		return -EIO;
 
 
@@ -3626,7 +3903,147 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
 	return err;
 	return err;
 }
 }
 
 
+
+static void
+brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+				   struct wireless_dev *wdev,
+				   u16 frame_type, bool reg)
+{
+	struct brcmf_if *ifp = netdev_priv(wdev->netdev);
+	struct brcmf_cfg80211_vif *vif = ifp->vif;
+	u16 mgmt_type;
+
+	brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
+
+	mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+	if (reg)
+		vif->mgmt_rx_reg |= BIT(mgmt_type);
+	else
+		vif->mgmt_rx_reg &= ~BIT(mgmt_type);
+}
+
+
+static int
+brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
+		       struct ieee80211_channel *chan, bool offchan,
+		       unsigned int wait, const u8 *buf, size_t len,
+		       bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	const struct ieee80211_mgmt *mgmt;
+	struct brcmf_if *ifp;
+	struct brcmf_cfg80211_vif *vif;
+	s32 err = 0;
+	s32 ie_offset;
+	s32 ie_len;
+	struct brcmf_fil_action_frame_le *action_frame;
+	struct brcmf_fil_af_params_le *af_params;
+	bool ack;
+	s32 chan_nr;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	*cookie = 0;
+
+	mgmt = (const struct ieee80211_mgmt *)buf;
+
+	if (!ieee80211_is_mgmt(mgmt->frame_control)) {
+		brcmf_err("Driver only allows MGMT packet type\n");
+		return -EPERM;
+	}
+
+	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+		/* Right now the only reason to get a probe response */
+		/* is for p2p listen response or for p2p GO from     */
+		/* wpa_supplicant. Unfortunately the probe is send   */
+		/* on primary ndev, while dongle wants it on the p2p */
+		/* vif. Since this is only reason for a probe        */
+		/* response to be sent, the vif is taken from cfg.   */
+		/* If ever desired to send proberesp for non p2p     */
+		/* response then data should be checked for          */
+		/* "DIRECT-". Note in future supplicant will take    */
+		/* dedicated p2p wdev to do this and then this 'hack'*/
+		/* is not needed anymore.                            */
+		ie_offset =  DOT11_MGMT_HDR_LEN +
+			     DOT11_BCN_PRB_FIXED_LEN;
+		ie_len = len - ie_offset;
+		ifp = netdev_priv(wdev->netdev);
+		vif = ifp->vif;
+		if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
+			vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+		err = brcmf_vif_set_mgmt_ie(vif,
+					    BRCMF_VNDR_IE_PRBRSP_FLAG,
+					    &buf[ie_offset],
+					    ie_len);
+		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
+					GFP_KERNEL);
+	} else if (ieee80211_is_action(mgmt->frame_control)) {
+		af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
+		if (af_params == NULL) {
+			brcmf_err("unable to allocate frame\n");
+			err = -ENOMEM;
+			goto exit;
+		}
+		action_frame = &af_params->action_frame;
+		/* Add the packet Id */
+		action_frame->packet_id = cpu_to_le32(*cookie);
+		/* Add BSSID */
+		memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
+		memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
+		/* Add the length exepted for 802.11 header  */
+		action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
+		/* Add the channel */
+		chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
+		af_params->channel = cpu_to_le32(chan_nr);
+
+		memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
+		       le16_to_cpu(action_frame->len));
+
+		brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
+			  *cookie, le16_to_cpu(action_frame->len),
+			  chan->center_freq);
+
+		ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev,
+						  af_params);
+
+		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
+					GFP_KERNEL);
+		kfree(af_params);
+	} else {
+		brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
+		brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
+	}
+
+exit:
+	return err;
+}
+
+
+static int
+brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+					struct wireless_dev *wdev,
+					u64 cookie)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_cfg80211_vif *vif;
+	int err = 0;
+
+	brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
+
+	vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (vif == NULL) {
+		brcmf_err("No p2p device available for probe response\n");
+		err = -ENODEV;
+		goto exit;
+	}
+	brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+exit:
+	return err;
+}
+
 static struct cfg80211_ops wl_cfg80211_ops = {
 static struct cfg80211_ops wl_cfg80211_ops = {
+	.add_virtual_intf = brcmf_cfg80211_add_iface,
+	.del_virtual_intf = brcmf_cfg80211_del_iface,
 	.change_virtual_intf = brcmf_cfg80211_change_iface,
 	.change_virtual_intf = brcmf_cfg80211_change_iface,
 	.scan = brcmf_cfg80211_scan,
 	.scan = brcmf_cfg80211_scan,
 	.set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
 	.set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
@@ -3650,28 +4067,43 @@ static struct cfg80211_ops wl_cfg80211_ops = {
 	.flush_pmksa = brcmf_cfg80211_flush_pmksa,
 	.flush_pmksa = brcmf_cfg80211_flush_pmksa,
 	.start_ap = brcmf_cfg80211_start_ap,
 	.start_ap = brcmf_cfg80211_start_ap,
 	.stop_ap = brcmf_cfg80211_stop_ap,
 	.stop_ap = brcmf_cfg80211_stop_ap,
+	.change_beacon = brcmf_cfg80211_change_beacon,
 	.del_station = brcmf_cfg80211_del_station,
 	.del_station = brcmf_cfg80211_del_station,
 	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
 	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
 	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
 	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
+	.mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
+	.mgmt_tx = brcmf_cfg80211_mgmt_tx,
+	.remain_on_channel = brcmf_p2p_remain_on_channel,
+	.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
 #ifdef CONFIG_NL80211_TESTMODE
 #ifdef CONFIG_NL80211_TESTMODE
 	.testmode_cmd = brcmf_cfg80211_testmode
 	.testmode_cmd = brcmf_cfg80211_testmode
 #endif
 #endif
 };
 };
 
 
-static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
+static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
 {
 {
-	s32 err = 0;
-
-	switch (mode) {
-	case WL_MODE_BSS:
-		return NL80211_IFTYPE_STATION;
-	case WL_MODE_IBSS:
-		return NL80211_IFTYPE_ADHOC;
+	switch (type) {
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_MESH_POINT:
+		return -ENOTSUPP;
+	case NL80211_IFTYPE_ADHOC:
+		return WL_MODE_IBSS;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+		return WL_MODE_BSS;
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		return WL_MODE_AP;
+	case NL80211_IFTYPE_P2P_DEVICE:
+		return WL_MODE_P2P;
+	case NL80211_IFTYPE_UNSPECIFIED:
 	default:
 	default:
-		return NL80211_IFTYPE_UNSPECIFIED;
+		break;
 	}
 	}
 
 
-	return err;
+	return -EINVAL;
 }
 }
 
 
 static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
 static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
@@ -3683,6 +4115,56 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
 	wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 	wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 }
 }
 
 
+static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
+	{
+		.max = 2,
+		.types = BIT(NL80211_IFTYPE_STATION) |
+			 BIT(NL80211_IFTYPE_ADHOC) |
+			 BIT(NL80211_IFTYPE_AP)
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+			 BIT(NL80211_IFTYPE_P2P_GO)
+	},
+};
+static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
+	{
+		 .max_interfaces = BRCMF_IFACE_MAX_CNT,
+		 .num_different_channels = 1, /* no multi-channel for now */
+		 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
+		 .limits = brcmf_iface_limits
+	}
+};
+
+static const struct ieee80211_txrx_stypes
+brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+	[NL80211_IFTYPE_STATION] = {
+		.tx = 0xffff,
+		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+	},
+	[NL80211_IFTYPE_P2P_CLIENT] = {
+		.tx = 0xffff,
+		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+	},
+	[NL80211_IFTYPE_P2P_GO] = {
+		.tx = 0xffff,
+		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+		      BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+		      BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+		      BIT(IEEE80211_STYPE_AUTH >> 4) |
+		      BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+		      BIT(IEEE80211_STYPE_ACTION >> 4)
+	}
+};
+
 static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 {
 {
 	struct wiphy *wiphy;
 	struct wiphy *wiphy;
@@ -3695,10 +4177,16 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 	}
 	}
 	set_wiphy_dev(wiphy, phydev);
 	set_wiphy_dev(wiphy, phydev);
 	wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
 	wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+	wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
 	wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
 	wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 				 BIT(NL80211_IFTYPE_ADHOC) |
 				 BIT(NL80211_IFTYPE_ADHOC) |
-				 BIT(NL80211_IFTYPE_AP);
+				 BIT(NL80211_IFTYPE_AP) |
+				 BIT(NL80211_IFTYPE_P2P_CLIENT) |
+				 BIT(NL80211_IFTYPE_P2P_GO) |
+				 BIT(NL80211_IFTYPE_P2P_DEVICE);
+	wiphy->iface_combinations = brcmf_iface_combos;
+	wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
 	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
 	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
 	wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set
 	wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set
 						* it as 11a by default.
 						* it as 11a by default.
@@ -3710,10 +4198,11 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 	wiphy->cipher_suites = __wl_cipher_suites;
 	wiphy->cipher_suites = __wl_cipher_suites;
 	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
 	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
-	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;	/* enable power
-								 * save mode
-								 * by default
-								 */
+	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
+			WIPHY_FLAG_OFFCHAN_TX |
+			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+	wiphy->mgmt_stypes = brcmf_txrx_stypes;
+	wiphy->max_remain_on_channel_duration = 5000;
 	brcmf_wiphy_pno_params(wiphy);
 	brcmf_wiphy_pno_params(wiphy);
 	err = wiphy_register(wiphy);
 	err = wiphy_register(wiphy);
 	if (err < 0) {
 	if (err < 0) {
@@ -3724,31 +4213,25 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 	return wiphy;
 	return wiphy;
 }
 }
 
 
-static
 struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
-					   struct net_device *netdev,
-					   s32 mode, bool pm_block)
+					   enum nl80211_iftype type,
+					   bool pm_block)
 {
 {
 	struct brcmf_cfg80211_vif *vif;
 	struct brcmf_cfg80211_vif *vif;
 
 
 	if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
 	if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
 		return ERR_PTR(-ENOSPC);
 		return ERR_PTR(-ENOSPC);
 
 
+	brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
+		  sizeof(*vif));
 	vif = kzalloc(sizeof(*vif), GFP_KERNEL);
 	vif = kzalloc(sizeof(*vif), GFP_KERNEL);
 	if (!vif)
 	if (!vif)
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
 
 
 	vif->wdev.wiphy = cfg->wiphy;
 	vif->wdev.wiphy = cfg->wiphy;
-	vif->wdev.netdev = netdev;
-	vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
-
-	if (netdev) {
-		vif->ifp = netdev_priv(netdev);
-		netdev->ieee80211_ptr = &vif->wdev;
-		SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
-	}
+	vif->wdev.iftype = type;
 
 
-	vif->mode = mode;
+	vif->mode = brcmf_nl80211_iftype_to_mode(type);
 	vif->pm_block = pm_block;
 	vif->pm_block = pm_block;
 	vif->roam_off = -1;
 	vif->roam_off = -1;
 
 
@@ -3759,7 +4242,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 	return vif;
 	return vif;
 }
 }
 
 
-static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
 {
 {
 	struct brcmf_cfg80211_info *cfg;
 	struct brcmf_cfg80211_info *cfg;
 	struct wiphy *wiphy;
 	struct wiphy *wiphy;
@@ -3833,9 +4316,9 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
 	conn_info->resp_ie_len = 0;
 	conn_info->resp_ie_len = 0;
 }
 }
 
 
-static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
+static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
+			       struct brcmf_if *ifp)
 {
 {
-	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
 	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
 	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
 	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
 	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
 	u32 req_len;
 	u32 req_len;
@@ -3911,9 +4394,9 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
 
 
 	brcmf_dbg(TRACE, "Enter\n");
 	brcmf_dbg(TRACE, "Enter\n");
 
 
-	brcmf_get_assoc_ies(cfg);
+	brcmf_get_assoc_ies(cfg, ifp);
 	memcpy(profile->bssid, e->addr, ETH_ALEN);
 	memcpy(profile->bssid, e->addr, ETH_ALEN);
-	brcmf_update_bss_info(cfg);
+	brcmf_update_bss_info(cfg, ifp);
 
 
 	buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
 	buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
 	if (buf == NULL) {
 	if (buf == NULL) {
@@ -3968,9 +4451,11 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
 	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 			       &ifp->vif->sme_state)) {
 			       &ifp->vif->sme_state)) {
 		if (completed) {
 		if (completed) {
-			brcmf_get_assoc_ies(cfg);
+			brcmf_get_assoc_ies(cfg, ifp);
 			memcpy(profile->bssid, e->addr, ETH_ALEN);
 			memcpy(profile->bssid, e->addr, ETH_ALEN);
-			brcmf_update_bss_info(cfg);
+			brcmf_update_bss_info(cfg, ifp);
+			set_bit(BRCMF_VIF_STATUS_CONNECTED,
+				&ifp->vif->sme_state);
 		}
 		}
 		cfg80211_connect_result(ndev,
 		cfg80211_connect_result(ndev,
 					(u8 *)profile->bssid,
 					(u8 *)profile->bssid,
@@ -3981,9 +4466,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
 					completed ? WLAN_STATUS_SUCCESS :
 					completed ? WLAN_STATUS_SUCCESS :
 						    WLAN_STATUS_AUTH_TIMEOUT,
 						    WLAN_STATUS_AUTH_TIMEOUT,
 					GFP_KERNEL);
 					GFP_KERNEL);
-		if (completed)
-			set_bit(BRCMF_VIF_STATUS_CONNECTED,
-				&ifp->vif->sme_state);
 		brcmf_dbg(CONN, "Report connect result - connection %s\n",
 		brcmf_dbg(CONN, "Report connect result - connection %s\n",
 			  completed ? "succeeded" : "failed");
 			  completed ? "succeeded" : "failed");
 	}
 	}
@@ -3996,38 +4478,38 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
 			       struct net_device *ndev,
 			       struct net_device *ndev,
 			       const struct brcmf_event_msg *e, void *data)
 			       const struct brcmf_event_msg *e, void *data)
 {
 {
-	s32 err = 0;
+	static int generation;
 	u32 event = e->event_code;
 	u32 event = e->event_code;
 	u32 reason = e->reason;
 	u32 reason = e->reason;
-	u32 len = e->datalen;
-	static int generation;
-
 	struct station_info sinfo;
 	struct station_info sinfo;
 
 
 	brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
 	brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
-	memset(&sinfo, 0, sizeof(sinfo));
+	if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
+	    ndev != cfg_to_ndev(cfg)) {
+		brcmf_dbg(CONN, "AP mode link down\n");
+		complete(&cfg->vif_disabled);
+		return 0;
+	}
 
 
-	sinfo.filled = 0;
 	if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
 	if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
-	    reason == BRCMF_E_STATUS_SUCCESS) {
+	    (reason == BRCMF_E_STATUS_SUCCESS)) {
+		memset(&sinfo, 0, sizeof(sinfo));
 		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
 		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
 		if (!data) {
 		if (!data) {
 			brcmf_err("No IEs present in ASSOC/REASSOC_IND");
 			brcmf_err("No IEs present in ASSOC/REASSOC_IND");
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 		sinfo.assoc_req_ies = data;
 		sinfo.assoc_req_ies = data;
-		sinfo.assoc_req_ies_len = len;
+		sinfo.assoc_req_ies_len = e->datalen;
 		generation++;
 		generation++;
 		sinfo.generation = generation;
 		sinfo.generation = generation;
-		cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
+		cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
 	} else if ((event == BRCMF_E_DISASSOC_IND) ||
 	} else if ((event == BRCMF_E_DISASSOC_IND) ||
 		   (event == BRCMF_E_DEAUTH_IND) ||
 		   (event == BRCMF_E_DEAUTH_IND) ||
 		   (event == BRCMF_E_DEAUTH)) {
 		   (event == BRCMF_E_DEAUTH)) {
-		generation++;
-		sinfo.generation = generation;
-		cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
+		cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
 	}
 	}
-	return err;
+	return 0;
 }
 }
 
 
 static s32
 static s32
@@ -4064,6 +4546,8 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
 		}
 		}
 		brcmf_link_down(ifp->vif);
 		brcmf_link_down(ifp->vif);
 		brcmf_init_prof(ndev_to_prof(ndev));
 		brcmf_init_prof(ndev_to_prof(ndev));
+		if (ndev != cfg_to_ndev(cfg))
+			complete(&cfg->vif_disabled);
 	} else if (brcmf_is_nonetwork(cfg, e)) {
 	} else if (brcmf_is_nonetwork(cfg, e)) {
 		if (brcmf_is_ibssmode(ifp->vif))
 		if (brcmf_is_ibssmode(ifp->vif))
 			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
@@ -4112,6 +4596,57 @@ brcmf_notify_mic_status(struct brcmf_if *ifp,
 	return 0;
 	return 0;
 }
 }
 
 
+static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
+				  const struct brcmf_event_msg *e, void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+	struct brcmf_cfg80211_vif *vif;
+
+	brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
+		  ifevent->action, ifevent->flags, ifevent->ifidx,
+		  ifevent->bssidx);
+
+	mutex_lock(&event->vif_event_lock);
+	event->action = ifevent->action;
+	vif = event->vif;
+
+	switch (ifevent->action) {
+	case BRCMF_E_IF_ADD:
+		/* waiting process may have timed out */
+		if (!cfg->vif_event.vif)
+			return -EBADF;
+
+		ifp->vif = vif;
+		vif->ifp = ifp;
+		vif->wdev.netdev = ifp->ndev;
+		ifp->ndev->ieee80211_ptr = &vif->wdev;
+		SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+		mutex_unlock(&event->vif_event_lock);
+		wake_up(&event->vif_wq);
+		return 0;
+
+	case BRCMF_E_IF_DEL:
+		ifp->vif = NULL;
+		mutex_unlock(&event->vif_event_lock);
+		/* event may not be upon user request */
+		if (brcmf_cfg80211_vif_event_armed(cfg))
+			wake_up(&event->vif_wq);
+		return 0;
+
+	case BRCMF_E_IF_CHANGE:
+		mutex_unlock(&event->vif_event_lock);
+		wake_up(&event->vif_wq);
+		return 0;
+
+	default:
+		mutex_unlock(&event->vif_event_lock);
+		break;
+	}
+	return -EINVAL;
+}
+
 static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
 static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
 {
 {
 	conf->frag_threshold = (u32)-1;
 	conf->frag_threshold = (u32)-1;
@@ -4143,6 +4678,18 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
 			    brcmf_notify_connect_status);
 			    brcmf_notify_connect_status);
 	brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
 	brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
 			    brcmf_notify_sched_scan_results);
 			    brcmf_notify_sched_scan_results);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
+			    brcmf_notify_vif_event);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
+			    brcmf_p2p_notify_rx_mgmt_p2p_probereq);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
+			    brcmf_p2p_notify_listen_complete);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
+			    brcmf_p2p_notify_action_frame_rx);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
+			    brcmf_p2p_notify_action_tx_complete);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
+			    brcmf_p2p_notify_action_tx_complete);
 }
 }
 
 
 static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
 static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -4198,7 +4745,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
 	mutex_init(&cfg->usr_sync);
 	mutex_init(&cfg->usr_sync);
 	brcmf_init_escan(cfg);
 	brcmf_init_escan(cfg);
 	brcmf_init_conf(cfg->conf);
 	brcmf_init_conf(cfg->conf);
-
+	init_completion(&cfg->vif_disabled);
 	return err;
 	return err;
 }
 }
 
 
@@ -4209,6 +4756,12 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
 	brcmf_deinit_priv_mem(cfg);
 	brcmf_deinit_priv_mem(cfg);
 }
 }
 
 
+static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
+{
+	init_waitqueue_head(&event->vif_wq);
+	mutex_init(&event->vif_event_lock);
+}
+
 struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
 struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
 						  struct device *busdev)
 						  struct device *busdev)
 {
 {
@@ -4232,25 +4785,41 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
 	cfg = wiphy_priv(wiphy);
 	cfg = wiphy_priv(wiphy);
 	cfg->wiphy = wiphy;
 	cfg->wiphy = wiphy;
 	cfg->pub = drvr;
 	cfg->pub = drvr;
+	init_vif_event(&cfg->vif_event);
 	INIT_LIST_HEAD(&cfg->vif_list);
 	INIT_LIST_HEAD(&cfg->vif_list);
 
 
-	vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
+	vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
 	if (IS_ERR(vif)) {
 	if (IS_ERR(vif)) {
 		wiphy_free(wiphy);
 		wiphy_free(wiphy);
 		return NULL;
 		return NULL;
 	}
 	}
 
 
+	vif->ifp = ifp;
+	vif->wdev.netdev = ndev;
+	ndev->ieee80211_ptr = &vif->wdev;
+	SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
+
 	err = wl_init_priv(cfg);
 	err = wl_init_priv(cfg);
 	if (err) {
 	if (err) {
 		brcmf_err("Failed to init iwm_priv (%d)\n", err);
 		brcmf_err("Failed to init iwm_priv (%d)\n", err);
 		goto cfg80211_attach_out;
 		goto cfg80211_attach_out;
 	}
 	}
-
 	ifp->vif = vif;
 	ifp->vif = vif;
+
+	err = brcmf_p2p_attach(cfg);
+	if (err) {
+		brcmf_err("P2P initilisation failed (%d)\n", err);
+		goto cfg80211_p2p_attach_out;
+	}
+
 	return cfg;
 	return cfg;
 
 
+cfg80211_p2p_attach_out:
+	wl_deinit_priv(cfg);
+
 cfg80211_attach_out:
 cfg80211_attach_out:
 	brcmf_free_vif(vif);
 	brcmf_free_vif(vif);
+	wiphy_free(wiphy);
 	return NULL;
 	return NULL;
 }
 }
 
 
@@ -4489,3 +5058,57 @@ s32 brcmf_cfg80211_down(struct net_device *ndev)
 	return err;
 	return err;
 }
 }
 
 
+u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
+{
+	struct brcmf_cfg80211_vif *vif;
+	bool result = 0;
+
+	list_for_each_entry(vif, &cfg->vif_list, list) {
+		if (test_bit(state, &vif->sme_state))
+			result++;
+	}
+	return result;
+}
+
+static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
+				    u8 action)
+{
+	u8 evt_action;
+
+	mutex_lock(&event->vif_event_lock);
+	evt_action = event->action;
+	mutex_unlock(&event->vif_event_lock);
+	return evt_action == action;
+}
+
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+				  struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+	mutex_lock(&event->vif_event_lock);
+	event->vif = vif;
+	event->action = 0;
+	mutex_unlock(&event->vif_event_lock);
+}
+
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+	bool armed;
+
+	mutex_lock(&event->vif_event_lock);
+	armed = event->vif != NULL;
+	mutex_unlock(&event->vif_event_lock);
+
+	return armed;
+}
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+					  u8 action, ulong timeout)
+{
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+	return wait_event_timeout(event->vif_wq,
+				  vif_event_equals(event, action), timeout);
+}
+

+ 111 - 2
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h

@@ -41,6 +41,38 @@
 #define WL_AUTH_SHARED_KEY		1	/* d11 shared authentication */
 #define WL_AUTH_SHARED_KEY		1	/* d11 shared authentication */
 #define IE_MAX_LEN			512
 #define IE_MAX_LEN			512
 
 
+/* IE TLV processing */
+#define TLV_LEN_OFF			1	/* length offset */
+#define TLV_HDR_LEN			2	/* header length */
+#define TLV_BODY_OFF			2	/* body offset */
+#define TLV_OUI_LEN			3	/* oui id length */
+
+/* 802.11 Mgmt Packet flags */
+#define BRCMF_VNDR_IE_BEACON_FLAG	0x1
+#define BRCMF_VNDR_IE_PRBRSP_FLAG	0x2
+#define BRCMF_VNDR_IE_ASSOCRSP_FLAG	0x4
+#define BRCMF_VNDR_IE_AUTHRSP_FLAG	0x8
+#define BRCMF_VNDR_IE_PRBREQ_FLAG	0x10
+#define BRCMF_VNDR_IE_ASSOCREQ_FLAG	0x20
+/* vendor IE in IW advertisement protocol ID field */
+#define BRCMF_VNDR_IE_IWAPID_FLAG	0x40
+/* allow custom IE id */
+#define BRCMF_VNDR_IE_CUSTOM_FLAG	0x100
+
+/* P2P Action Frames flags (spec ordered) */
+#define BRCMF_VNDR_IE_GONREQ_FLAG     0x001000
+#define BRCMF_VNDR_IE_GONRSP_FLAG     0x002000
+#define BRCMF_VNDR_IE_GONCFM_FLAG     0x004000
+#define BRCMF_VNDR_IE_INVREQ_FLAG     0x008000
+#define BRCMF_VNDR_IE_INVRSP_FLAG     0x010000
+#define BRCMF_VNDR_IE_DISREQ_FLAG     0x020000
+#define BRCMF_VNDR_IE_DISRSP_FLAG     0x040000
+#define BRCMF_VNDR_IE_PRDREQ_FLAG     0x080000
+#define BRCMF_VNDR_IE_PRDRSP_FLAG     0x100000
+
+#define BRCMF_VNDR_IE_P2PAF_SHIFT	12
+
+
 /**
 /**
  * enum brcmf_scan_status - dongle scan status
  * enum brcmf_scan_status - dongle scan status
  *
  *
@@ -52,11 +84,19 @@ enum brcmf_scan_status {
 	BRCMF_SCAN_STATUS_ABORT,
 	BRCMF_SCAN_STATUS_ABORT,
 };
 };
 
 
-/* wi-fi mode */
+/**
+ * enum wl_mode - driver mode of virtual interface.
+ *
+ * @WL_MODE_BSS: connects to BSS.
+ * @WL_MODE_IBSS: operate as ad-hoc.
+ * @WL_MODE_AP: operate as access-point.
+ * @WL_MODE_P2P: provide P2P discovery.
+ */
 enum wl_mode {
 enum wl_mode {
 	WL_MODE_BSS,
 	WL_MODE_BSS,
 	WL_MODE_IBSS,
 	WL_MODE_IBSS,
-	WL_MODE_AP
+	WL_MODE_AP,
+	WL_MODE_P2P
 };
 };
 
 
 /* dongle configuration */
 /* dongle configuration */
@@ -108,6 +148,7 @@ struct brcmf_cfg80211_profile {
  * @BRCMF_VIF_STATUS_READY: ready for operation.
  * @BRCMF_VIF_STATUS_READY: ready for operation.
  * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
  * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
  * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
  * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
  * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
  * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
  * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
  * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
  */
  */
@@ -115,6 +156,7 @@ enum brcmf_vif_status {
 	BRCMF_VIF_STATUS_READY,
 	BRCMF_VIF_STATUS_READY,
 	BRCMF_VIF_STATUS_CONNECTING,
 	BRCMF_VIF_STATUS_CONNECTING,
 	BRCMF_VIF_STATUS_CONNECTED,
 	BRCMF_VIF_STATUS_CONNECTED,
+	BRCMF_VIF_STATUS_DISCONNECTING,
 	BRCMF_VIF_STATUS_AP_CREATING,
 	BRCMF_VIF_STATUS_AP_CREATING,
 	BRCMF_VIF_STATUS_AP_CREATED
 	BRCMF_VIF_STATUS_AP_CREATED
 };
 };
@@ -122,16 +164,22 @@ enum brcmf_vif_status {
 /**
 /**
  * struct vif_saved_ie - holds saved IEs for a virtual interface.
  * struct vif_saved_ie - holds saved IEs for a virtual interface.
  *
  *
+ * @probe_req_ie: IE info for probe request.
  * @probe_res_ie: IE info for probe response.
  * @probe_res_ie: IE info for probe response.
  * @beacon_ie: IE info for beacon frame.
  * @beacon_ie: IE info for beacon frame.
+ * @probe_req_ie_len: IE info length for probe request.
  * @probe_res_ie_len: IE info length for probe response.
  * @probe_res_ie_len: IE info length for probe response.
  * @beacon_ie_len: IE info length for beacon frame.
  * @beacon_ie_len: IE info length for beacon frame.
  */
  */
 struct vif_saved_ie {
 struct vif_saved_ie {
+	u8  probe_req_ie[IE_MAX_LEN];
 	u8  probe_res_ie[IE_MAX_LEN];
 	u8  probe_res_ie[IE_MAX_LEN];
 	u8  beacon_ie[IE_MAX_LEN];
 	u8  beacon_ie[IE_MAX_LEN];
+	u8  assoc_req_ie[IE_MAX_LEN];
+	u32 probe_req_ie_len;
 	u32 probe_res_ie_len;
 	u32 probe_res_ie_len;
 	u32 beacon_ie_len;
 	u32 beacon_ie_len;
+	u32 assoc_req_ie_len;
 };
 };
 
 
 /**
 /**
@@ -145,6 +193,7 @@ struct vif_saved_ie {
  * @sme_state: SME state using enum brcmf_vif_status bits.
  * @sme_state: SME state using enum brcmf_vif_status bits.
  * @pm_block: power-management blocked.
  * @pm_block: power-management blocked.
  * @list: linked list.
  * @list: linked list.
+ * @mgmt_rx_reg: registered rx mgmt frame types.
  */
  */
 struct brcmf_cfg80211_vif {
 struct brcmf_cfg80211_vif {
 	struct brcmf_if *ifp;
 	struct brcmf_if *ifp;
@@ -156,6 +205,7 @@ struct brcmf_cfg80211_vif {
 	bool pm_block;
 	bool pm_block;
 	struct vif_saved_ie saved_ie;
 	struct vif_saved_ie saved_ie;
 	struct list_head list;
 	struct list_head list;
+	u16 mgmt_rx_reg;
 };
 };
 
 
 /* association inform */
 /* association inform */
@@ -189,6 +239,9 @@ struct escan_info {
 	u8 escan_buf[WL_ESCAN_BUF_SIZE];
 	u8 escan_buf[WL_ESCAN_BUF_SIZE];
 	struct wiphy *wiphy;
 	struct wiphy *wiphy;
 	struct net_device *ndev;
 	struct net_device *ndev;
+	s32 (*run)(struct brcmf_cfg80211_info *cfg,
+		   struct net_device *ndev,
+		   struct cfg80211_scan_request *request, u16 action);
 };
 };
 
 
 /**
 /**
@@ -272,11 +325,28 @@ struct brcmf_pno_scanresults_le {
 	__le32 count;
 	__le32 count;
 };
 };
 
 
+/**
+ * struct brcmf_cfg80211_vif_event - virtual interface event information.
+ *
+ * @vif_wq: waitqueue awaiting interface event from firmware.
+ * @vif_event_lock: protects other members in this structure.
+ * @vif_complete: completion for net attach.
+ * @action: either add, change, or delete.
+ * @vif: virtual interface object related to the event.
+ */
+struct brcmf_cfg80211_vif_event {
+	wait_queue_head_t vif_wq;
+	struct mutex vif_event_lock;
+	u8 action;
+	struct brcmf_cfg80211_vif *vif;
+};
+
 /**
 /**
  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
  *
  *
  * @wiphy: wiphy object for cfg80211 interface.
  * @wiphy: wiphy object for cfg80211 interface.
  * @conf: dongle configuration.
  * @conf: dongle configuration.
+ * @p2p: peer-to-peer specific information.
  * @scan_request: cfg80211 scan request object.
  * @scan_request: cfg80211 scan request object.
  * @usr_sync: mainly for dongle up/down synchronization.
  * @usr_sync: mainly for dongle up/down synchronization.
  * @bss_list: bss_list holding scanned ap information.
  * @bss_list: bss_list holding scanned ap information.
@@ -304,10 +374,12 @@ struct brcmf_pno_scanresults_le {
  * @escan_ioctl_buf: dongle command buffer for escan commands.
  * @escan_ioctl_buf: dongle command buffer for escan commands.
  * @vif_list: linked list of vif instances.
  * @vif_list: linked list of vif instances.
  * @vif_cnt: number of vif instances.
  * @vif_cnt: number of vif instances.
+ * @vif_event: vif event signalling.
  */
  */
 struct brcmf_cfg80211_info {
 struct brcmf_cfg80211_info {
 	struct wiphy *wiphy;
 	struct wiphy *wiphy;
 	struct brcmf_cfg80211_conf *conf;
 	struct brcmf_cfg80211_conf *conf;
+	struct brcmf_p2p_info p2p;
 	struct cfg80211_scan_request *scan_request;
 	struct cfg80211_scan_request *scan_request;
 	struct mutex usr_sync;
 	struct mutex usr_sync;
 	struct brcmf_scan_results *bss_list;
 	struct brcmf_scan_results *bss_list;
@@ -335,6 +407,21 @@ struct brcmf_cfg80211_info {
 	u8 *escan_ioctl_buf;
 	u8 *escan_ioctl_buf;
 	struct list_head vif_list;
 	struct list_head vif_list;
 	u8 vif_cnt;
 	u8 vif_cnt;
+	struct brcmf_cfg80211_vif_event vif_event;
+	struct completion vif_disabled;
+};
+
+/**
+ * struct brcmf_tlv - tag_ID/length/value_buffer tuple.
+ *
+ * @id: tag identifier.
+ * @len: number of bytes in value buffer.
+ * @data: value buffer.
+ */
+struct brcmf_tlv {
+	u8 id;
+	u8 len;
+	u8 data[1];
 };
 };
 
 
 static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
 static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
@@ -389,4 +476,26 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
 s32 brcmf_cfg80211_up(struct net_device *ndev);
 s32 brcmf_cfg80211_up(struct net_device *ndev);
 s32 brcmf_cfg80211_down(struct net_device *ndev);
 s32 brcmf_cfg80211_down(struct net_device *ndev);
 
 
+struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
+					   enum nl80211_iftype type,
+					   bool pm_block);
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
+
+s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
+			  const u8 *vndr_ie_buf, u32 vndr_ie_len);
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
+struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
+u16 channel_to_chanspec(struct ieee80211_channel *ch);
+u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+				  struct brcmf_cfg80211_vif *vif);
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+					  u8 action, ulong timeout);
+s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+				struct net_device *ndev,
+				bool aborted, bool fw_abort);
+void brcmf_set_mpc(struct net_device *ndev, int mpc);
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
+
 #endif				/* _wl_cfg80211_h_ */
 #endif				/* _wl_cfg80211_h_ */

+ 8 - 5
drivers/net/wireless/brcm80211/brcmsmac/main.c

@@ -101,8 +101,6 @@
 #define DOT11_RTS_LEN			16
 #define DOT11_RTS_LEN			16
 #define DOT11_CTS_LEN			10
 #define DOT11_CTS_LEN			10
 #define DOT11_BA_BITMAP_LEN		128
 #define DOT11_BA_BITMAP_LEN		128
-#define DOT11_MIN_BEACON_PERIOD		1
-#define DOT11_MAX_BEACON_PERIOD		0xFFFF
 #define DOT11_MAXNUMFRAGS		16
 #define DOT11_MAXNUMFRAGS		16
 #define DOT11_MAX_FRAG_LEN		2346
 #define DOT11_MAX_FRAG_LEN		2346
 
 
@@ -5555,8 +5553,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
 
 
 int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
 int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
 {
 {
-	if (period < DOT11_MIN_BEACON_PERIOD ||
-	    period > DOT11_MAX_BEACON_PERIOD)
+	if (period == 0)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	wlc->default_bss->beacon_period = period;
 	wlc->default_bss->beacon_period = period;
@@ -7408,9 +7405,13 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
 			      struct brcms_bss_cfg *cfg,
 			      struct brcms_bss_cfg *cfg,
 			      bool suspend)
 			      bool suspend)
 {
 {
-	u16 prb_resp[BCN_TMPL_LEN / 2];
+	u16 *prb_resp;
 	int len = BCN_TMPL_LEN;
 	int len = BCN_TMPL_LEN;
 
 
+	prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC);
+	if (!prb_resp)
+		return;
+
 	/*
 	/*
 	 * write the probe response to hardware, or save in
 	 * write the probe response to hardware, or save in
 	 * the config structure
 	 * the config structure
@@ -7444,6 +7445,8 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
 
 
 	if (suspend)
 	if (suspend)
 		brcms_c_enable_mac(wlc);
 		brcms_c_enable_mac(wlc);
+
+	kfree(prb_resp);
 }
 }
 
 
 void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
 void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)

+ 27 - 12
drivers/net/wireless/iwlegacy/3945-mac.c

@@ -1001,12 +1001,12 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
 	struct list_head *element;
 	struct list_head *element;
 	struct il_rx_buf *rxb;
 	struct il_rx_buf *rxb;
 	struct page *page;
 	struct page *page;
+	dma_addr_t page_dma;
 	unsigned long flags;
 	unsigned long flags;
 	gfp_t gfp_mask = priority;
 	gfp_t gfp_mask = priority;
 
 
 	while (1) {
 	while (1) {
 		spin_lock_irqsave(&rxq->lock, flags);
 		spin_lock_irqsave(&rxq->lock, flags);
-
 		if (list_empty(&rxq->rx_used)) {
 		if (list_empty(&rxq->rx_used)) {
 			spin_unlock_irqrestore(&rxq->lock, flags);
 			spin_unlock_irqrestore(&rxq->lock, flags);
 			return;
 			return;
@@ -1035,26 +1035,34 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
 			break;
 			break;
 		}
 		}
 
 
+		/* Get physical address of RB/SKB */
+		page_dma =
+		    pci_map_page(il->pci_dev, page, 0,
+				 PAGE_SIZE << il->hw_params.rx_page_order,
+				 PCI_DMA_FROMDEVICE);
+
+		if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) {
+			__free_pages(page, il->hw_params.rx_page_order);
+			break;
+		}
+
 		spin_lock_irqsave(&rxq->lock, flags);
 		spin_lock_irqsave(&rxq->lock, flags);
+
 		if (list_empty(&rxq->rx_used)) {
 		if (list_empty(&rxq->rx_used)) {
 			spin_unlock_irqrestore(&rxq->lock, flags);
 			spin_unlock_irqrestore(&rxq->lock, flags);
+			pci_unmap_page(il->pci_dev, page_dma,
+				       PAGE_SIZE << il->hw_params.rx_page_order,
+				       PCI_DMA_FROMDEVICE);
 			__free_pages(page, il->hw_params.rx_page_order);
 			__free_pages(page, il->hw_params.rx_page_order);
 			return;
 			return;
 		}
 		}
+
 		element = rxq->rx_used.next;
 		element = rxq->rx_used.next;
 		rxb = list_entry(element, struct il_rx_buf, list);
 		rxb = list_entry(element, struct il_rx_buf, list);
 		list_del(element);
 		list_del(element);
-		spin_unlock_irqrestore(&rxq->lock, flags);
 
 
 		rxb->page = page;
 		rxb->page = page;
-		/* Get physical address of RB/SKB */
-		rxb->page_dma =
-		    pci_map_page(il->pci_dev, page, 0,
-				 PAGE_SIZE << il->hw_params.rx_page_order,
-				 PCI_DMA_FROMDEVICE);
-
-		spin_lock_irqsave(&rxq->lock, flags);
-
+		rxb->page_dma = page_dma;
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
 		rxq->free_count++;
 		il->alloc_rxb_page++;
 		il->alloc_rxb_page++;
@@ -1284,8 +1292,15 @@ il3945_rx_handle(struct il_priv *il)
 			    pci_map_page(il->pci_dev, rxb->page, 0,
 			    pci_map_page(il->pci_dev, rxb->page, 0,
 					 PAGE_SIZE << il->hw_params.
 					 PAGE_SIZE << il->hw_params.
 					 rx_page_order, PCI_DMA_FROMDEVICE);
 					 rx_page_order, PCI_DMA_FROMDEVICE);
-			list_add_tail(&rxb->list, &rxq->rx_free);
-			rxq->free_count++;
+			if (unlikely(pci_dma_mapping_error(il->pci_dev,
+							   rxb->page_dma))) {
+				__il_free_pages(il, rxb->page);
+				rxb->page = NULL;
+				list_add_tail(&rxb->list, &rxq->rx_used);
+			} else {
+				list_add_tail(&rxb->list, &rxq->rx_free);
+				rxq->free_count++;
+			}
 		} else
 		} else
 			list_add_tail(&rxb->list, &rxq->rx_used);
 			list_add_tail(&rxb->list, &rxq->rx_used);
 
 

+ 39 - 17
drivers/net/wireless/iwlegacy/4965-mac.c

@@ -319,6 +319,7 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority)
 	struct list_head *element;
 	struct list_head *element;
 	struct il_rx_buf *rxb;
 	struct il_rx_buf *rxb;
 	struct page *page;
 	struct page *page;
+	dma_addr_t page_dma;
 	unsigned long flags;
 	unsigned long flags;
 	gfp_t gfp_mask = priority;
 	gfp_t gfp_mask = priority;
 
 
@@ -356,33 +357,35 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority)
 			return;
 			return;
 		}
 		}
 
 
+		/* Get physical address of the RB */
+		page_dma =
+		    pci_map_page(il->pci_dev, page, 0,
+				 PAGE_SIZE << il->hw_params.rx_page_order,
+				 PCI_DMA_FROMDEVICE);
+		if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) {
+			__free_pages(page, il->hw_params.rx_page_order);
+			break;
+		}
+
 		spin_lock_irqsave(&rxq->lock, flags);
 		spin_lock_irqsave(&rxq->lock, flags);
 
 
 		if (list_empty(&rxq->rx_used)) {
 		if (list_empty(&rxq->rx_used)) {
 			spin_unlock_irqrestore(&rxq->lock, flags);
 			spin_unlock_irqrestore(&rxq->lock, flags);
+			pci_unmap_page(il->pci_dev, page_dma,
+				       PAGE_SIZE << il->hw_params.rx_page_order,
+				       PCI_DMA_FROMDEVICE);
 			__free_pages(page, il->hw_params.rx_page_order);
 			__free_pages(page, il->hw_params.rx_page_order);
 			return;
 			return;
 		}
 		}
+
 		element = rxq->rx_used.next;
 		element = rxq->rx_used.next;
 		rxb = list_entry(element, struct il_rx_buf, list);
 		rxb = list_entry(element, struct il_rx_buf, list);
 		list_del(element);
 		list_del(element);
 
 
-		spin_unlock_irqrestore(&rxq->lock, flags);
-
 		BUG_ON(rxb->page);
 		BUG_ON(rxb->page);
-		rxb->page = page;
-		/* Get physical address of the RB */
-		rxb->page_dma =
-		    pci_map_page(il->pci_dev, page, 0,
-				 PAGE_SIZE << il->hw_params.rx_page_order,
-				 PCI_DMA_FROMDEVICE);
-		/* dma address must be no more than 36 bits */
-		BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-		/* and also 256 byte aligned! */
-		BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
-		spin_lock_irqsave(&rxq->lock, flags);
 
 
+		rxb->page = page;
+		rxb->page_dma = page_dma;
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
 		rxq->free_count++;
 		il->alloc_rxb_page++;
 		il->alloc_rxb_page++;
@@ -725,6 +728,16 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
 	if (rate_n_flags & RATE_MCS_SGI_MSK)
 	if (rate_n_flags & RATE_MCS_SGI_MSK)
 		rx_status.flag |= RX_FLAG_SHORT_GI;
 		rx_status.flag |= RX_FLAG_SHORT_GI;
 
 
+	if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) {
+		/* We know which subframes of an A-MPDU belong
+		 * together since we get a single PHY response
+		 * from the firmware for all of them.
+		 */
+
+		rx_status.flag |= RX_FLAG_AMPDU_DETAILS;
+		rx_status.ampdu_reference = il->_4965.ampdu_ref;
+	}
+
 	il4965_pass_packet_to_mac80211(il, header, len, ampdu_status, rxb,
 	il4965_pass_packet_to_mac80211(il, header, len, ampdu_status, rxb,
 				       &rx_status);
 				       &rx_status);
 }
 }
@@ -736,6 +749,7 @@ il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb)
 {
 {
 	struct il_rx_pkt *pkt = rxb_addr(rxb);
 	struct il_rx_pkt *pkt = rxb_addr(rxb);
 	il->_4965.last_phy_res_valid = true;
 	il->_4965.last_phy_res_valid = true;
+	il->_4965.ampdu_ref++;
 	memcpy(&il->_4965.last_phy_res, pkt->u.raw,
 	memcpy(&il->_4965.last_phy_res, pkt->u.raw,
 	       sizeof(struct il_rx_phy_res));
 	       sizeof(struct il_rx_phy_res));
 }
 }
@@ -4281,8 +4295,16 @@ il4965_rx_handle(struct il_priv *il)
 			    pci_map_page(il->pci_dev, rxb->page, 0,
 			    pci_map_page(il->pci_dev, rxb->page, 0,
 					 PAGE_SIZE << il->hw_params.
 					 PAGE_SIZE << il->hw_params.
 					 rx_page_order, PCI_DMA_FROMDEVICE);
 					 rx_page_order, PCI_DMA_FROMDEVICE);
-			list_add_tail(&rxb->list, &rxq->rx_free);
-			rxq->free_count++;
+
+			if (unlikely(pci_dma_mapping_error(il->pci_dev,
+							   rxb->page_dma))) {
+				__il_free_pages(il, rxb->page);
+				rxb->page = NULL;
+				list_add_tail(&rxb->list, &rxq->rx_used);
+			} else {
+				list_add_tail(&rxb->list, &rxq->rx_free);
+				rxq->free_count++;
+			}
 		} else
 		} else
 			list_add_tail(&rxb->list, &rxq->rx_used);
 			list_add_tail(&rxb->list, &rxq->rx_used);
 
 
@@ -5711,7 +5733,7 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
 	/* Tell mac80211 our characteristics */
 	/* Tell mac80211 our characteristics */
 	hw->flags =
 	hw->flags =
 	    IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
 	    IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
-	    IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT |
+	    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
 	    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 	    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 	if (il->cfg->sku & IL_SKU_N)
 	if (il->cfg->sku & IL_SKU_N)

+ 1 - 0
drivers/net/wireless/iwlegacy/commands.h

@@ -1136,6 +1136,7 @@ struct il_wep_cmd {
 #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
 #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
 #define RX_RES_PHY_FLAGS_ANTENNA_MSK		0x70
 #define RX_RES_PHY_FLAGS_ANTENNA_MSK		0x70
 #define RX_RES_PHY_FLAGS_ANTENNA_POS		4
 #define RX_RES_PHY_FLAGS_ANTENNA_POS		4
+#define RX_RES_PHY_FLAGS_AGG_MSK	cpu_to_le16(1 << 7)
 
 
 #define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
 #define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
 #define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
 #define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)

+ 1 - 0
drivers/net/wireless/iwlegacy/common.h

@@ -1356,6 +1356,7 @@ struct il_priv {
 		struct {
 		struct {
 			struct il_rx_phy_res last_phy_res;
 			struct il_rx_phy_res last_phy_res;
 			bool last_phy_res_valid;
 			bool last_phy_res_valid;
+			u32 ampdu_ref;
 
 
 			struct completion firmware_loading_complete;
 			struct completion firmware_loading_complete;
 
 

+ 1 - 1
drivers/net/wireless/iwlwifi/dvm/mac80211.c

@@ -145,7 +145,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
 	/* Tell mac80211 our characteristics */
 	/* Tell mac80211 our characteristics */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_AMPDU_AGGREGATION |
 		    IEEE80211_HW_AMPDU_AGGREGATION |
-		    IEEE80211_HW_NEED_DTIM_PERIOD |
+		    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
 		    IEEE80211_HW_SPECTRUM_MGMT |
 		    IEEE80211_HW_SPECTRUM_MGMT |
 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		    IEEE80211_HW_QUEUE_CONTROL |
 		    IEEE80211_HW_QUEUE_CONTROL |

+ 1 - 1
drivers/net/wireless/iwlwifi/mvm/mac80211.c

@@ -114,7 +114,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 		    IEEE80211_HW_QUEUE_CONTROL |
 		    IEEE80211_HW_QUEUE_CONTROL |
 		    IEEE80211_HW_WANT_MONITOR_VIF |
 		    IEEE80211_HW_WANT_MONITOR_VIF |
 		    IEEE80211_HW_SCAN_WHILE_IDLE |
 		    IEEE80211_HW_SCAN_WHILE_IDLE |
-		    IEEE80211_HW_NEED_DTIM_PERIOD |
+		    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
 		    IEEE80211_HW_SUPPORTS_PS |
 		    IEEE80211_HW_SUPPORTS_PS |
 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
 		    IEEE80211_HW_AMPDU_AGGREGATION;
 		    IEEE80211_HW_AMPDU_AGGREGATION;

+ 0 - 39
drivers/net/wireless/mwifiex/11n.c

@@ -399,45 +399,6 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 	return ret_len;
 	return ret_len;
 }
 }
 
 
-/*
- * This function reconfigures the Tx buffer size in firmware.
- *
- * This function prepares a firmware command and issues it, if
- * the current Tx buffer size is different from the one requested.
- * Maximum configurable Tx buffer size is limited by the HT capability
- * field value.
- */
-void
-mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
-		   struct mwifiex_bssdescriptor *bss_desc)
-{
-	u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
-	u16 tx_buf, curr_tx_buf_size = 0;
-
-	if (bss_desc->bcn_ht_cap) {
-		if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
-				IEEE80211_HT_CAP_MAX_AMSDU)
-			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
-		else
-			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
-	}
-
-	tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
-
-	dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
-		max_amsdu, priv->adapter->max_tx_buf_size);
-
-	if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
-		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
-	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
-		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
-	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
-		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
-	if (curr_tx_buf_size != tx_buf)
-		mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
-				       HostCmd_ACT_GEN_SET, 0, &tx_buf);
-}
-
 /*
 /*
  * This function checks if the given pointer is valid entry of
  * This function checks if the given pointer is valid entry of
  * Tx BA Stream table.
  * Tx BA Stream table.

+ 0 - 2
drivers/net/wireless/mwifiex/11n.h

@@ -34,8 +34,6 @@ int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
 int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 			       struct mwifiex_bssdescriptor *bss_desc,
 			       struct mwifiex_bssdescriptor *bss_desc,
 			       u8 **buffer);
 			       u8 **buffer);
-void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
-			struct mwifiex_bssdescriptor *bss_desc);
 void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
 void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
 			   struct mwifiex_ie_types_htcap *);
 			   struct mwifiex_ie_types_htcap *);
 int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
 int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,

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

@@ -20,12 +20,12 @@ config MWIFIEX_SDIO
 	  mwifiex_sdio.
 	  mwifiex_sdio.
 
 
 config MWIFIEX_PCIE
 config MWIFIEX_PCIE
-	tristate "Marvell WiFi-Ex Driver for PCIE 8766"
+	tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897"
 	depends on MWIFIEX && PCI
 	depends on MWIFIEX && PCI
 	select FW_LOADER
 	select FW_LOADER
 	---help---
 	---help---
 	  This adds support for wireless adapters based on Marvell
 	  This adds support for wireless adapters based on Marvell
-	  8766 chipset with PCIe interface.
+	  8766/8897 chipsets with PCIe interface.
 
 
 	  If you choose to build it as a module, it will be called
 	  If you choose to build it as a module, it will be called
 	  mwifiex_pcie.
 	  mwifiex_pcie.

+ 0 - 1
drivers/net/wireless/mwifiex/README

@@ -121,7 +121,6 @@ info
 	wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
 	wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
 	wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
 	wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
 	wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
 	wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
-	max_tx_buf_size = <maximum Tx buffer size>
 	tx_buf_size = <current Tx buffer size>
 	tx_buf_size = <current Tx buffer size>
 	curr_tx_buf_size = <current Tx buffer size>
 	curr_tx_buf_size = <current Tx buffer size>
 	ps_mode = <0/1, CAM mode/PS mode>
 	ps_mode = <0/1, CAM mode/PS mode>

+ 0 - 2
drivers/net/wireless/mwifiex/debugfs.c

@@ -58,8 +58,6 @@ static struct mwifiex_debug_data items[] = {
 	 item_addr(packets_out[WMM_AC_BE]), 1},
 	 item_addr(packets_out[WMM_AC_BE]), 1},
 	{"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
 	{"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
 	 item_addr(packets_out[WMM_AC_BK]), 1},
 	 item_addr(packets_out[WMM_AC_BK]), 1},
-	{"max_tx_buf_size", item_size(max_tx_buf_size),
-	 item_addr(max_tx_buf_size), 1},
 	{"tx_buf_size", item_size(tx_buf_size),
 	{"tx_buf_size", item_size(tx_buf_size),
 	 item_addr(tx_buf_size), 1},
 	 item_addr(tx_buf_size), 1},
 	{"curr_tx_buf_size", item_size(curr_tx_buf_size),
 	{"curr_tx_buf_size", item_size(curr_tx_buf_size),

+ 0 - 1
drivers/net/wireless/mwifiex/init.c

@@ -317,7 +317,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
 
 
 	adapter->pm_wakeup_fw_try = false;
 	adapter->pm_wakeup_fw_try = false;
 
 
-	adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 	adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 	adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 	adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 	adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 
 

+ 0 - 1
drivers/net/wireless/mwifiex/ioctl.h

@@ -178,7 +178,6 @@ struct mwifiex_ds_tx_ba_stream_tbl {
 struct mwifiex_debug_info {
 struct mwifiex_debug_info {
 	u32 int_counter;
 	u32 int_counter;
 	u32 packets_out[MAX_NUM_TID];
 	u32 packets_out[MAX_NUM_TID];
-	u32 max_tx_buf_size;
 	u32 tx_buf_size;
 	u32 tx_buf_size;
 	u32 curr_tx_buf_size;
 	u32 curr_tx_buf_size;
 	u32 tx_tbl_num;
 	u32 tx_tbl_num;

+ 0 - 2
drivers/net/wireless/mwifiex/join.c

@@ -398,8 +398,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
 
 
 	pos = (u8 *) assoc;
 	pos = (u8 *) assoc;
 
 
-	mwifiex_cfg_tx_buf(priv, bss_desc);
-
 	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
 	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
 
 
 	/* Save so we know which BSS Desc to use in the response handler */
 	/* Save so we know which BSS Desc to use in the response handler */

+ 0 - 1
drivers/net/wireless/mwifiex/main.h

@@ -631,7 +631,6 @@ struct mwifiex_adapter {
 	/* spin lock for main process */
 	/* spin lock for main process */
 	spinlock_t main_proc_lock;
 	spinlock_t main_proc_lock;
 	u32 mwifiex_processing;
 	u32 mwifiex_processing;
-	u16 max_tx_buf_size;
 	u16 tx_buf_size;
 	u16 tx_buf_size;
 	u16 curr_tx_buf_size;
 	u16 curr_tx_buf_size;
 	u32 ioport;
 	u32 ioport;

+ 479 - 260
drivers/net/wireless/mwifiex/pcie.c

@@ -94,6 +94,13 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
 
 
 	card->dev = pdev;
 	card->dev = pdev;
 
 
+	if (ent->driver_data) {
+		struct mwifiex_pcie_device *data = (void *)ent->driver_data;
+		card->pcie.firmware = data->firmware;
+		card->pcie.reg = data->reg;
+		card->pcie.blksz_fw_dl = data->blksz_fw_dl;
+	}
+
 	if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
 	if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
 			     MWIFIEX_PCIE)) {
 			     MWIFIEX_PCIE)) {
 		pr_err("%s failed\n", __func__);
 		pr_err("%s failed\n", __func__);
@@ -230,13 +237,16 @@ static int mwifiex_pcie_resume(struct pci_dev *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
-#define PCIE_VENDOR_ID_MARVELL              (0x11ab)
-#define PCIE_DEVICE_ID_MARVELL_88W8766P		(0x2b30)
-
 static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
 static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
 	{
 	{
 		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
 		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		.driver_data = (unsigned long) &mwifiex_pcie8766,
+	},
+	{
+		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		.driver_data = (unsigned long) &mwifiex_pcie8897,
 	},
 	},
 	{},
 	{},
 };
 };
@@ -364,25 +374,268 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
 }
 }
 
 
 /*
 /*
- * This function creates buffer descriptor ring for TX
+ * This function initializes TX buffer ring descriptors
  */
  */
-static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
+static int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		card->tx_buf_list[i] = NULL;
+		if (reg->pfu_enabled) {
+			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
+					     (sizeof(*desc2) * i);
+			desc2 = card->txbd_ring[i];
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
+					     (sizeof(*desc) * i);
+			desc = card->txbd_ring[i];
+			memset(desc, 0, sizeof(*desc));
+		}
+	}
+
+	return 0;
+}
+
+/* This function initializes RX buffer ring descriptors. Each SKB is allocated
+ * here and after mapping PCI memory, its physical address is assigned to
+ * PCIE Rx buffer descriptor's physical address.
+ */
+static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct sk_buff *skb;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	dma_addr_t buf_pa;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		/* Allocate skb here so that firmware can DMA data from it */
+		skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+		if (!skb) {
+			dev_err(adapter->dev,
+				"Unable to allocate skb for RX ring.\n");
+			kfree(card->rxbd_ring_vbase);
+			return -ENOMEM;
+		}
+
+		if (mwifiex_map_pci_memory(adapter, skb,
+					   MWIFIEX_RX_DATA_BUF_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
+
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+		dev_dbg(adapter->dev,
+			"info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+			skb, skb->len, skb->data, (u32)buf_pa,
+			(u32)((u64)buf_pa >> 32));
+
+		card->rx_buf_list[i] = skb;
+		if (reg->pfu_enabled) {
+			card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase +
+					     (sizeof(*desc2) * i);
+			desc2 = card->rxbd_ring[i];
+			desc2->paddr = buf_pa;
+			desc2->len = (u16)skb->len;
+			desc2->frag_len = (u16)skb->len;
+			desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop;
+			desc2->offset = 0;
+		} else {
+			card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase +
+					     (sizeof(*desc) * i));
+			desc = card->rxbd_ring[i];
+			desc->paddr = buf_pa;
+			desc->len = (u16)skb->len;
+			desc->flags = 0;
+		}
+	}
+
+	return 0;
+}
+
+/* This function initializes event buffer ring descriptors. Each SKB is
+ * allocated here and after mapping PCI memory, its physical address is assigned
+ * to PCIE Rx buffer descriptor's physical address
+ */
+static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	struct mwifiex_evt_buf_desc *desc;
+	struct sk_buff *skb;
+	dma_addr_t buf_pa;
 	int i;
 	int i;
 
 
+	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+		/* Allocate skb here so that firmware can DMA data from it */
+		skb = dev_alloc_skb(MAX_EVENT_SIZE);
+		if (!skb) {
+			dev_err(adapter->dev,
+				"Unable to allocate skb for EVENT buf.\n");
+			kfree(card->evtbd_ring_vbase);
+			return -ENOMEM;
+		}
+		skb_put(skb, MAX_EVENT_SIZE);
+
+		if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
+
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+		dev_dbg(adapter->dev,
+			"info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+			skb, skb->len, skb->data, (u32)buf_pa,
+			(u32)((u64)buf_pa >> 32));
+
+		card->evt_buf_list[i] = skb;
+		card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase +
+				      (sizeof(*desc) * i));
+		desc = card->evtbd_ring[i];
+		desc->paddr = buf_pa;
+		desc->len = (u16)skb->len;
+		desc->flags = 0;
+	}
+
+	return 0;
+}
+
+/* This function cleans up TX buffer rings. If any of the buffer list has valid
+ * SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct sk_buff *skb;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		if (reg->pfu_enabled) {
+			desc2 = card->txbd_ring[i];
+			if (card->tx_buf_list[i]) {
+				skb = card->tx_buf_list[i];
+				pci_unmap_single(card->dev, desc2->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			desc = card->txbd_ring[i];
+			if (card->tx_buf_list[i]) {
+				skb = card->tx_buf_list[i];
+				pci_unmap_single(card->dev, desc->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc, 0, sizeof(*desc));
+		}
+		card->tx_buf_list[i] = NULL;
+	}
+
+	return;
+}
+
+/* This function cleans up RX buffer rings. If any of the buffer list has valid
+ * SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	struct sk_buff *skb;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		if (reg->pfu_enabled) {
+			desc2 = card->rxbd_ring[i];
+			if (card->rx_buf_list[i]) {
+				skb = card->rx_buf_list[i];
+				pci_unmap_single(card->dev, desc2->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			desc = card->rxbd_ring[i];
+			if (card->rx_buf_list[i]) {
+				skb = card->rx_buf_list[i];
+				pci_unmap_single(card->dev, desc->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc, 0, sizeof(*desc));
+		}
+		card->rx_buf_list[i] = NULL;
+	}
+
+	return;
+}
+
+/* This function cleans up event buffer rings. If any of the buffer list has
+ * valid SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct mwifiex_evt_buf_desc *desc;
+	struct sk_buff *skb;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+		desc = card->evtbd_ring[i];
+		if (card->evt_buf_list[i]) {
+			skb = card->evt_buf_list[i];
+			pci_unmap_single(card->dev, desc->paddr, MAX_EVENT_SIZE,
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb_any(skb);
+		}
+		card->evt_buf_list[i] = NULL;
+		memset(desc, 0, sizeof(*desc));
+	}
+
+	return;
+}
+
+/* This function creates buffer descriptor ring for TX
+ */
+static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
 	/*
 	/*
 	 * driver maintaines the write pointer and firmware maintaines the read
 	 * driver maintaines the write pointer and firmware maintaines the read
 	 * pointer. The write pointer starts at 0 (zero) while the read pointer
 	 * pointer. The write pointer starts at 0 (zero) while the read pointer
 	 * starts at zero with rollover bit set
 	 * starts at zero with rollover bit set
 	 */
 	 */
 	card->txbd_wrptr = 0;
 	card->txbd_wrptr = 0;
-	card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+	if (reg->pfu_enabled)
+		card->txbd_rdptr = 0;
+	else
+		card->txbd_rdptr |= reg->tx_rollover_ind;
 
 
 	/* allocate shared memory for the BD ring and divide the same in to
 	/* allocate shared memory for the BD ring and divide the same in to
 	   several descriptors */
 	   several descriptors */
-	card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
-							MWIFIEX_MAX_TXRX_BD;
+	if (reg->pfu_enabled)
+		card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
+	else
+		card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
+
 	dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
 	dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
 		card->txbd_ring_size);
 		card->txbd_ring_size);
 	card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
 	card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
@@ -399,40 +652,15 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
 		card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
 		card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
 		(u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
 		(u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
 
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
-				     (card->txbd_ring_vbase +
-				      (sizeof(struct mwifiex_pcie_buf_desc)
-				       * i));
-
-		card->tx_buf_list[i] = NULL;
-		card->txbd_ring[i]->paddr = 0;
-		card->txbd_ring[i]->len = 0;
-		card->txbd_ring[i]->flags = 0;
-	}
-
-	return 0;
+	return mwifiex_init_txq_ring(adapter);
 }
 }
 
 
 static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		if (card->tx_buf_list[i]) {
-			skb = card->tx_buf_list[i];
-			pci_unmap_single(card->dev, card->txbd_ring[i]->paddr,
-					 skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_any(skb);
-		}
-		card->tx_buf_list[i] = NULL;
-		card->txbd_ring[i]->paddr = 0;
-		card->txbd_ring[i]->len = 0;
-		card->txbd_ring[i]->flags = 0;
-		card->txbd_ring[i] = NULL;
-	}
+	mwifiex_cleanup_txq_ring(adapter);
 
 
 	if (card->txbd_ring_vbase)
 	if (card->txbd_ring_vbase)
 		pci_free_consistent(card->dev, card->txbd_ring_size,
 		pci_free_consistent(card->dev, card->txbd_ring_size,
@@ -440,7 +668,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
 				    card->txbd_ring_pbase);
 				    card->txbd_ring_pbase);
 	card->txbd_ring_size = 0;
 	card->txbd_ring_size = 0;
 	card->txbd_wrptr = 0;
 	card->txbd_wrptr = 0;
-	card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->txbd_rdptr = 0 | reg->tx_rollover_ind;
 	card->txbd_ring_vbase = NULL;
 	card->txbd_ring_vbase = NULL;
 	card->txbd_ring_pbase = 0;
 	card->txbd_ring_pbase = 0;
 
 
@@ -453,9 +681,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
-	dma_addr_t buf_pa;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
 	/*
 	/*
 	 * driver maintaines the read pointer and firmware maintaines the write
 	 * driver maintaines the read pointer and firmware maintaines the write
@@ -463,10 +689,15 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
 	 * starts at zero with rollover bit set
 	 * starts at zero with rollover bit set
 	 */
 	 */
 	card->rxbd_wrptr = 0;
 	card->rxbd_wrptr = 0;
-	card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->rxbd_rdptr = reg->rx_rollover_ind;
+
+	if (reg->pfu_enabled)
+		card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
+	else
+		card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
 
 
-	card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
-							MWIFIEX_MAX_TXRX_BD;
 	dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
 	dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
 		card->rxbd_ring_size);
 		card->rxbd_ring_size);
 	card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
 	card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
@@ -485,39 +716,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
 		(u32)((u64)card->rxbd_ring_pbase >> 32),
 		(u32)((u64)card->rxbd_ring_pbase >> 32),
 		card->rxbd_ring_size);
 		card->rxbd_ring_size);
 
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
-				     (card->rxbd_ring_vbase +
-				      (sizeof(struct mwifiex_pcie_buf_desc)
-				       * i));
-
-		/* Allocate skb here so that firmware can DMA data from it */
-		skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
-		if (!skb) {
-			dev_err(adapter->dev,
-				"Unable to allocate skb for RX ring.\n");
-			kfree(card->rxbd_ring_vbase);
-			return -ENOMEM;
-		}
-		if (mwifiex_map_pci_memory(adapter, skb,
-					   MWIFIEX_RX_DATA_BUF_SIZE,
-					   PCI_DMA_FROMDEVICE))
-			return -1;
-
-		MWIFIEX_SKB_PACB(skb, &buf_pa);
-
-		dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
-			"buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-			skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32),
-			skb->len);
-
-		card->rx_buf_list[i] = skb;
-		card->rxbd_ring[i]->paddr = buf_pa;
-		card->rxbd_ring[i]->len = (u16)skb->len;
-		card->rxbd_ring[i]->flags = 0;
-	}
-
-	return 0;
+	return mwifiex_init_rxq_ring(adapter);
 }
 }
 
 
 /*
 /*
@@ -526,23 +725,9 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		if (card->rx_buf_list[i]) {
-			skb = card->rx_buf_list[i];
-			pci_unmap_single(card->dev, card->rxbd_ring[i]->paddr ,
-					 MWIFIEX_RX_DATA_BUF_SIZE,
-					 PCI_DMA_FROMDEVICE);
-			dev_kfree_skb_any(skb);
-		}
-		card->rx_buf_list[i] = NULL;
-		card->rxbd_ring[i]->paddr = 0;
-		card->rxbd_ring[i]->len = 0;
-		card->rxbd_ring[i]->flags = 0;
-		card->rxbd_ring[i] = NULL;
-	}
+	mwifiex_cleanup_rxq_ring(adapter);
 
 
 	if (card->rxbd_ring_vbase)
 	if (card->rxbd_ring_vbase)
 		pci_free_consistent(card->dev, card->rxbd_ring_size,
 		pci_free_consistent(card->dev, card->rxbd_ring_size,
@@ -550,7 +735,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
 				    card->rxbd_ring_pbase);
 				    card->rxbd_ring_pbase);
 	card->rxbd_ring_size = 0;
 	card->rxbd_ring_size = 0;
 	card->rxbd_wrptr = 0;
 	card->rxbd_wrptr = 0;
-	card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->rxbd_rdptr = 0 | reg->rx_rollover_ind;
 	card->rxbd_ring_vbase = NULL;
 	card->rxbd_ring_vbase = NULL;
 	card->rxbd_ring_pbase = 0;
 	card->rxbd_ring_pbase = 0;
 
 
@@ -563,9 +748,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
-	dma_addr_t buf_pa;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
 	/*
 	/*
 	 * driver maintaines the read pointer and firmware maintaines the write
 	 * driver maintaines the read pointer and firmware maintaines the write
@@ -573,10 +756,11 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
 	 * starts at zero with rollover bit set
 	 * starts at zero with rollover bit set
 	 */
 	 */
 	card->evtbd_wrptr = 0;
 	card->evtbd_wrptr = 0;
-	card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->evtbd_rdptr = reg->evt_rollover_ind;
+
+	card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) *
+				MWIFIEX_MAX_EVT_BD;
 
 
-	card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
-							MWIFIEX_MAX_EVT_BD;
 	dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
 	dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
 		card->evtbd_ring_size);
 		card->evtbd_ring_size);
 	card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
 	card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
@@ -595,39 +779,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
 		(u32)((u64)card->evtbd_ring_pbase >> 32),
 		(u32)((u64)card->evtbd_ring_pbase >> 32),
 		card->evtbd_ring_size);
 		card->evtbd_ring_size);
 
 
-	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
-		card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
-				      (card->evtbd_ring_vbase +
-				       (sizeof(struct mwifiex_pcie_buf_desc)
-					* i));
-
-		/* Allocate skb here so that firmware can DMA data from it */
-		skb = dev_alloc_skb(MAX_EVENT_SIZE);
-		if (!skb) {
-			dev_err(adapter->dev,
-				"Unable to allocate skb for EVENT buf.\n");
-			kfree(card->evtbd_ring_vbase);
-			return -ENOMEM;
-		}
-		skb_put(skb, MAX_EVENT_SIZE);
-
-		if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
-					   PCI_DMA_FROMDEVICE))
-			return -1;
-
-		MWIFIEX_SKB_PACB(skb, &buf_pa);
-		dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
-			"buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-			skb, skb->data, (u32)buf_pa, (u32)((u64)buf_pa >> 32),
-			skb->len);
-
-		card->evt_buf_list[i] = skb;
-		card->evtbd_ring[i]->paddr = buf_pa;
-		card->evtbd_ring[i]->len = (u16)skb->len;
-		card->evtbd_ring[i]->flags = 0;
-	}
-
-	return 0;
+	return mwifiex_pcie_init_evt_ring(adapter);
 }
 }
 
 
 /*
 /*
@@ -636,29 +788,16 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
-	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
-		if (card->evt_buf_list[i]) {
-			skb = card->evt_buf_list[i];
-			pci_unmap_single(card->dev, card->evtbd_ring[i]->paddr,
-					 MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE);
-			dev_kfree_skb_any(skb);
-		}
-		card->evt_buf_list[i] = NULL;
-		card->evtbd_ring[i]->paddr = 0;
-		card->evtbd_ring[i]->len = 0;
-		card->evtbd_ring[i]->flags = 0;
-		card->evtbd_ring[i] = NULL;
-	}
+	mwifiex_cleanup_evt_ring(adapter);
 
 
 	if (card->evtbd_ring_vbase)
 	if (card->evtbd_ring_vbase)
 		pci_free_consistent(card->dev, card->evtbd_ring_size,
 		pci_free_consistent(card->dev, card->evtbd_ring_size,
 				    card->evtbd_ring_vbase,
 				    card->evtbd_ring_vbase,
 				    card->evtbd_ring_pbase);
 				    card->evtbd_ring_pbase);
 	card->evtbd_wrptr = 0;
 	card->evtbd_wrptr = 0;
-	card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->evtbd_rdptr = 0 | reg->evt_rollover_ind;
 	card->evtbd_ring_size = 0;
 	card->evtbd_ring_size = 0;
 	card->evtbd_ring_vbase = NULL;
 	card->evtbd_ring_vbase = NULL;
 	card->evtbd_ring_pbase = 0;
 	card->evtbd_ring_pbase = 0;
@@ -771,12 +910,13 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
 static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
 static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	u32 rdptr;
 	u32 rdptr;
 
 
 	/* Read the TX ring read pointer set by firmware */
 	/* Read the TX ring read pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+	if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"Flush TXBD: failed to read REG_TXBD_RDPTR\n");
+			"Flush TXBD: failed to read reg->tx_rdptr\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -800,31 +940,35 @@ static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
  */
  */
 static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
 {
 {
-	const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	dma_addr_t buf_pa;
 	dma_addr_t buf_pa;
-	u32 wrdoneidx, rdptr, unmap_count = 0;
+	u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 		mwifiex_pm_wakeup_card(adapter);
 		mwifiex_pm_wakeup_card(adapter);
 
 
 	/* Read the TX ring read pointer set by firmware */
 	/* Read the TX ring read pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+	if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"SEND COMP: failed to read REG_TXBD_RDPTR\n");
+			"SEND COMP: failed to read reg->tx_rdptr\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
 	dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
 	dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
 		card->txbd_rdptr, rdptr);
 		card->txbd_rdptr, rdptr);
 
 
+	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
 	/* free from previous txbd_rdptr to current txbd_rdptr */
 	/* free from previous txbd_rdptr to current txbd_rdptr */
-	while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) !=
-		(rdptr & MWIFIEX_TXBD_MASK)) ||
-	       ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
-		(rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
-		wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK;
+	while (((card->txbd_rdptr & reg->tx_mask) !=
+		(rdptr & reg->tx_mask)) ||
+	       ((card->txbd_rdptr & reg->tx_rollover_ind) !=
+		(rdptr & reg->tx_rollover_ind))) {
+		wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >>
+			    reg->tx_start_ptr;
 
 
 		skb = card->tx_buf_list[wrdoneidx];
 		skb = card->tx_buf_list[wrdoneidx];
 		if (skb) {
 		if (skb) {
@@ -845,25 +989,38 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
 		}
 		}
 
 
 		card->tx_buf_list[wrdoneidx] = NULL;
 		card->tx_buf_list[wrdoneidx] = NULL;
-		card->txbd_ring[wrdoneidx]->paddr = 0;
-		card->txbd_ring[wrdoneidx]->len = 0;
-		card->txbd_ring[wrdoneidx]->flags = 0;
-		card->txbd_rdptr++;
 
 
-		if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs)
+		if (reg->pfu_enabled) {
+			desc2 = (void *)card->txbd_ring[wrdoneidx];
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			desc = card->txbd_ring[wrdoneidx];
+			memset(desc, 0, sizeof(*desc));
+		}
+		switch (card->dev->device) {
+		case PCIE_DEVICE_ID_MARVELL_88W8766P:
+			card->txbd_rdptr++;
+			break;
+		case PCIE_DEVICE_ID_MARVELL_88W8897:
+			card->txbd_rdptr += reg->ring_tx_start_ptr;
+			break;
+		}
+
+
+		if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs)
 			card->txbd_rdptr = ((card->txbd_rdptr &
 			card->txbd_rdptr = ((card->txbd_rdptr &
-					    MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
-					    MWIFIEX_BD_FLAG_ROLLOVER_IND);
+					     reg->tx_rollover_ind) ^
+					     reg->tx_rollover_ind);
 	}
 	}
 
 
 	if (unmap_count)
 	if (unmap_count)
 		adapter->data_sent = false;
 		adapter->data_sent = false;
 
 
 	if (card->txbd_flush) {
 	if (card->txbd_flush) {
-		if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
-		     (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) &&
-		    ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
-		     (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
+		if (((card->txbd_wrptr & reg->tx_mask) ==
+		     (card->txbd_rdptr & reg->tx_mask)) &&
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) !=
+		     (card->txbd_rdptr & reg->tx_rollover_ind)))
 			card->txbd_flush = 0;
 			card->txbd_flush = 0;
 		else
 		else
 			mwifiex_clean_pcie_ring_buf(adapter);
 			mwifiex_clean_pcie_ring_buf(adapter);
@@ -883,9 +1040,12 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
 		       struct mwifiex_tx_param *tx_param)
 		       struct mwifiex_tx_param *tx_param)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
-	u32 wrindx;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	u32 wrindx, num_tx_buffs, rx_val;
 	int ret;
 	int ret;
 	dma_addr_t buf_pa;
 	dma_addr_t buf_pa;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
 	__le16 *tmp;
 	__le16 *tmp;
 
 
 	if (!(skb->data && skb->len)) {
 	if (!(skb->data && skb->len)) {
@@ -897,6 +1057,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 		mwifiex_pm_wakeup_card(adapter);
 		mwifiex_pm_wakeup_card(adapter);
 
 
+	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
 	dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
 	dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
 		card->txbd_rdptr, card->txbd_wrptr);
 		card->txbd_rdptr, card->txbd_wrptr);
 	if (mwifiex_pcie_txbd_not_full(card)) {
 	if (mwifiex_pcie_txbd_not_full(card)) {
@@ -913,25 +1074,46 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
 					   PCI_DMA_TODEVICE))
 					   PCI_DMA_TODEVICE))
 			return -1;
 			return -1;
 
 
-		wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+		wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
 		MWIFIEX_SKB_PACB(skb, &buf_pa);
 		MWIFIEX_SKB_PACB(skb, &buf_pa);
 		card->tx_buf_list[wrindx] = skb;
 		card->tx_buf_list[wrindx] = skb;
-		card->txbd_ring[wrindx]->paddr = buf_pa;
-		card->txbd_ring[wrindx]->len = (u16)skb->len;
-		card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
-						MWIFIEX_BD_FLAG_LAST_DESC;
 
 
-		if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
-							MWIFIEX_MAX_TXRX_BD)
+		if (reg->pfu_enabled) {
+			desc2 = (void *)card->txbd_ring[wrindx];
+			desc2->paddr = buf_pa;
+			desc2->len = (u16)skb->len;
+			desc2->frag_len = (u16)skb->len;
+			desc2->offset = 0;
+			desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+					 MWIFIEX_BD_FLAG_LAST_DESC;
+		} else {
+			desc = card->txbd_ring[wrindx];
+			desc->paddr = buf_pa;
+			desc->len = (u16)skb->len;
+			desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+				      MWIFIEX_BD_FLAG_LAST_DESC;
+		}
+
+		switch (card->dev->device) {
+		case PCIE_DEVICE_ID_MARVELL_88W8766P:
+			card->txbd_wrptr++;
+			break;
+		case PCIE_DEVICE_ID_MARVELL_88W8897:
+			card->txbd_wrptr += reg->ring_tx_start_ptr;
+			break;
+		}
+
+		if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs)
 			card->txbd_wrptr = ((card->txbd_wrptr &
 			card->txbd_wrptr = ((card->txbd_wrptr &
-						MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
-						MWIFIEX_BD_FLAG_ROLLOVER_IND);
+						reg->tx_rollover_ind) ^
+						reg->tx_rollover_ind);
 
 
-		/* Write the TX ring write pointer in to REG_TXBD_WRPTR */
-		if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR,
-				      card->txbd_wrptr)) {
+		rx_val = card->rxbd_rdptr & reg->rx_wrap_mask;
+		/* Write the TX ring write pointer in to reg->tx_wrptr */
+		if (mwifiex_write_reg(adapter, reg->tx_wrptr,
+				      card->txbd_wrptr | rx_val)) {
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
-				"SEND DATA: failed to write REG_TXBD_WRPTR\n");
+				"SEND DATA: failed to write reg->tx_wrptr\n");
 			ret = -1;
 			ret = -1;
 			goto done_unmap;
 			goto done_unmap;
 		}
 		}
@@ -971,9 +1153,11 @@ done_unmap:
 	MWIFIEX_SKB_PACB(skb, &buf_pa);
 	MWIFIEX_SKB_PACB(skb, &buf_pa);
 	pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
 	pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
 	card->tx_buf_list[wrindx] = NULL;
 	card->tx_buf_list[wrindx] = NULL;
-	card->txbd_ring[wrindx]->paddr = 0;
-	card->txbd_ring[wrindx]->len = 0;
-	card->txbd_ring[wrindx]->flags = 0;
+	if (reg->pfu_enabled)
+		memset(desc2, 0, sizeof(*desc2));
+	else
+		memset(desc, 0, sizeof(*desc));
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -984,32 +1168,35 @@ done_unmap:
 static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
-	u32 wrptr, rd_index;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	u32 wrptr, rd_index, tx_val;
 	dma_addr_t buf_pa;
 	dma_addr_t buf_pa;
 	int ret = 0;
 	int ret = 0;
 	struct sk_buff *skb_tmp = NULL;
 	struct sk_buff *skb_tmp = NULL;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
 
 
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 		mwifiex_pm_wakeup_card(adapter);
 		mwifiex_pm_wakeup_card(adapter);
 
 
 	/* Read the RX ring Write pointer set by firmware */
 	/* Read the RX ring Write pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+	if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"RECV DATA: failed to read REG_TXBD_RDPTR\n");
+			"RECV DATA: failed to read reg->rx_wrptr\n");
 		ret = -1;
 		ret = -1;
 		goto done;
 		goto done;
 	}
 	}
 	card->rxbd_wrptr = wrptr;
 	card->rxbd_wrptr = wrptr;
 
 
-	while (((wrptr & MWIFIEX_RXBD_MASK) !=
-		(card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
-	       ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
-		(card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+	while (((wrptr & reg->rx_mask) !=
+		(card->rxbd_rdptr & reg->rx_mask)) ||
+	       ((wrptr & reg->rx_rollover_ind) ==
+		(card->rxbd_rdptr & reg->rx_rollover_ind))) {
 		struct sk_buff *skb_data;
 		struct sk_buff *skb_data;
 		u16 rx_len;
 		u16 rx_len;
 		__le16 pkt_len;
 		__le16 pkt_len;
 
 
-		rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
+		rd_index = card->rxbd_rdptr & reg->rx_mask;
 		skb_data = card->rx_buf_list[rd_index];
 		skb_data = card->rx_buf_list[rd_index];
 
 
 		MWIFIEX_SKB_PACB(skb_data, &buf_pa);
 		MWIFIEX_SKB_PACB(skb_data, &buf_pa);
@@ -1047,32 +1234,44 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
 			"RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
 			"RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
 			skb_tmp, rd_index);
 			skb_tmp, rd_index);
 		card->rx_buf_list[rd_index] = skb_tmp;
 		card->rx_buf_list[rd_index] = skb_tmp;
-		card->rxbd_ring[rd_index]->paddr = buf_pa;
-		card->rxbd_ring[rd_index]->len = skb_tmp->len;
-		card->rxbd_ring[rd_index]->flags = 0;
 
 
-		if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
+		if (reg->pfu_enabled) {
+			desc2 = (void *)card->rxbd_ring[rd_index];
+			desc2->paddr = buf_pa;
+			desc2->len = skb_tmp->len;
+			desc2->frag_len = skb_tmp->len;
+			desc2->offset = 0;
+			desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop;
+		} else {
+			desc = card->rxbd_ring[rd_index];
+			desc->paddr = buf_pa;
+			desc->len = skb_tmp->len;
+			desc->flags = 0;
+		}
+
+		if ((++card->rxbd_rdptr & reg->rx_mask) ==
 							MWIFIEX_MAX_TXRX_BD) {
 							MWIFIEX_MAX_TXRX_BD) {
 			card->rxbd_rdptr = ((card->rxbd_rdptr &
 			card->rxbd_rdptr = ((card->rxbd_rdptr &
-					     MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
-					    MWIFIEX_BD_FLAG_ROLLOVER_IND);
+					     reg->rx_rollover_ind) ^
+					     reg->rx_rollover_ind);
 		}
 		}
 		dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
 		dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
 			card->rxbd_rdptr, wrptr);
 			card->rxbd_rdptr, wrptr);
 
 
-		/* Write the RX ring read pointer in to REG_RXBD_RDPTR */
-		if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR,
-				      card->rxbd_rdptr)) {
+		tx_val = card->txbd_wrptr & reg->tx_wrap_mask;
+		/* Write the RX ring read pointer in to reg->rx_rdptr */
+		if (mwifiex_write_reg(adapter, reg->rx_rdptr,
+				      card->rxbd_rdptr | tx_val)) {
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
-				"RECV DATA: failed to write REG_RXBD_RDPTR\n");
+				"RECV DATA: failed to write reg->rx_rdptr\n");
 			ret = -1;
 			ret = -1;
 			goto done;
 			goto done;
 		}
 		}
 
 
 		/* Read the RX ring Write pointer set by firmware */
 		/* Read the RX ring Write pointer set by firmware */
-		if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+		if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
-				"RECV DATA: failed to read REG_TXBD_RDPTR\n");
+				"RECV DATA: failed to read reg->rx_wrptr\n");
 			ret = -1;
 			ret = -1;
 			goto done;
 			goto done;
 		}
 		}
@@ -1093,6 +1292,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 {
 {
 	dma_addr_t buf_pa;
 	dma_addr_t buf_pa;
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
 	if (!(skb->data && skb->len)) {
 	if (!(skb->data && skb->len)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
@@ -1106,9 +1306,10 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 
 
 	MWIFIEX_SKB_PACB(skb, &buf_pa);
 	MWIFIEX_SKB_PACB(skb, &buf_pa);
 
 
-	/* Write the lower 32bits of the physical address to scratch
-	 * register 0 */
-	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)buf_pa)) {
+	/* Write the lower 32bits of the physical address to low command
+	 * address scratch register
+	 */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
 			"%s: failed to write download command to boot code.\n",
 			"%s: failed to write download command to boot code.\n",
 			__func__);
 			__func__);
@@ -1117,9 +1318,10 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	/* Write the upper 32bits of the physical address to scratch
-	 * register 1 */
-	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
+	/* Write the upper 32bits of the physical address to high command
+	 * address scratch register
+	 */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
 			      (u32)((u64)buf_pa >> 32))) {
 			      (u32)((u64)buf_pa >> 32))) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
 			"%s: failed to write download command to boot code.\n",
 			"%s: failed to write download command to boot code.\n",
@@ -1129,10 +1331,10 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	/* Write the command length to scratch register 2 */
-	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) {
+	/* Write the command length to cmd_size scratch register */
+	if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"%s: failed to write command len to scratch reg 2\n",
+			"%s: failed to write command len to cmd_size scratch reg\n",
 			__func__);
 			__func__);
 		pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 		pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
 				 PCI_DMA_TODEVICE);
 				 PCI_DMA_TODEVICE);
@@ -1158,11 +1360,14 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask;
 
 
-	/* Write the RX ring read pointer in to REG_RXBD_RDPTR */
-	if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr | 0)) {
+	/* Write the RX ring read pointer in to reg->rx_rdptr */
+	if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
+			      tx_wrap)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"RECV DATA: failed to write REG_RXBD_RDPTR\n");
+			"RECV DATA: failed to write reg->rx_rdptr\n");
 		return -1;
 		return -1;
 	}
 	}
 	return 0;
 	return 0;
@@ -1174,6 +1379,7 @@ static int
 mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	int ret = 0;
 	int ret = 0;
 	dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
 	dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
 	u8 *payload = (u8 *)skb->data;
 	u8 *payload = (u8 *)skb->data;
@@ -1206,7 +1412,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 
 
 	/* To send a command, the driver will:
 	/* To send a command, the driver will:
 		1. Write the 64bit physical address of the data buffer to
 		1. Write the 64bit physical address of the data buffer to
-		   SCRATCH1 + SCRATCH0
+		   cmd response address low  + cmd response address high
 		2. Ring the door bell (i.e. set the door bell interrupt)
 		2. Ring the door bell (i.e. set the door bell interrupt)
 
 
 		In response to door bell interrupt, the firmware will perform
 		In response to door bell interrupt, the firmware will perform
@@ -1218,7 +1424,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 		MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa);
 		MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa);
 		/* Write the lower 32bits of the cmdrsp buffer physical
 		/* Write the lower 32bits of the cmdrsp buffer physical
 		   address */
 		   address */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
 				      (u32)cmdrsp_buf_pa)) {
 				      (u32)cmdrsp_buf_pa)) {
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
 				"Failed to write download cmd to boot code.\n");
 				"Failed to write download cmd to boot code.\n");
@@ -1227,7 +1433,7 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 		}
 		}
 		/* Write the upper 32bits of the cmdrsp buffer physical
 		/* Write the upper 32bits of the cmdrsp buffer physical
 		   address */
 		   address */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi,
 				      (u32)((u64)cmdrsp_buf_pa >> 32))) {
 				      (u32)((u64)cmdrsp_buf_pa >> 32))) {
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
 				"Failed to write download cmd to boot code.\n");
 				"Failed to write download cmd to boot code.\n");
@@ -1237,15 +1443,16 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 	}
 	}
 
 
 	MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa);
 	MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa);
-	/* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
-	if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)cmd_buf_pa)) {
+	/* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
+			      (u32)cmd_buf_pa)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
 			"Failed to write download cmd to boot code.\n");
 			"Failed to write download cmd to boot code.\n");
 		ret = -1;
 		ret = -1;
 		goto done;
 		goto done;
 	}
 	}
-	/* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
-	if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
+	/* Write the upper 32bits of the physical address to reg->cmd_addr_hi */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
 			      (u32)((u64)cmd_buf_pa >> 32))) {
 			      (u32)((u64)cmd_buf_pa >> 32))) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
 			"Failed to write download cmd to boot code.\n");
 			"Failed to write download cmd to boot code.\n");
@@ -1253,10 +1460,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 		goto done;
 		goto done;
 	}
 	}
 
 
-	/* Write the command length to REG_CMD_SIZE */
-	if (mwifiex_write_reg(adapter, REG_CMD_SIZE, card->cmd_buf->len)) {
+	/* Write the command length to reg->cmd_size */
+	if (mwifiex_write_reg(adapter, reg->cmd_size,
+			      card->cmd_buf->len)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"Failed to write cmd len to REG_CMD_SIZE\n");
+			"Failed to write cmd len to reg->cmd_size\n");
 		ret = -1;
 		ret = -1;
 		goto done;
 		goto done;
 	}
 	}
@@ -1283,6 +1491,7 @@ done:
 static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	struct sk_buff *skb = card->cmdrsp_buf;
 	struct sk_buff *skb = card->cmdrsp_buf;
 	int count = 0;
 	int count = 0;
 	u16 rx_len;
 	u16 rx_len;
@@ -1328,14 +1537,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
 		/* Clear the cmd-rsp buffer address in scratch registers. This
 		/* Clear the cmd-rsp buffer address in scratch registers. This
 		   will prevent firmware from writing to the same response
 		   will prevent firmware from writing to the same response
 		   buffer again. */
 		   buffer again. */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) {
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) {
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
 				"cmd_done: failed to clear cmd_rsp_addr_lo\n");
 				"cmd_done: failed to clear cmd_rsp_addr_lo\n");
 			return -1;
 			return -1;
 		}
 		}
 		/* Write the upper 32bits of the cmdrsp buffer physical
 		/* Write the upper 32bits of the cmdrsp buffer physical
 		   address */
 		   address */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) {
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) {
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
 				"cmd_done: failed to clear cmd_rsp_addr_hi\n");
 				"cmd_done: failed to clear cmd_rsp_addr_hi\n");
 			return -1;
 			return -1;
@@ -1380,9 +1589,11 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
 static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
 static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
 	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
 	u32 wrptr, event;
 	u32 wrptr, event;
 	dma_addr_t buf_pa;
 	dma_addr_t buf_pa;
+	struct mwifiex_evt_buf_desc *desc;
 
 
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 		mwifiex_pm_wakeup_card(adapter);
 		mwifiex_pm_wakeup_card(adapter);
@@ -1399,9 +1610,9 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
 	}
 	}
 
 
 	/* Read the event ring write pointer set by firmware */
 	/* Read the event ring write pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"EventReady: failed to read REG_EVTBD_WRPTR\n");
+			"EventReady: failed to read reg->evt_wrptr\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -1409,8 +1620,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
 		card->evtbd_rdptr, wrptr);
 		card->evtbd_rdptr, wrptr);
 	if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
 	if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
 					      & MWIFIEX_EVTBD_MASK)) ||
 					      & MWIFIEX_EVTBD_MASK)) ||
-	    ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
-	     (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+	    ((wrptr & reg->evt_rollover_ind) ==
+	     (card->evtbd_rdptr & reg->evt_rollover_ind))) {
 		struct sk_buff *skb_cmd;
 		struct sk_buff *skb_cmd;
 		__le16 data_len = 0;
 		__le16 data_len = 0;
 		u16 evt_len;
 		u16 evt_len;
@@ -1424,9 +1635,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
 		/* Take the pointer and set it to event pointer in adapter
 		/* Take the pointer and set it to event pointer in adapter
 		   and will return back after event handling callback */
 		   and will return back after event handling callback */
 		card->evt_buf_list[rdptr] = NULL;
 		card->evt_buf_list[rdptr] = NULL;
-		card->evtbd_ring[rdptr]->paddr = 0;
-		card->evtbd_ring[rdptr]->len = 0;
-		card->evtbd_ring[rdptr]->flags = 0;
+		desc = card->evtbd_ring[rdptr];
+		memset(desc, 0, sizeof(*desc));
 
 
 		event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN];
 		event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN];
 		adapter->event_cause = event;
 		adapter->event_cause = event;
@@ -1462,10 +1672,12 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
 				       struct sk_buff *skb)
 				       struct sk_buff *skb)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	int ret = 0;
 	int ret = 0;
 	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
 	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
 	u32 wrptr;
 	u32 wrptr;
 	dma_addr_t buf_pa;
 	dma_addr_t buf_pa;
+	struct mwifiex_evt_buf_desc *desc;
 
 
 	if (!skb)
 	if (!skb)
 		return 0;
 		return 0;
@@ -1477,9 +1689,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
 	}
 	}
 
 
 	/* Read the event ring write pointer set by firmware */
 	/* Read the event ring write pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"event_complete: failed to read REG_EVTBD_WRPTR\n");
+			"event_complete: failed to read reg->evt_wrptr\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -1492,9 +1704,10 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
 		MWIFIEX_SKB_PACB(skb, &buf_pa);
 		MWIFIEX_SKB_PACB(skb, &buf_pa);
 		card->evt_buf_list[rdptr] = skb;
 		card->evt_buf_list[rdptr] = skb;
 		MWIFIEX_SKB_PACB(skb, &buf_pa);
 		MWIFIEX_SKB_PACB(skb, &buf_pa);
-		card->evtbd_ring[rdptr]->paddr = buf_pa;
-		card->evtbd_ring[rdptr]->len = (u16)skb->len;
-		card->evtbd_ring[rdptr]->flags = 0;
+		desc = card->evtbd_ring[rdptr];
+		desc->paddr = buf_pa;
+		desc->len = (u16)skb->len;
+		desc->flags = 0;
 		skb = NULL;
 		skb = NULL;
 	} else {
 	} else {
 		dev_dbg(adapter->dev,
 		dev_dbg(adapter->dev,
@@ -1504,17 +1717,18 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
 
 
 	if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
 	if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
 		card->evtbd_rdptr = ((card->evtbd_rdptr &
 		card->evtbd_rdptr = ((card->evtbd_rdptr &
-					MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
-					MWIFIEX_BD_FLAG_ROLLOVER_IND);
+					reg->evt_rollover_ind) ^
+					reg->evt_rollover_ind);
 	}
 	}
 
 
 	dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
 	dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
 		card->evtbd_rdptr, wrptr);
 		card->evtbd_rdptr, wrptr);
 
 
-	/* Write the event ring read pointer in to REG_EVTBD_RDPTR */
-	if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) {
+	/* Write the event ring read pointer in to reg->evt_rdptr */
+	if (mwifiex_write_reg(adapter, reg->evt_rdptr,
+			      card->evtbd_rdptr)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
-			"event_complete: failed to read REG_EVTBD_RDPTR\n");
+			"event_complete: failed to read reg->evt_rdptr\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -1543,6 +1757,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
 	u32 block_retry_cnt = 0;
 	u32 block_retry_cnt = 0;
 	dma_addr_t buf_pa;
 	dma_addr_t buf_pa;
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
 	if (!firmware || !firmware_len) {
 	if (!firmware || !firmware_len) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
@@ -1574,7 +1789,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
 			break;
 			break;
 
 
 		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
 		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
-			ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG,
+			ret = mwifiex_read_reg(adapter, reg->cmd_size,
 					       &len);
 					       &len);
 			if (ret) {
 			if (ret) {
 				dev_warn(adapter->dev,
 				dev_warn(adapter->dev,
@@ -1620,16 +1835,15 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
 
 
 			dev_dbg(adapter->dev, ".");
 			dev_dbg(adapter->dev, ".");
 
 
-			tx_blocks = (txlen +
-				     MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) /
-				     MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD;
+			tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) /
+				    card->pcie.blksz_fw_dl;
 
 
 			/* Copy payload to buffer */
 			/* Copy payload to buffer */
 			memmove(skb->data, &firmware[offset], txlen);
 			memmove(skb->data, &firmware[offset], txlen);
 		}
 		}
 
 
 		skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
 		skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
-		skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD);
+		skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl);
 
 
 		/* Send the boot command to device */
 		/* Send the boot command to device */
 		if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
 		if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
@@ -1682,6 +1896,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 {
 {
 	int ret = 0;
 	int ret = 0;
 	u32 firmware_stat, winner_status;
 	u32 firmware_stat, winner_status;
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	u32 tries;
 	u32 tries;
 
 
 	/* Mask spurios interrupts */
 	/* Mask spurios interrupts */
@@ -1692,7 +1908,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 	}
 	}
 
 
 	dev_dbg(adapter->dev, "Setting driver ready signature\n");
 	dev_dbg(adapter->dev, "Setting driver ready signature\n");
-	if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) {
+	if (mwifiex_write_reg(adapter, reg->drv_rdy,
+			      FIRMWARE_READY_PCIE)) {
 		dev_err(adapter->dev,
 		dev_err(adapter->dev,
 			"Failed to write driver ready signature\n");
 			"Failed to write driver ready signature\n");
 		return -1;
 		return -1;
@@ -1700,7 +1917,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 
 
 	/* Wait for firmware initialization event */
 	/* Wait for firmware initialization event */
 	for (tries = 0; tries < poll_num; tries++) {
 	for (tries = 0; tries < poll_num; tries++) {
-		if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+		if (mwifiex_read_reg(adapter, reg->fw_status,
 				     &firmware_stat))
 				     &firmware_stat))
 			ret = -1;
 			ret = -1;
 		else
 		else
@@ -1717,7 +1934,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 	}
 	}
 
 
 	if (ret) {
 	if (ret) {
-		if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+		if (mwifiex_read_reg(adapter, reg->fw_status,
 				     &winner_status))
 				     &winner_status))
 			ret = -1;
 			ret = -1;
 		else if (!winner_status) {
 		else if (!winner_status) {
@@ -2061,10 +2278,11 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
 {
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pcie_service_card *card = adapter->card;
 	struct pci_dev *pdev = card->dev;
 	struct pci_dev *pdev = card->dev;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 
 	if (user_rmmod) {
 	if (user_rmmod) {
 		dev_dbg(adapter->dev, "Clearing driver ready signature\n");
 		dev_dbg(adapter->dev, "Clearing driver ready signature\n");
-		if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
+		if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
 			dev_err(adapter->dev,
 			dev_err(adapter->dev,
 				"Failed to write driver not-ready signature\n");
 				"Failed to write driver not-ready signature\n");
 	}
 	}
@@ -2102,7 +2320,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 	}
 	}
 
 
 	adapter->dev = &pdev->dev;
 	adapter->dev = &pdev->dev;
-	strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
+	strcpy(adapter->fw_name, card->pcie.firmware);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2162,7 +2380,7 @@ static int mwifiex_pcie_init_module(void)
 {
 {
 	int ret;
 	int ret;
 
 
-	pr_debug("Marvell 8766 PCIe Driver\n");
+	pr_debug("Marvell PCIe Driver\n");
 
 
 	sema_init(&add_remove_card_sem, 1);
 	sema_init(&add_remove_card_sem, 1);
 
 
@@ -2205,4 +2423,5 @@ MODULE_AUTHOR("Marvell International Ltd.");
 MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
 MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
 MODULE_VERSION(PCIE_VERSION);
 MODULE_VERSION(PCIE_VERSION);
 MODULE_LICENSE("GPL v2");
 MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin");
+MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME);

+ 178 - 34
drivers/net/wireless/mwifiex/pcie.h

@@ -29,6 +29,11 @@
 #include    "main.h"
 #include    "main.h"
 
 
 #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
 #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
+#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin"
+
+#define PCIE_VENDOR_ID_MARVELL              (0x11ab)
+#define PCIE_DEVICE_ID_MARVELL_88W8766P		(0x2b30)
+#define PCIE_DEVICE_ID_MARVELL_88W8897		(0x2b38)
 
 
 /* Constants for Buffer Descriptor (BD) rings */
 /* Constants for Buffer Descriptor (BD) rings */
 #define MWIFIEX_MAX_TXRX_BD			0x20
 #define MWIFIEX_MAX_TXRX_BD			0x20
@@ -57,6 +62,8 @@
 #define PCIE_SCRATCH_10_REG				0xCE8
 #define PCIE_SCRATCH_10_REG				0xCE8
 #define PCIE_SCRATCH_11_REG				0xCEC
 #define PCIE_SCRATCH_11_REG				0xCEC
 #define PCIE_SCRATCH_12_REG				0xCF0
 #define PCIE_SCRATCH_12_REG				0xCF0
+#define PCIE_RD_DATA_PTR_Q0_Q1                          0xC08C
+#define PCIE_WR_DATA_PTR_Q0_Q1                          0xC05C
 
 
 #define CPU_INTR_DNLD_RDY				BIT(0)
 #define CPU_INTR_DNLD_RDY				BIT(0)
 #define CPU_INTR_DOOR_BELL				BIT(1)
 #define CPU_INTR_DOOR_BELL				BIT(1)
@@ -75,27 +82,14 @@
 #define MWIFIEX_BD_FLAG_ROLLOVER_IND			BIT(7)
 #define MWIFIEX_BD_FLAG_ROLLOVER_IND			BIT(7)
 #define MWIFIEX_BD_FLAG_FIRST_DESC			BIT(0)
 #define MWIFIEX_BD_FLAG_FIRST_DESC			BIT(0)
 #define MWIFIEX_BD_FLAG_LAST_DESC			BIT(1)
 #define MWIFIEX_BD_FLAG_LAST_DESC			BIT(1)
-#define REG_CMD_ADDR_LO					PCIE_SCRATCH_0_REG
-#define REG_CMD_ADDR_HI					PCIE_SCRATCH_1_REG
-#define REG_CMD_SIZE					PCIE_SCRATCH_2_REG
-
-#define REG_CMDRSP_ADDR_LO				PCIE_SCRATCH_4_REG
-#define REG_CMDRSP_ADDR_HI				PCIE_SCRATCH_5_REG
-
-/* TX buffer description read pointer */
-#define REG_TXBD_RDPTR					PCIE_SCRATCH_6_REG
-/* TX buffer description write pointer */
-#define REG_TXBD_WRPTR					PCIE_SCRATCH_7_REG
-/* RX buffer description read pointer */
-#define REG_RXBD_RDPTR					PCIE_SCRATCH_8_REG
-/* RX buffer description write pointer */
-#define REG_RXBD_WRPTR					PCIE_SCRATCH_9_REG
-/* Event buffer description read pointer */
-#define REG_EVTBD_RDPTR					PCIE_SCRATCH_10_REG
-/* Event buffer description write pointer */
-#define REG_EVTBD_WRPTR					PCIE_SCRATCH_11_REG
-/* Driver ready signature write pointer */
-#define REG_DRV_READY					PCIE_SCRATCH_12_REG
+#define MWIFIEX_BD_FLAG_SOP				BIT(0)
+#define MWIFIEX_BD_FLAG_EOP				BIT(1)
+#define MWIFIEX_BD_FLAG_XS_SOP				BIT(2)
+#define MWIFIEX_BD_FLAG_XS_EOP				BIT(3)
+#define MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND		BIT(7)
+#define MWIFIEX_BD_FLAG_RX_ROLLOVER_IND			BIT(10)
+#define MWIFIEX_BD_FLAG_TX_START_PTR			BIT(16)
+#define MWIFIEX_BD_FLAG_TX_ROLLOVER_IND			BIT(26)
 
 
 /* Max retry number of command write */
 /* Max retry number of command write */
 #define MAX_WRITE_IOMEM_RETRY				2
 #define MAX_WRITE_IOMEM_RETRY				2
@@ -104,15 +98,139 @@
 /* FW awake cookie after FW ready */
 /* FW awake cookie after FW ready */
 #define FW_AWAKE_COOKIE						(0xAA55AA55)
 #define FW_AWAKE_COOKIE						(0xAA55AA55)
 
 
+struct mwifiex_pcie_card_reg {
+	u16 cmd_addr_lo;
+	u16 cmd_addr_hi;
+	u16 fw_status;
+	u16 cmd_size;
+	u16 cmdrsp_addr_lo;
+	u16 cmdrsp_addr_hi;
+	u16 tx_rdptr;
+	u16 tx_wrptr;
+	u16 rx_rdptr;
+	u16 rx_wrptr;
+	u16 evt_rdptr;
+	u16 evt_wrptr;
+	u16 drv_rdy;
+	u16 tx_start_ptr;
+	u32 tx_mask;
+	u32 tx_wrap_mask;
+	u32 rx_mask;
+	u32 rx_wrap_mask;
+	u32 tx_rollover_ind;
+	u32 rx_rollover_ind;
+	u32 evt_rollover_ind;
+	u8 ring_flag_sop;
+	u8 ring_flag_eop;
+	u8 ring_flag_xs_sop;
+	u8 ring_flag_xs_eop;
+	u32 ring_tx_start_ptr;
+	u8 pfu_enabled;
+};
+
+static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
+	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
+	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
+	.cmd_size = PCIE_SCRATCH_2_REG,
+	.fw_status = PCIE_SCRATCH_3_REG,
+	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
+	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
+	.tx_rdptr = PCIE_SCRATCH_6_REG,
+	.tx_wrptr = PCIE_SCRATCH_7_REG,
+	.rx_rdptr = PCIE_SCRATCH_8_REG,
+	.rx_wrptr = PCIE_SCRATCH_9_REG,
+	.evt_rdptr = PCIE_SCRATCH_10_REG,
+	.evt_wrptr = PCIE_SCRATCH_11_REG,
+	.drv_rdy = PCIE_SCRATCH_12_REG,
+	.tx_start_ptr = 0,
+	.tx_mask = MWIFIEX_TXBD_MASK,
+	.tx_wrap_mask = 0,
+	.rx_mask = MWIFIEX_RXBD_MASK,
+	.rx_wrap_mask = 0,
+	.tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+	.rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+	.evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+	.ring_flag_sop = 0,
+	.ring_flag_eop = 0,
+	.ring_flag_xs_sop = 0,
+	.ring_flag_xs_eop = 0,
+	.ring_tx_start_ptr = 0,
+	.pfu_enabled = 0,
+};
+
+static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
+	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
+	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
+	.cmd_size = PCIE_SCRATCH_2_REG,
+	.fw_status = PCIE_SCRATCH_3_REG,
+	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
+	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
+	.tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1,
+	.tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1,
+	.rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1,
+	.rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1,
+	.evt_rdptr = PCIE_SCRATCH_10_REG,
+	.evt_wrptr = PCIE_SCRATCH_11_REG,
+	.drv_rdy = PCIE_SCRATCH_12_REG,
+	.tx_start_ptr = 16,
+	.tx_mask = 0x03FF0000,
+	.tx_wrap_mask = 0x07FF0000,
+	.rx_mask = 0x000003FF,
+	.rx_wrap_mask = 0x000007FF,
+	.tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND,
+	.rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND,
+	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
+	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP,
+	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP,
+	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP,
+	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP,
+	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
+	.pfu_enabled = 1,
+};
+
+struct mwifiex_pcie_device {
+	const char *firmware;
+	const struct mwifiex_pcie_card_reg *reg;
+	u16 blksz_fw_dl;
+};
+
+static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
+	.firmware       = PCIE8766_DEFAULT_FW_NAME,
+	.reg            = &mwifiex_reg_8766,
+	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+};
+
+static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
+	.firmware       = PCIE8897_DEFAULT_FW_NAME,
+	.reg            = &mwifiex_reg_8897,
+	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+};
+
+struct mwifiex_evt_buf_desc {
+	u64 paddr;
+	u16 len;
+	u16 flags;
+} __packed;
+
 struct mwifiex_pcie_buf_desc {
 struct mwifiex_pcie_buf_desc {
 	u64 paddr;
 	u64 paddr;
 	u16 len;
 	u16 len;
 	u16 flags;
 	u16 flags;
 } __packed;
 } __packed;
 
 
+struct mwifiex_pfu_buf_desc {
+	u16 flags;
+	u16 offset;
+	u16 frag_len;
+	u16 len;
+	u64 paddr;
+	u32 reserved;
+} __packed;
+
 struct pcie_service_card {
 struct pcie_service_card {
 	struct pci_dev *dev;
 	struct pci_dev *dev;
 	struct mwifiex_adapter *adapter;
 	struct mwifiex_adapter *adapter;
+	struct mwifiex_pcie_device pcie;
 
 
 	u8 txbd_flush;
 	u8 txbd_flush;
 	u32 txbd_wrptr;
 	u32 txbd_wrptr;
@@ -120,7 +238,7 @@ struct pcie_service_card {
 	u32 txbd_ring_size;
 	u32 txbd_ring_size;
 	u8 *txbd_ring_vbase;
 	u8 *txbd_ring_vbase;
 	dma_addr_t txbd_ring_pbase;
 	dma_addr_t txbd_ring_pbase;
-	struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD];
+	void *txbd_ring[MWIFIEX_MAX_TXRX_BD];
 	struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
 	struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
 
 
 	u32 rxbd_wrptr;
 	u32 rxbd_wrptr;
@@ -128,7 +246,7 @@ struct pcie_service_card {
 	u32 rxbd_ring_size;
 	u32 rxbd_ring_size;
 	u8 *rxbd_ring_vbase;
 	u8 *rxbd_ring_vbase;
 	dma_addr_t rxbd_ring_pbase;
 	dma_addr_t rxbd_ring_pbase;
-	struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
+	void *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
 	struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
 	struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
 
 
 	u32 evtbd_wrptr;
 	u32 evtbd_wrptr;
@@ -136,7 +254,7 @@ struct pcie_service_card {
 	u32 evtbd_ring_size;
 	u32 evtbd_ring_size;
 	u8 *evtbd_ring_vbase;
 	u8 *evtbd_ring_vbase;
 	dma_addr_t evtbd_ring_pbase;
 	dma_addr_t evtbd_ring_pbase;
-	struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD];
+	void *evtbd_ring[MWIFIEX_MAX_EVT_BD];
 	struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
 	struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
 
 
 	struct sk_buff *cmd_buf;
 	struct sk_buff *cmd_buf;
@@ -150,11 +268,24 @@ struct pcie_service_card {
 static inline int
 static inline int
 mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
 mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
 {
 {
-	if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
-			(rdptr & MWIFIEX_TXBD_MASK)) &&
-	    ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
-			(rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
-		return 1;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+	switch (card->dev->device) {
+	case PCIE_DEVICE_ID_MARVELL_88W8766P:
+		if (((card->txbd_wrptr & reg->tx_mask) ==
+		     (rdptr & reg->tx_mask)) &&
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) !=
+		     (rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	case PCIE_DEVICE_ID_MARVELL_88W8897:
+		if (((card->txbd_wrptr & reg->tx_mask) ==
+		     (rdptr & reg->tx_mask)) &&
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) ==
+			(rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -162,11 +293,24 @@ mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
 static inline int
 static inline int
 mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
 mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
 {
 {
-	if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
-	     (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) ||
-	    ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
-	     (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
-		return 1;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+	switch (card->dev->device) {
+	case PCIE_DEVICE_ID_MARVELL_88W8766P:
+		if (((card->txbd_wrptr & reg->tx_mask) !=
+		     (card->txbd_rdptr & reg->tx_mask)) ||
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) !=
+		     (card->txbd_rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	case PCIE_DEVICE_ID_MARVELL_88W8897:
+		if (((card->txbd_wrptr & reg->tx_mask) !=
+		     (card->txbd_rdptr & reg->tx_mask)) ||
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) ==
+		     (card->txbd_rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	}
 
 
 	return 0;
 	return 0;
 }
 }

+ 2 - 3
drivers/net/wireless/mwifiex/sta_cmdresp.c

@@ -935,9 +935,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
 					/ MWIFIEX_SDIO_BLOCK_SIZE)
 					/ MWIFIEX_SDIO_BLOCK_SIZE)
 				       * MWIFIEX_SDIO_BLOCK_SIZE;
 				       * MWIFIEX_SDIO_BLOCK_SIZE;
 		adapter->curr_tx_buf_size = adapter->tx_buf_size;
 		adapter->curr_tx_buf_size = adapter->tx_buf_size;
-		dev_dbg(adapter->dev,
-			"cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
-			adapter->max_tx_buf_size, adapter->tx_buf_size);
+		dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n",
+			adapter->curr_tx_buf_size);
 
 
 		if (adapter->if_ops.update_mp_end_port)
 		if (adapter->if_ops.update_mp_end_port)
 			adapter->if_ops.update_mp_end_port(adapter,
 			adapter->if_ops.update_mp_end_port(adapter,

+ 1 - 1
drivers/net/wireless/mwifiex/util.c

@@ -91,7 +91,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
 		memcpy(info->packets_out,
 		memcpy(info->packets_out,
 		       priv->wmm.packets_out,
 		       priv->wmm.packets_out,
 		       sizeof(priv->wmm.packets_out));
 		       sizeof(priv->wmm.packets_out));
-		info->max_tx_buf_size = (u32) adapter->max_tx_buf_size;
+		info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size;
 		info->tx_buf_size = (u32) adapter->tx_buf_size;
 		info->tx_buf_size = (u32) adapter->tx_buf_size;
 		info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv,
 		info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv,
 							      info->rx_tbl);
 							      info->rx_tbl);

+ 2 - 2
drivers/net/wireless/mwl8k.c

@@ -1149,7 +1149,6 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 
 
 	rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL);
 	rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL);
 	if (rxq->buf == NULL) {
 	if (rxq->buf == NULL) {
-		wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n");
 		pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
 		pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
@@ -1442,7 +1441,6 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
 
 
 	txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL);
 	txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL);
 	if (txq->skb == NULL) {
 	if (txq->skb == NULL) {
-		wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n");
 		pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma);
 		pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
@@ -5473,6 +5471,8 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
 	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, },
 	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, },
 	{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, },
 	{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, },
 	{ PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, },
 	{ PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, },
+	{ PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, },
+	{ PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, },
 	{ PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
 	{ PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
 	{ },
 	{ },
 };
 };

+ 1 - 1
drivers/net/wireless/p54/p54usb.c

@@ -84,8 +84,8 @@ static struct usb_device_id p54u_table[] = {
 	{USB_DEVICE(0x06b9, 0x0121)},	/* Thomson SpeedTouch 121g */
 	{USB_DEVICE(0x06b9, 0x0121)},	/* Thomson SpeedTouch 121g */
 	{USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
 	{USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
 	{USB_DEVICE(0x0803, 0x4310)},	/* Zoom 4410a */
 	{USB_DEVICE(0x0803, 0x4310)},	/* Zoom 4410a */
-	{USB_DEVICE(0x083a, 0x4503)},	/* T-Com Sinus 154 data II */
 	{USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
 	{USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
+	{USB_DEVICE(0x083a, 0x4531)},	/* T-Com Sinus 154 data II */
 	{USB_DEVICE(0x083a, 0xc501)},	/* Zoom Wireless-G 4410 */
 	{USB_DEVICE(0x083a, 0xc501)},	/* Zoom Wireless-G 4410 */
 	{USB_DEVICE(0x083a, 0xf503)},	/* Accton FD7050E ver 1010ec  */
 	{USB_DEVICE(0x083a, 0xf503)},	/* Accton FD7050E ver 1010ec  */
 	{USB_DEVICE(0x0846, 0x4240)},	/* Netgear WG111 (v2) */
 	{USB_DEVICE(0x0846, 0x4240)},	/* Netgear WG111 (v2) */

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

@@ -1152,6 +1152,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
 	{ PCI_DEVICE(0x1814, 0x3562) },
 	{ PCI_DEVICE(0x1814, 0x3562) },
 	{ PCI_DEVICE(0x1814, 0x3592) },
 	{ PCI_DEVICE(0x1814, 0x3592) },
 	{ PCI_DEVICE(0x1814, 0x3593) },
 	{ PCI_DEVICE(0x1814, 0x3593) },
+	{ PCI_DEVICE(0x1814, 0x359f) },
 #endif
 #endif
 #ifdef CONFIG_RT2800PCI_RT53XX
 #ifdef CONFIG_RT2800PCI_RT53XX
 	{ PCI_DEVICE(0x1814, 0x5360) },
 	{ PCI_DEVICE(0x1814, 0x5360) },

+ 30 - 5
drivers/net/wireless/rt2x00/rt2800usb.c

@@ -968,6 +968,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x07d1, 0x3c13) },
 	{ USB_DEVICE(0x07d1, 0x3c13) },
 	{ USB_DEVICE(0x07d1, 0x3c15) },
 	{ USB_DEVICE(0x07d1, 0x3c15) },
 	{ USB_DEVICE(0x07d1, 0x3c16) },
 	{ USB_DEVICE(0x07d1, 0x3c16) },
+	{ USB_DEVICE(0x07d1, 0x3c17) },
 	{ USB_DEVICE(0x2001, 0x3c1b) },
 	{ USB_DEVICE(0x2001, 0x3c1b) },
 	/* Draytek */
 	/* Draytek */
 	{ USB_DEVICE(0x07fa, 0x7712) },
 	{ USB_DEVICE(0x07fa, 0x7712) },
@@ -1098,9 +1099,11 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x15a9, 0x0006) },
 	{ USB_DEVICE(0x15a9, 0x0006) },
 	/* Sweex */
 	/* Sweex */
 	{ USB_DEVICE(0x177f, 0x0153) },
 	{ USB_DEVICE(0x177f, 0x0153) },
+	{ USB_DEVICE(0x177f, 0x0164) },
 	{ USB_DEVICE(0x177f, 0x0302) },
 	{ USB_DEVICE(0x177f, 0x0302) },
 	{ USB_DEVICE(0x177f, 0x0313) },
 	{ USB_DEVICE(0x177f, 0x0313) },
 	{ USB_DEVICE(0x177f, 0x0323) },
 	{ USB_DEVICE(0x177f, 0x0323) },
+	{ USB_DEVICE(0x177f, 0x0324) },
 	/* U-Media */
 	/* U-Media */
 	{ USB_DEVICE(0x157e, 0x300e) },
 	{ USB_DEVICE(0x157e, 0x300e) },
 	{ USB_DEVICE(0x157e, 0x3013) },
 	{ USB_DEVICE(0x157e, 0x3013) },
@@ -1115,6 +1118,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	/* Zyxel */
 	/* Zyxel */
 	{ USB_DEVICE(0x0586, 0x3416) },
 	{ USB_DEVICE(0x0586, 0x3416) },
 	{ USB_DEVICE(0x0586, 0x3418) },
 	{ USB_DEVICE(0x0586, 0x3418) },
+	{ USB_DEVICE(0x0586, 0x341a) },
 	{ USB_DEVICE(0x0586, 0x341e) },
 	{ USB_DEVICE(0x0586, 0x341e) },
 	{ USB_DEVICE(0x0586, 0x343e) },
 	{ USB_DEVICE(0x0586, 0x343e) },
 #ifdef CONFIG_RT2800USB_RT33XX
 #ifdef CONFIG_RT2800USB_RT33XX
@@ -1131,6 +1135,9 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x148f, 0x8070) },
 	{ USB_DEVICE(0x148f, 0x8070) },
 	/* Sitecom */
 	/* Sitecom */
 	{ USB_DEVICE(0x0df6, 0x0050) },
 	{ USB_DEVICE(0x0df6, 0x0050) },
+	/* Sweex */
+	{ USB_DEVICE(0x177f, 0x0163) },
+	{ USB_DEVICE(0x177f, 0x0165) },
 #endif
 #endif
 #ifdef CONFIG_RT2800USB_RT35XX
 #ifdef CONFIG_RT2800USB_RT35XX
 	/* Allwin */
 	/* Allwin */
@@ -1166,6 +1173,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 #ifdef CONFIG_RT2800USB_RT53XX
 #ifdef CONFIG_RT2800USB_RT53XX
 	/* Arcadyan */
 	/* Arcadyan */
 	{ USB_DEVICE(0x043e, 0x7a12) },
 	{ USB_DEVICE(0x043e, 0x7a12) },
+	{ USB_DEVICE(0x043e, 0x7a32) },
 	/* Azurewave */
 	/* Azurewave */
 	{ USB_DEVICE(0x13d3, 0x3329) },
 	{ USB_DEVICE(0x13d3, 0x3329) },
 	{ USB_DEVICE(0x13d3, 0x3365) },
 	{ USB_DEVICE(0x13d3, 0x3365) },
@@ -1177,16 +1185,20 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x2001, 0x3c1e) },
 	{ USB_DEVICE(0x2001, 0x3c1e) },
 	/* LG innotek */
 	/* LG innotek */
 	{ USB_DEVICE(0x043e, 0x7a22) },
 	{ USB_DEVICE(0x043e, 0x7a22) },
+	{ USB_DEVICE(0x043e, 0x7a42) },
 	/* Panasonic */
 	/* Panasonic */
 	{ USB_DEVICE(0x04da, 0x1801) },
 	{ USB_DEVICE(0x04da, 0x1801) },
 	{ USB_DEVICE(0x04da, 0x1800) },
 	{ USB_DEVICE(0x04da, 0x1800) },
+	{ USB_DEVICE(0x04da, 0x23f6) },
 	/* Philips */
 	/* Philips */
 	{ USB_DEVICE(0x0471, 0x2104) },
 	{ USB_DEVICE(0x0471, 0x2104) },
+	{ USB_DEVICE(0x0471, 0x2126) },
+	{ USB_DEVICE(0x0471, 0x2180) },
+	{ USB_DEVICE(0x0471, 0x2181) },
+	{ USB_DEVICE(0x0471, 0x2182) },
 	/* Ralink */
 	/* Ralink */
 	{ USB_DEVICE(0x148f, 0x5370) },
 	{ USB_DEVICE(0x148f, 0x5370) },
 	{ USB_DEVICE(0x148f, 0x5372) },
 	{ USB_DEVICE(0x148f, 0x5372) },
-	/* Unknown */
-	{ USB_DEVICE(0x04da, 0x23f6) },
 #endif
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
 #ifdef CONFIG_RT2800USB_UNKNOWN
 	/*
 	/*
@@ -1207,10 +1219,15 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x0b05, 0x1760) },
 	{ USB_DEVICE(0x0b05, 0x1760) },
 	{ USB_DEVICE(0x0b05, 0x1761) },
 	{ USB_DEVICE(0x0b05, 0x1761) },
 	{ USB_DEVICE(0x0b05, 0x1790) },
 	{ USB_DEVICE(0x0b05, 0x1790) },
+	{ USB_DEVICE(0x0b05, 0x17a7) },
 	/* AzureWave */
 	/* AzureWave */
 	{ USB_DEVICE(0x13d3, 0x3262) },
 	{ USB_DEVICE(0x13d3, 0x3262) },
 	{ USB_DEVICE(0x13d3, 0x3284) },
 	{ USB_DEVICE(0x13d3, 0x3284) },
 	{ USB_DEVICE(0x13d3, 0x3322) },
 	{ USB_DEVICE(0x13d3, 0x3322) },
+	{ USB_DEVICE(0x13d3, 0x3340) },
+	{ USB_DEVICE(0x13d3, 0x3399) },
+	{ USB_DEVICE(0x13d3, 0x3400) },
+	{ USB_DEVICE(0x13d3, 0x3401) },
 	/* Belkin */
 	/* Belkin */
 	{ USB_DEVICE(0x050d, 0x1003) },
 	{ USB_DEVICE(0x050d, 0x1003) },
 	/* Buffalo */
 	/* Buffalo */
@@ -1223,13 +1240,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x18c5, 0x0008) },
 	{ USB_DEVICE(0x18c5, 0x0008) },
 	/* D-Link */
 	/* D-Link */
 	{ USB_DEVICE(0x07d1, 0x3c0b) },
 	{ USB_DEVICE(0x07d1, 0x3c0b) },
-	{ USB_DEVICE(0x07d1, 0x3c17) },
 	/* Encore */
 	/* Encore */
 	{ USB_DEVICE(0x203d, 0x14a1) },
 	{ USB_DEVICE(0x203d, 0x14a1) },
+	/* EnGenius */
+	{ USB_DEVICE(0x1740, 0x0600) },
+	{ USB_DEVICE(0x1740, 0x0602) },
 	/* Gemtek */
 	/* Gemtek */
 	{ USB_DEVICE(0x15a9, 0x0010) },
 	{ USB_DEVICE(0x15a9, 0x0010) },
 	/* Gigabyte */
 	/* Gigabyte */
 	{ USB_DEVICE(0x1044, 0x800c) },
 	{ USB_DEVICE(0x1044, 0x800c) },
+	/* Hercules */
+	{ USB_DEVICE(0x06f8, 0xe036) },
 	/* Huawei */
 	/* Huawei */
 	{ USB_DEVICE(0x148f, 0xf101) },
 	{ USB_DEVICE(0x148f, 0xf101) },
 	/* I-O DATA */
 	/* I-O DATA */
@@ -1256,13 +1277,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x0df6, 0x004a) },
 	{ USB_DEVICE(0x0df6, 0x004a) },
 	{ USB_DEVICE(0x0df6, 0x004d) },
 	{ USB_DEVICE(0x0df6, 0x004d) },
 	{ USB_DEVICE(0x0df6, 0x0053) },
 	{ USB_DEVICE(0x0df6, 0x0053) },
+	{ USB_DEVICE(0x0df6, 0x0069) },
+	{ USB_DEVICE(0x0df6, 0x006f) },
 	/* SMC */
 	/* SMC */
 	{ USB_DEVICE(0x083a, 0xa512) },
 	{ USB_DEVICE(0x083a, 0xa512) },
 	{ USB_DEVICE(0x083a, 0xc522) },
 	{ USB_DEVICE(0x083a, 0xc522) },
 	{ USB_DEVICE(0x083a, 0xd522) },
 	{ USB_DEVICE(0x083a, 0xd522) },
 	{ USB_DEVICE(0x083a, 0xf511) },
 	{ USB_DEVICE(0x083a, 0xf511) },
-	/* Zyxel */
-	{ USB_DEVICE(0x0586, 0x341a) },
+	/* Sweex */
+	{ USB_DEVICE(0x177f, 0x0254) },
+	/* TP-LINK */
+	{ USB_DEVICE(0xf201, 0x5370) },
 #endif
 #endif
 	{ 0, }
 	{ 0, }
 };
 };

+ 2 - 1
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c

@@ -669,7 +669,8 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
 	u8 thermalvalue, delta, delta_lck, delta_iqk;
 	u8 thermalvalue, delta, delta_lck, delta_iqk;
 	long ele_a, ele_d, temp_cck, val_x, value32;
 	long ele_a, ele_d, temp_cck, val_x, value32;
 	long val_y, ele_c = 0;
 	long val_y, ele_c = 0;
-	u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0;
+	u8 ofdm_index[2], ofdm_index_old[2], cck_index_old = 0;
+	s8 cck_index = 0;
 	int i;
 	int i;
 	bool is2t = IS_92C_SERIAL(rtlhal->version);
 	bool is2t = IS_92C_SERIAL(rtlhal->version);
 	s8 txpwr_level[2] = {0, 0};
 	s8 txpwr_level[2] = {0, 0};

+ 1 - 1
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c

@@ -488,7 +488,7 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
 	u8 *praddr;
 	u8 *praddr;
 	__le16 fc;
 	__le16 fc;
 	u16 type, c_fc;
 	u16 type, c_fc;
-	bool packet_matchbssid, packet_toself, packet_beacon;
+	bool packet_matchbssid, packet_toself, packet_beacon = false;
 
 
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 
 

+ 1 - 1
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c

@@ -1084,7 +1084,7 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw,
 	u8 *praddr;
 	u8 *praddr;
 	__le16 fc;
 	__le16 fc;
 	u16 type, cpu_fc;
 	u16 type, cpu_fc;
-	bool packet_matchbssid, packet_toself, packet_beacon;
+	bool packet_matchbssid, packet_toself, packet_beacon = false;
 
 
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 	hdr = (struct ieee80211_hdr *)tmp_buf;
 	hdr = (struct ieee80211_hdr *)tmp_buf;

+ 9 - 2
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c

@@ -76,7 +76,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
 				      GFP_KERNEL, hw, rtl_fw_cb);
 				      GFP_KERNEL, hw, rtl_fw_cb);
 
 
 
 
-	return 0;
+	return err;
 }
 }
 
 
 static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw)
 static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw)
@@ -285,6 +285,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
 	/* RTL8188CUS-VL */
 	/* RTL8188CUS-VL */
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)},
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)},
+	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x819a, rtl92cu_hal_cfg)},
 	/* 8188 Combo for BC4 */
 	/* 8188 Combo for BC4 */
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
 
 
@@ -363,9 +364,15 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
 
 
 MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids);
 MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids);
 
 
+static int rtl8192cu_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	return rtl_usb_probe(intf, id, &rtl92cu_hal_cfg);
+}
+
 static struct usb_driver rtl8192cu_driver = {
 static struct usb_driver rtl8192cu_driver = {
 	.name = "rtl8192cu",
 	.name = "rtl8192cu",
-	.probe = rtl_usb_probe,
+	.probe = rtl8192cu_probe,
 	.disconnect = rtl_usb_disconnect,
 	.disconnect = rtl_usb_disconnect,
 	.id_table = rtl8192c_usb_ids,
 	.id_table = rtl8192c_usb_ids,
 
 

+ 2 - 2
drivers/net/wireless/rtlwifi/rtl8192de/dm.c

@@ -841,9 +841,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
 	long ele_a = 0, ele_d, temp_cck, val_x, value32;
 	long ele_a = 0, ele_d, temp_cck, val_x, value32;
 	long val_y, ele_c = 0;
 	long val_y, ele_c = 0;
 	u8 ofdm_index[2];
 	u8 ofdm_index[2];
-	u8 cck_index = 0;
+	s8 cck_index = 0;
 	u8 ofdm_index_old[2];
 	u8 ofdm_index_old[2];
-	u8 cck_index_old = 0;
+	s8 cck_index_old = 0;
 	u8 index;
 	u8 index;
 	int i;
 	int i;
 	bool is2t = IS_92D_SINGLEPHY(rtlhal->version);
 	bool is2t = IS_92D_SINGLEPHY(rtlhal->version);

+ 0 - 2
drivers/net/wireless/rtlwifi/rtl8723ae/fw.c

@@ -512,7 +512,6 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl8192_tx_ring *ring;
 	struct rtl8192_tx_ring *ring;
 	struct rtl_tx_desc *pdesc;
 	struct rtl_tx_desc *pdesc;
-	u8 own;
 	unsigned long flags;
 	unsigned long flags;
 	struct sk_buff *pskb = NULL;
 	struct sk_buff *pskb = NULL;
 
 
@@ -525,7 +524,6 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 
 
 	pdesc = &ring->desc[0];
 	pdesc = &ring->desc[0];
-	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
 
 
 	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
 	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
 
 

+ 0 - 2
drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c

@@ -1433,7 +1433,6 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-	u8 bt_retry_cnt;
 	u8 bt_info_original;
 	u8 bt_info_original;
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[BTCoex] Get bt info by fw!!\n");
 		 "[BTCoex] Get bt info by fw!!\n");
@@ -1445,7 +1444,6 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw)
 				 "[BTCoex] c2h for btInfo not rcvd yet!!\n");
 				 "[BTCoex] c2h for btInfo not rcvd yet!!\n");
 	}
 	}
 
 
-	bt_retry_cnt = rtlhal->hal_coex_8723.bt_retry_cnt;
 	bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original;
 	bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original;
 
 
 	/* when bt inquiry or page scan, we have to set h2c 0x25
 	/* when bt inquiry or page scan, we have to set h2c 0x25

+ 2 - 6
drivers/net/wireless/rtlwifi/rtl8723ae/hw.c

@@ -703,11 +703,9 @@ static void _rtl8723ae_hw_configure(struct ieee80211_hw *hw)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	u8 reg_bw_opmode;
 	u8 reg_bw_opmode;
-	u32 reg_ratr, reg_prsr;
+	u32 reg_prsr;
 
 
 	reg_bw_opmode = BW_OPMODE_20MHZ;
 	reg_bw_opmode = BW_OPMODE_20MHZ;
-	reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
-	    RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
 	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
 	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
 
 
 	rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
 	rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
@@ -2030,7 +2028,7 @@ bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+	enum rf_pwrstate e_rfpowerstate_toset;
 	u8 u1tmp;
 	u8 u1tmp;
 	bool actuallyset = false;
 	bool actuallyset = false;
 
 
@@ -2049,8 +2047,6 @@ bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
 	}
 	}
 
 
-	cur_rfstate = ppsc->rfpwr_state;
-
 	rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
 	rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
 		       rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1)));
 		       rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1)));
 
 

+ 2 - 18
drivers/net/wireless/rtlwifi/rtl8723ae/phy.c

@@ -614,17 +614,11 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 {
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	int i;
 	int i;
-	bool rtstatus = true;
 	u32 *radioa_array_table;
 	u32 *radioa_array_table;
-	u32 *radiob_array_table;
-	u16 radioa_arraylen, radiob_arraylen;
+	u16 radioa_arraylen;
 
 
 	radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH;
 	radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH;
 	radioa_array_table = RTL8723E_RADIOA_1TARRAY;
 	radioa_array_table = RTL8723E_RADIOA_1TARRAY;
-	radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH;
-	radiob_array_table = RTL8723E_RADIOB_1TARRAY;
-
-	rtstatus = true;
 
 
 	switch (rfpath) {
 	switch (rfpath) {
 	case RF90_PATH_A:
 	case RF90_PATH_A:
@@ -1531,11 +1525,8 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
 		0x522, 0x550, 0x551, 0x040
 		0x522, 0x550, 0x551, 0x040
 	};
 	};
 	const u32 retrycount = 2;
 	const u32 retrycount = 2;
-	u32 bbvalue;
 
 
 	if (t == 0) {
 	if (t == 0) {
-		bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
-
 		phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
 		phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
 		phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
 		phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
 	}
 	}
@@ -1712,8 +1703,7 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
 	long result[4][8];
 	long result[4][8];
 	u8 i, final_candidate;
 	u8 i, final_candidate;
 	bool patha_ok, pathb_ok;
 	bool patha_ok, pathb_ok;
-	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
-	    reg_ecc, reg_tmp = 0;
+	long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0;
 	bool is12simular, is13simular, is23simular;
 	bool is12simular, is13simular, is23simular;
 	bool start_conttx = false, singletone = false;
 	bool start_conttx = false, singletone = false;
 	u32 iqk_bb_reg[10] = {
 	u32 iqk_bb_reg[10] = {
@@ -1780,21 +1770,15 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
 		reg_e94 = result[i][0];
 		reg_e94 = result[i][0];
 		reg_e9c = result[i][1];
 		reg_e9c = result[i][1];
 		reg_ea4 = result[i][2];
 		reg_ea4 = result[i][2];
-		reg_eac = result[i][3];
 		reg_eb4 = result[i][4];
 		reg_eb4 = result[i][4];
 		reg_ebc = result[i][5];
 		reg_ebc = result[i][5];
-		reg_ec4 = result[i][6];
-		reg_ecc = result[i][7];
 	}
 	}
 	if (final_candidate != 0xff) {
 	if (final_candidate != 0xff) {
 		rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
 		rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
 		rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
 		rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
 		reg_ea4 = result[final_candidate][2];
 		reg_ea4 = result[final_candidate][2];
-		reg_eac = result[final_candidate][3];
 		rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
 		rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
 		rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
 		rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
-		reg_ec4 = result[final_candidate][6];
-		reg_ecc = result[final_candidate][7];
 		patha_ok = pathb_ok = true;
 		patha_ok = pathb_ok = true;
 	} else {
 	} else {
 		rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
 		rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;

+ 0 - 2
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c

@@ -244,7 +244,6 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw,
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_hdr *hdr;
 	u8 *tmp_buf;
 	u8 *tmp_buf;
 	u8 *praddr;
 	u8 *praddr;
-	u8 *psaddr;
 	__le16 fc;
 	__le16 fc;
 	u16 type;
 	u16 type;
 	bool packet_matchbssid, packet_toself, packet_beacon = false;
 	bool packet_matchbssid, packet_toself, packet_beacon = false;
@@ -255,7 +254,6 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw,
 	fc = hdr->frame_control;
 	fc = hdr->frame_control;
 	type = WLAN_FC_GET_TYPE(fc);
 	type = WLAN_FC_GET_TYPE(fc);
 	praddr = hdr->addr1;
 	praddr = hdr->addr1;
-	psaddr = ieee80211_get_SA(hdr);
 
 
 	packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
 	packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
 			    (!compare_ether_addr(mac->bssid,
 			    (!compare_ether_addr(mac->bssid,

+ 3 - 6
drivers/net/wireless/rtlwifi/usb.c

@@ -825,8 +825,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
 	u32 ep_num;
 	u32 ep_num;
 	struct urb *_urb = NULL;
 	struct urb *_urb = NULL;
 	struct sk_buff *_skb = NULL;
 	struct sk_buff *_skb = NULL;
-	struct sk_buff_head *skb_list;
-	struct usb_anchor *urb_list;
 
 
 	WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl);
 	WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl);
 	if (unlikely(IS_USB_STOP(rtlusb))) {
 	if (unlikely(IS_USB_STOP(rtlusb))) {
@@ -836,7 +834,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
 		return;
 		return;
 	}
 	}
 	ep_num = rtlusb->ep_map.ep_mapping[qnum];
 	ep_num = rtlusb->ep_map.ep_mapping[qnum];
-	skb_list = &rtlusb->tx_skb_queue[ep_num];
 	_skb = skb;
 	_skb = skb;
 	_urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num);
 	_urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num);
 	if (unlikely(!_urb)) {
 	if (unlikely(!_urb)) {
@@ -844,7 +841,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
 			 "Can't allocate urb. Drop skb!\n");
 			 "Can't allocate urb. Drop skb!\n");
 		return;
 		return;
 	}
 	}
-	urb_list = &rtlusb->tx_pending[ep_num];
 	_rtl_submit_tx_urb(hw, _urb);
 	_rtl_submit_tx_urb(hw, _urb);
 }
 }
 
 
@@ -941,7 +937,8 @@ static struct rtl_intf_ops rtl_usb_ops = {
 };
 };
 
 
 int rtl_usb_probe(struct usb_interface *intf,
 int rtl_usb_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
+		  const struct usb_device_id *id,
+		  struct rtl_hal_cfg *rtl_hal_cfg)
 {
 {
 	int err;
 	int err;
 	struct ieee80211_hw *hw = NULL;
 	struct ieee80211_hw *hw = NULL;
@@ -976,7 +973,7 @@ int rtl_usb_probe(struct usb_interface *intf,
 	usb_set_intfdata(intf, hw);
 	usb_set_intfdata(intf, hw);
 	/* init cfg & intf_ops */
 	/* init cfg & intf_ops */
 	rtlpriv->rtlhal.interface = INTF_USB;
 	rtlpriv->rtlhal.interface = INTF_USB;
-	rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info);
+	rtlpriv->cfg = rtl_hal_cfg;
 	rtlpriv->intf_ops = &rtl_usb_ops;
 	rtlpriv->intf_ops = &rtl_usb_ops;
 	rtl_dbgp_flag_init(hw);
 	rtl_dbgp_flag_init(hw);
 	/* Init IO handler */
 	/* Init IO handler */

+ 2 - 1
drivers/net/wireless/rtlwifi/usb.h

@@ -157,7 +157,8 @@ struct rtl_usb_priv {
 
 
 
 
 int rtl_usb_probe(struct usb_interface *intf,
 int rtl_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *id);
+		  const struct usb_device_id *id,
+		  struct rtl_hal_cfg *rtl92cu_hal_cfg);
 void rtl_usb_disconnect(struct usb_interface *intf);
 void rtl_usb_disconnect(struct usb_interface *intf);
 int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message);
 int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message);
 int rtl_usb_resume(struct usb_interface *pusb_intf);
 int rtl_usb_resume(struct usb_interface *pusb_intf);

+ 1 - 1
drivers/net/wireless/rtlwifi/wifi.h

@@ -1702,7 +1702,7 @@ struct rtl_works {
 
 
 struct rtl_debug {
 struct rtl_debug {
 	u32 dbgp_type[DBGP_TYPE_MAX];
 	u32 dbgp_type[DBGP_TYPE_MAX];
-	u32 global_debuglevel;
+	int global_debuglevel;
 	u64 global_debugcomponents;
 	u64 global_debugcomponents;
 
 
 	/* add for proc debug */
 	/* add for proc debug */

+ 9 - 0
drivers/net/wireless/ti/Kconfig

@@ -12,4 +12,13 @@ source "drivers/net/wireless/ti/wl18xx/Kconfig"
 
 
 # keep last for automatic dependencies
 # keep last for automatic dependencies
 source "drivers/net/wireless/ti/wlcore/Kconfig"
 source "drivers/net/wireless/ti/wlcore/Kconfig"
+
+config WILINK_PLATFORM_DATA
+	bool "TI WiLink platform data"
+	depends on WLCORE_SDIO || WL1251_SDIO
+	default y
+	---help---
+	Small platform data bit needed to pass data to the sdio modules.
+
+
 endif # WL_TI
 endif # WL_TI

+ 3 - 1
drivers/net/wireless/ti/Makefile

@@ -1,5 +1,7 @@
 obj-$(CONFIG_WLCORE)			+= wlcore/
 obj-$(CONFIG_WLCORE)			+= wlcore/
 obj-$(CONFIG_WL12XX)			+= wl12xx/
 obj-$(CONFIG_WL12XX)			+= wl12xx/
-obj-$(CONFIG_WL12XX_PLATFORM_DATA)	+= wlcore/
 obj-$(CONFIG_WL1251)			+= wl1251/
 obj-$(CONFIG_WL1251)			+= wl1251/
 obj-$(CONFIG_WL18XX)			+= wl18xx/
 obj-$(CONFIG_WL18XX)			+= wl18xx/
+
+# small builtin driver bit
+obj-$(CONFIG_WILINK_PLATFORM_DATA)	+= wilink_platform_data.o

+ 0 - 0
drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c → drivers/net/wireless/ti/wilink_platform_data.c


+ 2 - 1
drivers/net/wireless/ti/wl12xx/main.c

@@ -1703,7 +1703,8 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 static int wl12xx_setup(struct wl1271 *wl)
 static int wl12xx_setup(struct wl1271 *wl)
 {
 {
 	struct wl12xx_priv *priv = wl->priv;
 	struct wl12xx_priv *priv = wl->priv;
-	struct wl12xx_platform_data *pdata = wl->pdev->dev.platform_data;
+	struct wlcore_platdev_data *pdev_data = wl->pdev->dev.platform_data;
+	struct wl12xx_platform_data *pdata = pdev_data->pdata;
 
 
 	wl->rtable = wl12xx_rtable;
 	wl->rtable = wl12xx_rtable;
 	wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
 	wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;

+ 4 - 3
drivers/net/wireless/ti/wl18xx/conf.h

@@ -23,7 +23,7 @@
 #define __WL18XX_CONF_H__
 #define __WL18XX_CONF_H__
 
 
 #define WL18XX_CONF_MAGIC	0x10e100ca
 #define WL18XX_CONF_MAGIC	0x10e100ca
-#define WL18XX_CONF_VERSION	(WLCORE_CONF_VERSION | 0x0005)
+#define WL18XX_CONF_VERSION	(WLCORE_CONF_VERSION | 0x0006)
 #define WL18XX_CONF_MASK	0x0000ffff
 #define WL18XX_CONF_MASK	0x0000ffff
 #define WL18XX_CONF_SIZE	(WLCORE_CONF_SIZE + \
 #define WL18XX_CONF_SIZE	(WLCORE_CONF_SIZE + \
 				 sizeof(struct wl18xx_priv_conf))
 				 sizeof(struct wl18xx_priv_conf))
@@ -70,8 +70,9 @@ struct wl18xx_mac_and_phy_params {
 	u8 pwr_limit_reference_11_abg;
 	u8 pwr_limit_reference_11_abg;
 	u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
 	u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
 	u8 pwr_limit_reference_11p;
 	u8 pwr_limit_reference_11p;
-	u8 spare1[9];
-	u8 spare2[9];
+	u8 spare1;
+	u8 per_chan_bo_mode_11_abg[13];
+	u8 per_chan_bo_mode_11_p[4];
 	u8 primary_clock_setting_time;
 	u8 primary_clock_setting_time;
 	u8 clock_valid_on_wake_up;
 	u8 clock_valid_on_wake_up;
 	u8 secondary_clock_setting_time;
 	u8 secondary_clock_setting_time;

+ 5 - 0
drivers/net/wireless/ti/wl18xx/main.c

@@ -547,6 +547,11 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
 			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 			0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
 			0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
 		.pwr_limit_reference_11p	= 0x64,
 		.pwr_limit_reference_11p	= 0x64,
+		.per_chan_bo_mode_11_abg	= { 0x00, 0x00, 0x00, 0x00,
+						    0x00, 0x00, 0x00, 0x00,
+						    0x00, 0x00, 0x00, 0x00,
+						    0x00 },
+		.per_chan_bo_mode_11_p		= { 0x00, 0x00, 0x00, 0x00 },
 		.per_chan_pwr_limit_arr_11p	= { 0xff, 0xff, 0xff, 0xff,
 		.per_chan_pwr_limit_arr_11p	= { 0xff, 0xff, 0xff, 0xff,
 						    0xff, 0xff, 0xff },
 						    0xff, 0xff, 0xff },
 		.psat				= 0,
 		.psat				= 0,

+ 0 - 5
drivers/net/wireless/ti/wlcore/Kconfig

@@ -33,8 +33,3 @@ config WLCORE_SDIO
 
 
 	  If you choose to build a module, it'll be called wlcore_sdio.
 	  If you choose to build a module, it'll be called wlcore_sdio.
 	  Say N if unsure.
 	  Say N if unsure.
-
-config WL12XX_PLATFORM_DATA
-	bool
-	depends on WLCORE_SDIO != n || WL1251_SDIO != n
-	default y

+ 0 - 3
drivers/net/wireless/ti/wlcore/Makefile

@@ -9,7 +9,4 @@ obj-$(CONFIG_WLCORE)			+= wlcore.o
 obj-$(CONFIG_WLCORE_SPI)		+= wlcore_spi.o
 obj-$(CONFIG_WLCORE_SPI)		+= wlcore_spi.o
 obj-$(CONFIG_WLCORE_SDIO)		+= wlcore_sdio.o
 obj-$(CONFIG_WLCORE_SDIO)		+= wlcore_sdio.o
 
 
-# small builtin driver bit
-obj-$(CONFIG_WL12XX_PLATFORM_DATA)	+= wl12xx_platform_data.o
-
 ccflags-y += -D__CHECK_ENDIAN__
 ccflags-y += -D__CHECK_ENDIAN__

+ 2 - 2
drivers/net/wireless/ti/wlcore/boot.c

@@ -84,8 +84,8 @@ out:
 static int wlcore_validate_fw_ver(struct wl1271 *wl)
 static int wlcore_validate_fw_ver(struct wl1271 *wl)
 {
 {
 	unsigned int *fw_ver = wl->chip.fw_ver;
 	unsigned int *fw_ver = wl->chip.fw_ver;
-	unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_NORMAL) ?
-		wl->min_sr_fw_ver : wl->min_mr_fw_ver;
+	unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_MULTI) ?
+		wl->min_mr_fw_ver : wl->min_sr_fw_ver;
 	char min_fw_str[32] = "";
 	char min_fw_str[32] = "";
 	int i;
 	int i;
 
 

+ 5 - 3
drivers/net/wireless/ti/wlcore/cmd.c

@@ -510,10 +510,12 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	cmd->sta.hlid = wlvif->sta.hlid;
 	cmd->sta.hlid = wlvif->sta.hlid;
 	cmd->sta.session = wl->session_ids[wlvif->sta.hlid];
 	cmd->sta.session = wl->session_ids[wlvif->sta.hlid];
 	/*
 	/*
-	 * We don't have the correct remote rates in this stage. the rates
-	 * will be reconfigured later, after authorization.
+	 * We don't have the correct remote rates in this stage.  The
+	 * rates will be reconfigured later, after association, if the
+	 * firmware supports ACX_PEER_CAP.  Otherwise, there's nothing
+	 * we can do, so use all supported_rates here.
 	 */
 	 */
-	cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set);
+	cmd->sta.remote_rates = cpu_to_le32(supported_rates);
 
 
 	wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
 	wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
 		     "basic_rate_set: 0x%x, remote_rates: 0x%x",
 		     "basic_rate_set: 0x%x, remote_rates: 0x%x",

+ 7 - 10
drivers/net/wireless/ti/wlcore/main.c

@@ -2162,7 +2162,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
 	return 0;
 	return 0;
 }
 }
 
 
-static bool wl12xx_init_fw(struct wl1271 *wl)
+static int wl12xx_init_fw(struct wl1271 *wl)
 {
 {
 	int retries = WL1271_BOOT_RETRIES;
 	int retries = WL1271_BOOT_RETRIES;
 	bool booted = false;
 	bool booted = false;
@@ -2228,7 +2228,7 @@ power_off:
 
 
 	wl->state = WLCORE_STATE_ON;
 	wl->state = WLCORE_STATE_ON;
 out:
 out:
-	return booted;
+	return ret;
 }
 }
 
 
 static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
 static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
@@ -2371,7 +2371,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 	struct vif_counter_data vif_count;
 	struct vif_counter_data vif_count;
 	int ret = 0;
 	int ret = 0;
 	u8 role_type;
 	u8 role_type;
-	bool booted = false;
 
 
 	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
 	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
 			     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
 			     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
@@ -2432,11 +2431,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 		 */
 		 */
 		memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
 		memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
 
 
-		booted = wl12xx_init_fw(wl);
-		if (!booted) {
-			ret = -EINVAL;
+		ret = wl12xx_init_fw(wl);
+		if (ret < 0)
 			goto out;
 			goto out;
-		}
 	}
 	}
 
 
 	ret = wl12xx_cmd_role_enable(wl, vif->addr,
 	ret = wl12xx_cmd_role_enable(wl, vif->addr,
@@ -5966,7 +5963,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
 {
 {
 	struct wl1271 *wl = context;
 	struct wl1271 *wl = context;
 	struct platform_device *pdev = wl->pdev;
 	struct platform_device *pdev = wl->pdev;
-	struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
+	struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data;
+	struct wl12xx_platform_data *pdata = pdev_data->pdata;
 	unsigned long irqflags;
 	unsigned long irqflags;
 	int ret;
 	int ret;
 
 
@@ -5995,8 +5993,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
 
 
 	wl->irq = platform_get_irq(pdev, 0);
 	wl->irq = platform_get_irq(pdev, 0);
 	wl->platform_quirks = pdata->platform_quirks;
 	wl->platform_quirks = pdata->platform_quirks;
-	wl->set_power = pdata->set_power;
-	wl->if_ops = pdata->ops;
+	wl->if_ops = pdev_data->if_ops;
 
 
 	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
 	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
 		irqflags = IRQF_TRIGGER_RISING;
 		irqflags = IRQF_TRIGGER_RISING;

+ 19 - 12
drivers/net/wireless/ti/wlcore/sdio.c

@@ -217,7 +217,7 @@ static struct wl1271_if_operations sdio_ops = {
 static int wl1271_probe(struct sdio_func *func,
 static int wl1271_probe(struct sdio_func *func,
 				  const struct sdio_device_id *id)
 				  const struct sdio_device_id *id)
 {
 {
-	struct wl12xx_platform_data *wlan_data;
+	struct wlcore_platdev_data *pdev_data;
 	struct wl12xx_sdio_glue *glue;
 	struct wl12xx_sdio_glue *glue;
 	struct resource res[1];
 	struct resource res[1];
 	mmc_pm_flag_t mmcflags;
 	mmc_pm_flag_t mmcflags;
@@ -228,10 +228,16 @@ static int wl1271_probe(struct sdio_func *func,
 	if (func->num != 0x02)
 	if (func->num != 0x02)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
+	if (!pdev_data)
+		goto out;
+
+	pdev_data->if_ops = &sdio_ops;
+
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
 	if (!glue) {
 		dev_err(&func->dev, "can't allocate glue\n");
 		dev_err(&func->dev, "can't allocate glue\n");
-		goto out;
+		goto out_free_pdev_data;
 	}
 	}
 
 
 	glue->dev = &func->dev;
 	glue->dev = &func->dev;
@@ -242,9 +248,9 @@ static int wl1271_probe(struct sdio_func *func,
 	/* Use block mode for transferring over one block size of data */
 	/* Use block mode for transferring over one block size of data */
 	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
 	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
 
 
-	wlan_data = wl12xx_get_platform_data();
-	if (IS_ERR(wlan_data)) {
-		ret = PTR_ERR(wlan_data);
+	pdev_data->pdata = wl12xx_get_platform_data();
+	if (IS_ERR(pdev_data->pdata)) {
+		ret = PTR_ERR(pdev_data->pdata);
 		dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
 		dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
 		goto out_free_glue;
 		goto out_free_glue;
 	}
 	}
@@ -254,9 +260,7 @@ static int wl1271_probe(struct sdio_func *func,
 	dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
 	dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
 
 
 	if (mmcflags & MMC_PM_KEEP_POWER)
 	if (mmcflags & MMC_PM_KEEP_POWER)
-		wlan_data->pwr_in_suspend = true;
-
-	wlan_data->ops = &sdio_ops;
+		pdev_data->pdata->pwr_in_suspend = true;
 
 
 	sdio_set_drvdata(func, glue);
 	sdio_set_drvdata(func, glue);
 
 
@@ -274,7 +278,7 @@ static int wl1271_probe(struct sdio_func *func,
 	else
 	else
 		chip_family = "wl12xx";
 		chip_family = "wl12xx";
 
 
-	glue->core = platform_device_alloc(chip_family, -1);
+	glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO);
 	if (!glue->core) {
 	if (!glue->core) {
 		dev_err(glue->dev, "can't allocate platform_device");
 		dev_err(glue->dev, "can't allocate platform_device");
 		ret = -ENOMEM;
 		ret = -ENOMEM;
@@ -285,7 +289,7 @@ static int wl1271_probe(struct sdio_func *func,
 
 
 	memset(res, 0x00, sizeof(res));
 	memset(res, 0x00, sizeof(res));
 
 
-	res[0].start = wlan_data->irq;
+	res[0].start = pdev_data->pdata->irq;
 	res[0].flags = IORESOURCE_IRQ;
 	res[0].flags = IORESOURCE_IRQ;
 	res[0].name = "irq";
 	res[0].name = "irq";
 
 
@@ -295,8 +299,8 @@ static int wl1271_probe(struct sdio_func *func,
 		goto out_dev_put;
 		goto out_dev_put;
 	}
 	}
 
 
-	ret = platform_device_add_data(glue->core, wlan_data,
-				       sizeof(*wlan_data));
+	ret = platform_device_add_data(glue->core, pdev_data,
+				       sizeof(*pdev_data));
 	if (ret) {
 	if (ret) {
 		dev_err(glue->dev, "can't add platform data\n");
 		dev_err(glue->dev, "can't add platform data\n");
 		goto out_dev_put;
 		goto out_dev_put;
@@ -315,6 +319,9 @@ out_dev_put:
 out_free_glue:
 out_free_glue:
 	kfree(glue);
 	kfree(glue);
 
 
+out_free_pdev_data:
+	kfree(pdev_data);
+
 out:
 out:
 	return ret;
 	return ret;
 }
 }

+ 18 - 8
drivers/net/wireless/ti/wlcore/spi.c

@@ -327,22 +327,27 @@ static struct wl1271_if_operations spi_ops = {
 static int wl1271_probe(struct spi_device *spi)
 static int wl1271_probe(struct spi_device *spi)
 {
 {
 	struct wl12xx_spi_glue *glue;
 	struct wl12xx_spi_glue *glue;
-	struct wl12xx_platform_data *pdata;
+	struct wlcore_platdev_data *pdev_data;
 	struct resource res[1];
 	struct resource res[1];
 	int ret = -ENOMEM;
 	int ret = -ENOMEM;
 
 
-	pdata = spi->dev.platform_data;
-	if (!pdata) {
+	pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
+	if (!pdev_data)
+		goto out;
+
+	pdev_data->pdata = spi->dev.platform_data;
+	if (!pdev_data->pdata) {
 		dev_err(&spi->dev, "no platform data\n");
 		dev_err(&spi->dev, "no platform data\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto out_free_pdev_data;
 	}
 	}
 
 
-	pdata->ops = &spi_ops;
+	pdev_data->if_ops = &spi_ops;
 
 
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
 	if (!glue) {
 		dev_err(&spi->dev, "can't allocate glue\n");
 		dev_err(&spi->dev, "can't allocate glue\n");
-		goto out;
+		goto out_free_pdev_data;
 	}
 	}
 
 
 	glue->dev = &spi->dev;
 	glue->dev = &spi->dev;
@@ -359,7 +364,7 @@ static int wl1271_probe(struct spi_device *spi)
 		goto out_free_glue;
 		goto out_free_glue;
 	}
 	}
 
 
-	glue->core = platform_device_alloc("wl12xx", -1);
+	glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
 	if (!glue->core) {
 	if (!glue->core) {
 		dev_err(glue->dev, "can't allocate platform_device\n");
 		dev_err(glue->dev, "can't allocate platform_device\n");
 		ret = -ENOMEM;
 		ret = -ENOMEM;
@@ -380,7 +385,8 @@ static int wl1271_probe(struct spi_device *spi)
 		goto out_dev_put;
 		goto out_dev_put;
 	}
 	}
 
 
-	ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata));
+	ret = platform_device_add_data(glue->core, pdev_data,
+				       sizeof(*pdev_data));
 	if (ret) {
 	if (ret) {
 		dev_err(glue->dev, "can't add platform data\n");
 		dev_err(glue->dev, "can't add platform data\n");
 		goto out_dev_put;
 		goto out_dev_put;
@@ -399,6 +405,10 @@ out_dev_put:
 
 
 out_free_glue:
 out_free_glue:
 	kfree(glue);
 	kfree(glue);
+
+out_free_pdev_data:
+	kfree(pdev_data);
+
 out:
 out:
 	return ret;
 	return ret;
 }
 }

+ 0 - 1
drivers/net/wireless/ti/wlcore/wlcore.h

@@ -183,7 +183,6 @@ struct wl1271 {
 
 
 	struct wl1271_if_operations *if_ops;
 	struct wl1271_if_operations *if_ops;
 
 
-	void (*set_power)(bool enable);
 	int irq;
 	int irq;
 
 
 	spinlock_t wl_lock;
 	spinlock_t wl_lock;

+ 5 - 0
drivers/net/wireless/ti/wlcore/wlcore_i.h

@@ -206,6 +206,11 @@ struct wl1271_if_operations {
 	void (*set_block_size) (struct device *child, unsigned int blksz);
 	void (*set_block_size) (struct device *child, unsigned int blksz);
 };
 };
 
 
+struct wlcore_platdev_data {
+	struct wl12xx_platform_data *pdata;
+	struct wl1271_if_operations *if_ops;
+};
+
 #define MAX_NUM_KEYS 14
 #define MAX_NUM_KEYS 14
 #define MAX_KEY_SIZE 32
 #define MAX_KEY_SIZE 32
 
 

+ 1 - 0
drivers/nfc/Kconfig

@@ -27,5 +27,6 @@ config NFC_WILINK
 	  into the kernel or say M to compile it as module.
 	  into the kernel or say M to compile it as module.
 
 
 source "drivers/nfc/pn544/Kconfig"
 source "drivers/nfc/pn544/Kconfig"
+source "drivers/nfc/microread/Kconfig"
 
 
 endmenu
 endmenu

+ 1 - 0
drivers/nfc/Makefile

@@ -3,6 +3,7 @@
 #
 #
 
 
 obj-$(CONFIG_NFC_PN544)		+= pn544/
 obj-$(CONFIG_NFC_PN544)		+= pn544/
+obj-$(CONFIG_NFC_MICROREAD)	+= microread/
 obj-$(CONFIG_NFC_PN533)		+= pn533.o
 obj-$(CONFIG_NFC_PN533)		+= pn533.o
 obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
 obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
 
 

+ 35 - 0
drivers/nfc/microread/Kconfig

@@ -0,0 +1,35 @@
+config NFC_MICROREAD
+	tristate "Inside Secure microread NFC driver"
+	depends on NFC_HCI
+	select CRC_CCITT
+	default n
+	---help---
+	  This module contains the main code for Inside Secure microread
+	  NFC chipsets. It implements the chipset HCI logic and hooks into
+	  the NFC kernel APIs. Physical layers will register against it.
+
+	  To compile this driver as a module, choose m here. The module will
+	  be called microread.
+	  Say N if unsure.
+
+config NFC_MICROREAD_I2C
+	tristate "NFC Microread i2c support"
+	depends on NFC_MICROREAD && I2C && NFC_SHDLC
+	---help---
+	  This module adds support for the i2c interface of adapters using
+	  Inside microread chipsets.  Select this if your platform is using
+	  the i2c bus.
+
+	  If you choose to build a module, it'll be called microread_i2c.
+	  Say N if unsure.
+
+config NFC_MICROREAD_MEI
+	tristate "NFC Microread MEI support"
+	depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC
+	---help---
+	  This module adds support for the mei interface of adapters using
+	  Inside microread chipsets.  Select this if your microread chipset
+	  is handled by Intel's Management Engine Interface on your platform.
+
+	  If you choose to build a module, it'll be called microread_mei.
+	  Say N if unsure.

+ 10 - 0
drivers/nfc/microread/Makefile

@@ -0,0 +1,10 @@
+#
+# Makefile for Microread HCI based NFC driver
+#
+
+microread_i2c-objs  = i2c.o
+microread_mei-objs  = mei.o
+
+obj-$(CONFIG_NFC_MICROREAD)     += microread.o
+obj-$(CONFIG_NFC_MICROREAD_I2C) += microread_i2c.o
+obj-$(CONFIG_NFC_MICROREAD_MEI) += microread_mei.o

+ 340 - 0
drivers/nfc/microread/i2c.c

@@ -0,0 +1,340 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip - i2c layer
+ *
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+#define MICROREAD_I2C_DRIVER_NAME "microread"
+
+#define MICROREAD_I2C_FRAME_HEADROOM 1
+#define MICROREAD_I2C_FRAME_TAILROOM 1
+
+/* framing in HCI mode */
+#define MICROREAD_I2C_LLC_LEN		1
+#define MICROREAD_I2C_LLC_CRC		1
+#define MICROREAD_I2C_LLC_LEN_CRC	(MICROREAD_I2C_LLC_LEN + \
+					MICROREAD_I2C_LLC_CRC)
+#define MICROREAD_I2C_LLC_MIN_SIZE	(1 + MICROREAD_I2C_LLC_LEN_CRC)
+#define MICROREAD_I2C_LLC_MAX_PAYLOAD	29
+#define MICROREAD_I2C_LLC_MAX_SIZE	(MICROREAD_I2C_LLC_LEN_CRC + 1 + \
+					MICROREAD_I2C_LLC_MAX_PAYLOAD)
+
+struct microread_i2c_phy {
+	struct i2c_client *i2c_dev;
+	struct nfc_hci_dev *hdev;
+
+	int irq;
+
+	int hard_fault;		/*
+				 * < 0 if hardware error occured (e.g. i2c err)
+				 * and prevents normal operation.
+				 */
+};
+
+#define I2C_DUMP_SKB(info, skb)					\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET,	\
+		       16, 1, (skb)->data, (skb)->len, 0);	\
+} while (0)
+
+static void microread_i2c_add_len_crc(struct sk_buff *skb)
+{
+	int i;
+	u8 crc = 0;
+	int len;
+
+	len = skb->len;
+	*skb_push(skb, 1) = len;
+
+	for (i = 0; i < skb->len; i++)
+		crc = crc ^ skb->data[i];
+
+	*skb_put(skb, 1) = crc;
+}
+
+static void microread_i2c_remove_len_crc(struct sk_buff *skb)
+{
+	skb_pull(skb, MICROREAD_I2C_FRAME_HEADROOM);
+	skb_trim(skb, MICROREAD_I2C_FRAME_TAILROOM);
+}
+
+static int check_crc(struct sk_buff *skb)
+{
+	int i;
+	u8 crc = 0;
+
+	for (i = 0; i < skb->len - 1; i++)
+		crc = crc ^ skb->data[i];
+
+	if (crc != skb->data[skb->len-1]) {
+		pr_err(MICROREAD_I2C_DRIVER_NAME
+		       ": CRC error 0x%x != 0x%x\n",
+		       crc, skb->data[skb->len-1]);
+
+		pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
+
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int microread_i2c_enable(void *phy_id)
+{
+	return 0;
+}
+
+static void microread_i2c_disable(void *phy_id)
+{
+	return;
+}
+
+static int microread_i2c_write(void *phy_id, struct sk_buff *skb)
+{
+	int r;
+	struct microread_i2c_phy *phy = phy_id;
+	struct i2c_client *client = phy->i2c_dev;
+
+	if (phy->hard_fault != 0)
+		return phy->hard_fault;
+
+	usleep_range(3000, 6000);
+
+	microread_i2c_add_len_crc(skb);
+
+	I2C_DUMP_SKB("i2c frame written", skb);
+
+	r = i2c_master_send(client, skb->data, skb->len);
+
+	if (r == -EREMOTEIO) {	/* Retry, chip was in standby */
+		usleep_range(6000, 10000);
+		r = i2c_master_send(client, skb->data, skb->len);
+	}
+
+	if (r >= 0) {
+		if (r != skb->len)
+			r = -EREMOTEIO;
+		else
+			r = 0;
+	}
+
+	microread_i2c_remove_len_crc(skb);
+
+	return r;
+}
+
+
+static int microread_i2c_read(struct microread_i2c_phy *phy,
+			      struct sk_buff **skb)
+{
+	int r;
+	u8 len;
+	u8 tmp[MICROREAD_I2C_LLC_MAX_SIZE - 1];
+	struct i2c_client *client = phy->i2c_dev;
+
+	pr_debug("%s\n", __func__);
+
+	r = i2c_master_recv(client, &len, 1);
+	if (r != 1) {
+		dev_err(&client->dev, "cannot read len byte\n");
+		return -EREMOTEIO;
+	}
+
+	if ((len < MICROREAD_I2C_LLC_MIN_SIZE) ||
+	    (len > MICROREAD_I2C_LLC_MAX_SIZE)) {
+		dev_err(&client->dev, "invalid len byte\n");
+		pr_err("invalid len byte\n");
+		r = -EBADMSG;
+		goto flush;
+	}
+
+	*skb = alloc_skb(1 + len, GFP_KERNEL);
+	if (*skb == NULL) {
+		r = -ENOMEM;
+		goto flush;
+	}
+
+	*skb_put(*skb, 1) = len;
+
+	r = i2c_master_recv(client, skb_put(*skb, len), len);
+	if (r != len) {
+		kfree_skb(*skb);
+		return -EREMOTEIO;
+	}
+
+	I2C_DUMP_SKB("cc frame read", *skb);
+
+	r = check_crc(*skb);
+	if (r != 0) {
+		kfree_skb(*skb);
+		r = -EBADMSG;
+		goto flush;
+	}
+
+	skb_pull(*skb, 1);
+	skb_trim(*skb, (*skb)->len - MICROREAD_I2C_FRAME_TAILROOM);
+
+	usleep_range(3000, 6000);
+
+	return 0;
+
+flush:
+	if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
+		r = -EREMOTEIO;
+
+	usleep_range(3000, 6000);
+
+	return r;
+}
+
+static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
+{
+	struct microread_i2c_phy *phy = phy_id;
+	struct i2c_client *client;
+	struct sk_buff *skb = NULL;
+	int r;
+
+	if (!phy || irq != phy->i2c_dev->irq) {
+		WARN_ON_ONCE(1);
+		return IRQ_NONE;
+	}
+
+	client = phy->i2c_dev;
+	dev_dbg(&client->dev, "IRQ\n");
+
+	if (phy->hard_fault != 0)
+		return IRQ_HANDLED;
+
+	r = microread_i2c_read(phy, &skb);
+	if (r == -EREMOTEIO) {
+		phy->hard_fault = r;
+
+		nfc_hci_recv_frame(phy->hdev, NULL);
+
+		return IRQ_HANDLED;
+	} else if ((r == -ENOMEM) || (r == -EBADMSG)) {
+		return IRQ_HANDLED;
+	}
+
+	nfc_hci_recv_frame(phy->hdev, skb);
+
+	return IRQ_HANDLED;
+}
+
+static struct nfc_phy_ops i2c_phy_ops = {
+	.write = microread_i2c_write,
+	.enable = microread_i2c_enable,
+	.disable = microread_i2c_disable,
+};
+
+static int microread_i2c_probe(struct i2c_client *client,
+			       const struct i2c_device_id *id)
+{
+	struct microread_i2c_phy *phy;
+	struct microread_nfc_platform_data *pdata =
+		dev_get_platdata(&client->dev);
+	int r;
+
+	dev_dbg(&client->dev, "client %p", client);
+
+	if (!pdata) {
+		dev_err(&client->dev, "client %p: missing platform data",
+			client);
+		return -EINVAL;
+	}
+
+	phy = devm_kzalloc(&client->dev, sizeof(struct microread_i2c_phy),
+			   GFP_KERNEL);
+	if (!phy) {
+		dev_err(&client->dev, "Can't allocate microread phy");
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, phy);
+	phy->i2c_dev = client;
+
+	r = request_threaded_irq(client->irq, NULL, microread_i2c_irq_thread_fn,
+				 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				 MICROREAD_I2C_DRIVER_NAME, phy);
+	if (r) {
+		dev_err(&client->dev, "Unable to register IRQ handler");
+		return r;
+	}
+
+	r = microread_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
+			    MICROREAD_I2C_FRAME_HEADROOM,
+			    MICROREAD_I2C_FRAME_TAILROOM,
+			    MICROREAD_I2C_LLC_MAX_PAYLOAD, &phy->hdev);
+	if (r < 0)
+		goto err_irq;
+
+	dev_info(&client->dev, "Probed");
+
+	return 0;
+
+err_irq:
+	free_irq(client->irq, phy);
+
+	return r;
+}
+
+static int microread_i2c_remove(struct i2c_client *client)
+{
+	struct microread_i2c_phy *phy = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __func__);
+
+	microread_remove(phy->hdev);
+
+	free_irq(client->irq, phy);
+
+	return 0;
+}
+
+static struct i2c_device_id microread_i2c_id[] = {
+	{ MICROREAD_I2C_DRIVER_NAME, 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, microread_i2c_id);
+
+static struct i2c_driver microread_i2c_driver = {
+	.driver = {
+		.name = MICROREAD_I2C_DRIVER_NAME,
+	},
+	.probe		= microread_i2c_probe,
+	.remove		= microread_i2c_remove,
+	.id_table	= microread_i2c_id,
+};
+
+module_i2c_driver(microread_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);

+ 246 - 0
drivers/nfc/microread/mei.c

@@ -0,0 +1,246 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip
+ *
+ * Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/mei_bus.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+#define MICROREAD_DRIVER_NAME "microread"
+
+#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
+			       0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
+
+struct mei_nfc_hdr {
+	u8 cmd;
+	u8 status;
+	u16 req_id;
+	u32 reserved;
+	u16 data_size;
+} __attribute__((packed));
+
+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
+
+struct microread_mei_phy {
+	struct mei_device *mei_device;
+	struct nfc_hci_dev *hdev;
+
+	int powered;
+
+	int hard_fault;		/*
+				 * < 0 if hardware error occured (e.g. i2c err)
+				 * and prevents normal operation.
+				 */
+};
+
+#define MEI_DUMP_SKB_IN(info, skb)					\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET,	\
+		       16, 1, (skb)->data, (skb)->len, 0);	\
+} while (0)
+
+#define MEI_DUMP_SKB_OUT(info, skb)					\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET,	\
+		       16, 1, (skb)->data, (skb)->len, 0);	\
+} while (0)
+
+static int microread_mei_enable(void *phy_id)
+{
+	struct microread_mei_phy *phy = phy_id;
+
+	pr_info(DRIVER_DESC ": %s\n", __func__);
+
+	phy->powered = 1;
+
+	return 0;
+}
+
+static void microread_mei_disable(void *phy_id)
+{
+	struct microread_mei_phy *phy = phy_id;
+
+	pr_info(DRIVER_DESC ": %s\n", __func__);
+
+	phy->powered = 0;
+}
+
+/*
+ * Writing a frame must not return the number of written bytes.
+ * It must return either zero for success, or <0 for error.
+ * In addition, it must not alter the skb
+ */
+static int microread_mei_write(void *phy_id, struct sk_buff *skb)
+{
+	struct microread_mei_phy *phy = phy_id;
+	int r;
+
+	MEI_DUMP_SKB_OUT("mei frame sent", skb);
+
+	r = mei_send(phy->device, skb->data, skb->len);
+	if (r > 0)
+		r = 0;
+
+	return r;
+}
+
+static void microread_event_cb(struct mei_device *device, u32 events,
+			       void *context)
+{
+	struct microread_mei_phy *phy = context;
+
+	if (phy->hard_fault != 0)
+		return;
+
+	if (events & BIT(MEI_EVENT_RX)) {
+		struct sk_buff *skb;
+		int reply_size;
+
+		skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
+		if (!skb)
+			return;
+
+		reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ);
+		if (reply_size < MEI_NFC_HEADER_SIZE) {
+			kfree(skb);
+			return;
+		}
+
+		skb_put(skb, reply_size);
+		skb_pull(skb, MEI_NFC_HEADER_SIZE);
+
+		MEI_DUMP_SKB_IN("mei frame read", skb);
+
+		nfc_hci_recv_frame(phy->hdev, skb);
+	}
+}
+
+static struct nfc_phy_ops mei_phy_ops = {
+	.write = microread_mei_write,
+	.enable = microread_mei_enable,
+	.disable = microread_mei_disable,
+};
+
+static int microread_mei_probe(struct mei_device *device,
+			       const struct mei_id *id)
+{
+	struct microread_mei_phy *phy;
+	int r;
+
+	pr_info("Probing NFC microread\n");
+
+	phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL);
+	if (!phy) {
+		pr_err("Cannot allocate memory for microread mei phy.\n");
+		return -ENOMEM;
+	}
+
+	phy->device = device;
+	mei_set_clientdata(device, phy);
+
+	r = mei_register_event_cb(device, microread_event_cb, phy);
+	if (r) {
+		pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
+		goto err_out;
+	}
+
+	r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
+			    MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
+			    &phy->hdev);
+	if (r < 0)
+		goto err_out;
+
+	return 0;
+
+err_out:
+	kfree(phy);
+
+	return r;
+}
+
+static int microread_mei_remove(struct mei_device *device)
+{
+	struct microread_mei_phy *phy = mei_get_clientdata(device);
+
+	pr_info("Removing microread\n");
+
+	microread_remove(phy->hdev);
+
+	if (phy->powered)
+		microread_mei_disable(phy);
+
+	kfree(phy);
+
+	return 0;
+}
+
+static struct mei_id microread_mei_tbl[] = {
+	{ MICROREAD_DRIVER_NAME, MICROREAD_UUID },
+
+	/* required last entry */
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mei, microread_mei_tbl);
+
+static struct mei_driver microread_driver = {
+	.id_table = microread_mei_tbl,
+	.name = MICROREAD_DRIVER_NAME,
+
+	.probe = microread_mei_probe,
+	.remove = microread_mei_remove,
+};
+
+static int microread_mei_init(void)
+{
+	int r;
+
+	pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+	r = mei_driver_register(&microread_driver);
+	if (r) {
+		pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n");
+		return r;
+	}
+
+	return 0;
+}
+
+static void microread_mei_exit(void)
+{
+	mei_driver_unregister(&microread_driver);
+}
+
+module_init(microread_mei_init);
+module_exit(microread_mei_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);

+ 728 - 0
drivers/nfc/microread/microread.c

@@ -0,0 +1,728 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip
+ *
+ * Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/crc-ccitt.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+/* Proprietary gates, events, commands and registers */
+/* Admin */
+#define MICROREAD_GATE_ID_ADM NFC_HCI_ADMIN_GATE
+#define MICROREAD_GATE_ID_MGT 0x01
+#define MICROREAD_GATE_ID_OS 0x02
+#define MICROREAD_GATE_ID_TESTRF 0x03
+#define MICROREAD_GATE_ID_LOOPBACK NFC_HCI_LOOPBACK_GATE
+#define MICROREAD_GATE_ID_IDT NFC_HCI_ID_MGMT_GATE
+#define MICROREAD_GATE_ID_LMS NFC_HCI_LINK_MGMT_GATE
+
+/* Reader */
+#define MICROREAD_GATE_ID_MREAD_GEN 0x10
+#define MICROREAD_GATE_ID_MREAD_ISO_B NFC_HCI_RF_READER_B_GATE
+#define MICROREAD_GATE_ID_MREAD_NFC_T1 0x12
+#define MICROREAD_GATE_ID_MREAD_ISO_A NFC_HCI_RF_READER_A_GATE
+#define MICROREAD_GATE_ID_MREAD_NFC_T3 0x14
+#define MICROREAD_GATE_ID_MREAD_ISO_15_3 0x15
+#define MICROREAD_GATE_ID_MREAD_ISO_15_2 0x16
+#define MICROREAD_GATE_ID_MREAD_ISO_B_3 0x17
+#define MICROREAD_GATE_ID_MREAD_BPRIME 0x18
+#define MICROREAD_GATE_ID_MREAD_ISO_A_3 0x19
+
+/* Card */
+#define MICROREAD_GATE_ID_MCARD_GEN 0x20
+#define MICROREAD_GATE_ID_MCARD_ISO_B 0x21
+#define MICROREAD_GATE_ID_MCARD_BPRIME 0x22
+#define MICROREAD_GATE_ID_MCARD_ISO_A 0x23
+#define MICROREAD_GATE_ID_MCARD_NFC_T3 0x24
+#define MICROREAD_GATE_ID_MCARD_ISO_15_3 0x25
+#define MICROREAD_GATE_ID_MCARD_ISO_15_2 0x26
+#define MICROREAD_GATE_ID_MCARD_ISO_B_2 0x27
+#define MICROREAD_GATE_ID_MCARD_ISO_CUSTOM 0x28
+#define MICROREAD_GATE_ID_SECURE_ELEMENT 0x2F
+
+/* P2P */
+#define MICROREAD_GATE_ID_P2P_GEN 0x30
+#define MICROREAD_GATE_ID_P2P_TARGET 0x31
+#define MICROREAD_PAR_P2P_TARGET_MODE 0x01
+#define MICROREAD_PAR_P2P_TARGET_GT 0x04
+#define MICROREAD_GATE_ID_P2P_INITIATOR 0x32
+#define MICROREAD_PAR_P2P_INITIATOR_GI 0x01
+#define MICROREAD_PAR_P2P_INITIATOR_GT 0x03
+
+/* Those pipes are created/opened by default in the chip */
+#define MICROREAD_PIPE_ID_LMS 0x00
+#define MICROREAD_PIPE_ID_ADMIN 0x01
+#define MICROREAD_PIPE_ID_MGT 0x02
+#define MICROREAD_PIPE_ID_OS 0x03
+#define MICROREAD_PIPE_ID_HDS_LOOPBACK 0x04
+#define MICROREAD_PIPE_ID_HDS_IDT 0x05
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B 0x08
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_BPRIME 0x09
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_A 0x0A
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_3 0x0B
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_2 0x0C
+#define MICROREAD_PIPE_ID_HDS_MCARD_NFC_T3 0x0D
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B_2 0x0E
+#define MICROREAD_PIPE_ID_HDS_MCARD_CUSTOM 0x0F
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B 0x10
+#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1 0x11
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A 0x12
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_3 0x13
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_2 0x14
+#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3 0x15
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B_3 0x16
+#define MICROREAD_PIPE_ID_HDS_MREAD_BPRIME 0x17
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3 0x18
+#define MICROREAD_PIPE_ID_HDS_MREAD_GEN 0x1B
+#define MICROREAD_PIPE_ID_HDS_STACKED_ELEMENT 0x1C
+#define MICROREAD_PIPE_ID_HDS_INSTANCES 0x1D
+#define MICROREAD_PIPE_ID_HDS_TESTRF 0x1E
+#define MICROREAD_PIPE_ID_HDS_P2P_TARGET 0x1F
+#define MICROREAD_PIPE_ID_HDS_P2P_INITIATOR 0x20
+
+/* Events */
+#define MICROREAD_EVT_MREAD_DISCOVERY_OCCURED NFC_HCI_EVT_TARGET_DISCOVERED
+#define MICROREAD_EVT_MREAD_CARD_FOUND 0x3D
+#define MICROREAD_EMCF_A_ATQA 0
+#define MICROREAD_EMCF_A_SAK 2
+#define MICROREAD_EMCF_A_LEN 3
+#define MICROREAD_EMCF_A_UID 4
+#define MICROREAD_EMCF_A3_ATQA 0
+#define MICROREAD_EMCF_A3_SAK 2
+#define MICROREAD_EMCF_A3_LEN 3
+#define MICROREAD_EMCF_A3_UID 4
+#define MICROREAD_EMCF_B_UID 0
+#define MICROREAD_EMCF_T1_ATQA 0
+#define MICROREAD_EMCF_T1_UID 4
+#define MICROREAD_EMCF_T3_UID 0
+#define MICROREAD_EVT_MREAD_DISCOVERY_START NFC_HCI_EVT_READER_REQUESTED
+#define MICROREAD_EVT_MREAD_DISCOVERY_START_SOME 0x3E
+#define MICROREAD_EVT_MREAD_DISCOVERY_STOP NFC_HCI_EVT_END_OPERATION
+#define MICROREAD_EVT_MREAD_SIM_REQUESTS 0x3F
+#define MICROREAD_EVT_MCARD_EXCHANGE NFC_HCI_EVT_TARGET_DISCOVERED
+#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF 0x20
+#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF 0x21
+#define MICROREAD_EVT_MCARD_FIELD_ON 0x11
+#define MICROREAD_EVT_P2P_TARGET_ACTIVATED 0x13
+#define MICROREAD_EVT_P2P_TARGET_DEACTIVATED 0x12
+#define MICROREAD_EVT_MCARD_FIELD_OFF 0x14
+
+/* Commands */
+#define MICROREAD_CMD_MREAD_EXCHANGE 0x10
+#define MICROREAD_CMD_MREAD_SUBSCRIBE 0x3F
+
+/* Hosts IDs */
+#define MICROREAD_ELT_ID_HDS NFC_HCI_TERMINAL_HOST_ID
+#define MICROREAD_ELT_ID_SIM NFC_HCI_UICC_HOST_ID
+#define MICROREAD_ELT_ID_SE1 0x03
+#define MICROREAD_ELT_ID_SE2 0x04
+#define MICROREAD_ELT_ID_SE3 0x05
+
+static struct nfc_hci_gate microread_gates[] = {
+	{MICROREAD_GATE_ID_ADM, MICROREAD_PIPE_ID_ADMIN},
+	{MICROREAD_GATE_ID_LOOPBACK, MICROREAD_PIPE_ID_HDS_LOOPBACK},
+	{MICROREAD_GATE_ID_IDT, MICROREAD_PIPE_ID_HDS_IDT},
+	{MICROREAD_GATE_ID_LMS, MICROREAD_PIPE_ID_LMS},
+	{MICROREAD_GATE_ID_MREAD_ISO_B, MICROREAD_PIPE_ID_HDS_MREAD_ISO_B},
+	{MICROREAD_GATE_ID_MREAD_ISO_A, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A},
+	{MICROREAD_GATE_ID_MREAD_ISO_A_3, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3},
+	{MICROREAD_GATE_ID_MGT, MICROREAD_PIPE_ID_MGT},
+	{MICROREAD_GATE_ID_OS, MICROREAD_PIPE_ID_OS},
+	{MICROREAD_GATE_ID_MREAD_NFC_T1, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1},
+	{MICROREAD_GATE_ID_MREAD_NFC_T3, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3},
+	{MICROREAD_GATE_ID_P2P_TARGET, MICROREAD_PIPE_ID_HDS_P2P_TARGET},
+	{MICROREAD_GATE_ID_P2P_INITIATOR, MICROREAD_PIPE_ID_HDS_P2P_INITIATOR}
+};
+
+/* Largest headroom needed for outgoing custom commands */
+#define MICROREAD_CMDS_HEADROOM	2
+#define MICROREAD_CMD_TAILROOM	2
+
+struct microread_info {
+	struct nfc_phy_ops *phy_ops;
+	void *phy_id;
+
+	struct nfc_hci_dev *hdev;
+
+	int async_cb_type;
+	data_exchange_cb_t async_cb;
+	void *async_cb_context;
+};
+
+static int microread_open(struct nfc_hci_dev *hdev)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	return info->phy_ops->enable(info->phy_id);
+}
+
+static void microread_close(struct nfc_hci_dev *hdev)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	info->phy_ops->disable(info->phy_id);
+}
+
+static int microread_hci_ready(struct nfc_hci_dev *hdev)
+{
+	int r;
+	u8 param[4];
+
+	param[0] = 0x03;
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 1, NULL);
+	if (r)
+		return r;
+
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A_3,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
+	if (r)
+		return r;
+
+	param[0] = 0x00;
+	param[1] = 0x03;
+	param[2] = 0x00;
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_B,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 3, NULL);
+	if (r)
+		return r;
+
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T1,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
+	if (r)
+		return r;
+
+	param[0] = 0xFF;
+	param[1] = 0xFF;
+	param[2] = 0x00;
+	param[3] = 0x00;
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T3,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 4, NULL);
+
+	return r;
+}
+
+static int microread_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	return info->phy_ops->write(info->phy_id, skb);
+}
+
+static int microread_start_poll(struct nfc_hci_dev *hdev,
+				u32 im_protocols, u32 tm_protocols)
+{
+	int r;
+
+	u8 param[2];
+	u8 mode;
+
+	param[0] = 0x00;
+	param[1] = 0x00;
+
+	if (im_protocols & NFC_PROTO_ISO14443_MASK)
+		param[0] |= (1 << 2);
+
+	if (im_protocols & NFC_PROTO_ISO14443_B_MASK)
+		param[0] |= 1;
+
+	if (im_protocols & NFC_PROTO_MIFARE_MASK)
+		param[1] |= 1;
+
+	if (im_protocols & NFC_PROTO_JEWEL_MASK)
+		param[0] |= (1 << 1);
+
+	if (im_protocols & NFC_PROTO_FELICA_MASK)
+		param[0] |= (1 << 5);
+
+	if (im_protocols & NFC_PROTO_NFC_DEP_MASK)
+		param[1] |= (1 << 1);
+
+	if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
+		hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
+						       &hdev->gb_len);
+		if (hdev->gb == NULL || hdev->gb_len == 0) {
+			im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+			tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+		}
+	}
+
+	r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+			       MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
+	if (r)
+		return r;
+
+	mode = 0xff;
+	r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+			      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+	if (r)
+		return r;
+
+	if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
+				      MICROREAD_PAR_P2P_INITIATOR_GI,
+				      hdev->gb, hdev->gb_len);
+		if (r)
+			return r;
+	}
+
+	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+				      MICROREAD_PAR_P2P_TARGET_GT,
+				      hdev->gb, hdev->gb_len);
+		if (r)
+			return r;
+
+		mode = 0x02;
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+				      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+		if (r)
+			return r;
+	}
+
+	return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+				  MICROREAD_EVT_MREAD_DISCOVERY_START_SOME,
+				  param, 2);
+}
+
+static int microread_dep_link_up(struct nfc_hci_dev *hdev,
+				struct nfc_target *target, u8 comm_mode,
+				u8 *gb, size_t gb_len)
+{
+	struct sk_buff *rgb_skb = NULL;
+	int r;
+
+	r = nfc_hci_get_param(hdev, target->hci_reader_gate,
+			      MICROREAD_PAR_P2P_INITIATOR_GT, &rgb_skb);
+	if (r < 0)
+		return r;
+
+	if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
+		r = -EPROTO;
+		goto exit;
+	}
+
+	r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
+					 rgb_skb->len);
+	if (r == 0)
+		r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
+				       NFC_RF_INITIATOR);
+exit:
+	kfree_skb(rgb_skb);
+
+	return r;
+}
+
+static int microread_dep_link_down(struct nfc_hci_dev *hdev)
+{
+	return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
+				  MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
+}
+
+static int microread_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
+				      struct nfc_target *target)
+{
+	switch (gate) {
+	case MICROREAD_GATE_ID_P2P_INITIATOR:
+		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+		break;
+	default:
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int microread_complete_target_discovered(struct nfc_hci_dev *hdev,
+						u8 gate,
+						struct nfc_target *target)
+{
+	return 0;
+}
+
+#define MICROREAD_CB_TYPE_READER_ALL 1
+
+static void microread_im_transceive_cb(void *context, struct sk_buff *skb,
+				       int err)
+{
+	struct microread_info *info = context;
+
+	switch (info->async_cb_type) {
+	case MICROREAD_CB_TYPE_READER_ALL:
+		if (err == 0) {
+			if (skb->len == 0) {
+				err = -EPROTO;
+				kfree_skb(skb);
+				info->async_cb(info->async_cb_context, NULL,
+					       -EPROTO);
+				return;
+			}
+
+			if (skb->data[skb->len - 1] != 0) {
+				err = nfc_hci_result_to_errno(
+						       skb->data[skb->len - 1]);
+				kfree_skb(skb);
+				info->async_cb(info->async_cb_context, NULL,
+					       err);
+				return;
+			}
+
+			skb_trim(skb, skb->len - 1);	/* RF Error ind. */
+		}
+		info->async_cb(info->async_cb_context, skb, err);
+		break;
+	default:
+		if (err == 0)
+			kfree_skb(skb);
+		break;
+	}
+}
+
+/*
+ * Returns:
+ * <= 0: driver handled the data exchange
+ *    1: driver doesn't especially handle, please do standard processing
+ */
+static int microread_im_transceive(struct nfc_hci_dev *hdev,
+				   struct nfc_target *target,
+				   struct sk_buff *skb, data_exchange_cb_t cb,
+				   void *cb_context)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+	u8 control_bits;
+	u16 crc;
+
+	pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate);
+
+	if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) {
+		*skb_push(skb, 1) = 0;
+
+		return nfc_hci_send_event(hdev, target->hci_reader_gate,
+				     MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF,
+				     skb->data, skb->len);
+	}
+
+	switch (target->hci_reader_gate) {
+	case MICROREAD_GATE_ID_MREAD_ISO_A:
+		control_bits = 0xCB;
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_A_3:
+		control_bits = 0xCB;
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_B:
+		control_bits = 0xCB;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T1:
+		control_bits = 0x1B;
+
+		crc = crc_ccitt(0xffff, skb->data, skb->len);
+		crc = ~crc;
+		*skb_put(skb, 1) = crc & 0xff;
+		*skb_put(skb, 1) = crc >> 8;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T3:
+		control_bits = 0xDB;
+		break;
+	default:
+		pr_info("Abort im_transceive to invalid gate 0x%x\n",
+			target->hci_reader_gate);
+		return 1;
+	}
+
+	*skb_push(skb, 1) = control_bits;
+
+	info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL;
+	info->async_cb = cb;
+	info->async_cb_context = cb_context;
+
+	return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
+				      MICROREAD_CMD_MREAD_EXCHANGE,
+				      skb->data, skb->len,
+				      microread_im_transceive_cb, info);
+}
+
+static int microread_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+	int r;
+
+	r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+			       MICROREAD_EVT_MCARD_EXCHANGE,
+			       skb->data, skb->len);
+
+	kfree_skb(skb);
+
+	return r;
+}
+
+static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
+					struct sk_buff *skb)
+{
+	struct nfc_target *targets;
+	int r = 0;
+
+	pr_info("target discovered to gate 0x%x\n", gate);
+
+	targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
+	if (targets == NULL) {
+		r = -ENOMEM;
+		goto exit;
+	}
+
+	targets->hci_reader_gate = gate;
+
+	switch (gate) {
+	case MICROREAD_GATE_ID_MREAD_ISO_A:
+		targets->supported_protocols =
+		      nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]);
+		targets->sens_res =
+			 be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]);
+		targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK];
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID],
+		       skb->data[MICROREAD_EMCF_A_LEN]);
+		targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN];
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_A_3:
+		targets->supported_protocols =
+		      nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]);
+		targets->sens_res =
+			 be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]);
+		targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK];
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID],
+		       skb->data[MICROREAD_EMCF_A3_LEN]);
+		targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN];
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_B:
+		targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK;
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4);
+		targets->nfcid1_len = 4;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T1:
+		targets->supported_protocols = NFC_PROTO_JEWEL_MASK;
+		targets->sens_res =
+			le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]);
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T1_UID], 4);
+		targets->nfcid1_len = 4;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T3:
+		targets->supported_protocols = NFC_PROTO_FELICA_MASK;
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8);
+		targets->nfcid1_len = 8;
+		break;
+	default:
+		pr_info("discard target discovered to gate 0x%x\n", gate);
+		goto exit_free;
+	}
+
+	r = nfc_targets_found(hdev->ndev, targets, 1);
+
+exit_free:
+	kfree(targets);
+
+exit:
+	kfree_skb(skb);
+
+	if (r)
+		pr_err("Failed to handle discovered target err=%d", r);
+}
+
+static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate,
+				     u8 event, struct sk_buff *skb)
+{
+	int r;
+	u8 mode;
+
+	pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate);
+
+	switch (event) {
+	case MICROREAD_EVT_MREAD_CARD_FOUND:
+		microread_target_discovered(hdev, gate, skb);
+		return 0;
+
+	case MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF:
+		if (skb->len < 1) {
+			kfree_skb(skb);
+			return -EPROTO;
+		}
+
+		if (skb->data[skb->len - 1]) {
+			kfree_skb(skb);
+			return -EIO;
+		}
+
+		skb_trim(skb, skb->len - 1);
+
+		r = nfc_tm_data_received(hdev->ndev, skb);
+		break;
+
+	case MICROREAD_EVT_MCARD_FIELD_ON:
+	case MICROREAD_EVT_MCARD_FIELD_OFF:
+		kfree_skb(skb);
+		return 0;
+
+	case MICROREAD_EVT_P2P_TARGET_ACTIVATED:
+		r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+				     NFC_COMM_PASSIVE, skb->data,
+				     skb->len);
+
+		kfree_skb(skb);
+		break;
+
+	case MICROREAD_EVT_MCARD_EXCHANGE:
+		if (skb->len < 1) {
+			kfree_skb(skb);
+			return -EPROTO;
+		}
+
+		if (skb->data[skb->len-1]) {
+			kfree_skb(skb);
+			return -EIO;
+		}
+
+		skb_trim(skb, skb->len - 1);
+
+		r = nfc_tm_data_received(hdev->ndev, skb);
+		break;
+
+	case MICROREAD_EVT_P2P_TARGET_DEACTIVATED:
+		kfree_skb(skb);
+
+		mode = 0xff;
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+				      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+		if (r)
+			break;
+
+		r = nfc_hci_send_event(hdev, gate,
+				       MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL,
+				       0);
+		break;
+
+	default:
+		return 1;
+	}
+
+	return r;
+}
+
+static struct nfc_hci_ops microread_hci_ops = {
+	.open = microread_open,
+	.close = microread_close,
+	.hci_ready = microread_hci_ready,
+	.xmit = microread_xmit,
+	.start_poll = microread_start_poll,
+	.dep_link_up = microread_dep_link_up,
+	.dep_link_down = microread_dep_link_down,
+	.target_from_gate = microread_target_from_gate,
+	.complete_target_discovered = microread_complete_target_discovered,
+	.im_transceive = microread_im_transceive,
+	.tm_send = microread_tm_send,
+	.check_presence = NULL,
+	.event_received = microread_event_received,
+};
+
+int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
+		    int phy_headroom, int phy_tailroom, int phy_payload,
+		    struct nfc_hci_dev **hdev)
+{
+	struct microread_info *info;
+	unsigned long quirks = 0;
+	u32 protocols, se;
+	struct nfc_hci_init_data init_data;
+	int r;
+
+	info = kzalloc(sizeof(struct microread_info), GFP_KERNEL);
+	if (!info) {
+		pr_err("Cannot allocate memory for microread_info.\n");
+		r = -ENOMEM;
+		goto err_info_alloc;
+	}
+
+	info->phy_ops = phy_ops;
+	info->phy_id = phy_id;
+
+	init_data.gate_count = ARRAY_SIZE(microread_gates);
+	memcpy(init_data.gates, microread_gates, sizeof(microread_gates));
+
+	strcpy(init_data.session_id, "MICROREA");
+
+	set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks);
+
+	protocols = NFC_PROTO_JEWEL_MASK |
+		    NFC_PROTO_MIFARE_MASK |
+		    NFC_PROTO_FELICA_MASK |
+		    NFC_PROTO_ISO14443_MASK |
+		    NFC_PROTO_ISO14443_B_MASK |
+		    NFC_PROTO_NFC_DEP_MASK;
+
+	se = NFC_SE_UICC | NFC_SE_EMBEDDED;
+
+	info->hdev = nfc_hci_allocate_device(&microread_hci_ops, &init_data,
+					     quirks, protocols, se, llc_name,
+					     phy_headroom +
+					     MICROREAD_CMDS_HEADROOM,
+					     phy_tailroom +
+					     MICROREAD_CMD_TAILROOM,
+					     phy_payload);
+	if (!info->hdev) {
+		pr_err("Cannot allocate nfc hdev.\n");
+		r = -ENOMEM;
+		goto err_alloc_hdev;
+	}
+
+	nfc_hci_set_clientdata(info->hdev, info);
+
+	r = nfc_hci_register_device(info->hdev);
+	if (r)
+		goto err_regdev;
+
+	*hdev = info->hdev;
+
+	return 0;
+
+err_regdev:
+	nfc_hci_free_device(info->hdev);
+
+err_alloc_hdev:
+	kfree(info);
+
+err_info_alloc:
+	return r;
+}
+EXPORT_SYMBOL(microread_probe);
+
+void microread_remove(struct nfc_hci_dev *hdev)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	nfc_hci_unregister_device(hdev);
+	nfc_hci_free_device(hdev);
+	kfree(info);
+}
+EXPORT_SYMBOL(microread_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);

+ 33 - 0
drivers/nfc/microread/microread.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 - 2012  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LOCAL_MICROREAD_H_
+#define __LOCAL_MICROREAD_H_
+
+#include <net/nfc/hci.h>
+
+#define DRIVER_DESC "NFC driver for microread"
+
+int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
+		    int phy_headroom, int phy_tailroom, int phy_payload,
+		    struct nfc_hci_dev **hdev);
+
+void microread_remove(struct nfc_hci_dev *hdev);
+
+#endif /* __LOCAL_MICROREAD_H_ */

+ 3 - 5
drivers/nfc/pn533.c

@@ -219,7 +219,7 @@ struct pn533_poll_modulations {
 	u8 len;
 	u8 len;
 };
 };
 
 
-const struct pn533_poll_modulations poll_mod[] = {
+static const struct pn533_poll_modulations poll_mod[] = {
 	[PN533_POLL_MOD_106KBPS_A] = {
 	[PN533_POLL_MOD_106KBPS_A] = {
 		.data = {
 		.data = {
 			.maxtg = 1,
 			.maxtg = 1,
@@ -485,7 +485,7 @@ static u8 pn533_get_cmd_code(void *frame)
 	return PN533_FRAME_CMD(f);
 	return PN533_FRAME_CMD(f);
 }
 }
 
 
-struct pn533_frame_ops pn533_std_frame_ops = {
+static struct pn533_frame_ops pn533_std_frame_ops = {
 	.tx_frame_init = pn533_tx_frame_init,
 	.tx_frame_init = pn533_tx_frame_init,
 	.tx_frame_finish = pn533_tx_frame_finish,
 	.tx_frame_finish = pn533_tx_frame_finish,
 	.tx_update_payload_len = pn533_tx_update_payload_len,
 	.tx_update_payload_len = pn533_tx_update_payload_len,
@@ -532,7 +532,6 @@ static void pn533_recv_response(struct urb *urb)
 			    urb->status);
 			    urb->status);
 		dev->wq_in_error = urb->status;
 		dev->wq_in_error = urb->status;
 		goto sched_wq;
 		goto sched_wq;
-		break;
 	case -ESHUTDOWN:
 	case -ESHUTDOWN:
 	default:
 	default:
 		nfc_dev_err(&dev->interface->dev,
 		nfc_dev_err(&dev->interface->dev,
@@ -589,7 +588,6 @@ static void pn533_recv_ack(struct urb *urb)
 			    urb->status);
 			    urb->status);
 		dev->wq_in_error = urb->status;
 		dev->wq_in_error = urb->status;
 		goto sched_wq;
 		goto sched_wq;
-		break;
 	case -ESHUTDOWN:
 	case -ESHUTDOWN:
 	default:
 	default:
 		nfc_dev_err(&dev->interface->dev,
 		nfc_dev_err(&dev->interface->dev,
@@ -1380,7 +1378,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev)
 		return NULL;
 		return NULL;
 
 
 	/* DEP support only */
 	/* DEP support only */
-	*skb_put(skb, 1) |= PN533_INIT_TARGET_DEP;
+	*skb_put(skb, 1) = PN533_INIT_TARGET_DEP;
 
 
 	/* MIFARE params */
 	/* MIFARE params */
 	memcpy(skb_put(skb, 6), mifare_params, 6);
 	memcpy(skb_put(skb, 6), mifare_params, 6);

+ 1 - 1
include/linux/bcma/bcma_driver_chipcommon.h

@@ -27,7 +27,7 @@
 #define   BCMA_CC_FLASHT_NONE		0x00000000	/* No flash */
 #define   BCMA_CC_FLASHT_NONE		0x00000000	/* No flash */
 #define   BCMA_CC_FLASHT_STSER		0x00000100	/* ST serial flash */
 #define   BCMA_CC_FLASHT_STSER		0x00000100	/* ST serial flash */
 #define   BCMA_CC_FLASHT_ATSER		0x00000200	/* Atmel serial flash */
 #define   BCMA_CC_FLASHT_ATSER		0x00000200	/* Atmel serial flash */
-#define   BCMA_CC_FLASHT_NFLASH		0x00000200	/* NAND flash */
+#define   BCMA_CC_FLASHT_NAND		0x00000300	/* NAND flash */
 #define	  BCMA_CC_FLASHT_PARA		0x00000700	/* Parallel flash */
 #define	  BCMA_CC_FLASHT_PARA		0x00000700	/* Parallel flash */
 #define  BCMA_CC_CAP_PLLT		0x00038000	/* PLL Type */
 #define  BCMA_CC_CAP_PLLT		0x00038000	/* PLL Type */
 #define   BCMA_PLLTYPE_NONE		0x00000000
 #define   BCMA_PLLTYPE_NONE		0x00000000

+ 8 - 0
include/linux/ieee80211.h

@@ -151,6 +151,11 @@
 /* Mesh Control 802.11s */
 /* Mesh Control 802.11s */
 #define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT  0x0100
 #define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT  0x0100
 
 
+/* Mesh Power Save Level */
+#define IEEE80211_QOS_CTL_MESH_PS_LEVEL		0x0200
+/* Mesh Receiver Service Period Initiated */
+#define IEEE80211_QOS_CTL_RSPI			0x0400
+
 /* U-APSD queue for WMM IEs sent by AP */
 /* U-APSD queue for WMM IEs sent by AP */
 #define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD	(1<<7)
 #define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD	(1<<7)
 #define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK	0x0f
 #define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK	0x0f
@@ -675,11 +680,14 @@ struct ieee80211_meshconf_ie {
  * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs
  * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs
  * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure
  * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure
  *	is ongoing
  *	is ongoing
+ * @IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL: STA is in deep sleep mode or has
+ *	neighbors in deep sleep mode
  */
  */
 enum mesh_config_capab_flags {
 enum mesh_config_capab_flags {
 	IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS		= 0x01,
 	IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS		= 0x01,
 	IEEE80211_MESHCONF_CAPAB_FORWARDING		= 0x08,
 	IEEE80211_MESHCONF_CAPAB_FORWARDING		= 0x08,
 	IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING		= 0x20,
 	IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING		= 0x20,
+	IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL	= 0x40,
 };
 };
 
 
 /**
 /**

+ 35 - 0
include/linux/platform_data/microread.h

@@ -0,0 +1,35 @@
+/*
+ * Driver include for the PN544 NFC chip.
+ *
+ * Copyright (C) 2011 Tieto Poland
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MICROREAD_H
+#define _MICROREAD_H
+
+#include <linux/i2c.h>
+
+#define MICROREAD_DRIVER_NAME	"microread"
+
+/* board config platform data for microread */
+struct microread_nfc_platform_data {
+	unsigned int rst_gpio;
+	unsigned int irq_gpio;
+	unsigned int ioh_gpio;
+};
+
+#endif /* _MICROREAD_H */

+ 11 - 5
include/linux/wl12xx.h

@@ -24,6 +24,8 @@
 #ifndef _LINUX_WL12XX_H
 #ifndef _LINUX_WL12XX_H
 #define _LINUX_WL12XX_H
 #define _LINUX_WL12XX_H
 
 
+#include <linux/err.h>
+
 /* Reference clock values */
 /* Reference clock values */
 enum {
 enum {
 	WL12XX_REFCLOCK_19	= 0, /* 19.2 MHz */
 	WL12XX_REFCLOCK_19	= 0, /* 19.2 MHz */
@@ -55,17 +57,17 @@ struct wl12xx_platform_data {
 	int board_tcxo_clock;
 	int board_tcxo_clock;
 	unsigned long platform_quirks;
 	unsigned long platform_quirks;
 	bool pwr_in_suspend;
 	bool pwr_in_suspend;
-
-	struct wl1271_if_operations *ops;
 };
 };
 
 
 /* Platform does not support level trigger interrupts */
 /* Platform does not support level trigger interrupts */
 #define WL12XX_PLATFORM_QUIRK_EDGE_IRQ	BIT(0)
 #define WL12XX_PLATFORM_QUIRK_EDGE_IRQ	BIT(0)
 
 
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
 
 
 int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
 int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
 
 
+struct wl12xx_platform_data *wl12xx_get_platform_data(void);
+
 #else
 #else
 
 
 static inline
 static inline
@@ -74,8 +76,12 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
 	return -ENOSYS;
 	return -ENOSYS;
 }
 }
 
 
-#endif
+static inline
+struct wl12xx_platform_data *wl12xx_get_platform_data(void)
+{
+	return ERR_PTR(-ENODATA);
+}
 
 
-struct wl12xx_platform_data *wl12xx_get_platform_data(void);
+#endif
 
 
 #endif
 #endif

+ 1 - 0
include/net/bluetooth/hci_core.h

@@ -86,6 +86,7 @@ struct bdaddr_list {
 struct bt_uuid {
 struct bt_uuid {
 	struct list_head list;
 	struct list_head list;
 	u8 uuid[16];
 	u8 uuid[16];
+	u8 size;
 	u8 svc_hint;
 	u8 svc_hint;
 };
 };
 
 

+ 49 - 11
include/net/cfg80211.h

@@ -672,8 +672,10 @@ struct station_parameters {
  * @STATION_INFO_SIGNAL: @signal filled
  * @STATION_INFO_SIGNAL: @signal filled
  * @STATION_INFO_TX_BITRATE: @txrate fields are filled
  * @STATION_INFO_TX_BITRATE: @txrate fields are filled
  *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
  *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
- * @STATION_INFO_RX_PACKETS: @rx_packets filled
- * @STATION_INFO_TX_PACKETS: @tx_packets filled
+ * @STATION_INFO_RX_PACKETS: @rx_packets filled with 32-bit value
+ * @STATION_INFO_TX_PACKETS: @tx_packets filled with 32-bit value
+ * @STATION_INFO_RX_PACKETS64: @rx_packets filled with 64-bit value
+ * @STATION_INFO_TX_PACKETS64: @tx_packets filled with 64-bit value
  * @STATION_INFO_TX_RETRIES: @tx_retries filled
  * @STATION_INFO_TX_RETRIES: @tx_retries filled
  * @STATION_INFO_TX_FAILED: @tx_failed filled
  * @STATION_INFO_TX_FAILED: @tx_failed filled
  * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
  * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
@@ -714,6 +716,8 @@ enum station_info_flags {
 	STATION_INFO_LOCAL_PM		= 1<<21,
 	STATION_INFO_LOCAL_PM		= 1<<21,
 	STATION_INFO_PEER_PM		= 1<<22,
 	STATION_INFO_PEER_PM		= 1<<22,
 	STATION_INFO_NONPEER_PM		= 1<<23,
 	STATION_INFO_NONPEER_PM		= 1<<23,
+	STATION_INFO_RX_BYTES64		= 1<<24,
+	STATION_INFO_TX_BYTES64		= 1<<25,
 };
 };
 
 
 /**
 /**
@@ -835,8 +839,8 @@ struct station_info {
 	u32 filled;
 	u32 filled;
 	u32 connected_time;
 	u32 connected_time;
 	u32 inactive_time;
 	u32 inactive_time;
-	u32 rx_bytes;
-	u32 tx_bytes;
+	u64 rx_bytes;
+	u64 tx_bytes;
 	u16 llid;
 	u16 llid;
 	u16 plid;
 	u16 plid;
 	u8 plink_state;
 	u8 plink_state;
@@ -1289,7 +1293,6 @@ struct cfg80211_bss_ies {
  * @beacon_ies: the information elements from the last Beacon frame
  * @beacon_ies: the information elements from the last Beacon frame
  * @proberesp_ies: the information elements from the last Probe Response frame
  * @proberesp_ies: the information elements from the last Probe Response frame
  * @signal: signal strength value (type depends on the wiphy's signal_type)
  * @signal: signal strength value (type depends on the wiphy's signal_type)
- * @free_priv: function pointer to free private data
  * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
  * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
  */
  */
 struct cfg80211_bss {
 struct cfg80211_bss {
@@ -1301,8 +1304,6 @@ struct cfg80211_bss {
 	const struct cfg80211_bss_ies __rcu *beacon_ies;
 	const struct cfg80211_bss_ies __rcu *beacon_ies;
 	const struct cfg80211_bss_ies __rcu *proberesp_ies;
 	const struct cfg80211_bss_ies __rcu *proberesp_ies;
 
 
-	void (*free_priv)(struct cfg80211_bss *bss);
-
 	s32 signal;
 	s32 signal;
 
 
 	u16 beacon_interval;
 	u16 beacon_interval;
@@ -1596,6 +1597,32 @@ struct cfg80211_wowlan {
 	int n_patterns;
 	int n_patterns;
 };
 };
 
 
+/**
+ * struct cfg80211_wowlan_wakeup - wakeup report
+ * @disconnect: woke up by getting disconnected
+ * @magic_pkt: woke up by receiving magic packet
+ * @gtk_rekey_failure: woke up by GTK rekey failure
+ * @eap_identity_req: woke up by EAP identity request packet
+ * @four_way_handshake: woke up by 4-way handshake
+ * @rfkill_release: woke up by rfkill being released
+ * @pattern_idx: pattern that caused wakeup, -1 if not due to pattern
+ * @packet_present_len: copied wakeup packet data
+ * @packet_len: original wakeup packet length
+ * @packet: The packet causing the wakeup, if any.
+ * @packet_80211:  For pattern match, magic packet and other data
+ *	frame triggers an 802.3 frame should be reported, for
+ *	disconnect due to deauth 802.11 frame. This indicates which
+ *	it is.
+ */
+struct cfg80211_wowlan_wakeup {
+	bool disconnect, magic_pkt, gtk_rekey_failure,
+	     eap_identity_req, four_way_handshake,
+	     rfkill_release, packet_80211;
+	s32 pattern_idx;
+	u32 packet_present_len, packet_len;
+	const void *packet;
+};
+
 /**
 /**
  * struct cfg80211_gtk_rekey_data - rekey data
  * struct cfg80211_gtk_rekey_data - rekey data
  * @kek: key encryption key
  * @kek: key encryption key
@@ -3137,10 +3164,6 @@ cfg80211_get_ibss(struct wiphy *wiphy,
 				WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
 				WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
 }
 }
 
 
-struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
-				       struct ieee80211_channel *channel,
-				       const u8 *meshid, size_t meshidlen,
-				       const u8 *meshcfg);
 /**
 /**
  * cfg80211_ref_bss - reference BSS struct
  * cfg80211_ref_bss - reference BSS struct
  * @bss: the BSS struct to reference
  * @bss: the BSS struct to reference
@@ -3852,6 +3875,21 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
 			  enum ieee80211_p2p_attr_id attr,
 			  enum ieee80211_p2p_attr_id attr,
 			  u8 *buf, unsigned int bufsize);
 			  u8 *buf, unsigned int bufsize);
 
 
+/**
+ * cfg80211_report_wowlan_wakeup - report wakeup from WoWLAN
+ * @wdev: the wireless device reporting the wakeup
+ * @wakeup: the wakeup report
+ * @gfp: allocation flags
+ *
+ * This function reports that the given device woke up. If it
+ * caused the wakeup, report the reason(s), otherwise you may
+ * pass %NULL as the @wakeup parameter to advertise that something
+ * else caused the wakeup.
+ */
+void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
+				   struct cfg80211_wowlan_wakeup *wakeup,
+				   gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 
 /* wiphy_printk helpers, similar to dev_printk */
 /* wiphy_printk helpers, similar to dev_printk */

+ 27 - 13
include/net/mac80211.h

@@ -208,6 +208,8 @@ struct ieee80211_chanctx_conf {
  * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
  * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
  * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS)
  * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS)
  *	changed (currently only in P2P client mode, GO mode will be later)
  *	changed (currently only in P2P client mode, GO mode will be later)
+ * @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when
+ *	it becomes valid, managed mode only)
  */
  */
 enum ieee80211_bss_change {
 enum ieee80211_bss_change {
 	BSS_CHANGED_ASSOC		= 1<<0,
 	BSS_CHANGED_ASSOC		= 1<<0,
@@ -230,6 +232,7 @@ enum ieee80211_bss_change {
 	BSS_CHANGED_PS			= 1<<17,
 	BSS_CHANGED_PS			= 1<<17,
 	BSS_CHANGED_TXPOWER		= 1<<18,
 	BSS_CHANGED_TXPOWER		= 1<<18,
 	BSS_CHANGED_P2P_PS		= 1<<19,
 	BSS_CHANGED_P2P_PS		= 1<<19,
+	BSS_CHANGED_DTIM_PERIOD		= 1<<20,
 
 
 	/* when adding here, make sure to change ieee80211_reconfig */
 	/* when adding here, make sure to change ieee80211_reconfig */
 };
 };
@@ -271,9 +274,8 @@ enum ieee80211_rssi_event {
  *	if the hardware cannot handle this it must set the
  *	if the hardware cannot handle this it must set the
  *	IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
  *	IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
  * @dtim_period: num of beacons before the next DTIM, for beaconing,
  * @dtim_period: num of beacons before the next DTIM, for beaconing,
- *	valid in station mode only while @assoc is true and if also
- *	requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf
- *	@ps_dtim_period)
+ *	valid in station mode only if after the driver was notified
+ *	with the %BSS_CHANGED_DTIM_PERIOD flag, will be non-zero then.
  * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old
  * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old
  *	as it may have been received during scanning long ago)
  *	as it may have been received during scanning long ago)
  * @sync_device_ts: the device timestamp corresponding to the sync_tsf,
  * @sync_device_ts: the device timestamp corresponding to the sync_tsf,
@@ -406,6 +408,9 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
  * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
  *	after TX status because the destination was asleep, it must not
  *	after TX status because the destination was asleep, it must not
  *	be modified again (no seqno assignment, crypto, etc.)
  *	be modified again (no seqno assignment, crypto, etc.)
+ * @IEEE80211_TX_INTFL_MLME_CONN_TX: This frame was transmitted by the MLME
+ *	code for connection establishment, this indicates that its status
+ *	should kick the MLME state machine.
  * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
  * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
  *	MLME command (internal to mac80211 to figure out whether to send TX
  *	MLME command (internal to mac80211 to figure out whether to send TX
  *	status to user space)
  *	status to user space)
@@ -457,7 +462,7 @@ enum mac80211_tx_control_flags {
 	IEEE80211_TX_CTL_NO_PS_BUFFER		= BIT(17),
 	IEEE80211_TX_CTL_NO_PS_BUFFER		= BIT(17),
 	IEEE80211_TX_CTL_MORE_FRAMES		= BIT(18),
 	IEEE80211_TX_CTL_MORE_FRAMES		= BIT(18),
 	IEEE80211_TX_INTFL_RETRANSMISSION	= BIT(19),
 	IEEE80211_TX_INTFL_RETRANSMISSION	= BIT(19),
-	/* hole at 20, use later */
+	IEEE80211_TX_INTFL_MLME_CONN_TX		= BIT(20),
 	IEEE80211_TX_INTFL_NL80211_FRAME_TX	= BIT(21),
 	IEEE80211_TX_INTFL_NL80211_FRAME_TX	= BIT(21),
 	IEEE80211_TX_CTL_LDPC			= BIT(22),
 	IEEE80211_TX_CTL_LDPC			= BIT(22),
 	IEEE80211_TX_CTL_STBC			= BIT(23) | BIT(24),
 	IEEE80211_TX_CTL_STBC			= BIT(23) | BIT(24),
@@ -1328,9 +1333,9 @@ struct ieee80211_tx_control {
  *      When this flag is set, signaling beacon-loss will cause an immediate
  *      When this flag is set, signaling beacon-loss will cause an immediate
  *      change to disassociated state.
  *      change to disassociated state.
  *
  *
- * @IEEE80211_HW_NEED_DTIM_PERIOD:
- *	This device needs to know the DTIM period for the BSS before
- *	associating.
+ * @IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC:
+ *	This device needs to get data from beacon before association (i.e.
+ *	dtim_period).
  *
  *
  * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports
  * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports
  *	per-station GTKs as used by IBSS RSN or during fast transition. If
  *	per-station GTKs as used by IBSS RSN or during fast transition. If
@@ -1366,10 +1371,6 @@ struct ieee80211_tx_control {
  * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any
  * @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any
  *	P2P Interface. This will be honoured even if more than one interface
  *	P2P Interface. This will be honoured even if more than one interface
  *	is supported.
  *	is supported.
- *
- * @IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL: On this hardware TX BA session
- *	should be tear down once BAR frame will not be acked.
- *
  */
  */
 enum ieee80211_hw_flags {
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
 	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
@@ -1379,7 +1380,7 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE	= 1<<4,
 	IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE	= 1<<4,
 	IEEE80211_HW_SIGNAL_UNSPEC			= 1<<5,
 	IEEE80211_HW_SIGNAL_UNSPEC			= 1<<5,
 	IEEE80211_HW_SIGNAL_DBM				= 1<<6,
 	IEEE80211_HW_SIGNAL_DBM				= 1<<6,
-	IEEE80211_HW_NEED_DTIM_PERIOD			= 1<<7,
+	IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC		= 1<<7,
 	IEEE80211_HW_SPECTRUM_MGMT			= 1<<8,
 	IEEE80211_HW_SPECTRUM_MGMT			= 1<<8,
 	IEEE80211_HW_AMPDU_AGGREGATION			= 1<<9,
 	IEEE80211_HW_AMPDU_AGGREGATION			= 1<<9,
 	IEEE80211_HW_SUPPORTS_PS			= 1<<10,
 	IEEE80211_HW_SUPPORTS_PS			= 1<<10,
@@ -1398,7 +1399,6 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TX_AMPDU_SETUP_IN_HW		= 1<<23,
 	IEEE80211_HW_TX_AMPDU_SETUP_IN_HW		= 1<<23,
 	IEEE80211_HW_SCAN_WHILE_IDLE			= 1<<24,
 	IEEE80211_HW_SCAN_WHILE_IDLE			= 1<<24,
 	IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF		= 1<<25,
 	IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF		= 1<<25,
-	IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL		= 1<<26,
 };
 };
 
 
 /**
 /**
@@ -3877,6 +3877,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
  * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, and
  * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, and
  * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
  * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
  * needs to inform if the connection to the AP has been lost.
  * needs to inform if the connection to the AP has been lost.
+ * The function may also be called if the connection needs to be terminated
+ * for some other reason, even if %IEEE80211_HW_CONNECTION_MONITOR isn't set.
  *
  *
  * This function will cause immediate change to disassociated state,
  * This function will cause immediate change to disassociated state,
  * without connection recovery attempts.
  * without connection recovery attempts.
@@ -4211,4 +4213,16 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
  */
  */
 int ieee80211_ave_rssi(struct ieee80211_vif *vif);
 int ieee80211_ave_rssi(struct ieee80211_vif *vif);
 
 
+/**
+ * ieee80211_report_wowlan_wakeup - report WoWLAN wakeup
+ * @vif: virtual interface
+ * @wakeup: wakeup reason(s)
+ * @gfp: allocation flags
+ *
+ * See cfg80211_report_wowlan_wakeup().
+ */
+void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
+				    struct cfg80211_wowlan_wakeup *wakeup,
+				    gfp_t gfp);
+
 #endif /* MAC80211_H */
 #endif /* MAC80211_H */

+ 35 - 0
include/uapi/linux/nl80211.h

@@ -513,6 +513,12 @@
  *	command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
  *	command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
  *	more background information, see
  *	more background information, see
  *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
  *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *	The @NL80211_CMD_SET_WOWLAN command can also be used as a notification
+ *	from the driver reporting the wakeup reason. In this case, the
+ *	@NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason
+ *	for the wakeup, if it was caused by wireless. If it is not present
+ *	in the wakeup notification, the wireless device didn't cause the
+ *	wakeup but reports that it was woken up.
  *
  *
  * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
  * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
  *	the necessary information for supporting GTK rekey offload. This
  *	the necessary information for supporting GTK rekey offload. This
@@ -1851,6 +1857,8 @@ enum nl80211_sta_bss_param {
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
  * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
  * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station)
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
  * 	containing info as possible, see &enum nl80211_rate_info
  * 	containing info as possible, see &enum nl80211_rate_info
@@ -1903,6 +1911,8 @@ enum nl80211_sta_info {
 	NL80211_STA_INFO_LOCAL_PM,
 	NL80211_STA_INFO_LOCAL_PM,
 	NL80211_STA_INFO_PEER_PM,
 	NL80211_STA_INFO_PEER_PM,
 	NL80211_STA_INFO_NONPEER_PM,
 	NL80211_STA_INFO_NONPEER_PM,
+	NL80211_STA_INFO_RX_BYTES64,
+	NL80211_STA_INFO_TX_BYTES64,
 
 
 	/* keep last */
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -2947,6 +2957,10 @@ struct nl80211_wowlan_pattern_support {
  *
  *
  *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
  *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
  *	carrying a &struct nl80211_wowlan_pattern_support.
  *	carrying a &struct nl80211_wowlan_pattern_support.
+ *
+ *	When reporting wakeup. it is a u32 attribute containing the 0-based
+ *	index of the pattern that caused the wakeup, in the patterns passed
+ *	to the kernel when configuring.
  * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
  * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
  *	used when setting, used only to indicate that GTK rekeying is supported
  *	used when setting, used only to indicate that GTK rekeying is supported
  *	by the device (flag)
  *	by the device (flag)
@@ -2957,8 +2971,25 @@ struct nl80211_wowlan_pattern_support {
  * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
  * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
  * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
  * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
  *	(on devices that have rfkill in the device) (flag)
  *	(on devices that have rfkill in the device) (flag)
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: For wakeup reporting only, contains
+ *	the 802.11 packet that caused the wakeup, e.g. a deauth frame. The frame
+ *	may be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN
+ *	attribute contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: Original length of the 802.11
+ *	packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211
+ *	attribute if the packet was truncated somewhere.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: For wakeup reporting only, contains the
+ *	802.11 packet that caused the wakeup, e.g. a magic packet. The frame may
+ *	be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN attribute
+ *	contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3
+ *	packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023
+ *	attribute if the packet was truncated somewhere.
  * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
  * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
  * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
  * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ *
+ * These nested attributes are used to configure the wakeup triggers and
+ * to report the wakeup reason(s).
  */
  */
 enum nl80211_wowlan_triggers {
 enum nl80211_wowlan_triggers {
 	__NL80211_WOWLAN_TRIG_INVALID,
 	__NL80211_WOWLAN_TRIG_INVALID,
@@ -2971,6 +3002,10 @@ enum nl80211_wowlan_triggers {
 	NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
 	NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
 	NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
 	NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
 	NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
 	NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+	NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211,
+	NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN,
+	NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023,
+	NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN,
 
 
 	/* keep last */
 	/* keep last */
 	NUM_NL80211_WOWLAN_TRIG,
 	NUM_NL80211_WOWLAN_TRIG,

+ 3 - 7
net/bluetooth/hci_core.c

@@ -1183,14 +1183,10 @@ static void hci_discov_off(struct work_struct *work)
 
 
 int hci_uuids_clear(struct hci_dev *hdev)
 int hci_uuids_clear(struct hci_dev *hdev)
 {
 {
-	struct list_head *p, *n;
-
-	list_for_each_safe(p, n, &hdev->uuids) {
-		struct bt_uuid *uuid;
+	struct bt_uuid *uuid, *tmp;
 
 
-		uuid = list_entry(p, struct bt_uuid, list);
-
-		list_del(p);
+	list_for_each_entry_safe(uuid, tmp, &hdev->uuids, list) {
+		list_del(&uuid->list);
 		kfree(uuid);
 		kfree(uuid);
 	}
 	}
 
 

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است