Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge
authorDavid S. Miller <davem@davemloft.net>
Thu, 15 Nov 2012 03:10:50 +0000 (22:10 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 15 Nov 2012 03:10:50 +0000 (22:10 -0500)
Included changes:
- hash computation improvements
- Bridge Loop Avoidance set-up phase optimisations
- Roaming handling code redesign
- some code cleanups

Signed-off-by: David S. Miller <davem@davemloft.net>
266 files changed:
Documentation/devicetree/bindings/net/cpsw.txt
MAINTAINERS
arch/arm/boot/dts/am335x-bone.dts
arch/arm/boot/dts/am335x-evm.dts
arch/arm/boot/dts/am33xx.dtsi
arch/arm/configs/omap2plus_defconfig
arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/mips/bcm47xx/nvram.c
arch/mips/bcm47xx/wgt634u.c
drivers/bcma/driver_chipcommon.c
drivers/bcma/driver_chipcommon_nflash.c
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/driver_chipcommon_sflash.c
drivers/bcma/driver_mips.c
drivers/bcma/driver_pci_host.c
drivers/bcma/host_pci.c
drivers/bcma/main.c
drivers/bcma/sprom.c
drivers/bluetooth/btmrvl_sdio.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
drivers/net/phy/davicom.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vxlan.c
drivers/net/wireless/airo.c
drivers/net/wireless/ath/Kconfig
drivers/net/wireless/ath/Makefile
drivers/net/wireless/ath/ar5523/Kconfig [new file with mode: 0644]
drivers/net/wireless/ath/ar5523/Makefile [new file with mode: 0644]
drivers/net/wireless/ath/ar5523/ar5523.c [new file with mode: 0644]
drivers/net/wireless/ath/ar5523/ar5523.h [new file with mode: 0644]
drivers/net/wireless/ath/ar5523/ar5523_hw.h [new file with mode: 0644]
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_mci.h
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/mci.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/wow.c
drivers/net/wireless/ath/carl9170/mac.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/ath/carl9170/usb.c
drivers/net/wireless/ath/hw.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/fwil.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/fwil.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/hostap/hostap_80211_rx.c
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/sta_rx.c
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/mwifiex/uap_txrx.c
drivers/net/wireless/mwifiex/util.c
drivers/net/wireless/orinoco/main.h
drivers/net/wireless/orinoco/orinoco_usb.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rtlwifi/cam.c
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192ce/def.h
drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192cu/dm.c
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
drivers/net/wireless/rtlwifi/rtl8192de/dm.c
drivers/net/wireless/rtlwifi/rtl8192de/phy.c
drivers/net/wireless/rtlwifi/rtl8192de/rf.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/dm.c
drivers/net/wireless/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/rf.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/nfc/Makefile
drivers/nfc/pn533.c
drivers/nfc/pn544/Makefile [new file with mode: 0644]
drivers/nfc/pn544/i2c.c [new file with mode: 0644]
drivers/nfc/pn544/pn544.c [moved from drivers/nfc/pn544_hci.c with 58% similarity]
drivers/nfc/pn544/pn544.h [new file with mode: 0644]
drivers/ssb/b43_pci_bridge.c
drivers/ssb/driver_chipcommon_pmu.c
drivers/ssb/driver_mipscore.c
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/bcma/bcma_driver_mips.h
include/linux/bcma/bcma_regs.h
include/linux/ieee80211.h
include/linux/if_tunnel.h
include/linux/pci.h
include/linux/platform_data/cpsw.h
include/linux/ssb/ssb_driver_mips.h
include/net/bluetooth/a2mp.h
include/net/bluetooth/amp.h [new file with mode: 0644]
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/ipip.h
include/net/mac80211.h
include/net/nfc/hci.h
include/net/nfc/nfc.h
include/uapi/linux/if_link.h
include/uapi/linux/if_tunnel.h
include/uapi/linux/nfc.h
include/uapi/linux/nl80211.h
net/bluetooth/Kconfig
net/bluetooth/Makefile
net/bluetooth/a2mp.c
net/bluetooth/af_bluetooth.c
net/bluetooth/amp.c [new file with mode: 0644]
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/lib.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_stp.c
net/bridge/br_stp_bpdu.c
net/bridge/br_sysfs_if.c
net/ipv4/ip_gre.c
net/ipv4/ip_vti.c
net/ipv4/ipip.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c
net/ipv6/route.c
net/ipv6/sit.c
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/aes_cmac.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.h
net/mac80211/debugfs_netdev.c
net/mac80211/driver-ops.h
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/mesh_sync.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/status.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c [new file with mode: 0644]
net/nfc/Kconfig
net/nfc/core.c
net/nfc/hci/command.c
net/nfc/hci/core.c
net/nfc/hci/llc.c
net/nfc/hci/llc_shdlc.c
net/nfc/llcp/Kconfig
net/nfc/llcp/commands.c
net/nfc/llcp/llcp.c
net/nfc/llcp/llcp.h
net/nfc/llcp/sock.c
net/nfc/nci/Kconfig
net/nfc/nci/core.c
net/nfc/netlink.c
net/nfc/nfc.h
net/nfc/rawsock.c
net/wireless/Makefile
net/wireless/ap.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ethtool.c
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h [new file with mode: 0644]
net/wireless/scan.c
net/wireless/sme.c
net/wireless/sysfs.c
net/wireless/trace.c [new file with mode: 0644]
net/wireless/trace.h [new file with mode: 0644]
net/wireless/util.c
net/wireless/wext-compat.c

index 2214607..6ddd028 100644 (file)
@@ -9,15 +9,7 @@ Required properties:
                          number
 - interrupt-parent     : The parent interrupt controller
 - cpdma_channels       : Specifies number of channels in CPDMA
-- host_port_no         : Specifies host port shift
-- cpdma_reg_ofs                : Specifies CPDMA submodule register offset
-- cpdma_sram_ofs       : Specifies CPDMA SRAM offset
-- ale_reg_ofs          : Specifies ALE submodule register offset
 - ale_entries          : Specifies No of entries ALE can hold
-- host_port_reg_ofs    : Specifies host port register offset
-- hw_stats_reg_ofs     : Specifies hardware statistics register offset
-- cpts_reg_ofs         : Specifies the offset of the CPTS registers
-- bd_ram_ofs           : Specifies internal desciptor RAM offset
 - bd_ram_size          : Specifies internal descriptor RAM size
 - rx_descs             : Specifies number of Rx descriptors
 - mac_control          : Specifies Default MAC control register content
@@ -26,8 +18,6 @@ Required properties:
 - cpts_active_slave    : Specifies the slave to use for time stamping
 - cpts_clock_mult      : Numerator to convert input clock ticks into nanoseconds
 - cpts_clock_shift     : Denominator to convert input clock ticks into nanoseconds
-- slave_reg_ofs                : Specifies slave register offset
-- sliver_reg_ofs       : Specifies slave sliver register offset
 - phy_id               : Specifies slave phy id
 - mac-address          : Specifies slave MAC address
 
@@ -49,15 +39,7 @@ Examples:
                interrupts = <55 0x4>;
                interrupt-parent = <&intc>;
                cpdma_channels = <8>;
-               host_port_no = <0>;
-               cpdma_reg_ofs = <0x800>;
-               cpdma_sram_ofs = <0xa00>;
-               ale_reg_ofs = <0xd00>;
                ale_entries = <1024>;
-               host_port_reg_ofs = <0x108>;
-               hw_stats_reg_ofs = <0x900>;
-               cpts_reg_ofs = <0xc00>;
-               bd_ram_ofs = <0x2000>;
                bd_ram_size = <0x2000>;
                no_bd_ram = <0>;
                rx_descs = <64>;
@@ -67,16 +49,12 @@ Examples:
                cpts_clock_mult = <0x80000000>;
                cpts_clock_shift = <29>;
                cpsw_emac0: slave@0 {
-                       slave_reg_ofs = <0x200>;
-                       sliver_reg_ofs = <0xd80>;
-                       phy_id = "davinci_mdio.16:00";
+                       phy_id = <&davinci_mdio>, <0>;
                        /* Filled in by U-Boot */
                        mac-address = [ 00 00 00 00 00 00 ];
                };
                cpsw_emac1: slave@1 {
-                       slave_reg_ofs = <0x300>;
-                       sliver_reg_ofs = <0xdc0>;
-                       phy_id = "davinci_mdio.16:01";
+                       phy_id = <&davinci_mdio>, <1>;
                        /* Filled in by U-Boot */
                        mac-address = [ 00 00 00 00 00 00 ];
                };
@@ -87,15 +65,7 @@ Examples:
                compatible = "ti,cpsw";
                ti,hwmods = "cpgmac0";
                cpdma_channels = <8>;
-               host_port_no = <0>;
-               cpdma_reg_ofs = <0x800>;
-               cpdma_sram_ofs = <0xa00>;
-               ale_reg_ofs = <0xd00>;
                ale_entries = <1024>;
-               host_port_reg_ofs = <0x108>;
-               hw_stats_reg_ofs = <0x900>;
-               cpts_reg_ofs = <0xc00>;
-               bd_ram_ofs = <0x2000>;
                bd_ram_size = <0x2000>;
                no_bd_ram = <0>;
                rx_descs = <64>;
@@ -105,16 +75,12 @@ Examples:
                cpts_clock_mult = <0x80000000>;
                cpts_clock_shift = <29>;
                cpsw_emac0: slave@0 {
-                       slave_reg_ofs = <0x200>;
-                       sliver_reg_ofs = <0xd80>;
-                       phy_id = "davinci_mdio.16:00";
+                       phy_id = <&davinci_mdio>, <0>;
                        /* Filled in by U-Boot */
                        mac-address = [ 00 00 00 00 00 00 ];
                };
                cpsw_emac1: slave@1 {
-                       slave_reg_ofs = <0x300>;
-                       sliver_reg_ofs = <0xdc0>;
-                       phy_id = "davinci_mdio.16:01";
+                       phy_id = <&davinci_mdio>, <1>;
                        /* Filled in by U-Boot */
                        mac-address = [ 00 00 00 00 00 00 ];
                };
index 4b062ff..aedb604 100644 (file)
@@ -7509,6 +7509,12 @@ S:       Maintained
 F:     Documentation/usb/acm.txt
 F:     drivers/usb/class/cdc-acm.*
 
+USB AR5523 WIRELESS DRIVER
+M:     Pontus Fuchs <pontus.fuchs@gmail.com>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+F:     drivers/net/wireless/ath/ar5523/
+
 USB ATTACHED SCSI
 M:     Matthew Wilcox <willy@linux.intel.com>
 M:     Sarah Sharp <sarah.a.sharp@linux.intel.com>
index c634f87..4fcd218 100644 (file)
                };
        };
 };
+
+&cpsw_emac0 {
+       phy_id = <&davinci_mdio>, <0>;
+};
+
+&cpsw_emac1 {
+       phy_id = <&davinci_mdio>, <1>;
+};
index 185d632..366d929 100644 (file)
                };
        };
 };
+
+&cpsw_emac0 {
+       phy_id = <&davinci_mdio>, <0>;
+};
+
+&cpsw_emac1 {
+       phy_id = <&davinci_mdio>, <1>;
+};
index bb31bff..a4615b4 100644 (file)
                        interrupt-parent = <&intc>;
                        interrupts = <91>;
                };
+
+               mac: ethernet@4a100000 {
+                       compatible = "ti,cpsw";
+                       ti,hwmods = "cpgmac0";
+                       cpdma_channels = <8>;
+                       ale_entries = <1024>;
+                       bd_ram_size = <0x2000>;
+                       no_bd_ram = <0>;
+                       rx_descs = <64>;
+                       mac_control = <0x20>;
+                       slaves = <2>;
+                       cpts_active_slave = <0>;
+                       cpts_clock_mult = <0x80000000>;
+                       cpts_clock_shift = <29>;
+                       reg = <0x4a100000 0x800
+                              0x4a101200 0x100>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       interrupt-parent = <&intc>;
+                       /*
+                        * c0_rx_thresh_pend
+                        * c0_rx_pend
+                        * c0_tx_pend
+                        * c0_misc_pend
+                        */
+                       interrupts = <40 41 42 43>;
+                       ranges;
+
+                       davinci_mdio: mdio@4a101000 {
+                               compatible = "ti,davinci_mdio";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               ti,hwmods = "davinci_mdio";
+                               bus_freq = <1000000>;
+                               reg = <0x4a101000 0x100>;
+                       };
+
+                       cpsw_emac0: slave@4a100200 {
+                               /* Filled in by U-Boot */
+                               mac-address = [ 00 00 00 00 00 00 ];
+                       };
+
+                       cpsw_emac1: slave@4a100300 {
+                               /* Filled in by U-Boot */
+                               mac-address = [ 00 00 00 00 00 00 ];
+                       };
+
+               };
        };
 };
index 6230304..a1dc5c0 100644 (file)
@@ -240,3 +240,6 @@ CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
 CONFIG_LIBCRC32C=y
 CONFIG_SOC_OMAP5=y
+CONFIG_TI_DAVINCI_MDIO=y
+CONFIG_TI_DAVINCI_CPDMA=y
+CONFIG_TI_CPSW=y
index 59d5c1c..3125835 100644 (file)
@@ -674,6 +674,7 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = {
        .name           = "cpgmac0",
        .class          = &am33xx_cpgmac0_hwmod_class,
        .clkdm_name     = "cpsw_125mhz_clkdm",
+       .flags          = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
        .mpu_irqs       = am33xx_cpgmac0_irqs,
        .main_clk       = "cpsw_125mhz_gclk",
        .prcm           = {
@@ -685,6 +686,20 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = {
 };
 
 /*
+ * mdio class
+ */
+static struct omap_hwmod_class am33xx_mdio_hwmod_class = {
+       .name           = "davinci_mdio",
+};
+
+static struct omap_hwmod am33xx_mdio_hwmod = {
+       .name           = "davinci_mdio",
+       .class          = &am33xx_mdio_hwmod_class,
+       .clkdm_name     = "cpsw_125mhz_clkdm",
+       .main_clk       = "cpsw_125mhz_gclk",
+};
+
+/*
  * dcan class
  */
 static struct omap_hwmod_class am33xx_dcan_hwmod_class = {
@@ -2501,6 +2516,21 @@ static struct omap_hwmod_ocp_if am33xx_l4_hs__cpgmac0 = {
        .user           = OCP_USER_MPU,
 };
 
+struct omap_hwmod_addr_space am33xx_mdio_addr_space[] = {
+       {
+               .pa_start       = 0x4A101000,
+               .pa_end         = 0x4A101000 + SZ_256 - 1,
+       },
+       { }
+};
+
+struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio = {
+       .master         = &am33xx_cpgmac0_hwmod,
+       .slave          = &am33xx_mdio_hwmod,
+       .addr           = am33xx_mdio_addr_space,
+       .user           = OCP_USER_MPU,
+};
+
 static struct omap_hwmod_addr_space am33xx_elm_addr_space[] = {
        {
                .pa_start       = 0x48080000,
@@ -3371,6 +3401,7 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_l3_main__tptc2,
        &am33xx_l3_s__usbss,
        &am33xx_l4_hs__cpgmac0,
+       &am33xx_cpgmac0__mdio,
        NULL,
 };
 
index d43ceff..48a4c70 100644 (file)
@@ -43,8 +43,8 @@ static void early_nvram_init(void)
 #ifdef CONFIG_BCM47XX_SSB
        case BCM47XX_BUS_TYPE_SSB:
                mcore_ssb = &bcm47xx_bus.ssb.mipscore;
-               base = mcore_ssb->flash_window;
-               lim = mcore_ssb->flash_window_size;
+               base = mcore_ssb->pflash.window;
+               lim = mcore_ssb->pflash.window_size;
                break;
 #endif
 #ifdef CONFIG_BCM47XX_BCMA
index e9f9ec8..e80d585 100644 (file)
@@ -156,10 +156,10 @@ static int __init wgt634u_init(void)
                                            SSB_CHIPCO_IRQ_GPIO);
                }
 
-               wgt634u_flash_data.width = mcore->flash_buswidth;
-               wgt634u_flash_resource.start = mcore->flash_window;
-               wgt634u_flash_resource.end = mcore->flash_window
-                                          + mcore->flash_window_size
+               wgt634u_flash_data.width = mcore->pflash.buswidth;
+               wgt634u_flash_resource.start = mcore->pflash.window;
+               wgt634u_flash_resource.end = mcore->pflash.window
+                                          + mcore->pflash.window_size
                                           - 1;
                return platform_add_devices(wgt634u_devices,
                                            ARRAY_SIZE(wgt634u_devices));
index a4c3ebc..ffd74e5 100644 (file)
@@ -22,12 +22,9 @@ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
        return value;
 }
 
-void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
+void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
 {
-       u32 leddc_on = 10;
-       u32 leddc_off = 90;
-
-       if (cc->setup_done)
+       if (cc->early_setup_done)
                return;
 
        if (cc->core->id.rev >= 11)
@@ -36,6 +33,22 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
        if (cc->core->id.rev >= 35)
                cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
 
+       if (cc->capabilities & BCMA_CC_CAP_PMU)
+               bcma_pmu_early_init(cc);
+
+       cc->early_setup_done = true;
+}
+
+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
+{
+       u32 leddc_on = 10;
+       u32 leddc_off = 90;
+
+       if (cc->setup_done)
+               return;
+
+       bcma_core_chipcommon_early_init(cc);
+
        if (cc->core->id.rev >= 20) {
                bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
                bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
index 9042781..dbda91e 100644 (file)
@@ -32,6 +32,9 @@ int bcma_nflash_init(struct bcma_drv_cc *cc)
        }
 
        cc->nflash.present = true;
+       if (cc->core->id.rev == 38 &&
+           (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT))
+               cc->nflash.boot = true;
 
        /* Prepare platform device, but don't register it yet. It's too early,
         * malloc (required by device_private_init) is not available yet. */
index 201faf1..a63ddd9 100644 (file)
@@ -144,7 +144,7 @@ static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
        }
 }
 
-void bcma_pmu_init(struct bcma_drv_cc *cc)
+void bcma_pmu_early_init(struct bcma_drv_cc *cc)
 {
        u32 pmucap;
 
@@ -153,7 +153,10 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
 
        bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
                   cc->pmu.rev, pmucap);
+}
 
+void bcma_pmu_init(struct bcma_drv_cc *cc)
+{
        if (cc->pmu.rev == 1)
                bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
                              ~BCMA_CC_PMU_CTL_NOILPONW);
index 2c4eec2..63e6883 100644 (file)
@@ -12,7 +12,7 @@
 
 static struct resource bcma_sflash_resource = {
        .name   = "bcma_sflash",
-       .start  = BCMA_SFLASH,
+       .start  = BCMA_SOC_FLASH2,
        .end    = 0,
        .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
 };
@@ -31,15 +31,42 @@ struct bcma_sflash_tbl_e {
 };
 
 static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
-       { "", 0x14, 0x10000, 32, },
+       { "M25P20", 0x11, 0x10000, 4, },
+       { "M25P40", 0x12, 0x10000, 8, },
+
+       { "M25P16", 0x14, 0x10000, 32, },
+       { "M25P32", 0x14, 0x10000, 64, },
+       { "M25P64", 0x16, 0x10000, 128, },
+       { "M25FL128", 0x17, 0x10000, 256, },
        { 0 },
 };
 
 static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+       { "SST25WF512", 1, 0x1000, 16, },
+       { "SST25VF512", 0x48, 0x1000, 16, },
+       { "SST25WF010", 2, 0x1000, 32, },
+       { "SST25VF010", 0x49, 0x1000, 32, },
+       { "SST25WF020", 3, 0x1000, 64, },
+       { "SST25VF020", 0x43, 0x1000, 64, },
+       { "SST25WF040", 4, 0x1000, 128, },
+       { "SST25VF040", 0x44, 0x1000, 128, },
+       { "SST25VF040B", 0x8d, 0x1000, 128, },
+       { "SST25WF080", 5, 0x1000, 256, },
+       { "SST25VF080B", 0x8e, 0x1000, 256, },
+       { "SST25VF016", 0x41, 0x1000, 512, },
+       { "SST25VF032", 0x4a, 0x1000, 1024, },
+       { "SST25VF064", 0x4b, 0x1000, 2048, },
        { 0 },
 };
 
 static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+       { "AT45DB011", 0xc, 256, 512, },
+       { "AT45DB021", 0x14, 256, 1024, },
+       { "AT45DB041", 0x1c, 256, 2048, },
+       { "AT45DB081", 0x24, 256, 4096, },
+       { "AT45DB161", 0x2c, 512, 4096, },
+       { "AT45DB321", 0x34, 512, 8192, },
+       { "AT45DB642", 0x3c, 1024, 8192, },
        { 0 },
 };
 
@@ -84,6 +111,8 @@ int bcma_sflash_init(struct bcma_drv_cc *cc)
                                        break;
                        }
                        break;
+               case 0x13:
+                       return -ENOTSUPP;
                default:
                        for (e = bcma_sflash_st_tbl; e->name; e++) {
                                if (e->id == id)
@@ -116,7 +145,7 @@ int bcma_sflash_init(struct bcma_drv_cc *cc)
                return -ENOTSUPP;
        }
 
-       sflash->window = BCMA_SFLASH;
+       sflash->window = BCMA_SOC_FLASH2;
        sflash->blocksize = e->blocksize;
        sflash->numblocks = e->numblocks;
        sflash->size = sflash->blocksize * sflash->numblocks;
index cc65b45..170822e 100644 (file)
@@ -181,47 +181,66 @@ EXPORT_SYMBOL(bcma_cpu_clock);
 static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 {
        struct bcma_bus *bus = mcore->core->bus;
+       struct bcma_drv_cc *cc = &bus->drv_cc;
 
-       switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
        case BCMA_CC_FLASHT_STSER:
        case BCMA_CC_FLASHT_ATSER:
                bcma_debug(bus, "Found serial flash\n");
-               bcma_sflash_init(&bus->drv_cc);
+               bcma_sflash_init(cc);
                break;
        case BCMA_CC_FLASHT_PARA:
                bcma_debug(bus, "Found parallel flash\n");
-               bus->drv_cc.pflash.window = 0x1c000000;
-               bus->drv_cc.pflash.window_size = 0x02000000;
+               cc->pflash.present = true;
+               cc->pflash.window = BCMA_SOC_FLASH2;
+               cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
 
-               if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
+               if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
                     BCMA_CC_FLASH_CFG_DS) == 0)
-                       bus->drv_cc.pflash.buswidth = 1;
+                       cc->pflash.buswidth = 1;
                else
-                       bus->drv_cc.pflash.buswidth = 2;
+                       cc->pflash.buswidth = 2;
                break;
        default:
                bcma_err(bus, "Flash type not supported\n");
        }
 
-       if (bus->drv_cc.core->id.rev == 38 ||
+       if (cc->core->id.rev == 38 ||
            bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
-               if (bus->drv_cc.capabilities & BCMA_CC_CAP_NFLASH) {
+               if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
                        bcma_debug(bus, "Found NAND flash\n");
-                       bcma_nflash_init(&bus->drv_cc);
+                       bcma_nflash_init(cc);
                }
        }
 }
 
+void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
+{
+       struct bcma_bus *bus = mcore->core->bus;
+
+       if (mcore->early_setup_done)
+               return;
+
+       bcma_chipco_serial_init(&bus->drv_cc);
+       bcma_core_mips_flash_detect(mcore);
+
+       mcore->early_setup_done = true;
+}
+
 void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 {
        struct bcma_bus *bus;
        struct bcma_device *core;
        bus = mcore->core->bus;
 
+       if (mcore->setup_done)
+               return;
+
        bcma_info(bus, "Initializing MIPS core...\n");
 
-       if (!mcore->setup_done)
-               mcore->assigned_irqs = 1;
+       bcma_core_mips_early_init(mcore);
+
+       mcore->assigned_irqs = 1;
 
        /* Assign IRQs to all cores on the bus */
        list_for_each_entry(core, &bus->cores, list) {
@@ -256,10 +275,5 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
        bcma_info(bus, "IRQ reconfiguration done\n");
        bcma_core_mips_dump_irq(bus);
 
-       if (mcore->setup_done)
-               return;
-
-       bcma_chipco_serial_init(&bus->drv_cc);
-       bcma_core_mips_flash_detect(mcore);
        mcore->setup_done = true;
 }
index 9baf886..e564495 100644 (file)
@@ -35,11 +35,6 @@ bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
            chipid_top != 0x5300)
                return false;
 
-       if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
-               bcma_info(bus, "This PCI core is disabled and not working\n");
-               return false;
-       }
-
        bcma_core_enable(pc->core, 0);
 
        return !mips_busprobe32(tmp, pc->core->io_addr);
@@ -396,6 +391,11 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
 
        bcma_info(bus, "PCIEcore in host mode found\n");
 
+       if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
+               bcma_info(bus, "This PCIE core is disabled and not working\n");
+               return;
+       }
+
        pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
        if (!pc_host)  {
                bcma_err(bus, "can not allocate memory");
@@ -452,6 +452,8 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
                        pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
                        pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
                                                    BCMA_SOC_PCI_MEM_SZ - 1;
+                       pc_host->io_resource.start = 0x100;
+                       pc_host->io_resource.end = 0x47F;
                        pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
                        pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
                                        tmp | BCMA_SOC_PCI_MEM);
@@ -459,6 +461,8 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
                        pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
                        pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
                                                    BCMA_SOC_PCI_MEM_SZ - 1;
+                       pc_host->io_resource.start = 0x480;
+                       pc_host->io_resource.end = 0x7FF;
                        pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
                        pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
                        pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
index b6b4b5e..98fdc3e 100644 (file)
@@ -238,7 +238,7 @@ static void __devexit bcma_host_pci_remove(struct pci_dev *dev)
        pci_set_drvdata(dev, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int bcma_host_pci_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -261,11 +261,11 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend,
                         bcma_host_pci_resume);
 #define BCMA_PM_OPS    (&bcma_pm_ops)
 
-#else /* CONFIG_PM */
+#else /* CONFIG_PM_SLEEP */
 
 #define BCMA_PM_OPS     NULL
 
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
index d865470..a971889 100644 (file)
@@ -81,6 +81,18 @@ struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
 }
 EXPORT_SYMBOL_GPL(bcma_find_core);
 
+static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+                                              u8 unit)
+{
+       struct bcma_device *core;
+
+       list_for_each_entry(core, &bus->cores, list) {
+               if (core->id.id == coreid && core->core_unit == unit)
+                       return core;
+       }
+       return NULL;
+}
+
 static void bcma_release_core_dev(struct device *dev)
 {
        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
@@ -183,6 +195,20 @@ int __devinit bcma_bus_register(struct bcma_bus *bus)
                return -1;
        }
 
+       /* Early init CC core */
+       core = bcma_find_core(bus, bcma_cc_core_id(bus));
+       if (core) {
+               bus->drv_cc.core = core;
+               bcma_core_chipcommon_early_init(&bus->drv_cc);
+       }
+
+       /* Try to get SPROM */
+       err = bcma_sprom_get(bus);
+       if (err == -ENOENT) {
+               bcma_err(bus, "No SPROM available\n");
+       } else if (err)
+               bcma_err(bus, "Failed to get SPROM: %d\n", err);
+
        /* Init CC core */
        core = bcma_find_core(bus, bcma_cc_core_id(bus));
        if (core) {
@@ -198,10 +224,17 @@ int __devinit bcma_bus_register(struct bcma_bus *bus)
        }
 
        /* Init PCIE core */
-       core = bcma_find_core(bus, BCMA_CORE_PCIE);
+       core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0);
        if (core) {
-               bus->drv_pci.core = core;
-               bcma_core_pci_init(&bus->drv_pci);
+               bus->drv_pci[0].core = core;
+               bcma_core_pci_init(&bus->drv_pci[0]);
+       }
+
+       /* Init PCIE core */
+       core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1);
+       if (core) {
+               bus->drv_pci[1].core = core;
+               bcma_core_pci_init(&bus->drv_pci[1]);
        }
 
        /* Init GBIT MAC COMMON core */
@@ -211,13 +244,6 @@ int __devinit bcma_bus_register(struct bcma_bus *bus)
                bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
        }
 
-       /* Try to get SPROM */
-       err = bcma_sprom_get(bus);
-       if (err == -ENOENT) {
-               bcma_err(bus, "No SPROM available\n");
-       } else if (err)
-               bcma_err(bus, "Failed to get SPROM: %d\n", err);
-
        /* Register found cores */
        bcma_register_cores(bus);
 
@@ -275,18 +301,18 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
                return -1;
        }
 
-       /* Init CC core */
+       /* Early init CC core */
        core = bcma_find_core(bus, bcma_cc_core_id(bus));
        if (core) {
                bus->drv_cc.core = core;
-               bcma_core_chipcommon_init(&bus->drv_cc);
+               bcma_core_chipcommon_early_init(&bus->drv_cc);
        }
 
-       /* Init MIPS core */
+       /* Early init MIPS core */
        core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
        if (core) {
                bus->drv_mips.core = core;
-               bcma_core_mips_init(&bus->drv_mips);
+               bcma_core_mips_early_init(&bus->drv_mips);
        }
 
        bcma_info(bus, "Early bus registered\n");
index 0d546b6..4adf9ef 100644 (file)
@@ -595,8 +595,11 @@ int bcma_sprom_get(struct bcma_bus *bus)
                bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
 
        err = bcma_sprom_valid(sprom);
-       if (err)
+       if (err) {
+               bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
+               err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
                goto out;
+       }
 
        bcma_sprom_extract_r8(bus, sprom);
 
index 3f4bfc8..9959d4c 100644 (file)
@@ -492,7 +492,7 @@ done:
 static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
 {
        u16 buf_len = 0;
-       int ret, buf_block_len, blksz;
+       int ret, num_blocks, blksz;
        struct sk_buff *skb = NULL;
        u32 type;
        u8 *payload = NULL;
@@ -514,18 +514,17 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
        }
 
        blksz = SDIO_BLOCK_SIZE;
-       buf_block_len = (buf_len + blksz - 1) / blksz;
+       num_blocks = DIV_ROUND_UP(buf_len, blksz);
 
        if (buf_len <= SDIO_HEADER_LEN
-                       || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
+           || (num_blocks * blksz) > ALLOC_BUF_SIZE) {
                BT_ERR("invalid packet length: %d", buf_len);
                ret = -EINVAL;
                goto exit;
        }
 
        /* Allocate buffer */
-       skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN,
-                                                               GFP_ATOMIC);
+       skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
        if (skb == NULL) {
                BT_ERR("No free skb");
                goto exit;
@@ -541,7 +540,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
        payload = skb->data;
 
        ret = sdio_readsb(card->func, payload, card->ioport,
-                         buf_block_len * blksz);
+                         num_blocks * blksz);
        if (ret < 0) {
                BT_ERR("readsb failed: %d", ret);
                ret = -EIO;
@@ -553,7 +552,16 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
         */
 
        buf_len = payload[0];
-       buf_len |= (u16) payload[1] << 8;
+       buf_len |= payload[1] << 8;
+       buf_len |= payload[2] << 16;
+
+       if (buf_len > blksz * num_blocks) {
+               BT_ERR("Skip incorrect packet: hdrlen %d buffer %d",
+                      buf_len, blksz * num_blocks);
+               ret = -EIO;
+               goto exit;
+       }
+
        type = payload[3];
 
        switch (type) {
@@ -589,8 +597,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
 
        default:
                BT_ERR("Unknown packet type:%d", type);
-               print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload,
-                                               blksz * buf_block_len);
+               BT_ERR("hex: %*ph", blksz * num_blocks, payload);
 
                kfree_skb(skb);
                skb = NULL;
@@ -849,8 +856,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
                if (ret < 0) {
                        i++;
                        BT_ERR("i=%d writesb failed: %d", i, ret);
-                       print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
-                                               payload, nb);
+                       BT_ERR("hex: %*ph", nb, payload);
                        ret = -EIO;
                        if (i > MAX_WRITE_IOMEM_RETRY)
                                goto exit;
index 038ce02..5cc976d 100644 (file)
@@ -90,10 +90,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 #define DRV_MODULE_NAME                "tg3"
 #define TG3_MAJ_NUM                    3
-#define TG3_MIN_NUM                    126
+#define TG3_MIN_NUM                    127
 #define DRV_MODULE_VERSION     \
        __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE     "November 05, 2012"
+#define DRV_MODULE_RELDATE     "November 14, 2012"
 
 #define RESET_KIND_SHUTDOWN    0
 #define RESET_KIND_INIT                1
@@ -226,6 +226,9 @@ static int tg3_debug = -1;  /* -1 == use TG3_DEF_MSG_ENABLE as value */
 module_param(tg3_debug, int, 0);
 MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
 
+#define TG3_DRV_DATA_FLAG_10_100_ONLY  0x0001
+#define TG3_DRV_DATA_FLAG_5705_10_100  0x0002
+
 static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)},
@@ -245,20 +248,28 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY |
+                       TG3_DRV_DATA_FLAG_5705_10_100},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY |
+                       TG3_DRV_DATA_FLAG_5705_10_100},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY |
+                       TG3_DRV_DATA_FLAG_5705_10_100},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755)},
@@ -266,8 +277,13 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5756)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)},
+       {PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5787M,
+                       PCI_VENDOR_ID_LENOVO,
+                       TG3PCI_SUBDEVICE_ID_LENOVO_5787M),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787F)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787F),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715)},
@@ -286,9 +302,16 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761SE)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_G)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_F)},
+       {PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780,
+                       PCI_VENDOR_ID_AI, TG3PCI_SUBDEVICE_ID_ACER_57780_A),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
+       {PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780,
+                       PCI_VENDOR_ID_AI, TG3PCI_SUBDEVICE_ID_ACER_57780_B),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57788)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5717)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5717_C)},
@@ -297,8 +320,10 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795),
+        .driver_data = TG3_DRV_DATA_FLAG_10_100_ONLY},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57762)},
@@ -399,19 +424,27 @@ static const struct {
 };
 
 #define TG3_NUM_STATS  ARRAY_SIZE(ethtool_stats_keys)
+#define TG3_NVRAM_TEST         0
+#define TG3_LINK_TEST          1
+#define TG3_REGISTER_TEST      2
+#define TG3_MEMORY_TEST                3
+#define TG3_MAC_LOOPB_TEST     4
+#define TG3_PHY_LOOPB_TEST     5
+#define TG3_EXT_LOOPB_TEST     6
+#define TG3_INTERRUPT_TEST     7
 
 
 static const struct {
        const char string[ETH_GSTRING_LEN];
 } ethtool_test_keys[] = {
-       { "nvram test        (online) " },
-       { "link test         (online) " },
-       { "register test     (offline)" },
-       { "memory test       (offline)" },
-       { "mac loopback test (offline)" },
-       { "phy loopback test (offline)" },
-       { "ext loopback test (offline)" },
-       { "interrupt test    (offline)" },
+       [TG3_NVRAM_TEST]        = { "nvram test        (online) " },
+       [TG3_LINK_TEST]         = { "link test         (online) " },
+       [TG3_REGISTER_TEST]     = { "register test     (offline)" },
+       [TG3_MEMORY_TEST]       = { "memory test       (offline)" },
+       [TG3_MAC_LOOPB_TEST]    = { "mac loopback test (offline)" },
+       [TG3_PHY_LOOPB_TEST]    = { "phy loopback test (offline)" },
+       [TG3_EXT_LOOPB_TEST]    = { "ext loopback test (offline)" },
+       [TG3_INTERRUPT_TEST]    = { "interrupt test    (offline)" },
 };
 
 #define TG3_NUM_TEST   ARRAY_SIZE(ethtool_test_keys)
@@ -2448,6 +2481,18 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
        return err;
 }
 
+static void tg3_carrier_on(struct tg3 *tp)
+{
+       netif_carrier_on(tp->dev);
+       tp->link_up = true;
+}
+
+static void tg3_carrier_off(struct tg3 *tp)
+{
+       netif_carrier_off(tp->dev);
+       tp->link_up = false;
+}
+
 /* This will reset the tigon3 PHY if there is no valid
  * link unless the FORCE argument is non-zero.
  */
@@ -2466,8 +2511,8 @@ static int tg3_phy_reset(struct tg3 *tp)
        if (err != 0)
                return -EBUSY;
 
-       if (netif_running(tp->dev) && netif_carrier_ok(tp->dev)) {
-               netif_carrier_off(tp->dev);
+       if (netif_running(tp->dev) && tp->link_up) {
+               tg3_carrier_off(tp);
                tg3_link_report(tp);
        }
 
@@ -4161,6 +4206,24 @@ static bool tg3_phy_copper_fetch_rmtadv(struct tg3 *tp, u32 *rmtadv)
        return true;
 }
 
+static bool tg3_test_and_report_link_chg(struct tg3 *tp, int curr_link_up)
+{
+       if (curr_link_up != tp->link_up) {
+               if (curr_link_up) {
+                       tg3_carrier_on(tp);
+               } else {
+                       tg3_carrier_off(tp);
+                       if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
+                               tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
+               }
+
+               tg3_link_report(tp);
+               return true;
+       }
+
+       return false;
+}
+
 static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 {
        int current_link_up;
@@ -4193,7 +4256,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
        if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
-           netif_carrier_ok(tp->dev)) {
+           tp->link_up) {
                tg3_readphy(tp, MII_BMSR, &bmsr);
                if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
                    !(bmsr & BMSR_LSTATUS))
@@ -4435,13 +4498,7 @@ relink:
                                                 PCI_EXP_LNKCTL_CLKREQ_EN);
        }
 
-       if (current_link_up != netif_carrier_ok(tp->dev)) {
-               if (current_link_up)
-                       netif_carrier_on(tp->dev);
-               else
-                       netif_carrier_off(tp->dev);
-               tg3_link_report(tp);
-       }
+       tg3_test_and_report_link_chg(tp, current_link_up);
 
        return 0;
 }
@@ -5081,7 +5138,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
        orig_active_duplex = tp->link_config.active_duplex;
 
        if (!tg3_flag(tp, HW_AUTONEG) &&
-           netif_carrier_ok(tp->dev) &&
+           tp->link_up &&
            tg3_flag(tp, INIT_COMPLETE)) {
                mac_status = tr32(MAC_STATUS);
                mac_status &= (MAC_STATUS_PCS_SYNCED |
@@ -5159,13 +5216,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
                                    LED_CTRL_TRAFFIC_OVERRIDE));
        }
 
-       if (current_link_up != netif_carrier_ok(tp->dev)) {
-               if (current_link_up)
-                       netif_carrier_on(tp->dev);
-               else
-                       netif_carrier_off(tp->dev);
-               tg3_link_report(tp);
-       } else {
+       if (!tg3_test_and_report_link_chg(tp, current_link_up)) {
                u32 now_pause_cfg = tp->link_config.active_flowctrl;
                if (orig_pause_cfg != now_pause_cfg ||
                    orig_active_speed != tp->link_config.active_speed ||
@@ -5258,7 +5309,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                        new_bmcr |= BMCR_SPEED1000;
 
                        /* Force a linkdown */
-                       if (netif_carrier_ok(tp->dev)) {
+                       if (tp->link_up) {
                                u32 adv;
 
                                err |= tg3_readphy(tp, MII_ADVERTISE, &adv);
@@ -5270,7 +5321,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                                                           BMCR_ANRESTART |
                                                           BMCR_ANENABLE);
                                udelay(10);
-                               netif_carrier_off(tp->dev);
+                               tg3_carrier_off(tp);
                        }
                        tg3_writephy(tp, MII_BMCR, new_bmcr);
                        bmcr = new_bmcr;
@@ -5336,15 +5387,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
        tp->link_config.active_speed = current_speed;
        tp->link_config.active_duplex = current_duplex;
 
-       if (current_link_up != netif_carrier_ok(tp->dev)) {
-               if (current_link_up)
-                       netif_carrier_on(tp->dev);
-               else {
-                       netif_carrier_off(tp->dev);
-                       tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
-               }
-               tg3_link_report(tp);
-       }
+       tg3_test_and_report_link_chg(tp, current_link_up);
        return err;
 }
 
@@ -5356,7 +5399,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
                return;
        }
 
-       if (!netif_carrier_ok(tp->dev) &&
+       if (!tp->link_up &&
            (tp->link_config.autoneg == AUTONEG_ENABLE)) {
                u32 bmcr;
 
@@ -5386,7 +5429,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
                                tp->phy_flags |= TG3_PHYFLG_PARALLEL_DETECT;
                        }
                }
-       } else if (netif_carrier_ok(tp->dev) &&
+       } else if (tp->link_up &&
                   (tp->link_config.autoneg == AUTONEG_ENABLE) &&
                   (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
                u32 phy2;
@@ -5452,7 +5495,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
                     (32 << TX_LENGTHS_SLOT_TIME_SHIFT));
 
        if (!tg3_flag(tp, 5705_PLUS)) {
-               if (netif_carrier_ok(tp->dev)) {
+               if (tp->link_up) {
                        tw32(HOSTCC_STAT_COAL_TICKS,
                             tp->coal.stats_block_coalesce_usecs);
                } else {
@@ -5462,7 +5505,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
 
        if (tg3_flag(tp, ASPM_WORKAROUND)) {
                val = tr32(PCIE_PWR_MGMT_THRESH);
-               if (!netif_carrier_ok(tp->dev))
+               if (!tp->link_up)
                        val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) |
                              tp->pwrmgmt_thresh;
                else
@@ -6478,6 +6521,7 @@ static inline void tg3_netif_stop(struct tg3 *tp)
 {
        tp->dev->trans_start = jiffies; /* prevent tx timeout */
        tg3_napi_disable(tp);
+       netif_carrier_off(tp->dev);
        netif_tx_disable(tp->dev);
 }
 
@@ -6489,6 +6533,9 @@ static inline void tg3_netif_start(struct tg3 *tp)
         */
        netif_tx_wake_all_queues(tp->dev);
 
+       if (tp->link_up)
+               netif_carrier_on(tp->dev);
+
        tg3_napi_enable(tp);
        tp->napi[0].hw_status->status |= SD_STATUS_UPDATED;
        tg3_enable_ints(tp);
@@ -8387,7 +8434,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
                tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq);
                tw32(HOSTCC_TXCOAL_TICK_INT, ec->tx_coalesce_usecs_irq);
 
-               if (!netif_carrier_ok(tp->dev))
+               if (!tp->link_up)
                        val = 0;
 
                tw32(HOSTCC_STAT_COAL_TICKS, val);
@@ -8663,14 +8710,14 @@ static void tg3_rss_check_indir_tbl(struct tg3 *tp)
        if (!tg3_flag(tp, SUPPORT_MSIX))
                return;
 
-       if (tp->irq_cnt <= 2) {
+       if (tp->rxq_cnt == 1) {
                memset(&tp->rss_ind_tbl[0], 0, sizeof(tp->rss_ind_tbl));
                return;
        }
 
        /* Validate table against current IRQ count */
        for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) {
-               if (tp->rss_ind_tbl[i] >= tp->irq_cnt - 1)
+               if (tp->rss_ind_tbl[i] >= tp->rxq_cnt)
                        break;
        }
 
@@ -9680,7 +9727,7 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
 {
        struct tg3_hw_stats *sp = tp->hw_stats;
 
-       if (!netif_carrier_ok(tp->dev))
+       if (!tp->link_up)
                return;
 
        TG3_STAT_ADD32(&sp->tx_octets, MAC_TX_STATS_OCTETS);
@@ -9824,11 +9871,11 @@ static void tg3_timer(unsigned long __opaque)
                        u32 mac_stat = tr32(MAC_STATUS);
                        int need_setup = 0;
 
-                       if (netif_carrier_ok(tp->dev) &&
+                       if (tp->link_up &&
                            (mac_stat & MAC_STATUS_LNKSTATE_CHANGED)) {
                                need_setup = 1;
                        }
-                       if (!netif_carrier_ok(tp->dev) &&
+                       if (!tp->link_up &&
                            (mac_stat & (MAC_STATUS_PCS_SYNCED |
                                         MAC_STATUS_SIGNAL_DET))) {
                                need_setup = 1;
@@ -10480,7 +10527,7 @@ static int tg3_open(struct net_device *dev)
                }
        }
 
-       netif_carrier_off(tp->dev);
+       tg3_carrier_off(tp);
 
        err = tg3_power_up(tp);
        if (err)
@@ -10513,7 +10560,7 @@ static int tg3_close(struct net_device *dev)
 
        tg3_power_down(tp);
 
-       netif_carrier_off(tp->dev);
+       tg3_carrier_off(tp);
 
        return 0;
 }
@@ -10887,7 +10934,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                        cmd->advertising |= ADVERTISED_Asym_Pause;
                }
        }
-       if (netif_running(dev) && netif_carrier_ok(dev)) {
+       if (netif_running(dev) && tp->link_up) {
                ethtool_cmd_speed_set(cmd, tp->link_config.active_speed);
                cmd->duplex = tp->link_config.active_duplex;
                cmd->lp_advertising = tp->link_config.rmt_adv;
@@ -11405,7 +11452,7 @@ static int tg3_set_channels(struct net_device *dev,
 
        tg3_stop(tp);
 
-       netif_carrier_off(dev);
+       tg3_carrier_off(tp);
 
        tg3_start(tp, true, false);
 
@@ -11754,7 +11801,7 @@ static int tg3_test_link(struct tg3 *tp)
                max = TG3_COPPER_TIMEOUT_SEC;
 
        for (i = 0; i < max; i++) {
-               if (netif_carrier_ok(tp->dev))
+               if (tp->link_up)
                        return 0;
 
                if (msleep_interruptible(1000))
@@ -12325,19 +12372,19 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
        tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
 
        if (!netif_running(tp->dev)) {
-               data[0] = TG3_LOOPBACK_FAILED;
-               data[1] = TG3_LOOPBACK_FAILED;
+               data[TG3_MAC_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
+               data[TG3_PHY_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
                if (do_extlpbk)
-                       data[2] = TG3_LOOPBACK_FAILED;
+                       data[TG3_EXT_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
                goto done;
        }
 
        err = tg3_reset_hw(tp, 1);
        if (err) {
-               data[0] = TG3_LOOPBACK_FAILED;
-               data[1] = TG3_LOOPBACK_FAILED;
+               data[TG3_MAC_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
+               data[TG3_PHY_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
                if (do_extlpbk)
-                       data[2] = TG3_LOOPBACK_FAILED;
+                       data[TG3_EXT_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
                goto done;
        }
 
@@ -12360,11 +12407,11 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                tg3_mac_loopback(tp, true);
 
                if (tg3_run_loopback(tp, ETH_FRAME_LEN, false))
-                       data[0] |= TG3_STD_LOOPBACK_FAILED;
+                       data[TG3_MAC_LOOPB_TEST] |= TG3_STD_LOOPBACK_FAILED;
 
                if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
                    tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
-                       data[0] |= TG3_JMB_LOOPBACK_FAILED;
+                       data[TG3_MAC_LOOPB_TEST] |= TG3_JMB_LOOPBACK_FAILED;
 
                tg3_mac_loopback(tp, false);
        }
@@ -12383,13 +12430,13 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                }
 
                if (tg3_run_loopback(tp, ETH_FRAME_LEN, false))
-                       data[1] |= TG3_STD_LOOPBACK_FAILED;
+                       data[TG3_PHY_LOOPB_TEST] |= TG3_STD_LOOPBACK_FAILED;
                if (tg3_flag(tp, TSO_CAPABLE) &&
                    tg3_run_loopback(tp, ETH_FRAME_LEN, true))
-                       data[1] |= TG3_TSO_LOOPBACK_FAILED;
+                       data[TG3_PHY_LOOPB_TEST] |= TG3_TSO_LOOPBACK_FAILED;
                if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
                    tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
-                       data[1] |= TG3_JMB_LOOPBACK_FAILED;
+                       data[TG3_PHY_LOOPB_TEST] |= TG3_JMB_LOOPBACK_FAILED;
 
                if (do_extlpbk) {
                        tg3_phy_lpbk_set(tp, 0, true);
@@ -12401,13 +12448,16 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                        mdelay(40);
 
                        if (tg3_run_loopback(tp, ETH_FRAME_LEN, false))
-                               data[2] |= TG3_STD_LOOPBACK_FAILED;
+                               data[TG3_EXT_LOOPB_TEST] |=
+                                                       TG3_STD_LOOPBACK_FAILED;
                        if (tg3_flag(tp, TSO_CAPABLE) &&
                            tg3_run_loopback(tp, ETH_FRAME_LEN, true))
-                               data[2] |= TG3_TSO_LOOPBACK_FAILED;
+                               data[TG3_EXT_LOOPB_TEST] |=
+                                                       TG3_TSO_LOOPBACK_FAILED;
                        if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
                            tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
-                               data[2] |= TG3_JMB_LOOPBACK_FAILED;
+                               data[TG3_EXT_LOOPB_TEST] |=
+                                                       TG3_JMB_LOOPBACK_FAILED;
                }
 
                /* Re-enable gphy autopowerdown. */
@@ -12415,7 +12465,8 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                        tg3_phy_toggle_apd(tp, true);
        }
 
-       err = (data[0] | data[1] | data[2]) ? -EIO : 0;
+       err = (data[TG3_MAC_LOOPB_TEST] | data[TG3_PHY_LOOPB_TEST] |
+              data[TG3_EXT_LOOPB_TEST]) ? -EIO : 0;
 
 done:
        tp->phy_flags |= eee_cap;
@@ -12440,11 +12491,11 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
 
        if (tg3_test_nvram(tp) != 0) {
                etest->flags |= ETH_TEST_FL_FAILED;
-               data[0] = 1;
+               data[TG3_NVRAM_TEST] = 1;
        }
        if (!doextlpbk && tg3_test_link(tp)) {
                etest->flags |= ETH_TEST_FL_FAILED;
-               data[1] = 1;
+               data[TG3_LINK_TEST] = 1;
        }
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
                int err, err2 = 0, irq_sync = 0;
@@ -12470,25 +12521,25 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
 
                if (tg3_test_registers(tp) != 0) {
                        etest->flags |= ETH_TEST_FL_FAILED;
-                       data[2] = 1;
+                       data[TG3_REGISTER_TEST] = 1;
                }
 
                if (tg3_test_memory(tp) != 0) {
                        etest->flags |= ETH_TEST_FL_FAILED;
-                       data[3] = 1;
+                       data[TG3_MEMORY_TEST] = 1;
                }
 
                if (doextlpbk)
                        etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
 
-               if (tg3_test_loopback(tp, &data[4], doextlpbk))
+               if (tg3_test_loopback(tp, data, doextlpbk))
                        etest->flags |= ETH_TEST_FL_FAILED;
 
                tg3_full_unlock(tp);
 
                if (tg3_test_interrupt(tp) != 0) {
                        etest->flags |= ETH_TEST_FL_FAILED;
-                       data[7] = 1;
+                       data[TG3_INTERRUPT_TEST] = 1;
                }
 
                tg3_full_lock(tp, 0);
@@ -14466,7 +14517,30 @@ static void __devinit tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
                tg3_flag_set(tp, 5705_PLUS);
 }
 
-static int __devinit tg3_get_invariants(struct tg3 *tp)
+static bool tg3_10_100_only_device(struct tg3 *tp,
+                                  const struct pci_device_id *ent)
+{
+       u32 grc_misc_cfg = tr32(GRC_MISC_CFG) & GRC_MISC_CFG_BOARD_ID_MASK;
+
+       if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+           (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
+           (tp->phy_flags & TG3_PHYFLG_IS_FET))
+               return true;
+
+       if (ent->driver_data & TG3_DRV_DATA_FLAG_10_100_ONLY) {
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+                       if (ent->driver_data & TG3_DRV_DATA_FLAG_5705_10_100)
+                               return true;
+               } else {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static int __devinit tg3_get_invariants(struct tg3 *tp,
+                                       const struct pci_device_id *ent)
 {
        u32 misc_ctrl_reg;
        u32 pci_state_reg, grc_misc_cfg;
@@ -15145,22 +15219,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        else
                tp->mac_mode = 0;
 
-       /* these are limited to 10/100 only */
-       if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
-            (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
-           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
-            tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
-            (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901 ||
-             tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2 ||
-             tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
-           (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
-            (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
-             tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F ||
-             tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) ||
-           tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 ||
-           tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
-           tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
-           (tp->phy_flags & TG3_PHYFLG_IS_FET))
+       if (tg3_10_100_only_device(tp, ent))
                tp->phy_flags |= TG3_PHYFLG_10_100_ONLY;
 
        err = tg3_phy_probe(tp);
@@ -16039,7 +16098,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        dev->netdev_ops = &tg3_netdev_ops;
        dev->irq = pdev->irq;
 
-       err = tg3_get_invariants(tp);
+       err = tg3_get_invariants(tp, ent);
        if (err) {
                dev_err(&pdev->dev,
                        "Problem fetching invariants of chip, aborting\n");
index b3c2bf2..4534804 100644 (file)
@@ -44,6 +44,7 @@
 #define  TG3PCI_DEVICE_TIGON3_5761S     0x1688
 #define  TG3PCI_DEVICE_TIGON3_5761SE    0x1689
 #define  TG3PCI_DEVICE_TIGON3_57780     0x1692
+#define  TG3PCI_DEVICE_TIGON3_5787M     0x1693
 #define  TG3PCI_DEVICE_TIGON3_57760     0x1690
 #define  TG3PCI_DEVICE_TIGON3_57790     0x1694
 #define  TG3PCI_DEVICE_TIGON3_57788     0x1691
 #define TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780_2    0x0099
 #define TG3PCI_SUBVENDOR_ID_IBM                        PCI_VENDOR_ID_IBM
 #define TG3PCI_SUBDEVICE_ID_IBM_5703SAX2       0x0281
+#define TG3PCI_SUBDEVICE_ID_ACER_57780_A       0x0601
+#define TG3PCI_SUBDEVICE_ID_ACER_57780_B       0x0612
+#define TG3PCI_SUBDEVICE_ID_LENOVO_5787M       0x3056
+
 /* 0x30 --> 0x64 unused */
 #define TG3PCI_MSI_DATA                        0x00000064
 /* 0x66 --> 0x68 unused */
@@ -3264,6 +3269,7 @@ struct tg3 {
 #if IS_ENABLED(CONFIG_HWMON)
        struct device                   *hwmon_dev;
 #endif
+       bool                            link_up;
 };
 
 #endif /* !(_T3_H) */
index 1fac769..edb2aba 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -107,6 +108,14 @@ void macb_set_hwaddr(struct macb *bp)
        macb_or_gem_writel(bp, SA1B, bottom);
        top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4)));
        macb_or_gem_writel(bp, SA1T, top);
+
+       /* Clear unused address register sets */
+       macb_or_gem_writel(bp, SA2B, 0);
+       macb_or_gem_writel(bp, SA2T, 0);
+       macb_or_gem_writel(bp, SA3B, 0);
+       macb_or_gem_writel(bp, SA3T, 0);
+       macb_or_gem_writel(bp, SA4B, 0);
+       macb_or_gem_writel(bp, SA4T, 0);
 }
 EXPORT_SYMBOL_GPL(macb_set_hwaddr);
 
@@ -261,7 +270,9 @@ static void macb_handle_link_change(struct net_device *dev)
 static int macb_mii_probe(struct net_device *dev)
 {
        struct macb *bp = netdev_priv(dev);
+       struct macb_platform_data *pdata;
        struct phy_device *phydev;
+       int phy_irq;
        int ret;
 
        phydev = phy_find_first(bp->mii_bus);
@@ -270,7 +281,14 @@ static int macb_mii_probe(struct net_device *dev)
                return -1;
        }
 
-       /* TODO : add pin_irq */
+       pdata = dev_get_platdata(&bp->pdev->dev);
+       if (pdata && gpio_is_valid(pdata->phy_irq_pin)) {
+               ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin, "phy int");
+               if (!ret) {
+                       phy_irq = gpio_to_irq(pdata->phy_irq_pin);
+                       phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq;
+               }
+       }
 
        /* attach the mac to the phy */
        ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0,
index 864e380..4414421 100644 (file)
 #define GEM_HRT                                        0x0084
 #define GEM_SA1B                               0x0088
 #define GEM_SA1T                               0x008C
+#define GEM_SA2B                               0x0090
+#define GEM_SA2T                               0x0094
+#define GEM_SA3B                               0x0098
+#define GEM_SA3T                               0x009C
+#define GEM_SA4B                               0x00A0
+#define GEM_SA4T                               0x00A4
 #define GEM_OTX                                        0x0100
 #define GEM_DCFG1                              0x0280
 #define GEM_DCFG2                              0x0284
index 7654a62..02c2477 100644 (file)
@@ -80,6 +80,29 @@ do {                                                         \
 
 #define CPSW_VERSION_1         0x19010a
 #define CPSW_VERSION_2         0x19010c
+
+#define HOST_PORT_NUM          0
+#define SLIVER_SIZE            0x40
+
+#define CPSW1_HOST_PORT_OFFSET 0x028
+#define CPSW1_SLAVE_OFFSET     0x050
+#define CPSW1_SLAVE_SIZE       0x040
+#define CPSW1_CPDMA_OFFSET     0x100
+#define CPSW1_STATERAM_OFFSET  0x200
+#define CPSW1_CPTS_OFFSET      0x500
+#define CPSW1_ALE_OFFSET       0x600
+#define CPSW1_SLIVER_OFFSET    0x700
+
+#define CPSW2_HOST_PORT_OFFSET 0x108
+#define CPSW2_SLAVE_OFFSET     0x200
+#define CPSW2_SLAVE_SIZE       0x100
+#define CPSW2_CPDMA_OFFSET     0x800
+#define CPSW2_STATERAM_OFFSET  0xa00
+#define CPSW2_CPTS_OFFSET      0xc00
+#define CPSW2_ALE_OFFSET       0xd00
+#define CPSW2_SLIVER_OFFSET    0xd80
+#define CPSW2_BD_OFFSET                0x2000
+
 #define CPDMA_RXTHRESH         0x0c0
 #define CPDMA_RXFREE           0x0e0
 #define CPDMA_TXHDP            0x00
@@ -87,21 +110,6 @@ do {                                                                \
 #define CPDMA_TXCP             0x40
 #define CPDMA_RXCP             0x60
 
-#define cpsw_dma_regs(base, offset)            \
-       (void __iomem *)((base) + (offset))
-#define cpsw_dma_rxthresh(base, offset)                \
-       (void __iomem *)((base) + (offset) + CPDMA_RXTHRESH)
-#define cpsw_dma_rxfree(base, offset)          \
-       (void __iomem *)((base) + (offset) + CPDMA_RXFREE)
-#define cpsw_dma_txhdp(base, offset)           \
-       (void __iomem *)((base) + (offset) + CPDMA_TXHDP)
-#define cpsw_dma_rxhdp(base, offset)           \
-       (void __iomem *)((base) + (offset) + CPDMA_RXHDP)
-#define cpsw_dma_txcp(base, offset)            \
-       (void __iomem *)((base) + (offset) + CPDMA_TXCP)
-#define cpsw_dma_rxcp(base, offset)            \
-       (void __iomem *)((base) + (offset) + CPDMA_RXCP)
-
 #define CPSW_POLL_WEIGHT       64
 #define CPSW_MIN_PACKET_SIZE   60
 #define CPSW_MAX_PACKET_SIZE   (1500 + 14 + 4 + 4)
@@ -629,8 +637,7 @@ static int cpsw_ndo_open(struct net_device *ndev)
 
        pm_runtime_get_sync(&priv->pdev->dev);
 
-       reg = __raw_readl(&priv->regs->id_ver);
-       priv->version = reg;
+       reg = priv->version;
 
        dev_info(priv->dev, "initializing cpsw version %d.%d (%d)\n",
                 CPSW_MAJOR_VERSION(reg), CPSW_MINOR_VERSION(reg),
@@ -691,12 +698,12 @@ static int cpsw_ndo_stop(struct net_device *ndev)
        struct cpsw_priv *priv = netdev_priv(ndev);
 
        cpsw_info(priv, ifdown, "shutting down cpsw device\n");
-       cpsw_intr_disable(priv);
-       cpdma_ctlr_int_ctrl(priv->dma, false);
-       cpdma_ctlr_stop(priv->dma);
        netif_stop_queue(priv->ndev);
        napi_disable(&priv->napi);
        netif_carrier_off(priv->ndev);
+       cpsw_intr_disable(priv);
+       cpdma_ctlr_int_ctrl(priv->dma, false);
+       cpdma_ctlr_stop(priv->dma);
        cpsw_ale_stop(priv->ale);
        for_each_slave(priv, cpsw_slave_stop, priv);
        pm_runtime_put_sync(&priv->pdev->dev);
@@ -995,15 +1002,16 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
        .get_ts_info    = cpsw_get_ts_info,
 };
 
-static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
+static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
+                           u32 slave_reg_ofs, u32 sliver_reg_ofs)
 {
        void __iomem            *regs = priv->regs;
        int                     slave_num = slave->slave_num;
        struct cpsw_slave_data  *data = priv->data.slave_data + slave_num;
 
        slave->data     = data;
-       slave->regs     = regs + data->slave_reg_ofs;
-       slave->sliver   = regs + data->sliver_reg_ofs;
+       slave->regs     = regs + slave_reg_ofs;
+       slave->sliver   = regs + sliver_reg_ofs;
 }
 
 static int cpsw_probe_dt(struct cpsw_platform_data *data,
@@ -1051,8 +1059,6 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                return -EINVAL;
        }
 
-       data->no_bd_ram = of_property_read_bool(node, "no_bd_ram");
-
        if (of_property_read_u32(node, "cpdma_channels", &prop)) {
                pr_err("Missing cpdma_channels property in the DT.\n");
                ret = -EINVAL;
@@ -1060,34 +1066,6 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
        }
        data->channels = prop;
 
-       if (of_property_read_u32(node, "host_port_no", &prop)) {
-               pr_err("Missing host_port_no property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->host_port_num = prop;
-
-       if (of_property_read_u32(node, "cpdma_reg_ofs", &prop)) {
-               pr_err("Missing cpdma_reg_ofs property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->cpdma_reg_ofs = prop;
-
-       if (of_property_read_u32(node, "cpdma_sram_ofs", &prop)) {
-               pr_err("Missing cpdma_sram_ofs property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->cpdma_sram_ofs = prop;
-
-       if (of_property_read_u32(node, "ale_reg_ofs", &prop)) {
-               pr_err("Missing ale_reg_ofs property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->ale_reg_ofs = prop;
-
        if (of_property_read_u32(node, "ale_entries", &prop)) {
                pr_err("Missing ale_entries property in the DT.\n");
                ret = -EINVAL;
@@ -1095,34 +1073,6 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
        }
        data->ale_entries = prop;
 
-       if (of_property_read_u32(node, "host_port_reg_ofs", &prop)) {
-               pr_err("Missing host_port_reg_ofs property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->host_port_reg_ofs = prop;
-
-       if (of_property_read_u32(node, "hw_stats_reg_ofs", &prop)) {
-               pr_err("Missing hw_stats_reg_ofs property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->hw_stats_reg_ofs = prop;
-
-       if (of_property_read_u32(node, "cpts_reg_ofs", &prop)) {
-               pr_err("Missing cpts_reg_ofs property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->cpts_reg_ofs = prop;
-
-       if (of_property_read_u32(node, "bd_ram_ofs", &prop)) {
-               pr_err("Missing bd_ram_ofs property in the DT.\n");
-               ret = -EINVAL;
-               goto error_ret;
-       }
-       data->bd_ram_ofs = prop;
-
        if (of_property_read_u32(node, "bd_ram_size", &prop)) {
                pr_err("Missing bd_ram_size property in the DT.\n");
                ret = -EINVAL;
@@ -1144,33 +1094,34 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
        }
        data->mac_control = prop;
 
-       for_each_child_of_node(node, slave_node) {
+       /*
+        * Populate all the child nodes here...
+        */
+       ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+       /* We do not want to force this, as in some cases may not have child */
+       if (ret)
+               pr_warn("Doesn't have any child node\n");
+
+       for_each_node_by_name(slave_node, "slave") {
                struct cpsw_slave_data *slave_data = data->slave_data + i;
-               const char *phy_id = NULL;
                const void *mac_addr = NULL;
-
-               if (of_property_read_string(slave_node, "phy_id", &phy_id)) {
+               u32 phyid;
+               int lenp;
+               const __be32 *parp;
+               struct device_node *mdio_node;
+               struct platform_device *mdio;
+
+               parp = of_get_property(slave_node, "phy_id", &lenp);
+               if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
                        pr_err("Missing slave[%d] phy_id property\n", i);
                        ret = -EINVAL;
                        goto error_ret;
                }
-               slave_data->phy_id = phy_id;
-
-               if (of_property_read_u32(slave_node, "slave_reg_ofs", &prop)) {
-                       pr_err("Missing slave[%d] slave_reg_ofs property\n", i);
-                       ret = -EINVAL;
-                       goto error_ret;
-               }
-               slave_data->slave_reg_ofs = prop;
-
-               if (of_property_read_u32(slave_node, "sliver_reg_ofs",
-                                        &prop)) {
-                       pr_err("Missing slave[%d] sliver_reg_ofs property\n",
-                               i);
-                       ret = -EINVAL;
-                       goto error_ret;
-               }
-               slave_data->sliver_reg_ofs = prop;
+               mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
+               phyid = be32_to_cpup(parp+1);
+               mdio = of_find_device_by_node(mdio_node);
+               snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+                        PHY_ID_FMT, mdio->name, phyid);
 
                mac_addr = of_get_mac_address(slave_node);
                if (mac_addr)
@@ -1193,8 +1144,9 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
        struct cpsw_priv                *priv;
        struct cpdma_params             dma_params;
        struct cpsw_ale_params          ale_params;
-       void __iomem                    *regs;
+       void __iomem                    *ss_regs, *wr_regs;
        struct resource                 *res;
+       u32 slave_offset, sliver_offset, slave_size;
        int ret = 0, i, k = 0;
 
        ndev = alloc_etherdev(sizeof(struct cpsw_priv));
@@ -1212,6 +1164,11 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
        priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
        priv->rx_packet_max = max(rx_packet_max, 128);
 
+       /*
+        * This may be required here for child devices.
+        */
+       pm_runtime_enable(&pdev->dev);
+
        if (cpsw_probe_dt(&priv->data, pdev)) {
                pr_err("cpsw: platform data missing\n");
                ret = -ENODEV;
@@ -1238,7 +1195,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
        for (i = 0; i < data->slaves; i++)
                priv->slaves[i].slave_num = i;
 
-       pm_runtime_enable(&pdev->dev);
        priv->clk = clk_get(&pdev->dev, "fck");
        if (IS_ERR(priv->clk)) {
                dev_err(&pdev->dev, "fck is not found\n");
@@ -1258,15 +1214,14 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
                ret = -ENXIO;
                goto clean_clk_ret;
        }
-       regs = ioremap(priv->cpsw_res->start, resource_size(priv->cpsw_res));
-       if (!regs) {
+       ss_regs = ioremap(priv->cpsw_res->start, resource_size(priv->cpsw_res));
+       if (!ss_regs) {
                dev_err(priv->dev, "unable to map i/o region\n");
                goto clean_cpsw_iores_ret;
        }
-       priv->regs = regs;
-       priv->host_port = data->host_port_num;
-       priv->host_port_regs = regs + data->host_port_reg_ofs;
-       priv->cpts.reg = regs + data->cpts_reg_ofs;
+       priv->regs = ss_regs;
+       priv->version = __raw_readl(&priv->regs->id_ver);
+       priv->host_port = HOST_PORT_NUM;
 
        priv->cpsw_wr_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!priv->cpsw_wr_res) {
@@ -1280,32 +1235,59 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
                ret = -ENXIO;
                goto clean_iomap_ret;
        }
-       regs = ioremap(priv->cpsw_wr_res->start,
+       wr_regs = ioremap(priv->cpsw_wr_res->start,
                                resource_size(priv->cpsw_wr_res));
-       if (!regs) {
+       if (!wr_regs) {
                dev_err(priv->dev, "unable to map i/o region\n");
                goto clean_cpsw_wr_iores_ret;
        }
-       priv->wr_regs = regs;
-
-       for_each_slave(priv, cpsw_slave_init, priv);
+       priv->wr_regs = wr_regs;
 
        memset(&dma_params, 0, sizeof(dma_params));
+       memset(&ale_params, 0, sizeof(ale_params));
+
+       switch (priv->version) {
+       case CPSW_VERSION_1:
+               priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
+               priv->cpts.reg       = ss_regs + CPSW1_CPTS_OFFSET;
+               dma_params.dmaregs   = ss_regs + CPSW1_CPDMA_OFFSET;
+               dma_params.txhdp     = ss_regs + CPSW1_STATERAM_OFFSET;
+               ale_params.ale_regs  = ss_regs + CPSW1_ALE_OFFSET;
+               slave_offset         = CPSW1_SLAVE_OFFSET;
+               slave_size           = CPSW1_SLAVE_SIZE;
+               sliver_offset        = CPSW1_SLIVER_OFFSET;
+               dma_params.desc_mem_phys = 0;
+               break;
+       case CPSW_VERSION_2:
+               priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
+               priv->cpts.reg       = ss_regs + CPSW2_CPTS_OFFSET;
+               dma_params.dmaregs   = ss_regs + CPSW2_CPDMA_OFFSET;
+               dma_params.txhdp     = ss_regs + CPSW2_STATERAM_OFFSET;
+               ale_params.ale_regs  = ss_regs + CPSW2_ALE_OFFSET;
+               slave_offset         = CPSW2_SLAVE_OFFSET;
+               slave_size           = CPSW2_SLAVE_SIZE;
+               sliver_offset        = CPSW2_SLIVER_OFFSET;
+               dma_params.desc_mem_phys =
+                       (u32 __force) priv->cpsw_res->start + CPSW2_BD_OFFSET;
+               break;
+       default:
+               dev_err(priv->dev, "unknown version 0x%08x\n", priv->version);
+               ret = -ENODEV;
+               goto clean_cpsw_wr_iores_ret;
+       }
+       for (i = 0; i < priv->data.slaves; i++) {
+               struct cpsw_slave *slave = &priv->slaves[i];
+               cpsw_slave_init(slave, priv, slave_offset, sliver_offset);
+               slave_offset  += slave_size;
+               sliver_offset += SLIVER_SIZE;
+       }
+
        dma_params.dev          = &pdev->dev;
-       dma_params.dmaregs      = cpsw_dma_regs((u32)priv->regs,
-                                               data->cpdma_reg_ofs);
-       dma_params.rxthresh     = cpsw_dma_rxthresh((u32)priv->regs,
-                                                   data->cpdma_reg_ofs);
-       dma_params.rxfree       = cpsw_dma_rxfree((u32)priv->regs,
-                                                 data->cpdma_reg_ofs);
-       dma_params.txhdp        = cpsw_dma_txhdp((u32)priv->regs,
-                                                data->cpdma_sram_ofs);
-       dma_params.rxhdp        = cpsw_dma_rxhdp((u32)priv->regs,
-                                                data->cpdma_sram_ofs);
-       dma_params.txcp         = cpsw_dma_txcp((u32)priv->regs,
-                                               data->cpdma_sram_ofs);
-       dma_params.rxcp         = cpsw_dma_rxcp((u32)priv->regs,
-                                               data->cpdma_sram_ofs);
+       dma_params.rxthresh     = dma_params.dmaregs + CPDMA_RXTHRESH;
+       dma_params.rxfree       = dma_params.dmaregs + CPDMA_RXFREE;
+       dma_params.rxhdp        = dma_params.txhdp + CPDMA_RXHDP;
+       dma_params.txcp         = dma_params.txhdp + CPDMA_TXCP;
+       dma_params.rxcp         = dma_params.txhdp + CPDMA_RXCP;
 
        dma_params.num_chan             = data->channels;
        dma_params.has_soft_reset       = true;
@@ -1313,10 +1295,7 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
        dma_params.desc_mem_size        = data->bd_ram_size;
        dma_params.desc_align           = 16;
        dma_params.has_ext_regs         = true;
-       dma_params.desc_mem_phys        = data->no_bd_ram ? 0 :
-                       (u32 __force)priv->cpsw_res->start + data->bd_ram_ofs;
-       dma_params.desc_hw_addr         = data->hw_ram_addr ?
-                       data->hw_ram_addr : dma_params.desc_mem_phys ;
+       dma_params.desc_hw_addr         = dma_params.desc_mem_phys;
 
        priv->dma = cpdma_ctlr_create(&dma_params);
        if (!priv->dma) {
@@ -1336,10 +1315,7 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
                goto clean_dma_ret;
        }
 
-       memset(&ale_params, 0, sizeof(ale_params));
        ale_params.dev                  = &ndev->dev;
-       ale_params.ale_regs             = (void *)((u32)priv->regs) +
-                                               ((u32)data->ale_reg_ofs);
        ale_params.ale_ageout           = ale_ageout;
        ale_params.ale_entries          = data->ale_entries;
        ale_params.ale_ports            = data->slaves;
index 51a96db..ae74280 100644 (file)
@@ -465,7 +465,7 @@ static int davinci_mdio_resume(struct device *dev)
        u32 ctrl;
 
        spin_lock(&data->lock);
-       pm_runtime_put_sync(data->dev);
+       pm_runtime_get_sync(data->dev);
 
        /* restart the scan state machine */
        ctrl = __raw_readl(&data->regs->control);
index 961c832..72b775f 100644 (file)
@@ -452,7 +452,7 @@ static size_t gelic_wl_synthesize_ie(u8 *buf,
        if (rsn)
                *buf++ = WLAN_EID_RSN;
        else
-               *buf++ = WLAN_EID_GENERIC;
+               *buf++ = WLAN_EID_VENDOR_SPECIFIC;
 
        /* length filed; set later */
        buf++;
@@ -540,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
                        break;
 
                switch (item_id) {
-               case WLAN_EID_GENERIC:
+               case WLAN_EID_VENDOR_SPECIFIC:
                        if ((OUI_LEN + 1 <= item_len) &&
                            !memcmp(pos, wpa_oui, OUI_LEN) &&
                            pos[OUI_LEN] == 0x01) {
index 81c7bc0..383e833 100644 (file)
@@ -150,18 +150,24 @@ static struct phy_driver dm91xx_driver[] = {
        .name           = "Davicom DM9161E",
        .phy_id_mask    = 0x0ffffff0,
        .features       = PHY_BASIC_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
        .config_init    = dm9161_config_init,
        .config_aneg    = dm9161_config_aneg,
        .read_status    = genphy_read_status,
+       .ack_interrupt  = dm9161_ack_interrupt,
+       .config_intr    = dm9161_config_intr,
        .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = 0x0181b8a0,
        .name           = "Davicom DM9161A",
        .phy_id_mask    = 0x0ffffff0,
        .features       = PHY_BASIC_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
        .config_init    = dm9161_config_init,
        .config_aneg    = dm9161_config_aneg,
        .read_status    = genphy_read_status,
+       .ack_interrupt  = dm9161_ack_interrupt,
+       .config_intr    = dm9161_config_intr,
        .driver         = { .owner = THIS_MODULE,},
 }, {
        .phy_id         = 0x00181b80,
index 7e9622f..e4a192b 100644 (file)
@@ -1094,10 +1094,10 @@ vmxnet3_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 
-               BUG_ON(skb->queue_mapping > adapter->num_tx_queues);
-               return vmxnet3_tq_xmit(skb,
-                                      &adapter->tx_queue[skb->queue_mapping],
-                                      adapter, netdev);
+       BUG_ON(skb->queue_mapping > adapter->num_tx_queues);
+       return vmxnet3_tq_xmit(skb,
+                              &adapter->tx_queue[skb->queue_mapping],
+                              adapter, netdev);
 }
 
 
@@ -1243,8 +1243,8 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                        skb_reserve(new_skb, NET_IP_ALIGN);
                        rbi->skb = new_skb;
                        rbi->dma_addr = pci_map_single(adapter->pdev,
-                                       rbi->skb->data, rbi->len,
-                                       PCI_DMA_FROMDEVICE);
+                                                      rbi->skb->data, rbi->len,
+                                                      PCI_DMA_FROMDEVICE);
                        rxd->addr = cpu_to_le64(rbi->dma_addr);
                        rxd->len = rbi->len;
 
@@ -1331,14 +1331,14 @@ rcd_done:
                /* if needed, update the register */
                if (unlikely(rq->shared->updateRxProd)) {
                        VMXNET3_WRITE_BAR0_REG(adapter,
-                               rxprod_reg[ring_idx] + rq->qid * 8,
-                               ring->next2fill);
+                                              rxprod_reg[ring_idx] + rq->qid * 8,
+                                              ring->next2fill);
                        rq->uncommitted[ring_idx] = 0;
                }
 
                vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
                vmxnet3_getRxComp(rcd,
-                    &rq->comp_ring.base[rq->comp_ring.next2proc].rcd, &rxComp);
+                                 &rq->comp_ring.base[rq->comp_ring.next2proc].rcd, &rxComp);
        }
 
        return num_rxd;
@@ -2949,11 +2949,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
 
        spin_lock_init(&adapter->cmd_lock);
        adapter->shared = pci_alloc_consistent(adapter->pdev,
-                         sizeof(struct Vmxnet3_DriverShared),
-                         &adapter->shared_pa);
+                                              sizeof(struct Vmxnet3_DriverShared),
+                                              &adapter->shared_pa);
        if (!adapter->shared) {
                printk(KERN_ERR "Failed to allocate memory for %s\n",
-                       pci_name(pdev));
+                      pci_name(pdev));
                err = -ENOMEM;
                goto err_alloc_shared;
        }
@@ -2964,16 +2964,16 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;
        size += sizeof(struct Vmxnet3_RxQueueDesc) * adapter->num_rx_queues;
        adapter->tqd_start = pci_alloc_consistent(adapter->pdev, size,
-                            &adapter->queue_desc_pa);
+                                                 &adapter->queue_desc_pa);
 
        if (!adapter->tqd_start) {
                printk(KERN_ERR "Failed to allocate memory for %s\n",
-                       pci_name(pdev));
+                      pci_name(pdev));
                err = -ENOMEM;
                goto err_alloc_queue_desc;
        }
        adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start +
-                                                       adapter->num_tx_queues);
+                                                           adapter->num_tx_queues);
 
        adapter->pm_conf = kmalloc(sizeof(struct Vmxnet3_PMConf), GFP_KERNEL);
        if (adapter->pm_conf == NULL) {
@@ -3019,7 +3019,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
 
        adapter->dev_number = atomic_read(&devices_found);
 
-        adapter->share_intr = irq_share_mode;
+       adapter->share_intr = irq_share_mode;
        if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE &&
            adapter->num_tx_queues != adapter->num_rx_queues)
                adapter->share_intr = VMXNET3_INTR_DONTSHARE;
@@ -3065,7 +3065,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
 
        if (err) {
                printk(KERN_ERR "Failed to register adapter %s\n",
-                       pci_name(pdev));
+                      pci_name(pdev));
                goto err_register;
        }
 
index 8aca888..9814d67 100644 (file)
@@ -769,7 +769,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 
        vxlan_set_owner(dev, skb);
 
-       /* See __IPTUNNEL_XMIT */
+       /* See iptunnel_xmit() */
        skb->ip_summed = CHECKSUM_NONE;
        ip_select_ident(iph, &rt->dst, NULL);
 
index 3cd05a7..57f7db1 100644 (file)
@@ -7433,7 +7433,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
                                        num_null_ies++;
                                break;
 
-                       case WLAN_EID_GENERIC:
+                       case WLAN_EID_VENDOR_SPECIFIC:
                                if (ie[1] >= 4 &&
                                    ie[2] == 0x00 &&
                                    ie[3] == 0x50 &&
index 0960224..c25dcf1 100644 (file)
@@ -26,5 +26,6 @@ source "drivers/net/wireless/ath/ath5k/Kconfig"
 source "drivers/net/wireless/ath/ath9k/Kconfig"
 source "drivers/net/wireless/ath/carl9170/Kconfig"
 source "drivers/net/wireless/ath/ath6kl/Kconfig"
+source "drivers/net/wireless/ath/ar5523/Kconfig"
 
 endif
index d716b74..1e18621 100644 (file)
@@ -2,6 +2,7 @@ obj-$(CONFIG_ATH5K)             += ath5k/
 obj-$(CONFIG_ATH9K_HW)         += ath9k/
 obj-$(CONFIG_CARL9170)         += carl9170/
 obj-$(CONFIG_ATH6KL)           += ath6kl/
+obj-$(CONFIG_AR5523)           += ar5523/
 
 obj-$(CONFIG_ATH_COMMON)       += ath.o
 
diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig
new file mode 100644 (file)
index 0000000..11d99ee
--- /dev/null
@@ -0,0 +1,7 @@
+config AR5523
+       tristate "Atheros AR5523 wireless driver support"
+       depends on MAC80211 && USB
+       select FW_LOADER
+       ---help---
+         This module add support for AR5523 based USB dongles such as D-Link
+         DWL-G132, Netgear WPN111 and many more.
diff --git a/drivers/net/wireless/ath/ar5523/Makefile b/drivers/net/wireless/ath/ar5523/Makefile
new file mode 100644 (file)
index 0000000..ebf7f3b
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_AR5523)   := ar5523.o
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
new file mode 100644 (file)
index 0000000..f782b6e
--- /dev/null
@@ -0,0 +1,1806 @@
+/*
+ * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007 Christoph Hellwig <hch@lst.de>
+ * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
+ * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com>
+ *
+ * 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.
+ */
+
+/*
+ * This driver is based on the uath driver written by Damien Bergamini for
+ * OpenBSD, who did black-box analysis of the Windows binary driver to find
+ * out how the hardware works.  It contains a lot magic numbers because of
+ * that and only has minimal functionality.
+ */
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/firmware.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+#include <net/mac80211.h>
+
+#include "ar5523.h"
+#include "ar5523_hw.h"
+
+/*
+ * Various supported device vendors/products.
+ * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11a/b/g
+ */
+
+static int ar5523_submit_rx_cmd(struct ar5523 *ar);
+static void ar5523_data_tx_pkt_put(struct ar5523 *ar);
+
+static void ar5523_read_reply(struct ar5523 *ar, struct ar5523_cmd_hdr *hdr,
+                             struct ar5523_tx_cmd *cmd)
+{
+       int dlen, olen;
+       u32 *rp;
+
+       dlen = hdr->len - sizeof(*hdr);
+
+       if (dlen < 0) {
+               WARN_ON(1);
+               goto out;
+       }
+
+       ar5523_dbg(ar, "Code = %d len = %d\n", hdr->code & 0xff, dlen);
+
+       rp = (u32 *)(hdr + 1);
+       if (dlen >= sizeof(u32)) {
+               olen = be32_to_cpu(rp[0]);
+               dlen -= sizeof(u32);
+               if (olen == 0) {
+                       /* convention is 0 =>'s one word */
+                       olen = sizeof(u32);
+               }
+       } else
+               olen = 0;
+
+       if (cmd->odata) {
+               if (cmd->olen < olen) {
+                       ar5523_err(ar, "olen to small %d < %d\n",
+                                  cmd->olen, olen);
+                       cmd->olen = 0;
+                       cmd->res = -EOVERFLOW;
+               } else {
+                       cmd->olen = olen;
+                       memcpy(cmd->odata, &rp[1], olen);
+                       cmd->res = 0;
+               }
+       }
+
+out:
+       complete(&cmd->done);
+}
+
+static void ar5523_cmd_rx_cb(struct urb *urb)
+{
+       struct ar5523 *ar = urb->context;
+       struct ar5523_tx_cmd *cmd = &ar->tx_cmd;
+       struct ar5523_cmd_hdr *hdr = ar->rx_cmd_buf;
+       int dlen;
+
+       if (urb->status) {
+               if (urb->status != -ESHUTDOWN)
+                       ar5523_err(ar, "RX USB error %d.\n", urb->status);
+               goto skip;
+       }
+
+       if (urb->actual_length < sizeof(struct ar5523_cmd_hdr)) {
+               ar5523_err(ar, "RX USB to short.\n");
+               goto skip;
+       }
+
+       ar5523_dbg(ar, "%s code %02x priv %d\n", __func__,
+                  be32_to_cpu(hdr->code) & 0xff, hdr->priv);
+
+       hdr->code = be32_to_cpu(hdr->code);
+       hdr->len = be32_to_cpu(hdr->len);
+
+       switch (hdr->code & 0xff) {
+       default:
+               /* reply to a read command */
+               if (hdr->priv != AR5523_CMD_ID) {
+                       ar5523_err(ar, "Unexpected command id: %02x\n",
+                                  hdr->code & 0xff);
+                       goto skip;
+               }
+               ar5523_read_reply(ar, hdr, cmd);
+               break;
+
+       case WDCMSG_DEVICE_AVAIL:
+               ar5523_dbg(ar, "WDCMSG_DEVICE_AVAIL\n");
+               cmd->res = 0;
+               cmd->olen = 0;
+               complete(&cmd->done);
+               break;
+
+       case WDCMSG_SEND_COMPLETE:
+               ar5523_dbg(ar, "WDCMSG_SEND_COMPLETE: %d pending\n",
+                       atomic_read(&ar->tx_nr_pending));
+               if (!test_bit(AR5523_HW_UP, &ar->flags))
+                       ar5523_dbg(ar, "Unexpected WDCMSG_SEND_COMPLETE\n");
+               else {
+                       mod_timer(&ar->tx_wd_timer,
+                                 jiffies + AR5523_TX_WD_TIMEOUT);
+                       ar5523_data_tx_pkt_put(ar);
+
+               }
+               break;
+
+       case WDCMSG_TARGET_START:
+               /* This command returns a bogus id so it needs special
+                  handling */
+               dlen = hdr->len - sizeof(*hdr);
+               if (dlen != (int)sizeof(u32)) {
+                       ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START");
+                       return;
+               }
+               memcpy(cmd->odata, hdr + 1, sizeof(u32));
+               cmd->olen = sizeof(u32);
+               cmd->res = 0;
+               complete(&cmd->done);
+               break;
+
+       case WDCMSG_STATS_UPDATE:
+               ar5523_dbg(ar, "WDCMSG_STATS_UPDATE\n");
+               break;
+       }
+
+skip:
+       ar5523_submit_rx_cmd(ar);
+}
+
+static int ar5523_alloc_rx_cmd(struct ar5523 *ar)
+{
+       ar->rx_cmd_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!ar->rx_cmd_urb)
+               return -ENOMEM;
+
+       ar->rx_cmd_buf = usb_alloc_coherent(ar->dev, AR5523_MAX_RXCMDSZ,
+                                           GFP_KERNEL,
+                                           &ar->rx_cmd_urb->transfer_dma);
+       if (!ar->rx_cmd_buf) {
+               usb_free_urb(ar->rx_cmd_urb);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void ar5523_cancel_rx_cmd(struct ar5523 *ar)
+{
+       usb_kill_urb(ar->rx_cmd_urb);
+}
+
+static void ar5523_free_rx_cmd(struct ar5523 *ar)
+{
+       usb_free_coherent(ar->dev, AR5523_MAX_RXCMDSZ,
+                         ar->rx_cmd_buf, ar->rx_cmd_urb->transfer_dma);
+       usb_free_urb(ar->rx_cmd_urb);
+}
+
+static int ar5523_submit_rx_cmd(struct ar5523 *ar)
+{
+       int error;
+
+       usb_fill_bulk_urb(ar->rx_cmd_urb, ar->dev,
+                         ar5523_cmd_rx_pipe(ar->dev), ar->rx_cmd_buf,
+                         AR5523_MAX_RXCMDSZ, ar5523_cmd_rx_cb, ar);
+       ar->rx_cmd_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       error = usb_submit_urb(ar->rx_cmd_urb, GFP_ATOMIC);
+       if (error) {
+               if (error != -ENODEV)
+                       ar5523_err(ar, "error %d when submitting rx urb\n",
+                                  error);
+               return error;
+       }
+       return 0;
+}
+
+/*
+ * Command submitted cb
+ */
+static void ar5523_cmd_tx_cb(struct urb *urb)
+{
+       struct ar5523_tx_cmd *cmd = urb->context;
+       struct ar5523 *ar = cmd->ar;
+
+       if (urb->status) {
+               ar5523_err(ar, "Failed to TX command. Status = %d\n",
+                          urb->status);
+               cmd->res = urb->status;
+               complete(&cmd->done);
+               return;
+       }
+
+       if (!(cmd->flags & AR5523_CMD_FLAG_READ)) {
+               cmd->res = 0;
+               complete(&cmd->done);
+       }
+}
+
+static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata,
+                     int ilen, void *odata, int olen, int flags)
+{
+       struct ar5523_cmd_hdr *hdr;
+       struct ar5523_tx_cmd *cmd = &ar->tx_cmd;
+       int xferlen, error;
+
+       /* always bulk-out a multiple of 4 bytes */
+       xferlen = (sizeof(struct ar5523_cmd_hdr) + ilen + 3) & ~3;
+
+       hdr = (struct ar5523_cmd_hdr *)cmd->buf_tx;
+       memset(hdr, 0, sizeof(struct ar5523_cmd_hdr));
+       hdr->len  = cpu_to_be32(xferlen);
+       hdr->code = cpu_to_be32(code);
+       hdr->priv = AR5523_CMD_ID;
+
+       if (flags & AR5523_CMD_FLAG_MAGIC)
+               hdr->magic = cpu_to_be32(1 << 24);
+       memcpy(hdr + 1, idata, ilen);
+
+       cmd->odata = odata;
+       cmd->olen = olen;
+       cmd->flags = flags;
+
+       ar5523_dbg(ar, "do cmd %02x\n", code);
+
+       usb_fill_bulk_urb(cmd->urb_tx, ar->dev, ar5523_cmd_tx_pipe(ar->dev),
+                         cmd->buf_tx, xferlen, ar5523_cmd_tx_cb, cmd);
+       cmd->urb_tx->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       error = usb_submit_urb(cmd->urb_tx, GFP_KERNEL);
+       if (error) {
+               ar5523_err(ar, "could not send command 0x%x, error=%d\n",
+                          code, error);
+               return error;
+       }
+
+       if (!wait_for_completion_timeout(&cmd->done, 2 * HZ)) {
+               cmd->odata = NULL;
+               ar5523_err(ar, "timeout waiting for command %02x reply\n",
+                          code);
+               cmd->res = -ETIMEDOUT;
+       }
+       return cmd->res;
+}
+
+static int ar5523_cmd_write(struct ar5523 *ar, u32 code, const void *data,
+                           int len, int flags)
+{
+       flags &= ~AR5523_CMD_FLAG_READ;
+       return ar5523_cmd(ar, code, data, len, NULL, 0, flags);
+}
+
+static int ar5523_cmd_read(struct ar5523 *ar, u32 code, const void *idata,
+                          int ilen, void *odata, int olen, int flags)
+{
+       flags |= AR5523_CMD_FLAG_READ;
+       return ar5523_cmd(ar, code, idata, ilen, odata, olen, flags);
+}
+
+static int ar5523_config(struct ar5523 *ar, u32 reg, u32 val)
+{
+       struct ar5523_write_mac write;
+       int error;
+
+       write.reg = cpu_to_be32(reg);
+       write.len = cpu_to_be32(0);     /* 0 = single write */
+       *(u32 *)write.data = cpu_to_be32(val);
+
+       error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write,
+                                3 * sizeof(u32), 0);
+       if (error != 0)
+               ar5523_err(ar, "could not write register 0x%02x\n", reg);
+       return error;
+}
+
+static int ar5523_config_multi(struct ar5523 *ar, u32 reg, const void *data,
+                              int len)
+{
+       struct ar5523_write_mac write;
+       int error;
+
+       write.reg = cpu_to_be32(reg);
+       write.len = cpu_to_be32(len);
+       memcpy(write.data, data, len);
+
+       /* properly handle the case where len is zero (reset) */
+       error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write,
+           (len == 0) ? sizeof(u32) : 2 * sizeof(u32) + len, 0);
+       if (error != 0)
+               ar5523_err(ar, "could not write %d bytes to register 0x%02x\n",
+                          len, reg);
+       return error;
+}
+
+static int ar5523_get_status(struct ar5523 *ar, u32 which, void *odata,
+                            int olen)
+{
+       int error;
+
+       which = cpu_to_be32(which);
+       error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_STATUS,
+           &which, sizeof(which), odata, olen, AR5523_CMD_FLAG_MAGIC);
+       if (error != 0)
+               ar5523_err(ar, "could not read EEPROM offset 0x%02x\n",
+                          be32_to_cpu(which));
+       return error;
+}
+
+static int ar5523_get_capability(struct ar5523 *ar, u32 cap, u32 *val)
+{
+       int error;
+
+       cap = cpu_to_be32(cap);
+       error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY,
+           &cap, sizeof(cap), val, sizeof(u32), AR5523_CMD_FLAG_MAGIC);
+       if (error != 0) {
+               ar5523_err(ar, "could not read capability %u\n",
+                          be32_to_cpu(cap));
+               return error;
+       }
+       *val = be32_to_cpu(*val);
+       return error;
+}
+
+static int ar5523_get_devcap(struct ar5523 *ar)
+{
+#define        GETCAP(x) do {                          \
+       error = ar5523_get_capability(ar, x, &cap);             \
+       if (error != 0)                                 \
+               return error;                           \
+       ar5523_info(ar, "Cap: "                 \
+           "%s=0x%08x\n", #x, cap);    \
+} while (0)
+       int error;
+       u32 cap;
+
+       /* collect device capabilities */
+       GETCAP(CAP_TARGET_VERSION);
+       GETCAP(CAP_TARGET_REVISION);
+       GETCAP(CAP_MAC_VERSION);
+       GETCAP(CAP_MAC_REVISION);
+       GETCAP(CAP_PHY_REVISION);
+       GETCAP(CAP_ANALOG_5GHz_REVISION);
+       GETCAP(CAP_ANALOG_2GHz_REVISION);
+
+       GETCAP(CAP_REG_DOMAIN);
+       GETCAP(CAP_REG_CAP_BITS);
+       GETCAP(CAP_WIRELESS_MODES);
+       GETCAP(CAP_CHAN_SPREAD_SUPPORT);
+       GETCAP(CAP_COMPRESS_SUPPORT);
+       GETCAP(CAP_BURST_SUPPORT);
+       GETCAP(CAP_FAST_FRAMES_SUPPORT);
+       GETCAP(CAP_CHAP_TUNING_SUPPORT);
+       GETCAP(CAP_TURBOG_SUPPORT);
+       GETCAP(CAP_TURBO_PRIME_SUPPORT);
+       GETCAP(CAP_DEVICE_TYPE);
+       GETCAP(CAP_WME_SUPPORT);
+       GETCAP(CAP_TOTAL_QUEUES);
+       GETCAP(CAP_CONNECTION_ID_MAX);
+
+       GETCAP(CAP_LOW_5GHZ_CHAN);
+       GETCAP(CAP_HIGH_5GHZ_CHAN);
+       GETCAP(CAP_LOW_2GHZ_CHAN);
+       GETCAP(CAP_HIGH_2GHZ_CHAN);
+       GETCAP(CAP_TWICE_ANTENNAGAIN_5G);
+       GETCAP(CAP_TWICE_ANTENNAGAIN_2G);
+
+       GETCAP(CAP_CIPHER_AES_CCM);
+       GETCAP(CAP_CIPHER_TKIP);
+       GETCAP(CAP_MIC_TKIP);
+       return 0;
+}
+
+static int ar5523_set_ledsteady(struct ar5523 *ar, int lednum, int ledmode)
+{
+       struct ar5523_cmd_ledsteady led;
+
+       led.lednum = cpu_to_be32(lednum);
+       led.ledmode = cpu_to_be32(ledmode);
+
+       ar5523_dbg(ar, "set %s led %s (steady)\n",
+                  (lednum == UATH_LED_LINK) ? "link" : "activity",
+                  ledmode ? "on" : "off");
+       return ar5523_cmd_write(ar, WDCMSG_SET_LED_STEADY, &led, sizeof(led),
+                                0);
+}
+
+static int ar5523_set_rxfilter(struct ar5523 *ar, u32 bits, u32 op)
+{
+       struct ar5523_cmd_rx_filter rxfilter;
+
+       rxfilter.bits = cpu_to_be32(bits);
+       rxfilter.op = cpu_to_be32(op);
+
+       ar5523_dbg(ar, "setting Rx filter=0x%x flags=0x%x\n", bits, op);
+       return ar5523_cmd_write(ar, WDCMSG_RX_FILTER, &rxfilter,
+                                sizeof(rxfilter), 0);
+}
+
+static int ar5523_reset_tx_queues(struct ar5523 *ar)
+{
+       __be32 qid = cpu_to_be32(0);
+
+       ar5523_dbg(ar, "resetting Tx queue\n");
+       return ar5523_cmd_write(ar, WDCMSG_RELEASE_TX_QUEUE,
+                                &qid, sizeof(qid), 0);
+}
+
+static int ar5523_set_chan(struct ar5523 *ar)
+{
+       struct ieee80211_conf *conf = &ar->hw->conf;
+
+       struct ar5523_cmd_reset reset;
+
+       memset(&reset, 0, sizeof(reset));
+       reset.flags |= cpu_to_be32(UATH_CHAN_2GHZ);
+       reset.flags |= cpu_to_be32(UATH_CHAN_OFDM);
+       reset.freq = cpu_to_be32(conf->channel->center_freq);
+       reset.maxrdpower = cpu_to_be32(50);     /* XXX */
+       reset.channelchange = cpu_to_be32(1);
+       reset.keeprccontent = cpu_to_be32(0);
+
+       ar5523_dbg(ar, "set chan flags 0x%x freq %d\n",
+                  be32_to_cpu(reset.flags),
+                  conf->channel->center_freq);
+       return ar5523_cmd_write(ar, WDCMSG_RESET, &reset, sizeof(reset), 0);
+}
+
+static int ar5523_queue_init(struct ar5523 *ar)
+{
+       struct ar5523_cmd_txq_setup qinfo;
+
+       ar5523_dbg(ar, "setting up Tx queue\n");
+       qinfo.qid            = cpu_to_be32(0);
+       qinfo.len            = cpu_to_be32(sizeof(qinfo.attr));
+       qinfo.attr.priority  = cpu_to_be32(0);  /* XXX */
+       qinfo.attr.aifs      = cpu_to_be32(3);
+       qinfo.attr.logcwmin  = cpu_to_be32(4);
+       qinfo.attr.logcwmax  = cpu_to_be32(10);
+       qinfo.attr.bursttime = cpu_to_be32(0);
+       qinfo.attr.mode      = cpu_to_be32(0);
+       qinfo.attr.qflags    = cpu_to_be32(1);  /* XXX? */
+       return ar5523_cmd_write(ar, WDCMSG_SETUP_TX_QUEUE, &qinfo,
+                                sizeof(qinfo), 0);
+}
+
+static int ar5523_switch_chan(struct ar5523 *ar)
+{
+       int error;
+
+       error = ar5523_set_chan(ar);
+       if (error) {
+               ar5523_err(ar, "could not set chan, error %d\n", error);
+               goto out_err;
+       }
+
+       /* reset Tx rings */
+       error = ar5523_reset_tx_queues(ar);
+       if (error) {
+               ar5523_err(ar, "could not reset Tx queues, error %d\n",
+                          error);
+               goto out_err;
+       }
+       /* set Tx rings WME properties */
+       error = ar5523_queue_init(ar);
+       if (error)
+               ar5523_err(ar, "could not init wme, error %d\n", error);
+
+out_err:
+       return error;
+}
+
+static void ar5523_rx_data_put(struct ar5523 *ar,
+                               struct ar5523_rx_data *data)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&ar->rx_data_list_lock, flags);
+       list_move(&data->list, &ar->rx_data_free);
+       spin_unlock_irqrestore(&ar->rx_data_list_lock, flags);
+}
+
+static void ar5523_data_rx_cb(struct urb *urb)
+{
+       struct ar5523_rx_data *data = urb->context;
+       struct ar5523 *ar = data->ar;
+       struct ar5523_rx_desc *desc;
+       struct ar5523_chunk *chunk;
+       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_rx_status *rx_status;
+       u32 rxlen;
+       int usblen = urb->actual_length;
+       int hdrlen, pad;
+
+       ar5523_dbg(ar, "%s\n", __func__);
+       /* sync/async unlink faults aren't errors */
+       if (urb->status) {
+               if (urb->status != -ESHUTDOWN)
+                       ar5523_err(ar, "%s: USB err: %d\n", __func__,
+                                  urb->status);
+               goto skip;
+       }
+
+       if (usblen < AR5523_MIN_RXBUFSZ) {
+               ar5523_err(ar, "RX: wrong xfer size (usblen=%d)\n", usblen);
+               goto skip;
+       }
+
+       chunk = (struct ar5523_chunk *) data->skb->data;
+
+       if (((chunk->flags & UATH_CFLAGS_FINAL) == 0) ||
+               chunk->seqnum != 0) {
+               ar5523_dbg(ar, "RX: No final flag. s: %d f: %02x l: %d\n",
+                          chunk->seqnum, chunk->flags,
+                          be16_to_cpu(chunk->length));
+               goto skip;
+       }
+
+       /* Rx descriptor is located at the end, 32-bit aligned */
+       desc = (struct ar5523_rx_desc *)
+               (data->skb->data + usblen - sizeof(struct ar5523_rx_desc));
+
+       rxlen = be32_to_cpu(desc->len);
+       if (rxlen > ar->rxbufsz) {
+               ar5523_dbg(ar, "RX: Bad descriptor (len=%d)\n",
+                          be32_to_cpu(desc->len));
+               goto skip;
+       }
+
+       if (!rxlen) {
+               ar5523_dbg(ar, "RX: rxlen is 0\n");
+               goto skip;
+       }
+
+       if (be32_to_cpu(desc->status) != 0) {
+               ar5523_dbg(ar, "Bad RX status (0x%x len = %d). Skip\n",
+                          be32_to_cpu(desc->status), be32_to_cpu(desc->len));
+               goto skip;
+       }
+
+       skb_reserve(data->skb, sizeof(*chunk));
+       skb_put(data->skb, rxlen - sizeof(struct ar5523_rx_desc));
+
+       hdrlen = ieee80211_get_hdrlen_from_skb(data->skb);
+       if (!IS_ALIGNED(hdrlen, 4)) {
+               ar5523_dbg(ar, "eek, alignment workaround activated\n");
+               pad = ALIGN(hdrlen, 4) - hdrlen;
+               memmove(data->skb->data + pad, data->skb->data, hdrlen);
+               skb_pull(data->skb, pad);
+               skb_put(data->skb, pad);
+       }
+
+       rx_status = IEEE80211_SKB_RXCB(data->skb);
+       memset(rx_status, 0, sizeof(*rx_status));
+       rx_status->freq = be32_to_cpu(desc->channel);
+       rx_status->band = hw->conf.channel->band;
+       rx_status->signal = -95 + be32_to_cpu(desc->rssi);
+
+       ieee80211_rx_irqsafe(hw, data->skb);
+       data->skb = NULL;
+
+skip:
+       if (data->skb) {
+               dev_kfree_skb_irq(data->skb);
+               data->skb = NULL;
+       }
+
+       ar5523_rx_data_put(ar, data);
+       if (atomic_inc_return(&ar->rx_data_free_cnt) >=
+           AR5523_RX_DATA_REFILL_COUNT &&
+           test_bit(AR5523_HW_UP, &ar->flags))
+               queue_work(ar->wq, &ar->rx_refill_work);
+}
+
+static void ar5523_rx_refill_work(struct work_struct *work)
+{
+       struct ar5523 *ar = container_of(work, struct ar5523, rx_refill_work);
+       struct ar5523_rx_data *data;
+       unsigned long flags;
+       int error;
+
+       ar5523_dbg(ar, "%s\n", __func__);
+       do {
+               spin_lock_irqsave(&ar->rx_data_list_lock, flags);
+
+               if (!list_empty(&ar->rx_data_free))
+                       data = (struct ar5523_rx_data *) ar->rx_data_free.next;
+               else
+                       data = NULL;
+               spin_unlock_irqrestore(&ar->rx_data_list_lock, flags);
+
+               if (!data)
+                       goto done;
+
+               data->skb = alloc_skb(ar->rxbufsz, GFP_KERNEL);
+               if (!data->skb) {
+                       ar5523_err(ar, "could not allocate rx skbuff\n");
+                       return;
+               }
+
+               usb_fill_bulk_urb(data->urb, ar->dev,
+                                 ar5523_data_rx_pipe(ar->dev), data->skb->data,
+                                 ar->rxbufsz, ar5523_data_rx_cb, data);
+
+               spin_lock_irqsave(&ar->rx_data_list_lock, flags);
+               list_move(&data->list, &ar->rx_data_used);
+               spin_unlock_irqrestore(&ar->rx_data_list_lock, flags);
+               atomic_dec(&ar->rx_data_free_cnt);
+
+               error = usb_submit_urb(data->urb, GFP_KERNEL);
+               if (error) {
+                       kfree_skb(data->skb);
+                       if (error != -ENODEV)
+                               ar5523_err(ar, "Err sending rx data urb %d\n",
+                                          error);
+                       ar5523_rx_data_put(ar, data);
+                       atomic_inc(&ar->rx_data_free_cnt);
+                       return;
+               }
+
+       } while (true);
+done:
+       return;
+}
+
+static void ar5523_cancel_rx_bufs(struct ar5523 *ar)
+{
+       struct ar5523_rx_data *data;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&ar->rx_data_list_lock, flags);
+               if (!list_empty(&ar->rx_data_used))
+                       data = (struct ar5523_rx_data *) ar->rx_data_used.next;
+               else
+                       data = NULL;
+               spin_unlock_irqrestore(&ar->rx_data_list_lock, flags);
+
+               if (!data)
+                       break;
+
+               usb_kill_urb(data->urb);
+               list_move(&data->list, &ar->rx_data_free);
+               atomic_inc(&ar->rx_data_free_cnt);
+       } while (data);
+}
+
+static void ar5523_free_rx_bufs(struct ar5523 *ar)
+{
+       struct ar5523_rx_data *data;
+
+       ar5523_cancel_rx_bufs(ar);
+       while (!list_empty(&ar->rx_data_free)) {
+               data = (struct ar5523_rx_data *) ar->rx_data_free.next;
+               list_del(&data->list);
+               usb_free_urb(data->urb);
+       }
+}
+
+static int ar5523_alloc_rx_bufs(struct ar5523 *ar)
+{
+       int i;
+
+       for (i = 0; i < AR5523_RX_DATA_COUNT; i++) {
+               struct ar5523_rx_data *data = &ar->rx_data[i];
+
+               data->ar = ar;
+               data->urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!data->urb) {
+                       ar5523_err(ar, "could not allocate rx data urb\n");
+                       goto err;
+               }
+               list_add_tail(&data->list, &ar->rx_data_free);
+               atomic_inc(&ar->rx_data_free_cnt);
+       }
+       return 0;
+
+err:
+       ar5523_free_rx_bufs(ar);
+       return -ENOMEM;
+}
+
+static void ar5523_data_tx_pkt_put(struct ar5523 *ar)
+{
+       atomic_dec(&ar->tx_nr_total);
+       if (!atomic_dec_return(&ar->tx_nr_pending)) {
+               del_timer(&ar->tx_wd_timer);
+               wake_up(&ar->tx_flush_waitq);
+       }
+
+       if (atomic_read(&ar->tx_nr_total) < AR5523_TX_DATA_RESTART_COUNT) {
+               ar5523_dbg(ar, "restart tx queue\n");
+               ieee80211_wake_queues(ar->hw);
+       }
+}
+
+static void ar5523_data_tx_cb(struct urb *urb)
+{
+       struct sk_buff *skb = urb->context;
+       struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
+       struct ar5523_tx_data *data = (struct ar5523_tx_data *)
+                                      txi->driver_data;
+       struct ar5523 *ar = data->ar;
+       unsigned long flags;
+
+       ar5523_dbg(ar, "data tx urb completed: %d\n", urb->status);
+
+       spin_lock_irqsave(&ar->tx_data_list_lock, flags);
+       list_del(&data->list);
+       spin_unlock_irqrestore(&ar->tx_data_list_lock, flags);
+
+       if (urb->status) {
+               ar5523_dbg(ar, "%s: urb status: %d\n", __func__, urb->status);
+               ar5523_data_tx_pkt_put(ar);
+               ieee80211_free_txskb(ar->hw, skb);
+       } else {
+               skb_pull(skb, sizeof(struct ar5523_tx_desc) + sizeof(__be32));
+               ieee80211_tx_status_irqsafe(ar->hw, skb);
+       }
+       usb_free_urb(urb);
+}
+
+static void ar5523_tx(struct ieee80211_hw *hw,
+                      struct ieee80211_tx_control *control,
+                      struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
+       struct ar5523_tx_data *data = (struct ar5523_tx_data *)
+                                       txi->driver_data;
+       struct ar5523 *ar = hw->priv;
+       unsigned long flags;
+
+       ar5523_dbg(ar, "tx called\n");
+       if (atomic_inc_return(&ar->tx_nr_total) >= AR5523_TX_DATA_COUNT) {
+               ar5523_dbg(ar, "tx queue full\n");
+               ar5523_dbg(ar, "stop queues (tot %d pend %d)\n",
+                          atomic_read(&ar->tx_nr_total),
+                          atomic_read(&ar->tx_nr_pending));
+               ieee80211_stop_queues(hw);
+       }
+
+       data->skb = skb;
+
+       spin_lock_irqsave(&ar->tx_data_list_lock, flags);
+       list_add_tail(&data->list, &ar->tx_queue_pending);
+       spin_unlock_irqrestore(&ar->tx_data_list_lock, flags);
+
+       ieee80211_queue_work(ar->hw, &ar->tx_work);
+}
+
+static void ar5523_tx_work_locked(struct ar5523 *ar)
+{
+       struct ar5523_tx_data *data;
+       struct ar5523_tx_desc *desc;
+       struct ar5523_chunk *chunk;
+       struct ieee80211_tx_info *txi;
+       struct urb *urb;
+       struct sk_buff *skb;
+       int error = 0, paylen;
+       u32 txqid;
+       unsigned long flags;
+
+       BUILD_BUG_ON(sizeof(struct ar5523_tx_data) >
+                    IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+
+       ar5523_dbg(ar, "%s\n", __func__);
+       do {
+               spin_lock_irqsave(&ar->tx_data_list_lock, flags);
+               if (!list_empty(&ar->tx_queue_pending)) {
+                       data = (struct ar5523_tx_data *)
+                               ar->tx_queue_pending.next;
+                       list_del(&data->list);
+               } else
+                       data = NULL;
+               spin_unlock_irqrestore(&ar->tx_data_list_lock, flags);
+
+               if (!data)
+                       break;
+
+               skb = data->skb;
+               txqid = 0;
+               txi = IEEE80211_SKB_CB(skb);
+               paylen = skb->len;
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       ar5523_err(ar, "Failed to allocate TX urb\n");
+                       ieee80211_free_txskb(ar->hw, skb);
+                       continue;
+               }
+
+               data->ar = ar;
+               data->urb = urb;
+
+               desc = (struct ar5523_tx_desc *)skb_push(skb, sizeof(*desc));
+               chunk = (struct ar5523_chunk *)skb_push(skb, sizeof(*chunk));
+
+               chunk->seqnum = 0;
+               chunk->flags = UATH_CFLAGS_FINAL;
+               chunk->length = cpu_to_be16(skb->len);
+
+               desc->msglen = cpu_to_be32(skb->len);
+               desc->msgid  = AR5523_DATA_ID;
+               desc->buflen = cpu_to_be32(paylen);
+               desc->type   = cpu_to_be32(WDCMSG_SEND);
+               desc->flags  = cpu_to_be32(UATH_TX_NOTIFY);
+
+               if (test_bit(AR5523_CONNECTED, &ar->flags))
+                       desc->connid = cpu_to_be32(AR5523_ID_BSS);
+               else
+                       desc->connid = cpu_to_be32(AR5523_ID_BROADCAST);
+
+               if (txi->flags & IEEE80211_TX_CTL_USE_MINRATE)
+                       txqid |= UATH_TXQID_MINRATE;
+
+               desc->txqid = cpu_to_be32(txqid);
+
+               urb->transfer_flags = URB_ZERO_PACKET;
+               usb_fill_bulk_urb(urb, ar->dev, ar5523_data_tx_pipe(ar->dev),
+                                 skb->data, skb->len, ar5523_data_tx_cb, skb);
+
+               spin_lock_irqsave(&ar->tx_data_list_lock, flags);
+               list_add_tail(&data->list, &ar->tx_queue_submitted);
+               spin_unlock_irqrestore(&ar->tx_data_list_lock, flags);
+               mod_timer(&ar->tx_wd_timer, jiffies + AR5523_TX_WD_TIMEOUT);
+               atomic_inc(&ar->tx_nr_pending);
+
+               ar5523_dbg(ar, "TX Frame (%d pending)\n",
+                          atomic_read(&ar->tx_nr_pending));
+               error = usb_submit_urb(urb, GFP_KERNEL);
+               if (error) {
+                       ar5523_err(ar, "error %d when submitting tx urb\n",
+                                  error);
+                       spin_lock_irqsave(&ar->tx_data_list_lock, flags);
+                       list_del(&data->list);
+                       spin_unlock_irqrestore(&ar->tx_data_list_lock, flags);
+                       atomic_dec(&ar->tx_nr_pending);
+                       ar5523_data_tx_pkt_put(ar);
+                       usb_free_urb(urb);
+                       ieee80211_free_txskb(ar->hw, skb);
+               }
+       } while (true);
+}
+
+static void ar5523_tx_work(struct work_struct *work)
+{
+       struct ar5523 *ar = container_of(work, struct ar5523, tx_work);
+
+       ar5523_dbg(ar, "%s\n", __func__);
+       mutex_lock(&ar->mutex);
+       ar5523_tx_work_locked(ar);
+       mutex_unlock(&ar->mutex);
+}
+
+static void ar5523_tx_wd_timer(unsigned long arg)
+{
+       struct ar5523 *ar = (struct ar5523 *) arg;
+
+       ar5523_dbg(ar, "TX watchdog timer triggered\n");
+       ieee80211_queue_work(ar->hw, &ar->tx_wd_work);
+}
+
+static void ar5523_tx_wd_work(struct work_struct *work)
+{
+       struct ar5523 *ar = container_of(work, struct ar5523, tx_wd_work);
+
+       /* Occasionally the TX queues stop responding. The only way to
+        * recover seems to be to reset the dongle.
+        */
+
+       mutex_lock(&ar->mutex);
+       ar5523_err(ar, "TX queue stuck (tot %d pend %d)\n",
+                  atomic_read(&ar->tx_nr_total),
+                  atomic_read(&ar->tx_nr_pending));
+
+       ar5523_err(ar, "Will restart dongle.\n");
+       ar5523_cmd_write(ar, WDCMSG_TARGET_RESET, NULL, 0, 0);
+       mutex_unlock(&ar->mutex);
+}
+
+static void ar5523_flush_tx(struct ar5523 *ar)
+{
+       ar5523_tx_work_locked(ar);
+
+       /* Don't waste time trying to flush if USB is disconnected */
+       if (test_bit(AR5523_USB_DISCONNECTED, &ar->flags))
+               return;
+       if (!wait_event_timeout(ar->tx_flush_waitq,
+           !atomic_read(&ar->tx_nr_pending), AR5523_FLUSH_TIMEOUT))
+               ar5523_err(ar, "flush timeout (tot %d pend %d)\n",
+                          atomic_read(&ar->tx_nr_total),
+                          atomic_read(&ar->tx_nr_pending));
+}
+
+static void ar5523_free_tx_cmd(struct ar5523 *ar)
+{
+       struct ar5523_tx_cmd *cmd = &ar->tx_cmd;
+
+       usb_free_coherent(ar->dev, AR5523_MAX_RXCMDSZ, cmd->buf_tx,
+                         cmd->urb_tx->transfer_dma);
+       usb_free_urb(cmd->urb_tx);
+}
+
+static int ar5523_alloc_tx_cmd(struct ar5523 *ar)
+{
+       struct ar5523_tx_cmd *cmd = &ar->tx_cmd;
+
+       cmd->ar = ar;
+       init_completion(&cmd->done);
+
+       cmd->urb_tx = usb_alloc_urb(0, GFP_KERNEL);
+       if (!cmd->urb_tx) {
+               ar5523_err(ar, "could not allocate urb\n");
+               return -ENOMEM;
+       }
+       cmd->buf_tx = usb_alloc_coherent(ar->dev, AR5523_MAX_TXCMDSZ,
+                                        GFP_KERNEL,
+                                        &cmd->urb_tx->transfer_dma);
+       if (!cmd->buf_tx) {
+               usb_free_urb(cmd->urb_tx);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+/*
+ * This function is called periodically (every second) when associated to
+ * query device statistics.
+ */
+static void ar5523_stat_work(struct work_struct *work)
+{
+       struct ar5523 *ar = container_of(work, struct ar5523, stat_work.work);
+       int error;
+
+       ar5523_dbg(ar, "%s\n", __func__);
+       mutex_lock(&ar->mutex);
+
+       /*
+        * Send request for statistics asynchronously once a second. This
+        * seems to be important. Throughput is a lot better if this is done.
+        */
+       error = ar5523_cmd_write(ar, WDCMSG_TARGET_GET_STATS, NULL, 0, 0);
+       if (error)
+               ar5523_err(ar, "could not query stats, error %d\n", error);
+       mutex_unlock(&ar->mutex);
+       ieee80211_queue_delayed_work(ar->hw, &ar->stat_work, HZ);
+}
+
+/*
+ * Interface routines to the mac80211 stack.
+ */
+static int ar5523_start(struct ieee80211_hw *hw)
+{
+       struct ar5523 *ar = hw->priv;
+       int error;
+       __be32 val;
+
+       ar5523_dbg(ar, "start called\n");
+
+       mutex_lock(&ar->mutex);
+       val = cpu_to_be32(0);
+       ar5523_cmd_write(ar, WDCMSG_BIND, &val, sizeof(val), 0);
+
+       /* set MAC address */
+       ar5523_config_multi(ar, CFG_MAC_ADDR, &ar->hw->wiphy->perm_addr,
+                           ETH_ALEN);
+
+       /* XXX honor net80211 state */
+       ar5523_config(ar, CFG_RATE_CONTROL_ENABLE, 0x00000001);
+       ar5523_config(ar, CFG_DIVERSITY_CTL, 0x00000001);
+       ar5523_config(ar, CFG_ABOLT, 0x0000003f);
+       ar5523_config(ar, CFG_WME_ENABLED, 0x00000000);
+
+       ar5523_config(ar, CFG_SERVICE_TYPE, 1);
+       ar5523_config(ar, CFG_TP_SCALE, 0x00000000);
+       ar5523_config(ar, CFG_TPC_HALF_DBM5, 0x0000003c);
+       ar5523_config(ar, CFG_TPC_HALF_DBM2, 0x0000003c);
+       ar5523_config(ar, CFG_OVERRD_TX_POWER, 0x00000000);
+       ar5523_config(ar, CFG_GMODE_PROTECTION, 0x00000000);
+       ar5523_config(ar, CFG_GMODE_PROTECT_RATE_INDEX, 0x00000003);
+       ar5523_config(ar, CFG_PROTECTION_TYPE, 0x00000000);
+       ar5523_config(ar, CFG_MODE_CTS, 0x00000002);
+
+       error = ar5523_cmd_read(ar, WDCMSG_TARGET_START, NULL, 0,
+           &val, sizeof(val), AR5523_CMD_FLAG_MAGIC);
+       if (error) {
+               ar5523_dbg(ar, "could not start target, error %d\n", error);
+               goto err;
+       }
+       ar5523_dbg(ar, "WDCMSG_TARGET_START returns handle: 0x%x\n",
+                  be32_to_cpu(val));
+
+       ar5523_switch_chan(ar);
+
+       val = cpu_to_be32(TARGET_DEVICE_AWAKE);
+       ar5523_cmd_write(ar, WDCMSG_SET_PWR_MODE, &val, sizeof(val), 0);
+       /* XXX? check */
+       ar5523_cmd_write(ar, WDCMSG_RESET_KEY_CACHE, NULL, 0, 0);
+
+       set_bit(AR5523_HW_UP, &ar->flags);
+       queue_work(ar->wq, &ar->rx_refill_work);
+
+       /* enable Rx */
+       ar5523_set_rxfilter(ar, 0, UATH_FILTER_OP_INIT);
+       ar5523_set_rxfilter(ar,
+                           UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST |
+                           UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON,
+                           UATH_FILTER_OP_SET);
+
+       ar5523_set_ledsteady(ar, UATH_LED_ACTIVITY, UATH_LED_ON);
+       ar5523_dbg(ar, "start OK\n");
+
+err:
+       mutex_unlock(&ar->mutex);
+       return error;
+}
+
+static void ar5523_stop(struct ieee80211_hw *hw)
+{
+       struct ar5523 *ar = hw->priv;
+
+       ar5523_dbg(ar, "stop called\n");
+
+       cancel_delayed_work_sync(&ar->stat_work);
+       mutex_lock(&ar->mutex);
+       clear_bit(AR5523_HW_UP, &ar->flags);
+
+       ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_OFF);
+       ar5523_set_ledsteady(ar, UATH_LED_ACTIVITY, UATH_LED_OFF);
+
+       ar5523_cmd_write(ar, WDCMSG_TARGET_STOP, NULL, 0, 0);
+
+       del_timer_sync(&ar->tx_wd_timer);
+       cancel_work_sync(&ar->tx_wd_work);
+       cancel_work_sync(&ar->rx_refill_work);
+       ar5523_cancel_rx_bufs(ar);
+       mutex_unlock(&ar->mutex);
+}
+
+static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+       struct ar5523 *ar = hw->priv;
+       int ret;
+
+       ar5523_dbg(ar, "set_rts_threshold called\n");
+       mutex_lock(&ar->mutex);
+
+       ret = ar5523_config(ar, CFG_USER_RTS_THRESHOLD, value);
+
+       mutex_unlock(&ar->mutex);
+       return ret;
+}
+
+static void ar5523_flush(struct ieee80211_hw *hw, bool drop)
+{
+       struct ar5523 *ar = hw->priv;
+
+       ar5523_dbg(ar, "flush called\n");
+       ar5523_flush_tx(ar);
+}
+
+static int ar5523_add_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif)
+{
+       struct ar5523 *ar = hw->priv;
+
+       ar5523_dbg(ar, "add interface called\n");
+
+       if (ar->vif) {
+               ar5523_dbg(ar, "invalid add_interface\n");
+               return -EOPNOTSUPP;
+       }
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               ar->vif = vif;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static void ar5523_remove_interface(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif)
+{
+       struct ar5523 *ar = hw->priv;
+
+       ar5523_dbg(ar, "remove interface called\n");
+       ar->vif = NULL;
+}
+
+static int ar5523_hwconfig(struct ieee80211_hw *hw, u32 changed)
+{
+       struct ar5523 *ar = hw->priv;
+
+       ar5523_dbg(ar, "config called\n");
+       mutex_lock(&ar->mutex);
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+               ar5523_dbg(ar, "Do channel switch\n");
+               ar5523_flush_tx(ar);
+               ar5523_switch_chan(ar);
+       }
+       mutex_unlock(&ar->mutex);
+       return 0;
+}
+
+static int ar5523_get_wlan_mode(struct ar5523 *ar,
+                               struct ieee80211_bss_conf *bss_conf)
+{
+       struct ieee80211_supported_band *band;
+       int bit;
+       struct ieee80211_sta *sta;
+       u32 sta_rate_set;
+
+       band = ar->hw->wiphy->bands[ar->hw->conf.channel->band];
+       sta = ieee80211_find_sta(ar->vif, bss_conf->bssid);
+       if (!sta) {
+               ar5523_info(ar, "STA not found!\n");
+               return WLAN_MODE_11b;
+       }
+       sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
+
+       for (bit = 0; bit < band->n_bitrates; bit++) {
+               if (sta_rate_set & 1) {
+                       int rate = band->bitrates[bit].bitrate;
+                       switch (rate) {
+                       case 60:
+                       case 90:
+                       case 120:
+                       case 180:
+                       case 240:
+                       case 360:
+                       case 480:
+                       case 540:
+                               return WLAN_MODE_11g;
+                       }
+               }
+               sta_rate_set >>= 1;
+       }
+       return WLAN_MODE_11b;
+}
+
+static void ar5523_create_rateset(struct ar5523 *ar,
+                                 struct ieee80211_bss_conf *bss_conf,
+                                 struct ar5523_cmd_rateset *rs,
+                                 bool basic)
+{
+       struct ieee80211_supported_band *band;
+       struct ieee80211_sta *sta;
+       int bit, i = 0;
+       u32 sta_rate_set, basic_rate_set;
+
+       sta = ieee80211_find_sta(ar->vif, bss_conf->bssid);
+       basic_rate_set = bss_conf->basic_rates;
+       if (!sta) {
+               ar5523_info(ar, "STA not found. Cannot set rates\n");
+               sta_rate_set = bss_conf->basic_rates;
+       }
+       sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
+
+       ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set);
+
+       band = ar->hw->wiphy->bands[ar->hw->conf.channel->band];
+       for (bit = 0; bit < band->n_bitrates; bit++) {
+               BUG_ON(i >= AR5523_MAX_NRATES);
+               ar5523_dbg(ar, "Considering rate %d : %d\n",
+                          band->bitrates[bit].hw_value, sta_rate_set & 1);
+               if (sta_rate_set & 1) {
+                       rs->set[i] = band->bitrates[bit].hw_value;
+                       if (basic_rate_set & 1 && basic)
+                               rs->set[i] |= 0x80;
+                       i++;
+               }
+               sta_rate_set >>= 1;
+               basic_rate_set >>= 1;
+       }
+
+       rs->length = i;
+}
+
+static int ar5523_set_basic_rates(struct ar5523 *ar,
+                                 struct ieee80211_bss_conf *bss)
+{
+       struct ar5523_cmd_rates rates;
+
+       memset(&rates, 0, sizeof(rates));
+       rates.connid = cpu_to_be32(2);          /* XXX */
+       rates.size   = cpu_to_be32(sizeof(struct ar5523_cmd_rateset));
+       ar5523_create_rateset(ar, bss, &rates.rateset, true);
+
+       return ar5523_cmd_write(ar, WDCMSG_SET_BASIC_RATE, &rates,
+                               sizeof(rates), 0);
+}
+
+static int ar5523_create_connection(struct ar5523 *ar,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *bss)
+{
+       struct ar5523_cmd_create_connection create;
+       int wlan_mode;
+
+       memset(&create, 0, sizeof(create));
+       create.connid = cpu_to_be32(2);
+       create.bssid = cpu_to_be32(0);
+       /* XXX packed or not?  */
+       create.size = cpu_to_be32(sizeof(struct ar5523_cmd_rateset));
+
+       ar5523_create_rateset(ar, bss, &create.connattr.rateset, false);
+
+       wlan_mode = ar5523_get_wlan_mode(ar, bss);
+       create.connattr.wlanmode = cpu_to_be32(wlan_mode);
+
+       return ar5523_cmd_write(ar, WDCMSG_CREATE_CONNECTION, &create,
+                               sizeof(create), 0);
+}
+
+static int ar5523_write_associd(struct ar5523 *ar,
+                               struct ieee80211_bss_conf *bss)
+{
+       struct ar5523_cmd_set_associd associd;
+
+       memset(&associd, 0, sizeof(associd));
+       associd.defaultrateix = cpu_to_be32(0); /* XXX */
+       associd.associd = cpu_to_be32(bss->aid);
+       associd.timoffset = cpu_to_be32(0x3b);  /* XXX */
+       memcpy(associd.bssid, bss->bssid, ETH_ALEN);
+       return ar5523_cmd_write(ar, WDCMSG_WRITE_ASSOCID, &associd,
+                               sizeof(associd), 0);
+}
+
+static void ar5523_bss_info_changed(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *bss,
+                                   u32 changed)
+{
+       struct ar5523 *ar = hw->priv;
+       int error;
+
+       ar5523_dbg(ar, "bss_info_changed called\n");
+       mutex_lock(&ar->mutex);
+
+       if (!(changed & BSS_CHANGED_ASSOC))
+               goto out_unlock;
+
+       if (bss->assoc) {
+               error = ar5523_create_connection(ar, vif, bss);
+               if (error) {
+                       ar5523_err(ar, "could not create connection\n");
+                       goto out_unlock;
+               }
+
+               error = ar5523_set_basic_rates(ar, bss);
+               if (error) {
+                       ar5523_err(ar, "could not set negotiated rate set\n");
+                       goto out_unlock;
+               }
+
+               error = ar5523_write_associd(ar, bss);
+               if (error) {
+                       ar5523_err(ar, "could not set association\n");
+                       goto out_unlock;
+               }
+
+               /* turn link LED on */
+               ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_ON);
+               set_bit(AR5523_CONNECTED, &ar->flags);
+               ieee80211_queue_delayed_work(hw, &ar->stat_work, HZ);
+
+       } else {
+               cancel_delayed_work(&ar->stat_work);
+               clear_bit(AR5523_CONNECTED, &ar->flags);
+               ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_OFF);
+       }
+
+out_unlock:
+       mutex_unlock(&ar->mutex);
+
+}
+
+#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+                                 FIF_ALLMULTI | \
+                                 FIF_FCSFAIL | \
+                                 FIF_OTHER_BSS)
+
+static void ar5523_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed_flags,
+                                   unsigned int *total_flags,
+                                   u64 multicast)
+{
+       struct ar5523 *ar = hw->priv;
+       u32 filter = 0;
+
+       ar5523_dbg(ar, "configure_filter called\n");
+       mutex_lock(&ar->mutex);
+       ar5523_flush_tx(ar);
+
+       *total_flags &= AR5523_SUPPORTED_FILTERS;
+
+       /* The filters seems strange. UATH_FILTER_RX_BCAST and
+        * UATH_FILTER_RX_MCAST does not result in those frames being RXed.
+        * The only way I have found to get [mb]cast frames seems to be
+        * to set UATH_FILTER_RX_PROM. */
+       filter |= UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST |
+                 UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON |
+                 UATH_FILTER_RX_PROM;
+
+       ar5523_set_rxfilter(ar, 0, UATH_FILTER_OP_INIT);
+       ar5523_set_rxfilter(ar, filter, UATH_FILTER_OP_SET);
+
+       mutex_unlock(&ar->mutex);
+}
+
+static const struct ieee80211_ops ar5523_ops = {
+       .start                  = ar5523_start,
+       .stop                   = ar5523_stop,
+       .tx                     = ar5523_tx,
+       .set_rts_threshold      = ar5523_set_rts_threshold,
+       .add_interface          = ar5523_add_interface,
+       .remove_interface       = ar5523_remove_interface,
+       .config                 = ar5523_hwconfig,
+       .bss_info_changed       = ar5523_bss_info_changed,
+       .configure_filter       = ar5523_configure_filter,
+       .flush                  = ar5523_flush,
+};
+
+static int ar5523_host_available(struct ar5523 *ar)
+{
+       struct ar5523_cmd_host_available setup;
+
+       /* inform target the host is available */
+       setup.sw_ver_major = cpu_to_be32(ATH_SW_VER_MAJOR);
+       setup.sw_ver_minor = cpu_to_be32(ATH_SW_VER_MINOR);
+       setup.sw_ver_patch = cpu_to_be32(ATH_SW_VER_PATCH);
+       setup.sw_ver_build = cpu_to_be32(ATH_SW_VER_BUILD);
+       return ar5523_cmd_read(ar, WDCMSG_HOST_AVAILABLE,
+                              &setup, sizeof(setup), NULL, 0, 0);
+}
+
+static int ar5523_get_devstatus(struct ar5523 *ar)
+{
+       u8 macaddr[ETH_ALEN];
+       int error;
+
+       /* retrieve MAC address */
+       error = ar5523_get_status(ar, ST_MAC_ADDR, macaddr, ETH_ALEN);
+       if (error) {
+               ar5523_err(ar, "could not read MAC address\n");
+               return error;
+       }
+
+       SET_IEEE80211_PERM_ADDR(ar->hw, macaddr);
+
+       error = ar5523_get_status(ar, ST_SERIAL_NUMBER,
+           &ar->serial[0], sizeof(ar->serial));
+       if (error) {
+               ar5523_err(ar, "could not read device serial number\n");
+               return error;
+       }
+       return 0;
+}
+
+#define AR5523_SANE_RXBUFSZ 2000
+
+static int ar5523_get_max_rxsz(struct ar5523 *ar)
+{
+       int error;
+       __be32 rxsize;
+
+       /* Get max rx size */
+       error = ar5523_get_status(ar, ST_WDC_TRANSPORT_CHUNK_SIZE, &rxsize,
+                                 sizeof(rxsize));
+       if (error != 0) {
+               ar5523_err(ar, "could not read max RX size\n");
+               return error;
+       }
+
+       ar->rxbufsz = be32_to_cpu(rxsize);
+
+       if (!ar->rxbufsz || ar->rxbufsz > AR5523_SANE_RXBUFSZ) {
+               ar5523_err(ar, "Bad rxbufsz from device. Using %d instead\n",
+                          AR5523_SANE_RXBUFSZ);
+               ar->rxbufsz = AR5523_SANE_RXBUFSZ;
+       }
+
+       ar5523_dbg(ar, "Max RX buf size: %d\n", ar->rxbufsz);
+       return 0;
+}
+
+/*
+ * This is copied from rtl818x, but we should probably move this
+ * to common code as in OpenBSD.
+ */
+static const struct ieee80211_rate ar5523_rates[] = {
+       { .bitrate = 10, .hw_value = 2, },
+       { .bitrate = 20, .hw_value = 4 },
+       { .bitrate = 55, .hw_value = 11, },
+       { .bitrate = 110, .hw_value = 22, },
+       { .bitrate = 60, .hw_value = 12, },
+       { .bitrate = 90, .hw_value = 18, },
+       { .bitrate = 120, .hw_value = 24, },
+       { .bitrate = 180, .hw_value = 36, },
+       { .bitrate = 240, .hw_value = 48, },
+       { .bitrate = 360, .hw_value = 72, },
+       { .bitrate = 480, .hw_value = 96, },
+       { .bitrate = 540, .hw_value = 108, },
+};
+
+static const struct ieee80211_channel ar5523_channels[] = {
+       { .center_freq = 2412 },
+       { .center_freq = 2417 },
+       { .center_freq = 2422 },
+       { .center_freq = 2427 },
+       { .center_freq = 2432 },
+       { .center_freq = 2437 },
+       { .center_freq = 2442 },
+       { .center_freq = 2447 },
+       { .center_freq = 2452 },
+       { .center_freq = 2457 },
+       { .center_freq = 2462 },
+       { .center_freq = 2467 },
+       { .center_freq = 2472 },
+       { .center_freq = 2484 },
+};
+
+static int ar5523_init_modes(struct ar5523 *ar)
+{
+       BUILD_BUG_ON(sizeof(ar->channels) != sizeof(ar5523_channels));
+       BUILD_BUG_ON(sizeof(ar->rates) != sizeof(ar5523_rates));
+
+       memcpy(ar->channels, ar5523_channels, sizeof(ar5523_channels));
+       memcpy(ar->rates, ar5523_rates, sizeof(ar5523_rates));
+
+       ar->band.band = IEEE80211_BAND_2GHZ;
+       ar->band.channels = ar->channels;
+       ar->band.n_channels = ARRAY_SIZE(ar5523_channels);
+       ar->band.bitrates = ar->rates;
+       ar->band.n_bitrates = ARRAY_SIZE(ar5523_rates);
+       ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar->band;
+       return 0;
+}
+
+/*
+ * Load the MIPS R4000 microcode into the device.  Once the image is loaded,
+ * the device will detach itself from the bus and reattach later with a new
+ * product Id (a la ezusb).
+ */
+static int ar5523_load_firmware(struct usb_device *dev)
+{
+       struct ar5523_fwblock *txblock, *rxblock;
+       const struct firmware *fw;
+       void *fwbuf;
+       int len, offset;
+       int foolen; /* XXX(hch): handle short transfers */
+       int error = -ENXIO;
+
+       if (request_firmware(&fw, AR5523_FIRMWARE_FILE, &dev->dev)) {
+               dev_err(&dev->dev, "no firmware found: %s\n",
+                       AR5523_FIRMWARE_FILE);
+               return -ENOENT;
+       }
+
+       txblock = kmalloc(sizeof(*txblock), GFP_KERNEL);
+       if (!txblock)
+               goto out;
+
+       rxblock = kmalloc(sizeof(*rxblock), GFP_KERNEL);
+       if (!rxblock)
+               goto out_free_txblock;
+
+       fwbuf = kmalloc(AR5523_MAX_FWBLOCK_SIZE, GFP_KERNEL);
+       if (!fwbuf)
+               goto out_free_rxblock;
+
+       memset(txblock, 0, sizeof(struct ar5523_fwblock));
+       txblock->flags = cpu_to_be32(AR5523_WRITE_BLOCK);
+       txblock->total = cpu_to_be32(fw->size);
+
+       offset = 0;
+       len = fw->size;
+       while (len > 0) {
+               int mlen = min(len, AR5523_MAX_FWBLOCK_SIZE);
+
+               txblock->remain = cpu_to_be32(len - mlen);
+               txblock->len = cpu_to_be32(mlen);
+
+               /* send firmware block meta-data */
+               error = usb_bulk_msg(dev, ar5523_cmd_tx_pipe(dev),
+                                    txblock, sizeof(*txblock), &foolen,
+                                    AR5523_CMD_TIMEOUT);
+               if (error) {
+                       dev_err(&dev->dev,
+                               "could not send firmware block info\n");
+                       goto out_free_fwbuf;
+               }
+
+               /* send firmware block data */
+               memcpy(fwbuf, fw->data + offset, mlen);
+               error = usb_bulk_msg(dev, ar5523_data_tx_pipe(dev),
+                                    fwbuf, mlen, &foolen,
+                                    AR5523_DATA_TIMEOUT);
+               if (error) {
+                       dev_err(&dev->dev,
+                               "could not send firmware block data\n");
+                       goto out_free_fwbuf;
+               }
+
+               /* wait for ack from firmware */
+               error = usb_bulk_msg(dev, ar5523_cmd_rx_pipe(dev),
+                                    rxblock, sizeof(*rxblock), &foolen,
+                                    AR5523_CMD_TIMEOUT);
+               if (error) {
+                       dev_err(&dev->dev,
+                               "could not read firmware answer\n");
+                       goto out_free_fwbuf;
+               }
+
+               len -= mlen;
+               offset += mlen;
+       }
+
+       /*
+        * Set the error to -ENXIO to make sure we continue probing for
+        * a driver.
+        */
+       error = -ENXIO;
+
+ out_free_fwbuf:
+       kfree(fwbuf);
+ out_free_rxblock:
+       kfree(rxblock);
+ out_free_txblock:
+       kfree(txblock);
+ out:
+       release_firmware(fw);
+       return error;
+}
+
+static int ar5523_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct ieee80211_hw *hw;
+       struct ar5523 *ar;
+       int error = -ENOMEM;
+
+       /*
+        * Load firmware if the device requires it.  This will return
+        * -ENXIO on success and we'll get called back afer the usb
+        * id changes to indicate that the firmware is present.
+        */
+       if (id->driver_info & AR5523_FLAG_PRE_FIRMWARE)
+               return ar5523_load_firmware(dev);
+
+
+       hw = ieee80211_alloc_hw(sizeof(*ar), &ar5523_ops);
+       if (!hw)
+               goto out;
+       SET_IEEE80211_DEV(hw, &intf->dev);
+
+       ar = hw->priv;
+       ar->hw = hw;
+       ar->dev = dev;
+       mutex_init(&ar->mutex);
+
+       INIT_DELAYED_WORK(&ar->stat_work, ar5523_stat_work);
+       init_timer(&ar->tx_wd_timer);
+       setup_timer(&ar->tx_wd_timer, ar5523_tx_wd_timer, (unsigned long) ar);
+       INIT_WORK(&ar->tx_wd_work, ar5523_tx_wd_work);
+       INIT_WORK(&ar->tx_work, ar5523_tx_work);
+       INIT_LIST_HEAD(&ar->tx_queue_pending);
+       INIT_LIST_HEAD(&ar->tx_queue_submitted);
+       spin_lock_init(&ar->tx_data_list_lock);
+       atomic_set(&ar->tx_nr_total, 0);
+       atomic_set(&ar->tx_nr_pending, 0);
+       init_waitqueue_head(&ar->tx_flush_waitq);
+
+       atomic_set(&ar->rx_data_free_cnt, 0);
+       INIT_WORK(&ar->rx_refill_work, ar5523_rx_refill_work);
+       INIT_LIST_HEAD(&ar->rx_data_free);
+       INIT_LIST_HEAD(&ar->rx_data_used);
+       spin_lock_init(&ar->rx_data_list_lock);
+
+       ar->wq = create_singlethread_workqueue("ar5523");
+       if (!ar->wq) {
+               ar5523_err(ar, "Could not create wq\n");
+               goto out_free_ar;
+       }
+
+       error = ar5523_alloc_rx_bufs(ar);
+       if (error) {
+               ar5523_err(ar, "Could not allocate rx buffers\n");
+               goto out_free_wq;
+       }
+
+       error = ar5523_alloc_rx_cmd(ar);
+       if (error) {
+               ar5523_err(ar, "Could not allocate rx command buffers\n");
+               goto out_free_rx_bufs;
+       }
+
+       error = ar5523_alloc_tx_cmd(ar);
+       if (error) {
+               ar5523_err(ar, "Could not allocate tx command buffers\n");
+               goto out_free_rx_cmd;
+       }
+
+       error = ar5523_submit_rx_cmd(ar);
+       if (error) {
+               ar5523_err(ar, "Failed to submit rx cmd\n");
+               goto out_free_tx_cmd;
+       }
+
+       /*
+        * We're now ready to send/receive firmware commands.
+        */
+       error = ar5523_host_available(ar);
+       if (error) {
+               ar5523_err(ar, "could not initialize adapter\n");
+               goto out_cancel_rx_cmd;
+       }
+
+       error = ar5523_get_max_rxsz(ar);
+       if (error) {
+               ar5523_err(ar, "could not get caps from adapter\n");
+               goto out_cancel_rx_cmd;
+       }
+
+       error = ar5523_get_devcap(ar);
+       if (error) {
+               ar5523_err(ar, "could not get caps from adapter\n");
+               goto out_cancel_rx_cmd;
+       }
+
+       error = ar5523_get_devstatus(ar);
+       if (error != 0) {
+               ar5523_err(ar, "could not get device status\n");
+               goto out_cancel_rx_cmd;
+       }
+
+       ar5523_info(ar, "MAC/BBP AR5523, RF AR%c112\n",
+                       (id->driver_info & AR5523_FLAG_ABG) ? '5' : '2');
+
+       ar->vif = NULL;
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+                   IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_HAS_RATE_CONTROL;
+       hw->extra_tx_headroom = sizeof(struct ar5523_tx_desc) +
+                               sizeof(struct ar5523_chunk);
+       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       hw->queues = 1;
+
+       error = ar5523_init_modes(ar);
+       if (error)
+               goto out_cancel_rx_cmd;
+
+       usb_set_intfdata(intf, hw);
+
+       error = ieee80211_register_hw(hw);
+       if (error) {
+               ar5523_err(ar, "could not register device\n");
+               goto out_cancel_rx_cmd;
+       }
+
+       ar5523_info(ar, "Found and initialized AR5523 device\n");
+       return 0;
+
+out_cancel_rx_cmd:
+       ar5523_cancel_rx_cmd(ar);
+out_free_tx_cmd:
+       ar5523_free_tx_cmd(ar);
+out_free_rx_cmd:
+       ar5523_free_rx_cmd(ar);
+out_free_rx_bufs:
+       ar5523_free_rx_bufs(ar);
+out_free_wq:
+       destroy_workqueue(ar->wq);
+out_free_ar:
+       ieee80211_free_hw(hw);
+out:
+       return error;
+}
+
+static void ar5523_disconnect(struct usb_interface *intf)
+{
+       struct ieee80211_hw *hw = usb_get_intfdata(intf);
+       struct ar5523 *ar = hw->priv;
+
+       ar5523_dbg(ar, "detaching\n");
+       set_bit(AR5523_USB_DISCONNECTED, &ar->flags);
+
+       ieee80211_unregister_hw(hw);
+
+       ar5523_cancel_rx_cmd(ar);
+       ar5523_free_tx_cmd(ar);
+       ar5523_free_rx_cmd(ar);
+       ar5523_free_rx_bufs(ar);
+
+       destroy_workqueue(ar->wq);
+
+       ieee80211_free_hw(hw);
+       usb_set_intfdata(intf, NULL);
+}
+
+#define AR5523_DEVICE_UG(vendor, device) \
+       { USB_DEVICE((vendor), (device)) }, \
+       { USB_DEVICE((vendor), (device) + 1), \
+               .driver_info = AR5523_FLAG_PRE_FIRMWARE }
+#define AR5523_DEVICE_UX(vendor, device) \
+       { USB_DEVICE((vendor), (device)), \
+               .driver_info = AR5523_FLAG_ABG }, \
+       { USB_DEVICE((vendor), (device) + 1), \
+               .driver_info = AR5523_FLAG_ABG|AR5523_FLAG_PRE_FIRMWARE }
+
+static struct usb_device_id ar5523_id_table[] = {
+       AR5523_DEVICE_UG(0x168c, 0x0001),       /* Atheros / AR5523 */
+       AR5523_DEVICE_UG(0x0cf3, 0x0001),       /* Atheros2 / AR5523_1 */
+       AR5523_DEVICE_UG(0x0cf3, 0x0003),       /* Atheros2 / AR5523_2 */
+       AR5523_DEVICE_UX(0x0cf3, 0x0005),       /* Atheros2 / AR5523_3 */
+       AR5523_DEVICE_UG(0x0d8e, 0x7801),       /* Conceptronic / AR5523_1 */
+       AR5523_DEVICE_UX(0x0d8e, 0x7811),       /* Conceptronic / AR5523_2 */
+       AR5523_DEVICE_UX(0x2001, 0x3a00),       /* Dlink / DWLAG132 */
+       AR5523_DEVICE_UG(0x2001, 0x3a02),       /* Dlink / DWLG132 */
+       AR5523_DEVICE_UX(0x2001, 0x3a04),       /* Dlink / DWLAG122 */
+       AR5523_DEVICE_UG(0x1690, 0x0712),       /* Gigaset / AR5523 */
+       AR5523_DEVICE_UG(0x1690, 0x0710),       /* Gigaset / SMCWUSBTG */
+       AR5523_DEVICE_UG(0x129b, 0x160c),       /* Gigaset / USB stick 108
+                                                  (CyberTAN Technology) */
+       AR5523_DEVICE_UG(0x16ab, 0x7801),       /* Globalsun / AR5523_1 */
+       AR5523_DEVICE_UX(0x16ab, 0x7811),       /* Globalsun / AR5523_2 */
+       AR5523_DEVICE_UG(0x0d8e, 0x7802),       /* Globalsun / AR5523_3 */
+       AR5523_DEVICE_UX(0x0846, 0x4300),       /* Netgear / WG111U */
+       AR5523_DEVICE_UG(0x0846, 0x4250),       /* Netgear / WG111T */
+       AR5523_DEVICE_UG(0x0846, 0x5f00),       /* Netgear / WPN111 */
+       AR5523_DEVICE_UG(0x157e, 0x3006),       /* Umedia / AR5523_1 */
+       AR5523_DEVICE_UX(0x157e, 0x3205),       /* Umedia / AR5523_2 */
+       AR5523_DEVICE_UG(0x157e, 0x3006),       /* Umedia / TEW444UBEU */
+       AR5523_DEVICE_UG(0x1435, 0x0826),       /* Wistronneweb / AR5523_1 */
+       AR5523_DEVICE_UX(0x1435, 0x0828),       /* Wistronneweb / AR5523_2 */
+       AR5523_DEVICE_UG(0x0cde, 0x0012),       /* Zcom / AR5523 */
+       AR5523_DEVICE_UG(0x1385, 0x4250),       /* Netgear3 / WG111T (2) */
+       AR5523_DEVICE_UG(0x1385, 0x5f00),       /* Netgear / WPN111 */
+       AR5523_DEVICE_UG(0x1385, 0x5f02),       /* Netgear / WPN111 */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, ar5523_id_table);
+
+static struct usb_driver ar5523_driver = {
+       .name           = "ar5523",
+       .id_table       = ar5523_id_table,
+       .probe          = ar5523_probe,
+       .disconnect     = ar5523_disconnect,
+};
+
+static int __init ar5523_init(void)
+{
+       return usb_register(&ar5523_driver);
+}
+
+static void __exit ar5523_exit(void)
+{
+       usb_deregister(&ar5523_driver);
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_FIRMWARE(AR5523_FIRMWARE_FILE);
+
+module_init(ar5523_init);
+module_exit(ar5523_exit);
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.h b/drivers/net/wireless/ath/ar5523/ar5523.h
new file mode 100644 (file)
index 0000000..00c6fd3
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007 Christoph Hellwig <hch@lst.de>
+ * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
+ * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com>
+ *
+ * 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.
+ */
+
+#define AR5523_FLAG_PRE_FIRMWARE       (1 << 0)
+#define AR5523_FLAG_ABG                        (1 << 1)
+
+#define AR5523_FIRMWARE_FILE   "ar5523.bin"
+
+#define AR5523_CMD_TX_PIPE     0x01
+#define        AR5523_DATA_TX_PIPE     0x02
+#define        AR5523_CMD_RX_PIPE      0x81
+#define        AR5523_DATA_RX_PIPE     0x82
+
+#define ar5523_cmd_tx_pipe(dev) \
+       usb_sndbulkpipe((dev), AR5523_CMD_TX_PIPE)
+#define ar5523_data_tx_pipe(dev) \
+       usb_sndbulkpipe((dev), AR5523_DATA_TX_PIPE)
+#define ar5523_cmd_rx_pipe(dev) \
+       usb_rcvbulkpipe((dev), AR5523_CMD_RX_PIPE)
+#define ar5523_data_rx_pipe(dev) \
+       usb_rcvbulkpipe((dev), AR5523_DATA_RX_PIPE)
+
+#define        AR5523_DATA_TIMEOUT     10000
+#define        AR5523_CMD_TIMEOUT      1000
+
+#define AR5523_TX_DATA_COUNT           8
+#define AR5523_TX_DATA_RESTART_COUNT   2
+#define AR5523_RX_DATA_COUNT           16
+#define AR5523_RX_DATA_REFILL_COUNT    8
+
+#define AR5523_CMD_ID  1
+#define AR5523_DATA_ID 2
+
+#define AR5523_TX_WD_TIMEOUT   (HZ * 2)
+#define AR5523_FLUSH_TIMEOUT   (HZ * 3)
+
+enum AR5523_flags {
+       AR5523_HW_UP,
+       AR5523_USB_DISCONNECTED,
+       AR5523_CONNECTED
+};
+
+struct ar5523_tx_cmd {
+       struct ar5523           *ar;
+       struct urb              *urb_tx;
+       void                    *buf_tx;
+       void                    *odata;
+       int                     olen;
+       int                     flags;
+       int                     res;
+       struct completion       done;
+};
+
+/* This struct is placed in tx_info->driver_data. It must not be larger
+ *  than IEEE80211_TX_INFO_DRIVER_DATA_SIZE.
+ */
+struct ar5523_tx_data {
+       struct list_head        list;
+       struct ar5523           *ar;
+       struct sk_buff          *skb;
+       struct urb              *urb;
+};
+
+struct ar5523_rx_data {
+       struct  list_head       list;
+       struct ar5523           *ar;
+       struct urb              *urb;
+       struct sk_buff          *skb;
+};
+
+struct ar5523 {
+       struct usb_device       *dev;
+       struct ieee80211_hw     *hw;
+
+       unsigned long           flags;
+       struct mutex            mutex;
+       struct workqueue_struct *wq;
+
+       struct ar5523_tx_cmd    tx_cmd;
+
+       struct delayed_work     stat_work;
+
+       struct timer_list       tx_wd_timer;
+       struct work_struct      tx_wd_work;
+       struct work_struct      tx_work;
+       struct list_head        tx_queue_pending;
+       struct list_head        tx_queue_submitted;
+       spinlock_t              tx_data_list_lock;
+       wait_queue_head_t       tx_flush_waitq;
+
+       /* Queued + Submitted TX frames */
+       atomic_t                tx_nr_total;
+
+       /* Submitted TX frames */
+       atomic_t                tx_nr_pending;
+
+       void                    *rx_cmd_buf;
+       struct urb              *rx_cmd_urb;
+
+       struct ar5523_rx_data   rx_data[AR5523_RX_DATA_COUNT];
+       spinlock_t              rx_data_list_lock;
+       struct list_head        rx_data_free;
+       struct list_head        rx_data_used;
+       atomic_t                rx_data_free_cnt;
+
+       struct work_struct      rx_refill_work;
+
+       unsigned int            rxbufsz;
+       u8                      serial[16];
+
+       struct ieee80211_channel channels[14];
+       struct ieee80211_rate   rates[12];
+       struct ieee80211_supported_band band;
+       struct ieee80211_vif    *vif;
+};
+
+/* flags for sending firmware commands */
+#define AR5523_CMD_FLAG_READ   (1 << 1)
+#define AR5523_CMD_FLAG_MAGIC  (1 << 2)
+
+#define ar5523_dbg(ar, format, arg...) \
+       dev_dbg(&(ar)->dev->dev, format, ## arg)
+
+/* On USB hot-unplug there can be a lot of URBs in flight and they'll all
+ * fail. Instead of dealing with them in every possible place just surpress
+ * any messages on USB disconnect.
+ */
+#define ar5523_err(ar, format, arg...) \
+do { \
+       if (!test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) { \
+               dev_err(&(ar)->dev->dev, format, ## arg); \
+       } \
+} while (0)
+#define ar5523_info(ar, format, arg...)        \
+       dev_info(&(ar)->dev->dev, format, ## arg)
diff --git a/drivers/net/wireless/ath/ar5523/ar5523_hw.h b/drivers/net/wireless/ath/ar5523/ar5523_hw.h
new file mode 100644 (file)
index 0000000..a0e8bf4
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007 Christoph Hellwig <hch@lst.de>
+ * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
+ * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com>
+ *
+ * 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.
+ */
+
+/* all fields are big endian */
+struct ar5523_fwblock {
+       __be32          flags;
+#define AR5523_WRITE_BLOCK     (1 << 4)
+
+       __be32  len;
+#define AR5523_MAX_FWBLOCK_SIZE        2048
+
+       __be32          total;
+       __be32          remain;
+       __be32          rxtotal;
+       __be32          pad[123];
+} __packed;
+
+#define AR5523_MAX_RXCMDSZ     1024
+#define AR5523_MAX_TXCMDSZ     1024
+
+struct ar5523_cmd_hdr {
+       __be32          len;
+       __be32          code;
+/* NB: these are defined for rev 1.5 firmware; rev 1.6 is different */
+/* messages from Host -> Target */
+#define        WDCMSG_HOST_AVAILABLE           0x01
+#define WDCMSG_BIND                    0x02
+#define WDCMSG_TARGET_RESET            0x03
+#define WDCMSG_TARGET_GET_CAPABILITY   0x04
+#define WDCMSG_TARGET_SET_CONFIG       0x05
+#define WDCMSG_TARGET_GET_STATUS       0x06
+#define WDCMSG_TARGET_GET_STATS                0x07
+#define WDCMSG_TARGET_START            0x08
+#define WDCMSG_TARGET_STOP             0x09
+#define WDCMSG_TARGET_ENABLE           0x0a
+#define WDCMSG_TARGET_DISABLE          0x0b
+#define        WDCMSG_CREATE_CONNECTION        0x0c
+#define WDCMSG_UPDATE_CONNECT_ATTR     0x0d
+#define        WDCMSG_DELETE_CONNECT           0x0e
+#define        WDCMSG_SEND                     0x0f
+#define WDCMSG_FLUSH                   0x10
+/* messages from Target -> Host */
+#define        WDCMSG_STATS_UPDATE             0x11
+#define        WDCMSG_BMISS                    0x12
+#define        WDCMSG_DEVICE_AVAIL             0x13
+#define        WDCMSG_SEND_COMPLETE            0x14
+#define        WDCMSG_DATA_AVAIL               0x15
+#define        WDCMSG_SET_PWR_MODE             0x16
+#define        WDCMSG_BMISS_ACK                0x17
+#define        WDCMSG_SET_LED_STEADY           0x18
+#define        WDCMSG_SET_LED_BLINK            0x19
+/* more messages */
+#define        WDCMSG_SETUP_BEACON_DESC        0x1a
+#define        WDCMSG_BEACON_INIT              0x1b
+#define        WDCMSG_RESET_KEY_CACHE          0x1c
+#define        WDCMSG_RESET_KEY_CACHE_ENTRY    0x1d
+#define        WDCMSG_SET_KEY_CACHE_ENTRY      0x1e
+#define        WDCMSG_SET_DECOMP_MASK          0x1f
+#define        WDCMSG_SET_REGULATORY_DOMAIN    0x20
+#define        WDCMSG_SET_LED_STATE            0x21
+#define        WDCMSG_WRITE_ASSOCID            0x22
+#define        WDCMSG_SET_STA_BEACON_TIMERS    0x23
+#define        WDCMSG_GET_TSF                  0x24
+#define        WDCMSG_RESET_TSF                0x25
+#define        WDCMSG_SET_ADHOC_MODE           0x26
+#define        WDCMSG_SET_BASIC_RATE           0x27
+#define        WDCMSG_MIB_CONTROL              0x28
+#define        WDCMSG_GET_CHANNEL_DATA         0x29
+#define        WDCMSG_GET_CUR_RSSI             0x2a
+#define        WDCMSG_SET_ANTENNA_SWITCH       0x2b
+#define        WDCMSG_USE_SHORT_SLOT_TIME      0x2f
+#define        WDCMSG_SET_POWER_MODE           0x30
+#define        WDCMSG_SETUP_PSPOLL_DESC        0x31
+#define        WDCMSG_SET_RX_MULTICAST_FILTER  0x32
+#define        WDCMSG_RX_FILTER                0x33
+#define        WDCMSG_PER_CALIBRATION          0x34
+#define        WDCMSG_RESET                    0x35
+#define        WDCMSG_DISABLE                  0x36
+#define        WDCMSG_PHY_DISABLE              0x37
+#define        WDCMSG_SET_TX_POWER_LIMIT       0x38
+#define        WDCMSG_SET_TX_QUEUE_PARAMS      0x39
+#define        WDCMSG_SETUP_TX_QUEUE           0x3a
+#define        WDCMSG_RELEASE_TX_QUEUE         0x3b
+#define        WDCMSG_SET_DEFAULT_KEY          0x43
+
+       __u32           priv;   /* driver private data,
+                                  don't care about endianess */
+       __be32          magic;
+       __be32          reserved2[4];
+};
+
+struct ar5523_cmd_host_available {
+       __be32  sw_ver_major;
+       __be32  sw_ver_minor;
+       __be32  sw_ver_patch;
+       __be32  sw_ver_build;
+} __packed;
+
+#define        ATH_SW_VER_MAJOR        1
+#define        ATH_SW_VER_MINOR        5
+#define        ATH_SW_VER_PATCH        0
+#define        ATH_SW_VER_BUILD        9999
+
+struct ar5523_chunk {
+       u8              seqnum;         /* sequence number for ordering */
+       u8              flags;
+#define        UATH_CFLAGS_FINAL       0x01    /* final chunk of a msg */
+#define        UATH_CFLAGS_RXMSG       0x02    /* chunk contains rx completion */
+#define        UATH_CFLAGS_DEBUG       0x04    /* for debugging */
+       __be16          length;         /* chunk size in bytes */
+       /* chunk data follows */
+} __packed;
+
+/*
+ * Message format for a WDCMSG_DATA_AVAIL message from Target to Host.
+ */
+struct ar5523_rx_desc {
+       __be32  len;            /* msg length including header */
+       __be32  code;           /* WDCMSG_DATA_AVAIL */
+       __be32  gennum;         /* generation number */
+       __be32  status;         /* start of RECEIVE_INFO */
+#define        UATH_STATUS_OK                  0
+#define        UATH_STATUS_STOP_IN_PROGRESS    1
+#define        UATH_STATUS_CRC_ERR             2
+#define        UATH_STATUS_PHY_ERR             3
+#define        UATH_STATUS_DECRYPT_CRC_ERR     4
+#define        UATH_STATUS_DECRYPT_MIC_ERR     5
+#define        UATH_STATUS_DECOMP_ERR          6
+#define        UATH_STATUS_KEY_ERR             7
+#define        UATH_STATUS_ERR                 8
+       __be32  tstamp_low;     /* low-order 32-bits of rx timestamp */
+       __be32  tstamp_high;    /* high-order 32-bits of rx timestamp */
+       __be32  framelen;       /* frame length */
+       __be32  rate;           /* rx rate code */
+       __be32  antenna;
+       __be32  rssi;
+       __be32  channel;
+       __be32  phyerror;
+       __be32  connix;         /* key table ix for bss traffic */
+       __be32  decrypterror;
+       __be32  keycachemiss;
+       __be32  pad;            /* XXX? */
+} __packed;
+
+struct ar5523_tx_desc {
+       __be32  msglen;
+       __be32  msgid;          /* msg id (supplied by host) */
+       __be32  type;           /* opcode: WDMSG_SEND or WDCMSG_FLUSH */
+       __be32  txqid;          /* tx queue id and flags */
+#define        UATH_TXQID_MASK         0x0f
+#define        UATH_TXQID_MINRATE      0x10    /* use min tx rate */
+#define        UATH_TXQID_FF           0x20    /* content is fast frame */
+       __be32  connid;         /* tx connection id */
+#define UATH_ID_INVALID        0xffffffff      /* for sending prior to connection */
+       __be32  flags;          /* non-zero if response desired */
+#define UATH_TX_NOTIFY (1 << 24)       /* f/w will send a UATH_NOTIF_TX */
+       __be32  buflen;         /* payload length */
+} __packed;
+
+
+#define AR5523_ID_BSS          2
+#define AR5523_ID_BROADCAST    0xffffffff
+
+/* structure for command UATH_CMD_WRITE_MAC */
+struct ar5523_write_mac {
+       __be32  reg;
+       __be32  len;
+       u8              data[32];
+} __packed;
+
+struct ar5523_cmd_rateset {
+       __u8            length;
+#define AR5523_MAX_NRATES      32
+       __u8            set[AR5523_MAX_NRATES];
+};
+
+struct ar5523_cmd_set_associd {                /* AR5523_WRITE_ASSOCID */
+       __be32  defaultrateix;
+       __be32  associd;
+       __be32  timoffset;
+       __be32  turboprime;
+       __u8    bssid[6];
+} __packed;
+
+/* structure for command WDCMSG_RESET */
+struct ar5523_cmd_reset {
+       __be32  flags;          /* channel flags */
+#define        UATH_CHAN_TURBO 0x0100
+#define        UATH_CHAN_CCK   0x0200
+#define        UATH_CHAN_OFDM  0x0400
+#define        UATH_CHAN_2GHZ  0x1000
+#define        UATH_CHAN_5GHZ  0x2000
+       __be32  freq;           /* channel frequency */
+       __be32  maxrdpower;
+       __be32  cfgctl;
+       __be32  twiceantennareduction;
+       __be32  channelchange;
+       __be32  keeprccontent;
+} __packed;
+
+/* structure for command WDCMSG_SET_BASIC_RATE */
+struct ar5523_cmd_rates {
+       __be32  connid;
+       __be32  keeprccontent;
+       __be32  size;
+       struct ar5523_cmd_rateset rateset;
+} __packed;
+
+enum {
+       WLAN_MODE_NONE = 0,
+       WLAN_MODE_11b,
+       WLAN_MODE_11a,
+       WLAN_MODE_11g,
+       WLAN_MODE_11a_TURBO,
+       WLAN_MODE_11g_TURBO,
+       WLAN_MODE_11a_TURBO_PRIME,
+       WLAN_MODE_11g_TURBO_PRIME,
+       WLAN_MODE_11a_XR,
+       WLAN_MODE_11g_XR,
+};
+
+struct ar5523_cmd_connection_attr {
+       __be32  longpreambleonly;
+       struct ar5523_cmd_rateset       rateset;
+       __be32  wlanmode;
+} __packed;
+
+/* structure for command AR5523_CREATE_CONNECTION */
+struct ar5523_cmd_create_connection {
+       __be32  connid;
+       __be32  bssid;
+       __be32  size;
+       struct ar5523_cmd_connection_attr       connattr;
+} __packed;
+
+struct ar5523_cmd_ledsteady {          /* WDCMSG_SET_LED_STEADY */
+       __be32  lednum;
+#define UATH_LED_LINK          0
+#define UATH_LED_ACTIVITY      1
+       __be32  ledmode;
+#define UATH_LED_OFF   0
+#define UATH_LED_ON    1
+} __packed;
+
+struct ar5523_cmd_ledblink {           /* WDCMSG_SET_LED_BLINK */
+       __be32  lednum;
+       __be32  ledmode;
+       __be32  blinkrate;
+       __be32  slowmode;
+} __packed;
+
+struct ar5523_cmd_ledstate {           /* WDCMSG_SET_LED_STATE */
+       __be32  connected;
+} __packed;
+
+struct ar5523_cmd_txq_attr {
+       __be32  priority;
+       __be32  aifs;
+       __be32  logcwmin;
+       __be32  logcwmax;
+       __be32  bursttime;
+       __be32  mode;
+       __be32  qflags;
+} __packed;
+
+struct ar5523_cmd_txq_setup {          /* WDCMSG_SETUP_TX_QUEUE */
+       __be32  qid;
+       __be32  len;
+       struct ar5523_cmd_txq_attr attr;
+} __packed;
+
+struct ar5523_cmd_rx_filter {          /* WDCMSG_RX_FILTER */
+       __be32  bits;
+#define UATH_FILTER_RX_UCAST           0x00000001
+#define UATH_FILTER_RX_MCAST           0x00000002
+#define UATH_FILTER_RX_BCAST           0x00000004
+#define UATH_FILTER_RX_CONTROL         0x00000008
+#define UATH_FILTER_RX_BEACON          0x00000010      /* beacon frames */
+#define UATH_FILTER_RX_PROM            0x00000020      /* promiscuous mode */
+#define UATH_FILTER_RX_PHY_ERR         0x00000040      /* phy errors */
+#define UATH_FILTER_RX_PHY_RADAR       0x00000080      /* radar phy errors */
+#define UATH_FILTER_RX_XR_POOL         0x00000400      /* XR group polls */
+#define UATH_FILTER_RX_PROBE_REQ       0x00000800
+       __be32  op;
+#define UATH_FILTER_OP_INIT            0x0
+#define UATH_FILTER_OP_SET             0x1
+#define UATH_FILTER_OP_CLEAR           0x2
+#define UATH_FILTER_OP_TEMP            0x3
+#define UATH_FILTER_OP_RESTORE         0x4
+} __packed;
+
+enum {
+       CFG_NONE,                       /* Sentinal to indicate "no config" */
+       CFG_REG_DOMAIN,                 /* Regulatory Domain */
+       CFG_RATE_CONTROL_ENABLE,
+       CFG_DEF_XMIT_DATA_RATE,         /* NB: if rate control is not enabled */
+       CFG_HW_TX_RETRIES,
+       CFG_SW_TX_RETRIES,
+       CFG_SLOW_CLOCK_ENABLE,
+       CFG_COMP_PROC,
+       CFG_USER_RTS_THRESHOLD,
+       CFG_XR2NORM_RATE_THRESHOLD,
+       CFG_XRMODE_SWITCH_COUNT,
+       CFG_PROTECTION_TYPE,
+       CFG_BURST_SEQ_THRESHOLD,
+       CFG_ABOLT,
+       CFG_IQ_LOG_COUNT_MAX,
+       CFG_MODE_CTS,
+       CFG_WME_ENABLED,
+       CFG_GPRS_CBR_PERIOD,
+       CFG_SERVICE_TYPE,
+       /* MAC Address to use.  Overrides EEPROM */
+       CFG_MAC_ADDR,
+       CFG_DEBUG_EAR,
+       CFG_INIT_REGS,
+       /* An ID for use in error & debug messages */
+       CFG_DEBUG_ID,
+       CFG_COMP_WIN_SZ,
+       CFG_DIVERSITY_CTL,
+       CFG_TP_SCALE,
+       CFG_TPC_HALF_DBM5,
+       CFG_TPC_HALF_DBM2,
+       CFG_OVERRD_TX_POWER,
+       CFG_USE_32KHZ_CLOCK,
+       CFG_GMODE_PROTECTION,
+       CFG_GMODE_PROTECT_RATE_INDEX,
+       CFG_GMODE_NON_ERP_PREAMBLE,
+       CFG_WDC_TRANSPORT_CHUNK_SIZE,
+};
+
+enum {
+       /* Sentinal to indicate "no capability" */
+       CAP_NONE,
+       CAP_ALL,                        /* ALL capabilities */
+       CAP_TARGET_VERSION,
+       CAP_TARGET_REVISION,
+       CAP_MAC_VERSION,
+       CAP_MAC_REVISION,
+       CAP_PHY_REVISION,
+       CAP_ANALOG_5GHz_REVISION,
+       CAP_ANALOG_2GHz_REVISION,
+       /* Target supports WDC message debug features */
+       CAP_DEBUG_WDCMSG_SUPPORT,
+
+       CAP_REG_DOMAIN,
+       CAP_COUNTRY_CODE,
+       CAP_REG_CAP_BITS,
+
+       CAP_WIRELESS_MODES,
+       CAP_CHAN_SPREAD_SUPPORT,
+       CAP_SLEEP_AFTER_BEACON_BROKEN,
+       CAP_COMPRESS_SUPPORT,
+       CAP_BURST_SUPPORT,
+       CAP_FAST_FRAMES_SUPPORT,
+       CAP_CHAP_TUNING_SUPPORT,
+       CAP_TURBOG_SUPPORT,
+       CAP_TURBO_PRIME_SUPPORT,
+       CAP_DEVICE_TYPE,
+       CAP_XR_SUPPORT,
+       CAP_WME_SUPPORT,
+       CAP_TOTAL_QUEUES,
+       CAP_CONNECTION_ID_MAX,          /* Should absorb CAP_KEY_CACHE_SIZE */
+
+       CAP_LOW_5GHZ_CHAN,
+       CAP_HIGH_5GHZ_CHAN,
+       CAP_LOW_2GHZ_CHAN,
+       CAP_HIGH_2GHZ_CHAN,
+
+       CAP_MIC_AES_CCM,
+       CAP_MIC_CKIP,
+       CAP_MIC_TKIP,
+       CAP_MIC_TKIP_WME,
+       CAP_CIPHER_AES_CCM,
+       CAP_CIPHER_CKIP,
+       CAP_CIPHER_TKIP,
+
+       CAP_TWICE_ANTENNAGAIN_5G,
+       CAP_TWICE_ANTENNAGAIN_2G,
+};
+
+enum {
+       ST_NONE,                    /* Sentinal to indicate "no status" */
+       ST_ALL,
+       ST_SERVICE_TYPE,
+       ST_WLAN_MODE,
+       ST_FREQ,
+       ST_BAND,
+       ST_LAST_RSSI,
+       ST_PS_FRAMES_DROPPED,
+       ST_CACHED_DEF_ANT,
+       ST_COUNT_OTHER_RX_ANT,
+       ST_USE_FAST_DIVERSITY,
+       ST_MAC_ADDR,
+       ST_RX_GENERATION_NUM,
+       ST_TX_QUEUE_DEPTH,
+       ST_SERIAL_NUMBER,
+       ST_WDC_TRANSPORT_CHUNK_SIZE,
+};
+
+enum {
+       TARGET_DEVICE_AWAKE,
+       TARGET_DEVICE_SLEEP,
+       TARGET_DEVICE_PWRDN,
+       TARGET_DEVICE_PWRSAVE,
+       TARGET_DEVICE_SUSPEND,
+       TARGET_DEVICE_RESUME,
+};
+
+/* this is in net/ieee80211.h, but that conflicts with the mac80211 headers */
+#define IEEE80211_2ADDR_LEN    16
+
+#define AR5523_MIN_RXBUFSZ                             \
+       (((sizeof(__be32) + IEEE80211_2ADDR_LEN +       \
+          sizeof(struct ar5523_rx_desc)) + 3) & ~3)
index 7089f81..2770899 100644 (file)
@@ -301,7 +301,7 @@ static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
 
 static bool ath6kl_is_wpa_ie(const u8 *pos)
 {
-       return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
+       return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
                pos[2] == 0x00 && pos[3] == 0x50 &&
                pos[4] == 0xf2 && pos[5] == 0x01;
 }
@@ -3651,7 +3651,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
 
        if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
                     ar->fw_capabilities))
-               ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER;
+               ar->wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
 
        ar->wiphy->probe_resp_offload =
                NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
index 84b558d..162401f 100644 (file)
@@ -276,6 +276,11 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
                                offset_array[i],
                                REG_READ(ah, offset_array[i]));
 
+                       if (AR_SREV_9565(ah) &&
+                           (iCoff == 63 || qCoff == 63 ||
+                            iCoff == -63 || qCoff == -63))
+                               return;
+
                        REG_RMW_FIELD(ah, offset_array[i],
                                      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
                                      iCoff);
index 5bbe505..c86cb64 100644 (file)
@@ -18,6 +18,7 @@
 #include "hw.h"
 #include "ar9003_phy.h"
 #include "ar9003_eeprom.h"
+#include "ar9003_mci.h"
 
 #define COMP_HDR_LEN 4
 #define COMP_CKSUM_LEN 2
@@ -41,7 +42,6 @@
 static int ar9003_hw_power_interpolate(int32_t x,
                                       int32_t *px, int32_t *py, u_int16_t np);
 
-
 static const struct ar9300_eeprom ar9300_default = {
        .eepromVersion = 2,
        .templateVersion = 2,
@@ -2989,7 +2989,7 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
        case EEP_PAPRD:
                if (AR_SREV_9462(ah))
                        return false;
-               if (!ah->config.enable_paprd);
+               if (!ah->config.enable_paprd)
                        return false;
                return !!(pBase->featureEnable & BIT(5));
        case EEP_CHAIN_MASK_REDUCE:
@@ -3601,7 +3601,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
         *   7:4 R/W  SWITCH_TABLE_COM_SPDT_WLAN_IDLE
         * SWITCH_TABLE_COM_SPDT_WLAN_IDLE
         */
-       if (AR_SREV_9462_20_OR_LATER(ah)) {
+       if (AR_SREV_9462_20(ah) || AR_SREV_9565(ah)) {
                value = ar9003_switch_com_spdt_get(ah, is2ghz);
                REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
                                AR_SWITCH_TABLE_COM_SPDT_ALL, value);
@@ -5037,16 +5037,28 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
                case CTL_5GHT20:
                case CTL_2GHT20:
                        for (i = ALL_TARGET_HT20_0_8_16;
-                            i <= ALL_TARGET_HT20_23; i++)
+                            i <= ALL_TARGET_HT20_23; i++) {
                                pPwrArray[i] = (u8)min((u16)pPwrArray[i],
                                                       minCtlPower);
+                               if (ath9k_hw_mci_is_enabled(ah))
+                                       pPwrArray[i] =
+                                               (u8)min((u16)pPwrArray[i],
+                                               ar9003_mci_get_max_txpower(ah,
+                                                       pCtlMode[ctlMode]));
+                       }
                        break;
                case CTL_5GHT40:
                case CTL_2GHT40:
                        for (i = ALL_TARGET_HT40_0_8_16;
-                            i <= ALL_TARGET_HT40_23; i++)
+                            i <= ALL_TARGET_HT40_23; i++) {
                                pPwrArray[i] = (u8)min((u16)pPwrArray[i],
                                                       minCtlPower);
+                               if (ath9k_hw_mci_is_enabled(ah))
+                                       pPwrArray[i] =
+                                               (u8)min((u16)pPwrArray[i],
+                                               ar9003_mci_get_max_txpower(ah,
+                                                       pCtlMode[ctlMode]));
+                       }
                        break;
                default:
                        break;
index 1a36fa2..0693cd9 100644 (file)
@@ -219,10 +219,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
 
                /* Awake -> Sleep Setting */
                INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                              ar9462_pciephy_pll_on_clkreq_disable_L1_2p0);
+                              ar9462_pciephy_clkreq_disable_L1_2p0);
                /* Sleep -> Awake Setting */
                INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-                              ar9462_pciephy_pll_on_clkreq_disable_L1_2p0);
+                              ar9462_pciephy_clkreq_disable_L1_2p0);
 
                /* Fast clock modal settings */
                INIT_INI_ARRAY(&ah->iniModesFastClock,
@@ -328,9 +328,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                               ar9565_1p0_Modes_lowest_ob_db_tx_gain_table);
 
                INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                              ar9565_1p0_pciephy_pll_on_clkreq_disable_L1);
+                              ar9565_1p0_pciephy_clkreq_disable_L1);
                INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-                              ar9565_1p0_pciephy_pll_on_clkreq_disable_L1);
+                              ar9565_1p0_pciephy_clkreq_disable_L1);
 
                INIT_INI_ARRAY(&ah->iniModesFastClock,
                                ar9565_1p0_modes_fast_clock);
index 44c202c..42b4412 100644 (file)
@@ -750,6 +750,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        mci_hw->bt_state = MCI_BT_AWAKE;
 
+       REG_CLR_BIT(ah, AR_PHY_TIMING4,
+                   1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT);
+
        if (caldata) {
                caldata->done_txiqcal_once = false;
                caldata->done_txclcal_once = false;
@@ -759,6 +762,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (!ath9k_hw_init_cal(ah, chan))
                return -EIO;
 
+       REG_SET_BIT(ah, AR_PHY_TIMING4,
+                   1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT);
+
 exit:
        ar9003_mci_enable_interrupt(ah);
        return 0;
@@ -799,6 +805,9 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
        REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
                      AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
 
+       if (AR_SREV_9565(ah))
+               REG_RMW_FIELD(ah, AR_MCI_MISC, AR_MCI_MISC_HW_FIX_EN, 1);
+
        if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
                thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
                REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
@@ -818,7 +827,7 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 regval;
+       u32 regval, i;
 
        ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n",
                is_full_sleep, is_2g);
@@ -847,11 +856,18 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
                 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
                 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
                 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
-                SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
-                SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
                 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
                 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
                 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+       if (AR_SREV_9565(ah)) {
+               regval |= SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
+                         SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK);
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2,
+                             AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1);
+       } else {
+               regval |= SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
+                         SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK);
+       }
 
        REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
 
@@ -865,9 +881,24 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
        REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
                      AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
 
-       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
+       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0);
        REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
 
+       /* Set the time out to 3.125ms (5 BT slots) */
+       REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090);
+
+       /* concurrent tx priority */
+       if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) {
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2,
+                             AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0);
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2,
+                             AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f);
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                             AR_BTCOEX_CTRL_REDUCE_TXPWR, 0);
+               for (i = 0; i < 8; i++)
+                       REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f);
+       }
+
        regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
        REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval);
        REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
@@ -910,6 +941,9 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
        mci->ready = true;
        ar9003_mci_prep_interface(ah);
 
+       if (AR_SREV_9565(ah))
+               REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL,
+                             AR_MCI_DBG_CNT_CTRL_ENABLE, 0);
        if (en_int)
                ar9003_mci_enable_interrupt(ah);
 
@@ -1028,7 +1062,9 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
 
                if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
                        ar9003_mci_osla_setup(ah, true);
-               REG_WRITE(ah, AR_SELFGEN_MASK, 0x02);
+
+               if (AR_SREV_9462(ah))
+                       REG_WRITE(ah, AR_SELFGEN_MASK, 0x02);
        } else {
                ar9003_mci_send_lna_take(ah, true);
                udelay(5);
@@ -1170,7 +1206,7 @@ EXPORT_SYMBOL(ar9003_mci_cleanup);
 u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 value = 0;
+       u32 value = 0, tsf;
        u8 query_type;
 
        switch (state_type) {
@@ -1228,6 +1264,14 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
                ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
                break;
        case MCI_STATE_RECOVER_RX:
+               tsf = ath9k_hw_gettsf32(ah);
+               if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) {
+                       ath_dbg(ath9k_hw_common(ah), MCI,
+                               "(MCI) ignore Rx recovery\n");
+                       break;
+               }
+               ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n");
+               mci->last_recovery = tsf;
                ar9003_mci_prep_interface(ah);
                mci->query_bt = true;
                mci->need_flush_btinfo = true;
@@ -1426,3 +1470,17 @@ void ar9003_mci_send_wlan_channels(struct ath_hw *ah)
        ar9003_mci_send_coex_wlan_channels(ah, true);
 }
 EXPORT_SYMBOL(ar9003_mci_send_wlan_channels);
+
+u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode)
+{
+       if (!ah->btcoex_hw.mci.concur_tx)
+               goto out;
+
+       if (ctlmode == CTL_2GHT20)
+               return ATH_BTCOEX_HT20_MAX_TXPOWER;
+       else if (ctlmode == CTL_2GHT40)
+               return ATH_BTCOEX_HT40_MAX_TXPOWER;
+
+out:
+       return -1;
+}
index 2a2d018..66d7ab9 100644 (file)
@@ -18,6 +18,7 @@
 #define AR9003_MCI_H
 
 #define MCI_FLAG_DISABLE_TIMESTAMP      0x00000001      /* Disable time stamp */
+#define MCI_RECOVERY_DUR_TSF           (100 * 1000)    /* 100 ms */
 
 /* Default remote BT device MCI COEX version */
 #define MCI_GPM_COEX_MAJOR_VERSION_DEFAULT  3
@@ -125,6 +126,7 @@ enum ath_mci_gpm_coex_profile_type {
        MCI_GPM_COEX_PROFILE_HID,
        MCI_GPM_COEX_PROFILE_BNEP,
        MCI_GPM_COEX_PROFILE_VOICE,
+       MCI_GPM_COEX_PROFILE_A2DPVO,
        MCI_GPM_COEX_PROFILE_MAX
 };
 
@@ -196,7 +198,6 @@ enum mci_state_type {
        MCI_STATE_SEND_WLAN_COEX_VERSION,
        MCI_STATE_SEND_VERSION_QUERY,
        MCI_STATE_SEND_STATUS_QUERY,
-       MCI_STATE_SET_CONCUR_TX_PRI,
        MCI_STATE_RECOVER_RX,
        MCI_STATE_NEED_FTP_STOMP,
        MCI_STATE_DEBUG,
@@ -278,6 +279,7 @@ void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
 void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
 void ar9003_mci_set_power_awake(struct ath_hw *ah);
 void ar9003_mci_check_gpm_offset(struct ath_hw *ah);
+u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode);
 
 #else
 
@@ -324,6 +326,10 @@ static inline void ar9003_mci_set_power_awake(struct ath_hw *ah)
 static inline void ar9003_mci_check_gpm_offset(struct ath_hw *ah)
 {
 }
+static inline u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode)
+{
+       return -1;
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #endif
index 9a48e3d..8f58523 100644 (file)
@@ -32,6 +32,7 @@
 #define AR_PHY_SPUR_REG     (AR_CHAN_BASE + 0x1c)
 #define AR_PHY_RX_IQCAL_CORR_B0    (AR_CHAN_BASE + 0xdc)
 #define AR_PHY_TX_IQCAL_CONTROL_3  (AR_CHAN_BASE + 0xb0)
+#define AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT 16
 
 #define AR_PHY_TIMING11_SPUR_FREQ_SD    0x3FF00000
 #define AR_PHY_TIMING11_SPUR_FREQ_SD_S  20
index 843e79f..0c2ac0c 100644 (file)
@@ -768,9 +768,9 @@ static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = {
        {0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 };
 
-static const u32 ar9565_1p0_pciephy_pll_on_clkreq_disable_L1[][2] = {
+static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = {
        /* Addr      allmodes  */
-       {0x00018c00, 0x18212ede},
+       {0x00018c00, 0x18213ede},
        {0x00018c04, 0x000801d8},
        {0x00018c08, 0x0003780c},
 };
index dfe6a47..4e125d8 100644 (file)
@@ -437,6 +437,7 @@ void ath9k_set_beacon(struct ath_softc *sc);
 #define ATH_LONG_CALINTERVAL_INT  1000    /* 1000 ms */
 #define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
+#define ATH_ANI_MAX_SKIP_COUNT  10
 
 #define ATH_PAPRD_TIMEOUT      100 /* msecs */
 #define ATH_PLL_WORK_INTERVAL   100
@@ -478,6 +479,7 @@ struct ath_btcoex {
        u32 btscan_no_stomp; /* in usec */
        u32 duty_cycle;
        u32 bt_wait_time;
+       int rssi_count;
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
        struct ath_mci_profile mci;
 };
@@ -492,6 +494,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
 void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);
 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);
 void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc);
+int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size);
 #else
 static inline int ath9k_init_btcoex(struct ath_softc *sc)
 {
@@ -518,6 +521,11 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,
 static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
 {
 }
+static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf,
+                                   u32 len, u32 size)
+{
+       return 0;
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 struct ath9k_wow_pattern {
@@ -642,6 +650,7 @@ enum sc_op_flags {
 #define PS_WAIT_FOR_PSPOLL_DATA   BIT(2)
 #define PS_WAIT_FOR_TX_ACK        BIT(3)
 #define PS_BEACON_SYNC            BIT(4)
+#define PS_WAIT_FOR_ANI           BIT(5)
 
 struct ath_rate_table;
 
index 419e9a3..c90e9bc 100644 (file)
@@ -195,7 +195,7 @@ void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)
        ah->btcoex_hw.mci.need_flush_btinfo = false;
        ah->btcoex_hw.mci.wlan_cal_seq = 0;
        ah->btcoex_hw.mci.wlan_cal_done = 0;
-       ah->btcoex_hw.mci.config = 0x2201;
+       ah->btcoex_hw.mci.config = (AR_SREV_9462(ah)) ? 0x2201 : 0xa4c1;
 }
 EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci);
 
@@ -218,27 +218,45 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
                                enum ath_stomp_type stomp_type)
 {
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+       u8 txprio_shift[] = { 24, 16, 16, 0 }; /* tx priority weight */
+       bool concur_tx = (mci_hw->concur_tx && btcoex_hw->tx_prio[stomp_type]);
+       const u32 *weight = ar9003_wlan_weights[stomp_type];
+       int i;
 
-       if (AR_SREV_9300_20_OR_LATER(ah)) {
-               const u32 *weight = ar9003_wlan_weights[stomp_type];
-               int i;
-
-               if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
-                       if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
-                           btcoex_hw->mci.stomp_ftp)
-                               stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
-                       weight = mci_wlan_weights[stomp_type];
-               }
-
-               for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
-                       btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
-                       btcoex_hw->wlan_weight[i] = weight[i];
-               }
-       } else {
+       if (!AR_SREV_9300_20_OR_LATER(ah)) {
                btcoex_hw->bt_coex_weights =
                        SM(bt_weight, AR_BTCOEX_BT_WGHT) |
                        SM(wlan_weight, AR_BTCOEX_WL_WGHT);
+               return;
+       }
+
+       if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+               enum ath_stomp_type stype =
+                       ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
+                        btcoex_hw->mci.stomp_ftp) ?
+                       ATH_BTCOEX_STOMP_LOW_FTP : stomp_type;
+               weight = mci_wlan_weights[stype];
        }
+
+       for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
+               btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
+               btcoex_hw->wlan_weight[i] = weight[i];
+               if (concur_tx && i) {
+                       btcoex_hw->wlan_weight[i] &=
+                               ~(0xff << txprio_shift[i-1]);
+                       btcoex_hw->wlan_weight[i] |=
+                               (btcoex_hw->tx_prio[stomp_type] <<
+                                txprio_shift[i-1]);
+               }
+       }
+       /* Last WLAN weight has to be adjusted wrt tx priority */
+       if (concur_tx) {
+               btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]);
+               btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type]
+                                                     << txprio_shift[i-1]);
+       }
+
 }
 EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
 
@@ -385,3 +403,13 @@ void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
        }
 }
 EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp);
+
+void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio)
+{
+       struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
+       int i;
+
+       for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
+               btcoex->tx_prio[i] = stomp_txprio[i];
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_set_concur_txprio);
index 385197a..2f84ab2 100644 (file)
@@ -39,6 +39,9 @@
 #define ATH_BTCOEX_RX_WAIT_TIME       100
 #define ATH_BTCOEX_STOMP_FTP_THRESH   5
 
+#define ATH_BTCOEX_HT20_MAX_TXPOWER   0x14
+#define ATH_BTCOEX_HT40_MAX_TXPOWER   0x10
+
 #define AR9300_NUM_BT_WEIGHTS   4
 #define AR9300_NUM_WLAN_WEIGHTS 4
 /* Defines the BT AR_BT_COEX_WGHT used */
@@ -84,6 +87,8 @@ struct ath9k_hw_mci {
        u8 bt_ver_minor;
        u8 bt_state;
        u8 stomp_ftp;
+       bool concur_tx;
+       u32 last_recovery;
 };
 
 struct ath_btcoex_hw {
@@ -98,6 +103,7 @@ struct ath_btcoex_hw {
        u32 bt_coex_mode2;      /* Register setting for AR_BT_COEX_MODE2 */
        u32 bt_weight[AR9300_NUM_BT_WEIGHTS];
        u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
+       u8 tx_prio[ATH_BTCOEX_STOMP_MAX];
 };
 
 void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah);
@@ -112,5 +118,6 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
 void ath9k_hw_btcoex_disable(struct ath_hw *ah);
 void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
                              enum ath_stomp_type stomp_type);
+void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio);
 
 #endif
index e5cceb0..f3448a0 100644 (file)
@@ -410,6 +410,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
 
        ah->caldata->channel = chan->channel;
        ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
+       ah->caldata->chanmode = chan->chanmode;
        h = ah->caldata->nfCalHist;
        default_nf = ath9k_hw_get_default_nf(ah, chan);
        for (i = 0; i < NUM_NF_READINGS; i++) {
index 6727b56..a8be94b 100644 (file)
@@ -1586,6 +1586,35 @@ static const struct file_operations fops_samps = {
 
 #endif
 
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       u32 len = 0, size = 1500;
+       char *buf;
+       size_t retval;
+
+       buf = kzalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       len = ath9k_dump_btcoex(sc, buf, len, size);
+
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+
+       return retval;
+}
+
+static const struct file_operations fops_btcoex = {
+       .read = read_file_btcoex,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+#endif
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1658,6 +1687,9 @@ int ath9k_init_debug(struct ath_hw *ah)
                           sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
        debugfs_create_file("diversity", S_IRUSR | S_IWUSR,
                            sc->debug.debugfs_phy, sc, &fops_ant_diversity);
-
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+       debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
+                           &fops_btcoex);
+#endif
        return 0;
 }
index d9ed141..a8ea57b 100644 (file)
@@ -187,6 +187,24 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
        }
 }
 
+static void ath_mci_ftp_adjust(struct ath_softc *sc)
+{
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_hw *ah = sc->sc_ah;
+
+       if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
+               if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&
+                   (mci->num_pan || mci->num_other_acl))
+                       ah->btcoex_hw.mci.stomp_ftp =
+                               (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
+               else
+                       ah->btcoex_hw.mci.stomp_ftp = false;
+               btcoex->bt_wait_time = 0;
+               sc->rx.num_pkts = 0;
+       }
+}
+
 /*
  * This is the master bt coex timer which runs for every
  * 45ms, bt traffic will be given priority during 55% of this
@@ -197,41 +215,43 @@ static void ath_btcoex_period_timer(unsigned long data)
        struct ath_softc *sc = (struct ath_softc *) data;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex *btcoex = &sc->btcoex;
-       struct ath_mci_profile *mci = &btcoex->mci;
+       enum ath_stomp_type stomp_type;
        u32 timer_period;
-       bool is_btscan;
        unsigned long flags;
 
        spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) {
+               btcoex->bt_wait_time += btcoex->btcoex_period;
                spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
                goto skip_hw_wakeup;
        }
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
+       ath9k_mci_update_rssi(sc);
+
        ath9k_ps_wakeup(sc);
+
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
                ath_detect_bt_priority(sc);
-       is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags);
 
-       btcoex->bt_wait_time += btcoex->btcoex_period;
-       if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
-               if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&
-                   (mci->num_pan || mci->num_other_acl))
-                       ah->btcoex_hw.mci.stomp_ftp =
-                               (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
-               else
-                       ah->btcoex_hw.mci.stomp_ftp = false;
-               btcoex->bt_wait_time = 0;
-               sc->rx.num_pkts = 0;
-       }
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+               ath_mci_ftp_adjust(sc);
 
        spin_lock_bh(&btcoex->btcoex_lock);
 
-       ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
-                             btcoex->bt_stomp_type);
+       stomp_type = btcoex->bt_stomp_type;
+       timer_period = btcoex->btcoex_no_stomp;
+
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) {
+               if (test_bit(BT_OP_SCAN, &btcoex->op_flags)) {
+                       stomp_type = ATH_BTCOEX_STOMP_ALL;
+                       timer_period = btcoex->btscan_no_stomp;
+               }
+       }
 
+       ath9k_hw_btcoex_bt_stomp(ah, stomp_type);
        ath9k_hw_btcoex_enable(ah);
+
        spin_unlock_bh(&btcoex->btcoex_lock);
 
        /*
@@ -243,17 +263,16 @@ static void ath_btcoex_period_timer(unsigned long data)
                if (btcoex->hw_timer_enabled)
                        ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
 
-               timer_period = is_btscan ? btcoex->btscan_no_stomp :
-                                          btcoex->btcoex_no_stomp;
                ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
                                      timer_period * 10);
                btcoex->hw_timer_enabled = true;
        }
 
        ath9k_ps_restore(sc);
+
 skip_hw_wakeup:
-       timer_period = btcoex->btcoex_period;
-       mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
+       mod_timer(&btcoex->period_timer,
+                 jiffies + msecs_to_jiffies(btcoex->btcoex_period));
 }
 
 /*
@@ -273,7 +292,8 @@ static void ath_btcoex_no_stomp_timer(void *arg)
        spin_lock_bh(&btcoex->btcoex_lock);
 
        if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
-           test_bit(BT_OP_SCAN, &btcoex->op_flags))
+           (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) &&
+            test_bit(BT_OP_SCAN, &btcoex->op_flags)))
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
         else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
@@ -474,4 +494,52 @@ int ath9k_init_btcoex(struct ath_softc *sc)
        return 0;
 }
 
+int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size)
+{
+#define ATH_DUMP_BTCOEX(_s, _val)                                \
+       do {                                                     \
+               len += snprintf(buf + len, size - len,           \
+                               "%20s : %10d\n", _s, (_val));    \
+       } while (0)
+
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+       int i;
+
+       ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci));
+       ATH_DUMP_BTCOEX("Number of MGMT", mci->num_mgmt);
+       ATH_DUMP_BTCOEX("Number of SCO", mci->num_sco);
+       ATH_DUMP_BTCOEX("Number of A2DP", mci->num_a2dp);
+       ATH_DUMP_BTCOEX("Number of HID", mci->num_hid);
+       ATH_DUMP_BTCOEX("Number of PAN", mci->num_pan);
+       ATH_DUMP_BTCOEX("Number of ACL", mci->num_other_acl);
+       ATH_DUMP_BTCOEX("Number of BDR", mci->num_bdr);
+       ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit);
+       ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type);
+       ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period);
+       ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle);
+       ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time);
+       ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx);
+       ATH_DUMP_BTCOEX("Concur RSSI count", btcoex->rssi_count);
+       len += snprintf(buf + len, size - len, "BT Weights: ");
+       for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
+               len += snprintf(buf + len, size - len, "%08x ",
+                               btcoex_hw->bt_weight[i]);
+       len += snprintf(buf + len, size - len, "\n");
+       len += snprintf(buf + len, size - len, "WLAN Weights: ");
+       for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
+               len += snprintf(buf + len, size - len, "%08x ",
+                               btcoex_hw->wlan_weight[i]);
+       len += snprintf(buf + len, size - len, "\n");
+       len += snprintf(buf + len, size - len, "Tx Priorities: ");
+       for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
+               len += snprintf(buf + len, size - len, "%08x ",
+                               btcoex_hw->tx_prio[i]);
+       len += snprintf(buf + len, size - len, "\n");
+#undef ATH_DUMP_BTCOEX
+
+       return len;
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
index d98255e..5ecf128 100644 (file)
@@ -694,6 +694,20 @@ err_hw:
        return ret;
 }
 
+static const struct ieee80211_iface_limit if_limits[] = {
+       { .max = 2,     .types = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_P2P_CLIENT) },
+       { .max = 2,     .types = BIT(NL80211_IFTYPE_AP) |
+                                BIT(NL80211_IFTYPE_P2P_GO) },
+};
+
+static const struct ieee80211_iface_combination if_comb = {
+       .limits = if_limits,
+       .n_limits = ARRAY_SIZE(if_limits),
+       .max_interfaces = 2,
+       .num_different_channels = 1,
+};
+
 static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
                               struct ieee80211_hw *hw)
 {
@@ -716,6 +730,9 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
                BIT(NL80211_IFTYPE_P2P_GO) |
                BIT(NL80211_IFTYPE_P2P_CLIENT);
 
+       hw->wiphy->iface_combinations = &if_comb;
+       hw->wiphy->n_iface_combinations = 1;
+
        hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
index ca78e33..66f6a74 100644 (file)
@@ -1036,26 +1036,6 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       if (priv->nvifs >= ATH9K_HTC_MAX_VIF) {
-               mutex_unlock(&priv->mutex);
-               return -ENOBUFS;
-       }
-
-       if (priv->num_ibss_vif ||
-           (priv->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
-               ath_err(common, "IBSS coexistence with other modes is not allowed\n");
-               mutex_unlock(&priv->mutex);
-               return -ENOBUFS;
-       }
-
-       if (((vif->type == NL80211_IFTYPE_AP) ||
-            (vif->type == NL80211_IFTYPE_ADHOC)) &&
-           ((priv->num_ap_vif + priv->num_ibss_vif) >= ATH9K_HTC_MAX_BCN_VIF)) {
-               ath_err(common, "Max. number of beaconing interfaces reached\n");
-               mutex_unlock(&priv->mutex);
-               return -ENOBUFS;
-       }
-
        ath9k_htc_ps_wakeup(priv);
        memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
        memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
index 8e1559a..71cd9f0 100644 (file)
@@ -2153,9 +2153,6 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
                    AR_RTC_FORCE_WAKE_EN);
        udelay(50);
 
-       if (ath9k_hw_mci_is_enabled(ah))
-               ar9003_mci_set_power_awake(ah);
-
        for (i = POWER_UP_TIME / 50; i > 0; i--) {
                val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
                if (val == AR_RTC_STATUS_ON)
@@ -2171,6 +2168,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
                return false;
        }
 
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_set_power_awake(ah);
+
        REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
 
        return true;
index dbc1b7a..3e73bfe 100644 (file)
@@ -401,6 +401,7 @@ enum ath9k_int {
 struct ath9k_hw_cal_data {
        u16 channel;
        u32 channelFlags;
+       u32 chanmode;
        int32_t CalValid;
        int8_t iCoff;
        int8_t qCoff;
@@ -834,6 +835,7 @@ struct ath_hw {
        int coarse_low[5];
        int firpwr[5];
        enum ath9k_ani_cmd ani_function;
+       u32 ani_skip_count;
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex_hw btcoex_hw;
index fad3ccd..546bae9 100644 (file)
@@ -687,6 +687,7 @@ static const struct ieee80211_iface_combination if_comb = {
        .n_limits = ARRAY_SIZE(if_limits),
        .max_interfaces = 2048,
        .num_different_channels = 1,
+       .beacon_int_infra_match = true,
 };
 
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
index 7b88b9c..223b969 100644 (file)
@@ -350,8 +350,18 @@ void ath_ani_calibrate(unsigned long data)
                ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
 
        /* Only calibrate if awake */
-       if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
+       if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
+               if (++ah->ani_skip_count >= ATH_ANI_MAX_SKIP_COUNT) {
+                       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+                       sc->ps_flags |= PS_WAIT_FOR_ANI;
+                       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+               }
                goto set_timer;
+       }
+       ah->ani_skip_count = 0;
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       sc->ps_flags &= ~PS_WAIT_FOR_ANI;
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        ath9k_ps_wakeup(sc);
 
index dd45edf..578a723 100644 (file)
@@ -131,7 +131,8 @@ void ath9k_ps_restore(struct ath_softc *sc)
                   !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                     PS_WAIT_FOR_CAB |
                                     PS_WAIT_FOR_PSPOLL_DATA |
-                                    PS_WAIT_FOR_TX_ACK))) {
+                                    PS_WAIT_FOR_TX_ACK |
+                                    PS_WAIT_FOR_ANI))) {
                mode = ATH9K_PM_NETWORK_SLEEP;
                if (ath9k_hw_btcoex_is_enabled(sc->sc_ah))
                        ath9k_btcoex_stop_gen_timer(sc);
@@ -292,6 +293,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
                goto out;
        }
 
+       if (ath9k_hw_mci_is_enabled(sc->sc_ah) &&
+           (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
+               ath9k_mci_set_txpower(sc, true, false);
+
        if (!ath_complete_reset(sc, true))
                r = -EIO;
 
@@ -1449,6 +1454,9 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
        sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
+       if (ath9k_hw_mci_is_enabled(sc->sc_ah))
+               ath9k_mci_update_wlan_channels(sc, false);
+
        ath_dbg(common, CONFIG,
                "Primary Station interface: %pM, BSSID: %pM\n",
                vif->addr, common->curbssid);
@@ -1505,6 +1513,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                        memset(common->curbssid, 0, ETH_ALEN);
                        common->curaid = 0;
                        ath9k_hw_write_associd(sc->sc_ah);
+                       if (ath9k_hw_mci_is_enabled(sc->sc_ah))
+                               ath9k_mci_update_wlan_channels(sc, true);
                }
        }
 
index ec2d7c8..0dd2cbb 100644 (file)
@@ -43,6 +43,7 @@ static bool ath_mci_add_profile(struct ath_common *common,
                                struct ath_mci_profile_info *info)
 {
        struct ath_mci_profile_info *entry;
+       u8 voice_priority[] = { 110, 110, 110, 112, 110, 110, 114, 116, 118 };
 
        if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
            (info->type == MCI_GPM_COEX_PROFILE_VOICE))
@@ -59,6 +60,12 @@ static bool ath_mci_add_profile(struct ath_common *common,
        memcpy(entry, info, 10);
        INC_PROF(mci, info);
        list_add_tail(&entry->list, &mci->info);
+       if (info->type == MCI_GPM_COEX_PROFILE_VOICE) {
+               if (info->voice_type < sizeof(voice_priority))
+                       mci->voice_priority = voice_priority[info->voice_type];
+               else
+                       mci->voice_priority = 110;
+       }
 
        return true;
 }
@@ -150,7 +157,7 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
                         * For single PAN/FTP profile, allocate 35% for BT
                         * to improve WLAN throughput.
                         */
-                       btcoex->duty_cycle = 35;
+                       btcoex->duty_cycle = AR_SREV_9565(sc->sc_ah) ? 40 : 35;
                        btcoex->btcoex_period = 53;
                        ath_dbg(common, MCI,
                                "Single PAN/FTP bt period %d ms dutycycle %d\n",
@@ -250,6 +257,57 @@ static void ath9k_mci_work(struct work_struct *work)
        ath_mci_update_scheme(sc);
 }
 
+static void ath_mci_update_stomp_txprio(u8 cur_txprio, u8 *stomp_prio)
+{
+       if (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_NONE])
+               stomp_prio[ATH_BTCOEX_STOMP_NONE] = cur_txprio;
+
+       if (cur_txprio > stomp_prio[ATH_BTCOEX_STOMP_ALL])
+               stomp_prio[ATH_BTCOEX_STOMP_ALL] = cur_txprio;
+
+       if ((cur_txprio > ATH_MCI_HI_PRIO) &&
+           (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_LOW]))
+               stomp_prio[ATH_BTCOEX_STOMP_LOW] = cur_txprio;
+}
+
+static void ath_mci_set_concur_txprio(struct ath_softc *sc)
+{
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       u8 stomp_txprio[] = { 0, 0, 0, 0 }; /* all, low, none, low_ftp */
+
+       if (mci->num_mgmt) {
+               stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO;
+               if (!mci->num_pan && !mci->num_other_acl)
+                       stomp_txprio[ATH_BTCOEX_STOMP_NONE] =
+                               ATH_MCI_INQUIRY_PRIO;
+       } else {
+               u8 prof_prio[] = { 50, 90, 94, 52 };/* RFCOMM, A2DP, HID, PAN */
+
+               stomp_txprio[ATH_BTCOEX_STOMP_LOW] =
+               stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0xff;
+
+               if (mci->num_sco)
+                       ath_mci_update_stomp_txprio(mci->voice_priority,
+                                                   stomp_txprio);
+               if (mci->num_other_acl)
+                       ath_mci_update_stomp_txprio(prof_prio[0], stomp_txprio);
+               if (mci->num_a2dp)
+                       ath_mci_update_stomp_txprio(prof_prio[1], stomp_txprio);
+               if (mci->num_hid)
+                       ath_mci_update_stomp_txprio(prof_prio[2], stomp_txprio);
+               if (mci->num_pan)
+                       ath_mci_update_stomp_txprio(prof_prio[3], stomp_txprio);
+
+               if (stomp_txprio[ATH_BTCOEX_STOMP_NONE] == 0xff)
+                       stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0;
+
+               if (stomp_txprio[ATH_BTCOEX_STOMP_LOW] == 0xff)
+                       stomp_txprio[ATH_BTCOEX_STOMP_LOW] = 0;
+       }
+       ath9k_hw_btcoex_set_concur_txprio(sc->sc_ah, stomp_txprio);
+}
+
 static u8 ath_mci_process_profile(struct ath_softc *sc,
                                  struct ath_mci_profile_info *info)
 {
@@ -281,6 +339,7 @@ static u8 ath_mci_process_profile(struct ath_softc *sc,
        } else
                ath_mci_del_profile(common, mci, entry);
 
+       ath_mci_set_concur_txprio(sc);
        return 1;
 }
 
@@ -314,6 +373,7 @@ static u8 ath_mci_process_status(struct ath_softc *sc,
                        mci->num_mgmt++;
        } while (++i < ATH_MCI_MAX_PROFILE);
 
+       ath_mci_set_concur_txprio(sc);
        if (old_num_mgmt != mci->num_mgmt)
                return 1;
 
@@ -600,3 +660,112 @@ void ath_mci_enable(struct ath_softc *sc)
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
                sc->sc_ah->imask |= ATH9K_INT_MCI;
 }
+
+void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       struct ath9k_channel *chan = ah->curchan;
+       u32 channelmap[] = {0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff};
+       int i;
+       s16 chan_start, chan_end;
+       u16 wlan_chan;
+
+       if (!chan || !IS_CHAN_2GHZ(chan))
+               return;
+
+       if (allow_all)
+               goto send_wlan_chan;
+
+       wlan_chan = chan->channel - 2402;
+
+       chan_start = wlan_chan - 10;
+       chan_end = wlan_chan + 10;
+
+       if (chan->chanmode == CHANNEL_G_HT40PLUS)
+               chan_end += 20;
+       else if (chan->chanmode == CHANNEL_G_HT40MINUS)
+               chan_start -= 20;
+
+       /* adjust side band */
+       chan_start -= 7;
+       chan_end += 7;
+
+       if (chan_start <= 0)
+               chan_start = 0;
+       if (chan_end >= ATH_MCI_NUM_BT_CHANNELS)
+               chan_end = ATH_MCI_NUM_BT_CHANNELS - 1;
+
+       ath_dbg(ath9k_hw_common(ah), MCI,
+               "WLAN current channel %d mask BT channel %d - %d\n",
+               wlan_chan, chan_start, chan_end);
+
+       for (i = chan_start; i < chan_end; i++)
+               MCI_GPM_CLR_CHANNEL_BIT(&channelmap, i);
+
+send_wlan_chan:
+       /* update and send wlan channels info to BT */
+       for (i = 0; i < 4; i++)
+               mci->wlan_channels[i] = channelmap[i];
+       ar9003_mci_send_wlan_channels(ah);
+       ar9003_mci_state(ah, MCI_STATE_SEND_VERSION_QUERY);
+}
+
+void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
+                          bool concur_tx)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
+       bool old_concur_tx = mci_hw->concur_tx;
+
+       if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) {
+               mci_hw->concur_tx = false;
+               return;
+       }
+
+       if (!IS_CHAN_2GHZ(ah->curchan))
+               return;
+
+       if (setchannel) {
+               struct ath9k_hw_cal_data *caldata = &sc->caldata;
+               if ((caldata->chanmode == CHANNEL_G_HT40PLUS) &&
+                   (ah->curchan->channel > caldata->channel) &&
+                   (ah->curchan->channel <= caldata->channel + 20))
+                       return;
+               if ((caldata->chanmode == CHANNEL_G_HT40MINUS) &&
+                   (ah->curchan->channel < caldata->channel) &&
+                   (ah->curchan->channel >= caldata->channel - 20))
+                       return;
+               mci_hw->concur_tx = false;
+       } else
+               mci_hw->concur_tx = concur_tx;
+
+       if (old_concur_tx != mci_hw->concur_tx)
+               ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
+}
+
+void ath9k_mci_update_rssi(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
+
+       if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX))
+               return;
+
+       if (ah->stats.avgbrssi >= 40) {
+               if (btcoex->rssi_count < 0)
+                       btcoex->rssi_count = 0;
+               if (++btcoex->rssi_count >= ATH_MCI_CONCUR_TX_SWITCH) {
+                       btcoex->rssi_count = 0;
+                       ath9k_mci_set_txpower(sc, false, true);
+               }
+       } else {
+               if (btcoex->rssi_count > 0)
+                       btcoex->rssi_count = 0;
+               if (--btcoex->rssi_count <= -ATH_MCI_CONCUR_TX_SWITCH) {
+                       btcoex->rssi_count = 0;
+                       ath9k_mci_set_txpower(sc, false, false);
+               }
+       }
+}
index fc14eea..0695883 100644 (file)
 #define ATH_MCI_MAX_PROFILE            (ATH_MCI_MAX_ACL_PROFILE +\
                                         ATH_MCI_MAX_SCO_PROFILE)
 
+#define ATH_MCI_INQUIRY_PRIO         62
+#define ATH_MCI_HI_PRIO              60
+#define ATH_MCI_NUM_BT_CHANNELS      79
+#define ATH_MCI_CONCUR_TX_SWITCH      5
+
+#define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan)                        \
+       do {                                                              \
+               if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) {                 \
+                       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \
+                               (_bt_chan / 8)) |= (1 << (_bt_chan & 7)); \
+               }                                                         \
+       } while (0)
+
+#define MCI_GPM_CLR_CHANNEL_BIT(_p_gpm, _bt_chan)                        \
+       do {                                                              \
+               if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) {                 \
+                       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \
+                               (_bt_chan / 8)) &= ~(1 << (_bt_chan & 7));\
+               }                                                         \
+       } while (0)
+
 #define INC_PROF(_mci, _info) do {              \
                switch (_info->type) {           \
                case MCI_GPM_COEX_PROFILE_RFCOMM:\
@@ -49,6 +70,7 @@
                        _mci->num_pan++;         \
                        break;                   \
                case MCI_GPM_COEX_PROFILE_VOICE: \
+               case MCI_GPM_COEX_PROFILE_A2DPVO:\
                        _mci->num_sco++;         \
                        break;                   \
                default:                         \
@@ -73,6 +95,7 @@
                        _mci->num_pan--;         \
                        break;                   \
                case MCI_GPM_COEX_PROFILE_VOICE: \
+               case MCI_GPM_COEX_PROFILE_A2DPVO:\
                        _mci->num_sco--;         \
                        break;                   \
                default:                         \
@@ -113,6 +136,7 @@ struct ath_mci_profile {
        u8 num_pan;
        u8 num_other_acl;
        u8 num_bdr;
+       u8 voice_priority;
 };
 
 struct ath_mci_buf {
@@ -130,13 +154,25 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci);
 int ath_mci_setup(struct ath_softc *sc);
 void ath_mci_cleanup(struct ath_softc *sc);
 void ath_mci_intr(struct ath_softc *sc);
+void ath9k_mci_update_rssi(struct ath_softc *sc);
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 void ath_mci_enable(struct ath_softc *sc);
+void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all);
+void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
+                          bool concur_tx);
 #else
 static inline void ath_mci_enable(struct ath_softc *sc)
 {
 }
+static inline void ath9k_mci_update_wlan_channels(struct ath_softc *sc,
+                                                 bool allow_all)
+{
+}
+static inline void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
+                                        bool concur_tx)
+{
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #endif /* MCI_H*/
index 83d16e7..a04028b 100644 (file)
@@ -1105,7 +1105,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                else
                        rs.is_mybeacon = false;
 
-               sc->rx.num_pkts++;
+               if (ieee80211_is_data_present(hdr->frame_control) &&
+                   !ieee80211_is_qos_nullfunc(hdr->frame_control))
+                       sc->rx.num_pkts++;
+
                ath_debug_stat_rx(sc, &rs);
 
                /*
index 4e6760f..ad3c82c 100644 (file)
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20))
 
-#define AR_SREV_9462_20_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
-       ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20))
-
 #define AR_SREV_9565(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
 
@@ -2315,6 +2311,8 @@ enum {
 #define AR_BTCOEX_MAX_TXPWR(_x)                                (0x18c0 + ((_x) << 2))
 #define AR_BTCOEX_WL_LNA                               0x1940
 #define AR_BTCOEX_RFGAIN_CTRL                          0x1944
+#define AR_BTCOEX_WL_LNA_TIMEOUT                       0x003FFFFF
+#define AR_BTCOEX_WL_LNA_TIMEOUT_S                     0
 
 #define AR_BTCOEX_CTRL2                                        0x1948
 #define AR_BTCOEX_CTRL2_TXPWR_THRESH                   0x0007F800
@@ -2360,4 +2358,11 @@ enum {
 #define AR_GLB_SWREG_DISCONT_MODE         0x2002c
 #define AR_GLB_SWREG_DISCONT_EN_BT_WLAN   0x3
 
+#define AR_MCI_MISC                    0x1a74
+#define AR_MCI_MISC_HW_FIX_EN          0x00000001
+#define AR_MCI_MISC_HW_FIX_EN_S        0
+#define AR_MCI_DBG_CNT_CTRL            0x1a78
+#define AR_MCI_DBG_CNT_CTRL_ENABLE     0x00000001
+#define AR_MCI_DBG_CNT_CTRL_ENABLE_S   0
+
 #endif
index a483d51..9f85630 100644 (file)
@@ -118,7 +118,7 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
                       (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
        data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
 
-       if (AR_SREV_9462_20_OR_LATER(ah)) {
+       if (AR_SREV_9462_20(ah)) {
                /* AR9462 2.0 has an extra descriptor word (time based
                 * discard) compared to other chips */
                REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0);
index e3b1b6e..24d75ab 100644 (file)
@@ -343,7 +343,24 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
                        break;
                }
        } else {
-               mac_addr = NULL;
+               /*
+                * Enable monitor mode
+                *
+                * rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER;
+                * sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC;
+                *
+                * When the hardware is in SNIFFER_PROMISC mode,
+                * it generates spurious ACKs for every incoming
+                * frame. This confuses every peer in the
+                * vicinity and the network throughput will suffer
+                * badly.
+                *
+                * Hence, the hardware will be put into station
+                * mode and just the rx filters are disabled.
+                */
+               cam_mode |= AR9170_MAC_CAM_STA;
+               rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST;
+               mac_addr = common->macaddr;
                bssid = NULL;
        }
        rcu_read_unlock();
@@ -355,8 +372,6 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
                enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;
 
        if (ar->sniffer_enabled) {
-               rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER;
-               sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC;
                enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;
        }
 
index a0b7230..6d22382 100644 (file)
@@ -164,9 +164,6 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
        struct carl9170_rsp *cmd = buf;
        struct ieee80211_vif *vif;
 
-       if (carl9170_check_sequence(ar, cmd->hdr.seq))
-               return;
-
        if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) {
                if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG))
                        carl9170_cmd_callback(ar, len, buf);
@@ -663,6 +660,35 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms,
        return false;
 }
 
+static int carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len,
+                               struct ieee80211_rx_status *status)
+{
+       struct sk_buff *skb;
+
+       /* (driver) frame trap handler
+        *
+        * Because power-saving mode handing has to be implemented by
+        * the driver/firmware. We have to check each incoming beacon
+        * from the associated AP, if there's new data for us (either
+        * broadcast/multicast or unicast) we have to react quickly.
+        *
+        * So, if you have you want to add additional frame trap
+        * handlers, this would be the perfect place!
+        */
+
+       carl9170_ps_beacon(ar, buf, len);
+
+       carl9170_ba_check(ar, buf, len);
+
+       skb = carl9170_rx_copy_data(buf, len);
+       if (!skb)
+               return -ENOMEM;
+
+       memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+       ieee80211_rx(ar->hw, skb);
+       return 0;
+}
+
 /*
  * If the frame alignment is right (or the kernel has
  * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
@@ -672,14 +698,12 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms,
  * mode, and we need to observe the proper ordering,
  * this is non-trivial.
  */
-
-static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
+static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len)
 {
        struct ar9170_rx_head *head;
        struct ar9170_rx_macstatus *mac;
        struct ar9170_rx_phystatus *phy = NULL;
        struct ieee80211_rx_status status;
-       struct sk_buff *skb;
        int mpdu_len;
        u8 mac_status;
 
@@ -791,18 +815,10 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
        if (phy)
                carl9170_rx_phy_status(ar, phy, &status);
 
-       carl9170_ps_beacon(ar, buf, mpdu_len);
-
-       carl9170_ba_check(ar, buf, mpdu_len);
-
-       skb = carl9170_rx_copy_data(buf, mpdu_len);
-       if (!skb)
+       if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status))
                goto drop;
 
-       memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
-       ieee80211_rx(ar->hw, skb);
        return;
-
 drop:
        ar->rx_dropped++;
 }
@@ -820,6 +836,9 @@ static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf,
                if (unlikely(i > resplen))
                        break;
 
+               if (carl9170_check_sequence(ar, cmd->hdr.seq))
+                       break;
+
                carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4);
        }
 
@@ -851,7 +870,7 @@ static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len)
        if (i == 12)
                carl9170_rx_untie_cmds(ar, buf, len);
        else
-               carl9170_handle_mpdu(ar, buf, len);
+               carl9170_rx_untie_data(ar, buf, len);
 }
 
 static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
index 888152c..307bc0d 100644 (file)
@@ -295,6 +295,13 @@ static void carl9170_usb_rx_irq_complete(struct urb *urb)
                goto resubmit;
        }
 
+       /*
+        * While the carl9170 firmware does not use this EP, the
+        * firmware loader in the EEPROM unfortunately does.
+        * Therefore we need to be ready to handle out-of-band
+        * responses and traps in case the firmware crashed and
+        * the loader took over again.
+        */
        carl9170_handle_command_response(ar, urb->transfer_buffer,
                                         urb->actual_length);
 
index 19befb3..39e8a59 100644 (file)
@@ -20,8 +20,8 @@
 #include "ath.h"
 #include "reg.h"
 
-#define REG_READ       (common->ops->read)
-#define REG_WRITE      (common->ops->write)
+#define REG_READ                       (common->ops->read)
+#define REG_WRITE(_ah, _reg, _val)     (common->ops->write)(_ah, _val, _reg)
 
 /**
  * ath_hw_set_bssid_mask - filter out bssids we listen
@@ -119,8 +119,8 @@ void ath_hw_setbssidmask(struct ath_common *common)
 {
        void *ah = common->ah;
 
-       REG_WRITE(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL);
-       REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU);
+       REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask));
+       REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4));
 }
 EXPORT_SYMBOL(ath_hw_setbssidmask);
 
@@ -139,7 +139,7 @@ void ath_hw_cycle_counters_update(struct ath_common *common)
        void *ah = common->ah;
 
        /* freeze */
-       REG_WRITE(ah, AR_MIBC_FMC, AR_MIBC);
+       REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
 
        /* read */
        cycles = REG_READ(ah, AR_CCCNT);
@@ -148,13 +148,13 @@ void ath_hw_cycle_counters_update(struct ath_common *common)
        tx = REG_READ(ah, AR_TFCNT);
 
        /* clear */
-       REG_WRITE(ah, 0, AR_CCCNT);
-       REG_WRITE(ah, 0, AR_RFCNT);
-       REG_WRITE(ah, 0, AR_RCCNT);
-       REG_WRITE(ah, 0, AR_TFCNT);
+       REG_WRITE(ah, AR_CCCNT, 0);
+       REG_WRITE(ah, AR_RFCNT, 0);
+       REG_WRITE(ah, AR_RCCNT, 0);
+       REG_WRITE(ah, AR_TFCNT, 0);
 
        /* unfreeze */
-       REG_WRITE(ah, 0, AR_MIBC);
+       REG_WRITE(ah, AR_MIBC, 0);
 
        /* update all cycle counters here */
        common->cc_ani.cycles += cycles;
index c5a99c8..ddd6a4f 100644 (file)
@@ -4652,7 +4652,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        switch (dev->dev->bus_type) {
 #ifdef CONFIG_B43_BCMA
        case B43_BUS_BCMA:
-               bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
+               bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
                                      dev->dev->bdev, true);
                break;
 #endif
index 9d5170b..fe80b63 100644 (file)
@@ -24,6 +24,7 @@ ccflags-y += -D__CHECK_ENDIAN__
 obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += \
                wl_cfg80211.o \
+               fwil.o \
                dhd_cdc.o \
                dhd_common.o \
                dhd_linux.o
index 17e7ae7..8704daa 100644 (file)
@@ -318,6 +318,12 @@ struct brcmf_event {
 #define BRCMF_E_LINK_ASSOC_REC                 3
 #define BRCMF_E_LINK_BSSCFG_DIS                        4
 
+/* Small, medium and maximum buffer size for dcmd
+ */
+#define BRCMF_DCMD_SMLEN       256
+#define BRCMF_DCMD_MEDLEN      1536
+#define BRCMF_DCMD_MAXLEN      8192
+
 /* Pattern matching filter. Specifies an offset within received packets to
  * start matching, the pattern to match, the size of the pattern, and a bitmask
  * that indicates which bits within the pattern should be matched.
@@ -623,7 +629,6 @@ struct brcmf_pub {
        u8 wme_dp;              /* wme discard priority */
 
        /* Dongle media info */
-       bool iswl;              /* Dongle-resident driver is wl */
        unsigned long drv_version;      /* Version of dongle-resident driver */
        u8 mac[ETH_ALEN];               /* MAC address obtained from dongle */
 
@@ -651,16 +656,10 @@ struct brcmf_pub {
        int in_suspend;         /* flag set to 1 when early suspend called */
        int dtim_skip;          /* dtim skip , default 0 means wake each dtim */
 
-       /* Pkt filter defination */
-       char *pktfilter[100];
-       int pktfilter_count;
-
-       u8 country_code[BRCM_CNTRY_BUF_SZ];
-       char eventmask[BRCMF_EVENTING_MASK_LEN];
-
        struct brcmf_if *iflist[BRCMF_MAX_IFS];
 
        struct mutex proto_block;
+       unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 
        struct work_struct setmacaddr_work;
        struct work_struct multicast_work;
@@ -671,6 +670,11 @@ struct brcmf_pub {
 #endif
 };
 
+struct bcmevent_name {
+       uint event;
+       const char *name;
+};
+
 struct brcmf_if_event {
        u8 ifidx;
        u8 action;
@@ -678,47 +682,60 @@ struct brcmf_if_event {
        u8 bssidx;
 };
 
-struct bcmevent_name {
-       uint event;
-       const char *name;
+/* forward declaration */
+struct brcmf_cfg80211_vif;
+
+/**
+ * struct brcmf_if - interface control information.
+ *
+ * @drvr: points to device related information.
+ * @vif: points to cfg80211 specific interface information.
+ * @ndev: associated network device.
+ * @stats: interface specific network statistics.
+ * @idx: interface index in device firmware.
+ * @bssidx: index of bss associated with this interface.
+ * @mac_addr: assigned mac address.
+ */
+struct brcmf_if {
+       struct brcmf_pub *drvr;
+       struct brcmf_cfg80211_vif *vif;
+       struct net_device *ndev;
+       struct net_device_stats stats;
+       int idx;
+       s32 bssidx;
+       u8 mac_addr[ETH_ALEN];
 };
 
+static inline s32 brcmf_ndev_bssidx(struct net_device *ndev)
+{
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       return ifp->bssidx;
+}
+
 extern const struct bcmevent_name bcmevent_names[];
 
 extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
                          char *buf, uint len);
-extern uint brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen,
-                                  char *buf, uint buflen, s32 bssidx);
 
 extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
 
-extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len);
-extern int brcmf_netlink_dcmd(struct net_device *ndev, struct brcmf_dcmd *dcmd);
-
 /* Return pointer to interface name */
 extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
 
 /* Query dongle */
 extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
                                       uint cmd, void *buf, uint len);
-
-#ifdef DEBUG
-extern int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size);
-#endif                         /* DEBUG */
+extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+                                   void *buf, uint len);
 
 extern int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name);
 extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx,
                              void *pktdata, struct brcmf_event_msg *,
                              void **data_ptr);
 
+extern int brcmf_net_attach(struct brcmf_if *ifp);
+extern struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
+                                    char *name, u8 *mac_addr);
 extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx);
 
-extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg);
-extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg,
-                                            int enable, int master_mode);
-
-#define        BRCMF_DCMD_SMLEN        256     /* "small" cmd buffer required */
-#define BRCMF_DCMD_MEDLEN      1536    /* "med" cmd buffer required */
-#define        BRCMF_DCMD_MAXLEN       8192    /* max length cmd buffer required */
-
 #endif                         /* _BRCMF_H_ */
index 9b8ee19..265580f 100644 (file)
@@ -111,9 +111,6 @@ extern void brcmf_txcomplete(struct device *dev, struct sk_buff *txp,
 
 extern int brcmf_bus_start(struct device *dev);
 
-extern int brcmf_add_if(struct device *dev, int ifidx,
-                       char *name, u8 *mac_addr);
-
 #ifdef CONFIG_BRCMFMAC_SDIO
 extern void brcmf_sdio_exit(void);
 extern void brcmf_sdio_init(void);
index a5c15ca..b9d8a5a 100644 (file)
@@ -458,35 +458,6 @@ void brcmf_proto_detach(struct brcmf_pub *drvr)
        drvr->prot = NULL;
 }
 
-int brcmf_proto_init(struct brcmf_pub *drvr)
-{
-       int ret = 0;
-       char buf[128];
-
-       brcmf_dbg(TRACE, "Enter\n");
-
-       mutex_lock(&drvr->proto_block);
-
-       /* Get the device MAC address */
-       strcpy(buf, "cur_etheraddr");
-       ret = brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR,
-                                         buf, sizeof(buf));
-       if (ret < 0) {
-               mutex_unlock(&drvr->proto_block);
-               return ret;
-       }
-       memcpy(drvr->mac, buf, ETH_ALEN);
-
-       mutex_unlock(&drvr->proto_block);
-
-       ret = brcmf_c_preinit_dcmds(drvr);
-
-       /* Always assumes wl for now */
-       drvr->iswl = true;
-
-       return ret;
-}
-
 void brcmf_proto_stop(struct brcmf_pub *drvr)
 {
        /* Nothing to do for CDC */
index 15c5db5..866b669 100644 (file)
 #include "dhd_bus.h"
 #include "dhd_proto.h"
 #include "dhd_dbg.h"
+#include "fwil.h"
 
 #define BRCM_OUI                       "\x00\x10\x18"
 #define DOT11_OUI_LEN                  3
 #define BCMILCP_BCM_SUBTYPE_EVENT      1
-#define PKTFILTER_BUF_SIZE             2048
+#define PKTFILTER_BUF_SIZE             128
 #define BRCMF_ARPOL_MODE               0xb     /* agent|snoop|peer_autoreply */
+#define BRCMF_DEFAULT_BCN_TIMEOUT      3
+#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME        40
+#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
+#define BRCMF_DEFAULT_PACKET_FILTER    "100 0 0 0 0x01 0x00"
 
 #define MSGTRACE_VERSION       1
 
@@ -88,52 +93,6 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
        return len;
 }
 
-uint
-brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen,
-                      char *buf, uint buflen, s32 bssidx)
-{
-       const s8 *prefix = "bsscfg:";
-       s8 *p;
-       u32 prefixlen;
-       u32 namelen;
-       u32 iolen;
-       __le32 bssidx_le;
-
-       if (bssidx == 0)
-               return brcmf_c_mkiovar(name, data, datalen, buf, buflen);
-
-       prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */
-       namelen = (u32) strlen(name) + 1; /* lengh of iovar  name + null */
-       iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen;
-
-       if (buflen < 0 || iolen > (u32)buflen) {
-               brcmf_dbg(ERROR, "buffer is too short\n");
-               return 0;
-       }
-
-       p = buf;
-
-       /* copy prefix, no null */
-       memcpy(p, prefix, prefixlen);
-       p += prefixlen;
-
-       /* copy iovar name including null */
-       memcpy(p, name, namelen);
-       p += namelen;
-
-       /* bss config index as first data */
-       bssidx_le = cpu_to_le32(bssidx);
-       memcpy(p, &bssidx_le, sizeof(bssidx_le));
-       p += sizeof(bssidx_le);
-
-       /* parameter buffer follows */
-       if (datalen)
-               memcpy(p, data, datalen);
-
-       return iolen;
-
-}
-
 bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
                      struct sk_buff *pkt, int prec)
 {
@@ -490,6 +449,7 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
        /* check whether packet is a BRCM event pkt */
        struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
        struct brcmf_if_event *ifevent;
+       struct brcmf_if *ifp;
        char *event_data;
        u32 type, status;
        u16 flags;
@@ -525,12 +485,17 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
                brcmf_dbg(TRACE, "if event\n");
 
                if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
-                       if (ifevent->action == BRCMF_E_IF_ADD)
-                               brcmf_add_if(drvr->dev, ifevent->ifidx,
-                                            event->ifname,
-                                            pvt_data->eth.h_dest);
-                       else
+                       if (ifevent->action == BRCMF_E_IF_ADD) {
+                               ifp = brcmf_add_if(drvr->dev, ifevent->ifidx,
+                                                  ifevent->bssidx,
+                                                  event->ifname,
+                                                  pvt_data->eth.h_dest);
+                               if (IS_ERR(ifp))
+                                       return PTR_ERR(ifp);
+                               brcmf_net_attach(ifp);
+                       } else {
                                brcmf_del_if(drvr, ifevent->ifidx);
+                       }
                } else {
                        brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",
                                  ifevent->ifidx, event->ifname);
@@ -603,90 +568,57 @@ static int brcmf_c_pattern_atoh(char *src, char *dst)
        return i;
 }
 
-void
-brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable,
-                            int master_mode)
+static void
+brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable,
+                                int master_mode)
 {
        unsigned long res;
-       char *argv[8];
-       int i = 0;
-       const char *str;
-       int buf_len;
-       int str_len;
+       char *argv;
        char *arg_save = NULL, *arg_org = NULL;
-       int rc;
-       char buf[128];
+       s32 err;
        struct brcmf_pkt_filter_enable_le enable_parm;
-       struct brcmf_pkt_filter_enable_le *pkt_filterp;
-       __le32 mmode_le;
 
-       arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
+       arg_save = kstrdup(arg, GFP_ATOMIC);
        if (!arg_save)
                goto fail;
 
        arg_org = arg_save;
-       memcpy(arg_save, arg, strlen(arg) + 1);
 
-       argv[i] = strsep(&arg_save, " ");
+       argv = strsep(&arg_save, " ");
 
-       i = 0;
-       if (NULL == argv[i]) {
+       if (argv == NULL) {
                brcmf_dbg(ERROR, "No args provided\n");
                goto fail;
        }
 
-       str = "pkt_filter_enable";
-       str_len = strlen(str);
-       strncpy(buf, str, str_len);
-       buf[str_len] = '\0';
-       buf_len = str_len + 1;
-
-       pkt_filterp = (struct brcmf_pkt_filter_enable_le *) (buf + str_len + 1);
-
        /* Parse packet filter id. */
        enable_parm.id = 0;
-       if (!kstrtoul(argv[i], 0, &res))
+       if (!kstrtoul(argv, 0, &res))
                enable_parm.id = cpu_to_le32((u32)res);
 
-       /* Parse enable/disable value. */
+       /* Enable/disable the specified filter. */
        enable_parm.enable = cpu_to_le32(enable);
 
-       buf_len += sizeof(enable_parm);
-       memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm));
+       err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm,
+                                      sizeof(enable_parm));
+       if (err)
+               brcmf_dbg(ERROR, "Set pkt_filter_enable error (%d)\n", err);
 
-       /* Enable/disable the specified filter. */
-       rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
-       rc = rc >= 0 ? 0 : rc;
-       if (rc)
-               brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
-                         arg, rc);
-       else
-               brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg);
-
-       /* Contorl the master mode */
-       mmode_le = cpu_to_le32(master_mode);
-       brcmf_c_mkiovar("pkt_filter_mode", (char *)&mmode_le, 4, buf,
-                   sizeof(buf));
-       rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf,
-                                      sizeof(buf));
-       rc = rc >= 0 ? 0 : rc;
-       if (rc)
-               brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
-                         arg, rc);
+       /* Control the master mode */
+       err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode);
+       if (err)
+               brcmf_dbg(ERROR, "Set pkt_filter_mode error (%d)\n", err);
 
 fail:
        kfree(arg_org);
 }
 
-void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
+static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
 {
-       const char *str;
-       struct brcmf_pkt_filter_le pkt_filter;
-       struct brcmf_pkt_filter_le *pkt_filterp;
+       struct brcmf_pkt_filter_le *pkt_filter;
        unsigned long res;
        int buf_len;
-       int str_len;
-       int rc;
+       s32 err;
        u32 mask_size;
        u32 pattern_size;
        char *argv[8], *buf = NULL;
@@ -704,104 +636,64 @@ void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
                goto fail;
 
        argv[i] = strsep(&arg_save, " ");
-       while (argv[i++])
+       while (argv[i]) {
+               i++;
+               if (i >= 8) {
+                       brcmf_dbg(ERROR, "Too many parameters\n");
+                       goto fail;
+               }
                argv[i] = strsep(&arg_save, " ");
+       }
 
-       i = 0;
-       if (NULL == argv[i]) {
-               brcmf_dbg(ERROR, "No args provided\n");
+       if (i != 6) {
+               brcmf_dbg(ERROR, "Not enough args provided %d\n", i);
                goto fail;
        }
 
-       str = "pkt_filter_add";
-       strcpy(buf, str);
-       str_len = strlen(str);
-       buf_len = str_len + 1;
-
-       pkt_filterp = (struct brcmf_pkt_filter_le *) (buf + str_len + 1);
+       pkt_filter = (struct brcmf_pkt_filter_le *)buf;
 
        /* Parse packet filter id. */
-       pkt_filter.id = 0;
-       if (!kstrtoul(argv[i], 0, &res))
-               pkt_filter.id = cpu_to_le32((u32)res);
-
-       if (NULL == argv[++i]) {
-               brcmf_dbg(ERROR, "Polarity not provided\n");
-               goto fail;
-       }
+       pkt_filter->id = 0;
+       if (!kstrtoul(argv[0], 0, &res))
+               pkt_filter->id = cpu_to_le32((u32)res);
 
        /* Parse filter polarity. */
-       pkt_filter.negate_match = 0;
-       if (!kstrtoul(argv[i], 0, &res))
-               pkt_filter.negate_match = cpu_to_le32((u32)res);
-
-       if (NULL == argv[++i]) {
-               brcmf_dbg(ERROR, "Filter type not provided\n");
-               goto fail;
-       }
+       pkt_filter->negate_match = 0;
+       if (!kstrtoul(argv[1], 0, &res))
+               pkt_filter->negate_match = cpu_to_le32((u32)res);
 
        /* Parse filter type. */
-       pkt_filter.type = 0;
-       if (!kstrtoul(argv[i], 0, &res))
-               pkt_filter.type = cpu_to_le32((u32)res);
-
-       if (NULL == argv[++i]) {
-               brcmf_dbg(ERROR, "Offset not provided\n");
-               goto fail;
-       }
+       pkt_filter->type = 0;
+       if (!kstrtoul(argv[2], 0, &res))
+               pkt_filter->type = cpu_to_le32((u32)res);
 
        /* Parse pattern filter offset. */
-       pkt_filter.u.pattern.offset = 0;
-       if (!kstrtoul(argv[i], 0, &res))
-               pkt_filter.u.pattern.offset = cpu_to_le32((u32)res);
-
-       if (NULL == argv[++i]) {
-               brcmf_dbg(ERROR, "Bitmask not provided\n");
-               goto fail;
-       }
+       pkt_filter->u.pattern.offset = 0;
+       if (!kstrtoul(argv[3], 0, &res))
+               pkt_filter->u.pattern.offset = cpu_to_le32((u32)res);
 
        /* Parse pattern filter mask. */
-       mask_size =
-           brcmf_c_pattern_atoh
-                  (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern);
-
-       if (NULL == argv[++i]) {
-               brcmf_dbg(ERROR, "Pattern not provided\n");
-               goto fail;
-       }
+       mask_size = brcmf_c_pattern_atoh(argv[4],
+                       (char *)pkt_filter->u.pattern.mask_and_pattern);
 
        /* Parse pattern filter pattern. */
-       pattern_size =
-           brcmf_c_pattern_atoh(argv[i],
-                                  (char *)&pkt_filterp->u.pattern.
-                                  mask_and_pattern[mask_size]);
+       pattern_size = brcmf_c_pattern_atoh(argv[5],
+               (char *)&pkt_filter->u.pattern.mask_and_pattern[mask_size]);
 
        if (mask_size != pattern_size) {
                brcmf_dbg(ERROR, "Mask and pattern not the same size\n");
                goto fail;
        }
 
-       pkt_filter.u.pattern.size_bytes = cpu_to_le32(mask_size);
-       buf_len += BRCMF_PKT_FILTER_FIXED_LEN;
-       buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
-
-       /* Keep-alive attributes are set in local
-        * variable (keep_alive_pkt), and
-        ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
-        ** guarantee that the buffer is properly aligned.
-        */
-       memcpy((char *)pkt_filterp,
-              &pkt_filter,
-              BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN);
-
-       rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
-       rc = rc >= 0 ? 0 : rc;
+       pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
+       buf_len = sizeof(*pkt_filter);
+       buf_len -= sizeof(pkt_filter->u.pattern.mask_and_pattern);
+       buf_len += mask_size + pattern_size;
 
-       if (rc)
-               brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
-                         arg, rc);
-       else
-               brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg);
+       err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,
+                                      buf_len);
+       if (err)
+               brcmf_dbg(ERROR, "Set pkt_filter_add error (%d)\n", err);
 
 fail:
        kfree(arg_org);
@@ -809,130 +701,125 @@ fail:
        kfree(buf);
 }
 
-static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode)
+int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
 {
-       char iovbuf[32];
-       int retcode;
-       __le32 arp_mode_le;
-
-       arp_mode_le = cpu_to_le32(arp_mode);
-       brcmf_c_mkiovar("arp_ol", (char *)&arp_mode_le, 4, iovbuf,
-                       sizeof(iovbuf));
-       retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
-                                  iovbuf, sizeof(iovbuf));
-       retcode = retcode >= 0 ? 0 : retcode;
-       if (retcode)
-               brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, retcode = %d\n",
-                         arp_mode, retcode);
-       else
-               brcmf_dbg(TRACE, "successfully set ARP offload mode to 0x%x\n",
-                         arp_mode);
-}
-
-static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable)
-{
-       char iovbuf[32];
-       int retcode;
-       __le32 arp_enable_le;
-
-       arp_enable_le = cpu_to_le32(arp_enable);
-
-       brcmf_c_mkiovar("arpoe", (char *)&arp_enable_le, 4,
-                       iovbuf, sizeof(iovbuf));
-       retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
-                                  iovbuf, sizeof(iovbuf));
-       retcode = retcode >= 0 ? 0 : retcode;
-       if (retcode)
-               brcmf_dbg(TRACE, "failed to enable ARP offload to %d, retcode = %d\n",
-                         arp_enable, retcode);
-       else
-               brcmf_dbg(TRACE, "successfully enabled ARP offload to %d\n",
-                         arp_enable);
-}
-
-int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
-{
-       char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];      /*  Room for
-                                "event_msgs" + '\0' + bitvec  */
-       char buf[128], *ptr;
-       __le32 roaming_le = cpu_to_le32(1);
-       __le32 bcn_timeout_le = cpu_to_le32(3);
-       __le32 scan_assoc_time_le = cpu_to_le32(40);
-       __le32 scan_unassoc_time_le = cpu_to_le32(40);
-       int i;
+       s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+       u8 buf[BRCMF_DCMD_SMLEN];
+       char *ptr;
+       s32 err;
        struct brcmf_bus_dcmd *cmdlst;
        struct list_head *cur, *q;
 
-       mutex_lock(&drvr->proto_block);
-
-       /* Set Country code */
-       if (drvr->country_code[0] != 0) {
-               if (brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_COUNTRY,
-                                             drvr->country_code,
-                                             sizeof(drvr->country_code)) < 0)
-                       brcmf_dbg(ERROR, "country code setting failed\n");
+       /* retreive mac address */
+       err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
+                                      sizeof(ifp->mac_addr));
+       if (err < 0) {
+               brcmf_dbg(ERROR, "Retreiving cur_etheraddr failed, %d\n",
+                         err);
+               goto done;
        }
+       memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
 
        /* query for 'ver' to get version info from firmware */
        memset(buf, 0, sizeof(buf));
-       ptr = buf;
-       brcmf_c_mkiovar("ver", NULL, 0, buf, sizeof(buf));
-       brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf));
+       strcpy(buf, "ver");
+       err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
+       if (err < 0) {
+               brcmf_dbg(ERROR, "Retreiving version information failed, %d\n",
+                         err);
+               goto done;
+       }
+       ptr = (char *)buf;
        strsep(&ptr, "\n");
        /* Print fw version info */
        brcmf_dbg(ERROR, "Firmware version = %s\n", buf);
 
-       /* Setup timeout if Beacons are lost and roam is off to report
-                link down */
-       brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout_le, 4, iovbuf,
-                   sizeof(iovbuf));
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
-                                 sizeof(iovbuf));
+       /*
+        * Setup timeout if Beacons are lost and roam is off to report
+        * link down
+        */
+       err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
+                                     BRCMF_DEFAULT_BCN_TIMEOUT);
+       if (err) {
+               brcmf_dbg(ERROR, "bcn_timeout error (%d)\n", err);
+               goto done;
+       }
 
        /* Enable/Disable build-in roaming to allowed ext supplicant to take
-                of romaing */
-       brcmf_c_mkiovar("roam_off", (char *)&roaming_le, 4,
-                     iovbuf, sizeof(iovbuf));
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
-                                 sizeof(iovbuf));
-
-       /* Setup event_msgs */
-       brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
-                     iovbuf, sizeof(iovbuf));
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
-                                 sizeof(iovbuf));
-
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME,
-                (char *)&scan_assoc_time_le, sizeof(scan_assoc_time_le));
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME,
-                (char *)&scan_unassoc_time_le, sizeof(scan_unassoc_time_le));
-
-       /* Set and enable ARP offload feature */
-       brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE);
-       brcmf_c_arp_offload_enable(drvr, true);
-
-       /* Set up pkt filter */
-       for (i = 0; i < drvr->pktfilter_count; i++) {
-               brcmf_c_pktfilter_offload_set(drvr, drvr->pktfilter[i]);
-               brcmf_c_pktfilter_offload_enable(drvr, drvr->pktfilter[i],
-                                                0, true);
+        * of romaing
+        */
+       err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
+       if (err) {
+               brcmf_dbg(ERROR, "roam_off error (%d)\n", err);
+               goto done;
+       }
+
+       /* Setup event_msgs, enable E_IF */
+       err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
+                                      BRCMF_EVENTING_MASK_LEN);
+       if (err) {
+               brcmf_dbg(ERROR, "Get event_msgs error (%d)\n", err);
+               goto done;
+       }
+       setbit(eventmask, BRCMF_E_IF);
+       err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
+                                      BRCMF_EVENTING_MASK_LEN);
+       if (err) {
+               brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err);
+               goto done;
+       }
+
+       /* Setup default scan channel time */
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+                                   BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
+       if (err) {
+               brcmf_dbg(ERROR, "BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
+                         err);
+               goto done;
        }
 
+       /* Setup default scan unassoc time */
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+                                   BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
+       if (err) {
+               brcmf_dbg(ERROR, "BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
+                         err);
+               goto done;
+       }
+
+       /* Try to set and enable ARP offload feature, this may fail */
+       err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE);
+       if (err) {
+               brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
+                         BRCMF_ARPOL_MODE, err);
+               err = 0;
+       } else {
+               err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1);
+               if (err) {
+                       brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n",
+                                 err);
+                       err = 0;
+               } else
+                       brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n",
+                                 BRCMF_ARPOL_MODE);
+       }
+
+       /* Setup packet filter */
+       brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
+       brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
+                                        0, true);
+
        /* set bus specific command if there is any */
-       list_for_each_safe(cur, q, &drvr->bus_if->dcmd_list) {
+       list_for_each_safe(cur, q, &ifp->drvr->bus_if->dcmd_list) {
                cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list);
                if (cmdlst->name && cmdlst->param && cmdlst->param_len) {
-                       brcmf_c_mkiovar(cmdlst->name, cmdlst->param,
-                                       cmdlst->param_len, iovbuf,
-                                       sizeof(iovbuf));
-                       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
-                                                iovbuf, sizeof(iovbuf));
+                       brcmf_fil_iovar_data_set(ifp, cmdlst->name,
+                                                cmdlst->param,
+                                                cmdlst->param_len);
                }
                list_del(cur);
                kfree(cmdlst);
        }
-
-       mutex_unlock(&drvr->proto_block);
-
-       return 0;
+done:
+       return err;
 }
index 7f89540..862d2ac 100644 (file)
 #include <linux/debugfs.h>
 #include <linux/if_ether.h>
 #include <linux/if.h>
+#include <linux/netdevice.h>
 #include <linux/ieee80211.h>
 #include <linux/module.h>
+#include <linux/netdevice.h>
 
 #include <defs.h>
 #include <brcmu_wifi.h>
index fb508c2..eefa6c2 100644 (file)
@@ -31,6 +31,7 @@
 #define BRCMF_EVENT_VAL        0x0800
 #define BRCMF_BTA_VAL  0x1000
 #define BRCMF_ISCAN_VAL 0x2000
+#define BRCMF_FIL_VAL  0x4000
 
 #if defined(DEBUG)
 
@@ -56,6 +57,7 @@ do {                                                                  \
 #define BRCMF_BYTES_ON()       (brcmf_msg_level & BRCMF_BYTES_VAL)
 #define BRCMF_GLOM_ON()                (brcmf_msg_level & BRCMF_GLOM_VAL)
 #define BRCMF_EVENT_ON()       (brcmf_msg_level & BRCMF_EVENT_VAL)
+#define BRCMF_FIL_ON()         (brcmf_msg_level & BRCMF_FIL_VAL)
 
 #else  /* (defined DEBUG) || (defined DEBUG) */
 
@@ -67,6 +69,7 @@ do {                                                                  \
 #define BRCMF_BYTES_ON()       0
 #define BRCMF_GLOM_ON()                0
 #define BRCMF_EVENT_ON()       0
+#define BRCMF_FIL_ON()         0
 
 #endif                         /* defined(DEBUG) */
 
index d7c76ce..2976523 100644 (file)
@@ -52,16 +52,6 @@ MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
 
-/* Interface control information */
-struct brcmf_if {
-       struct brcmf_pub *drvr; /* back pointer to brcmf_pub */
-       /* OS/stack specifics */
-       struct net_device *ndev;
-       struct net_device_stats stats;
-       int idx;                /* iface idx in dongle */
-       u8 mac_addr[ETH_ALEN];  /* assigned MAC address */
-};
-
 /* Error bits */
 int brcmf_msg_level = BRCMF_ERROR_VAL;
 module_param(brcmf_msg_level, int, 0);
@@ -629,12 +619,9 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
                        brcmf_dbg(ERROR, "dongle is not up\n");
                        return -ENODEV;
                }
-
                /* finally, report dongle driver type */
-               else if (drvr->iswl)
-                       sprintf(info.driver, "wl");
                else
-                       sprintf(info.driver, "xx");
+                       sprintf(info.driver, "wl");
 
                sprintf(info.version, "%lu", drvr->drv_version);
                if (copy_to_user(uaddr, &info, sizeof(info)))
@@ -719,65 +706,6 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
        return -EOPNOTSUPP;
 }
 
-/* called only from within this driver. Sends a command to the dongle. */
-s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
-{
-       struct brcmf_dcmd dcmd;
-       s32 err = 0;
-       int buflen = 0;
-       bool is_set_key_cmd;
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_pub *drvr = ifp->drvr;
-
-       memset(&dcmd, 0, sizeof(dcmd));
-       dcmd.cmd = cmd;
-       dcmd.buf = arg;
-       dcmd.len = len;
-
-       if (dcmd.buf != NULL)
-               buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
-
-       /* send to dongle (must be up, and wl) */
-       if ((drvr->bus_if->state != BRCMF_BUS_DATA)) {
-               brcmf_dbg(ERROR, "DONGLE_DOWN\n");
-               err = -EIO;
-               goto done;
-       }
-
-       if (!drvr->iswl) {
-               err = -EIO;
-               goto done;
-       }
-
-       /*
-        * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and
-        * set key CMD to prevent M4 encryption.
-        */
-       is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) ||
-                         ((dcmd.cmd == BRCMF_C_SET_VAR) &&
-                          !(strncmp("wsec_key", dcmd.buf, 9))) ||
-                         ((dcmd.cmd == BRCMF_C_SET_VAR) &&
-                          !(strncmp("bsscfg:wsec_key", dcmd.buf, 15))));
-       if (is_set_key_cmd)
-               brcmf_netdev_wait_pend8021x(ndev);
-
-       err = brcmf_proto_dcmd(drvr, ifp->idx, &dcmd, buflen);
-
-done:
-       if (err > 0)
-               err = 0;
-
-       return err;
-}
-
-int brcmf_netlink_dcmd(struct net_device *ndev, struct brcmf_dcmd *dcmd)
-{
-       brcmf_dbg(TRACE, "enter: cmd %x buf %p len %d\n",
-                 dcmd->cmd, dcmd->buf, dcmd->len);
-
-       return brcmf_exec_dcmd(ndev, dcmd->cmd, dcmd->buf, dcmd->len);
-}
-
 static int brcmf_netdev_stop(struct net_device *ndev)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
@@ -851,7 +779,7 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
        .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
 };
 
-static int brcmf_net_attach(struct brcmf_if *ifp)
+int brcmf_net_attach(struct brcmf_if *ifp)
 {
        struct brcmf_pub *drvr = ifp->drvr;
        struct net_device *ndev;
@@ -885,15 +813,6 @@ static int brcmf_net_attach(struct brcmf_if *ifp)
 
        memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
 
-       /* attach to cfg80211 for primary interface */
-       if (!ifp->idx) {
-               drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr);
-               if (drvr->config == NULL) {
-                       brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
-                       goto fail;
-               }
-       }
-
        if (register_netdev(ndev) != 0) {
                brcmf_dbg(ERROR, "couldn't register the net device\n");
                goto fail;
@@ -905,11 +824,12 @@ static int brcmf_net_attach(struct brcmf_if *ifp)
 
 fail:
        ndev->netdev_ops = NULL;
+       free_netdev(ndev);
        return -EBADE;
 }
 
-int
-brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)
+struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
+                             char *name, u8 *mac_addr)
 {
        struct brcmf_if *ifp;
        struct net_device *ndev;
@@ -936,7 +856,7 @@ brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)
        ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
        if (!ndev) {
                brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
        }
 
        ifp = netdev_priv(ndev);
@@ -944,20 +864,14 @@ brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)
        ifp->drvr = drvr;
        drvr->iflist[ifidx] = ifp;
        ifp->idx = ifidx;
+       ifp->bssidx = bssidx;
        if (mac_addr != NULL)
                memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
 
-       if (brcmf_net_attach(ifp)) {
-               brcmf_dbg(ERROR, "brcmf_net_attach failed");
-               free_netdev(ifp->ndev);
-               drvr->iflist[ifidx] = NULL;
-               return -EOPNOTSUPP;
-       }
-
        brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
                  current->pid, ifp->ndev->name);
 
-       return 0;
+       return ifp;
 }
 
 void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
@@ -1036,10 +950,9 @@ fail:
 int brcmf_bus_start(struct device *dev)
 {
        int ret = -1;
-       /* Room for "event_msgs" + '\0' + bitvec */
-       char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
+       struct brcmf_if *ifp;
 
        brcmf_dbg(TRACE, "\n");
 
@@ -1050,49 +963,30 @@ int brcmf_bus_start(struct device *dev)
                return ret;
        }
 
-       brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
-                     iovbuf, sizeof(iovbuf));
-       brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
-                                   sizeof(iovbuf));
-       memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
-
-       setbit(drvr->eventmask, BRCMF_E_SET_SSID);
-       setbit(drvr->eventmask, BRCMF_E_PRUNE);
-       setbit(drvr->eventmask, BRCMF_E_AUTH);
-       setbit(drvr->eventmask, BRCMF_E_REASSOC);
-       setbit(drvr->eventmask, BRCMF_E_REASSOC_IND);
-       setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND);
-       setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND);
-       setbit(drvr->eventmask, BRCMF_E_DISASSOC);
-       setbit(drvr->eventmask, BRCMF_E_JOIN);
-       setbit(drvr->eventmask, BRCMF_E_ASSOC_IND);
-       setbit(drvr->eventmask, BRCMF_E_PSK_SUP);
-       setbit(drvr->eventmask, BRCMF_E_LINK);
-       setbit(drvr->eventmask, BRCMF_E_NDIS_LINK);
-       setbit(drvr->eventmask, BRCMF_E_MIC_ERROR);
-       setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE);
-       setbit(drvr->eventmask, BRCMF_E_TXFAIL);
-       setbit(drvr->eventmask, BRCMF_E_JOIN_START);
-       setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE);
-
-/* enable dongle roaming event */
-
-       drvr->pktfilter_count = 1;
-       /* Setup filter to allow only unicast */
-       drvr->pktfilter[0] = "100 0 0 0 0x01 0x00";
-
-       /* Bus is ready, do any protocol initialization */
-       ret = brcmf_proto_init(drvr);
+       /* add primary networking interface */
+       ifp = brcmf_add_if(dev, 0, 0, "wlan%d", NULL);
+       if (IS_ERR(ifp))
+               return PTR_ERR(ifp);
+
+       /* signal bus ready */
+       bus_if->state = BRCMF_BUS_DATA;
+
+       /* Bus is ready, do any initialization */
+       ret = brcmf_c_preinit_dcmds(ifp);
        if (ret < 0)
                return ret;
 
-       /* add primary networking interface */
-       ret = brcmf_add_if(dev, 0, "wlan%d", drvr->mac);
-       if (ret < 0)
+       drvr->config = brcmf_cfg80211_attach(drvr);
+       if (drvr->config == NULL)
+               return -ENOMEM;
+
+       ret = brcmf_net_attach(ifp);
+       if (ret < 0) {
+               brcmf_dbg(ERROR, "brcmf_net_attach failed");
+               drvr->iflist[0] = NULL;
                return ret;
+       }
 
-       /* signal bus ready */
-       bus_if->state = BRCMF_BUS_DATA;
        return 0;
 }
 
@@ -1163,42 +1057,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
        return pend;
 }
 
-#ifdef DEBUG
-int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size)
-{
-       int ret = 0;
-       struct file *fp;
-       mm_segment_t old_fs;
-       loff_t pos = 0;
-
-       /* change to KERNEL_DS address limit */
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-
-       /* open file to write */
-       fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640);
-       if (!fp) {
-               brcmf_dbg(ERROR, "open file error\n");
-               ret = -1;
-               goto exit;
-       }
-
-       /* Write buf to file */
-       fp->f_op->write(fp, (char __user *)buf, size, &pos);
-
-exit:
-       /* free buf before return */
-       kfree(buf);
-       /* close file before return */
-       if (fp)
-               filp_close(fp, NULL);
-       /* restore previous address limit */
-       set_fs(old_fs);
-
-       return ret;
-}
-#endif                         /* DEBUG */
-
 static void brcmf_driver_init(struct work_struct *work)
 {
        brcmf_debugfs_init();
index 6bc4425..7fe6779 100644 (file)
@@ -27,11 +27,6 @@ extern int brcmf_proto_attach(struct brcmf_pub *drvr);
 /* Unlink, frees allocated protocol memory (including brcmf_proto) */
 extern void brcmf_proto_detach(struct brcmf_pub *drvr);
 
-/* Initialize protocol: sync w/dongle state.
- * Sets dongle media info (iswl, drv_version, mac address).
- */
-extern int brcmf_proto_init(struct brcmf_pub *drvr);
-
 /* Stop protocol: sync w/dongle state. */
 extern void brcmf_proto_stop(struct brcmf_pub *drvr);
 
@@ -45,7 +40,8 @@ extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,
 extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx,
                                struct brcmf_dcmd *dcmd, int len);
 
-extern int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr);
+/* Sets dongle media info (drv_version, mac address). */
+extern int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
 
 extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx,
                                     uint cmd, void *buf, uint len);
index 3564686..415f2be 100644 (file)
@@ -614,6 +614,12 @@ static const uint max_roundup = 512;
 
 #define ALIGNMENT  4
 
+enum brcmf_sdio_frmtype {
+       BRCMF_SDIO_FT_NORMAL,
+       BRCMF_SDIO_FT_SUPER,
+       BRCMF_SDIO_FT_SUB,
+};
+
 static void pkt_align(struct sk_buff *p, int len, int align)
 {
        uint datalign;
@@ -1032,7 +1038,8 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
 }
 
 static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
-                               struct brcmf_sdio_read *rd)
+                               struct brcmf_sdio_read *rd,
+                               enum brcmf_sdio_frmtype type)
 {
        u16 len, checksum;
        u8 rx_seq, fc, tx_seq_max;
@@ -1059,6 +1066,15 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
                brcmf_dbg(ERROR, "HW header length error\n");
                return false;
        }
+       if (type == BRCMF_SDIO_FT_SUPER &&
+           (roundup(len, bus->blocksize) != rd->len)) {
+               brcmf_dbg(ERROR, "HW superframe header length error\n");
+               return false;
+       }
+       if (type == BRCMF_SDIO_FT_SUB && len > rd->len) {
+               brcmf_dbg(ERROR, "HW subframe header length error\n");
+               return false;
+       }
        rd->len = len;
 
        /*
@@ -1071,9 +1087,16 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
         * Byte 5: Maximum Sequence number allow for Tx
         * Byte 6~7: Reserved
         */
+       if (type == BRCMF_SDIO_FT_SUPER &&
+           SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) {
+               brcmf_dbg(ERROR, "Glom descriptor found in superframe head\n");
+               rd->len = 0;
+               return false;
+       }
        rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);
        rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]);
-       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) {
                brcmf_dbg(ERROR, "HW header length too long\n");
                bus->sdiodev->bus_if->dstats.rx_errors++;
                bus->sdcnt.rx_toolong++;
@@ -1081,6 +1104,17 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
                rd->len = 0;
                return false;
        }
+       if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) {
+               brcmf_dbg(ERROR, "Wrong channel for superframe\n");
+               rd->len = 0;
+               return false;
+       }
+       if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL &&
+           rd->channel != SDPCM_EVENT_CHANNEL) {
+               brcmf_dbg(ERROR, "Wrong channel for subframe\n");
+               rd->len = 0;
+               return false;
+       }
        rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);
        if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
                brcmf_dbg(ERROR, "seq %d: bad data offset\n", rx_seq);
@@ -1095,6 +1129,9 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
                bus->sdcnt.rx_badseq++;
                rd->seq_num = rx_seq;
        }
+       /* no need to check the reset for subframe */
+       if (type == BRCMF_SDIO_FT_SUB)
+               return true;
        rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
        if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
                /* only warm for NON glom packet */
@@ -1126,16 +1163,16 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
        u16 dlen, totlen;
        u8 *dptr, num = 0;
 
-       u16 sublen, check;
+       u16 sublen;
        struct sk_buff *pfirst, *pnext;
 
        int errcode;
-       u8 chan, seq, doff, sfdoff;
-       u8 txmax;
+       u8 doff, sfdoff;
 
        int ifidx = 0;
        bool usechain = bus->use_rxchain;
-       u16 next_len;
+
+       struct brcmf_sdio_read rd_new;
 
        /* If packets, issue read(s) and send up packet chain */
        /* Return sequence numbers consumed? */
@@ -1279,68 +1316,15 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                   pfirst->data, min_t(int, pfirst->len, 48),
                                   "SUPERFRAME:\n");
 
-               /* Validate the superframe header */
-               dptr = (u8 *) (pfirst->data);
-               sublen = get_unaligned_le16(dptr);
-               check = get_unaligned_le16(dptr + sizeof(u16));
-
-               chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
-               seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
-               next_len = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
-               if ((next_len << 4) > MAX_RX_DATASZ) {
-                       brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n",
-                                 next_len, seq);
-                       next_len = 0;
-               }
-               bus->cur_read.len = next_len << 4;
-               doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
-               txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
-
-               errcode = 0;
-               if ((u16)~(sublen ^ check)) {
-                       brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
-                                 sublen, check);
-                       errcode = -1;
-               } else if (roundup(sublen, bus->blocksize) != dlen) {
-                       brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
-                                 sublen, roundup(sublen, bus->blocksize),
-                                 dlen);
-                       errcode = -1;
-               } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
-                          SDPCM_GLOM_CHANNEL) {
-                       brcmf_dbg(ERROR, "(superframe): bad channel %d\n",
-                                 SDPCM_PACKET_CHANNEL(
-                                         &dptr[SDPCM_FRAMETAG_LEN]));
-                       errcode = -1;
-               } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
-                       brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n");
-                       errcode = -1;
-               } else if ((doff < SDPCM_HDRLEN) ||
-                          (doff > (pfirst->len - SDPCM_HDRLEN))) {
-                       brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n",
-                                 doff, sublen, pfirst->len, SDPCM_HDRLEN);
-                       errcode = -1;
-               }
-
-               /* Check sequence number of superframe SW header */
-               if (rxseq != seq) {
-                       brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
-                                 seq, rxseq);
-                       bus->sdcnt.rx_badseq++;
-                       rxseq = seq;
-               }
-
-               /* Check window for sanity */
-               if ((u8) (txmax - bus->tx_seq) > 0x40) {
-                       brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
-                                 txmax, bus->tx_seq);
-                       txmax = bus->tx_seq + 2;
-               }
-               bus->tx_max = txmax;
+               rd_new.seq_num = rxseq;
+               rd_new.len = dlen;
+               errcode = -!brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
+                                                  BRCMF_SDIO_FT_SUPER);
+               bus->cur_read.len = rd_new.len_nxtfrm << 4;
 
                /* Remove superframe header, remember offset */
-               skb_pull(pfirst, doff);
-               sfdoff = doff;
+               skb_pull(pfirst, rd_new.dat_offset);
+               sfdoff = rd_new.dat_offset;
                num = 0;
 
                /* Validate all the subframe headers */
@@ -1349,34 +1333,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        if (errcode)
                                break;
 
-                       dptr = (u8 *) (pnext->data);
-                       dlen = (u16) (pnext->len);
-                       sublen = get_unaligned_le16(dptr);
-                       check = get_unaligned_le16(dptr + sizeof(u16));
-                       chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
-                       doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+                       rd_new.len = pnext->len;
+                       rd_new.seq_num = rxseq++;
+                       errcode = -!brcmf_sdio_hdparser(bus, pnext->data,
+                                                          &rd_new,
+                                                          BRCMF_SDIO_FT_SUB);
                        brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
-                                          dptr, 32, "subframe:\n");
+                                          pnext->data, 32, "subframe:\n");
 
-                       if ((u16)~(sublen ^ check)) {
-                               brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n",
-                                         num, sublen, check);
-                               errcode = -1;
-                       } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
-                               brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n",
-                                         num, sublen, dlen);
-                               errcode = -1;
-                       } else if ((chan != SDPCM_DATA_CHANNEL) &&
-                                  (chan != SDPCM_EVENT_CHANNEL)) {
-                               brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n",
-                                         num, chan);
-                               errcode = -1;
-                       } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
-                               brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n",
-                                         num, doff, sublen, SDPCM_HDRLEN);
-                               errcode = -1;
-                       }
-                       /* increase the subframe count */
                        num++;
                }
 
@@ -1402,27 +1366,11 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
                        dptr = (u8 *) (pfirst->data);
                        sublen = get_unaligned_le16(dptr);
-                       chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
-                       seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
                        doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
 
-                       brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
-                                 num, pfirst, pfirst->data,
-                                 pfirst->len, sublen, chan, seq);
-
-                       /* precondition: chan == SDPCM_DATA_CHANNEL ||
-                                        chan == SDPCM_EVENT_CHANNEL */
-
-                       if (rxseq != seq) {
-                               brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
-                                         seq, rxseq);
-                               bus->sdcnt.rx_badseq++;
-                               rxseq = seq;
-                       }
-                       rxseq++;
-
                        brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
-                                          dptr, dlen, "Rx Subframe Data:\n");
+                                          dptr, pfirst->len,
+                                          "Rx Subframe Data:\n");
 
                        __skb_trim(pfirst, sublen);
                        skb_pull(pfirst, doff);
@@ -1642,7 +1590,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                           bus->rxhdr, SDPCM_HDRLEN,
                                           "RxHdr:\n");
 
-                       if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd)) {
+                       if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
+                                                BRCMF_SDIO_FT_NORMAL)) {
                                if (!bus->rxpending)
                                        break;
                                else
@@ -1701,7 +1650,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                } else {
                        memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
                        rd_new.seq_num = rd->seq_num;
-                       if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new)) {
+                       if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
+                                                BRCMF_SDIO_FT_NORMAL)) {
                                rd->len = 0;
                                brcmu_pkt_buf_free_skb(pkt);
                        }
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
new file mode 100644 (file)
index 0000000..4b272c3
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * 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.
+ */
+
+/* FWIL is the Firmware Interface Layer. In this module the support functions
+ * are located to set and get variables to and from the firmware.
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <defs.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_dbg.h"
+#include "fwil.h"
+
+
+static s32
+brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
+{
+       struct brcmf_pub *drvr = ifp->drvr;
+       s32 err;
+
+       if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
+               brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
+               return -EIO;
+       }
+
+       if (data != NULL)
+               len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
+       if (set)
+               err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len);
+       else
+               err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data,
+                                                len);
+
+       if (err >= 0)
+               err = 0;
+       else
+               brcmf_dbg(ERROR, "Failed err=%d\n", err);
+
+       return err;
+}
+
+s32
+brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
+{
+       s32 err;
+
+       mutex_lock(&ifp->drvr->proto_block);
+
+       brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+
+       err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
+       mutex_unlock(&ifp->drvr->proto_block);
+
+       return err;
+}
+
+s32
+brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
+{
+       s32 err;
+
+       mutex_lock(&ifp->drvr->proto_block);
+       err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
+
+       brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+
+       mutex_unlock(&ifp->drvr->proto_block);
+
+       return err;
+}
+
+
+s32
+brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
+{
+       s32 err;
+       __le32 data_le = cpu_to_le32(data);
+
+       mutex_lock(&ifp->drvr->proto_block);
+       err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
+       mutex_unlock(&ifp->drvr->proto_block);
+
+       return err;
+}
+
+s32
+brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
+{
+       s32 err;
+       __le32 data_le = cpu_to_le32(*data);
+
+       mutex_lock(&ifp->drvr->proto_block);
+       err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
+       mutex_unlock(&ifp->drvr->proto_block);
+       *data = le32_to_cpu(data_le);
+
+       return err;
+}
+
+static u32
+brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)
+{
+       u32 len;
+
+       len = strlen(name) + 1;
+
+       if ((len + datalen) > buflen)
+               return 0;
+
+       memcpy(buf, name, len);
+
+       /* append data onto the end of the name string */
+       if (data && datalen)
+               memcpy(&buf[len], data, datalen);
+
+       return len + datalen;
+}
+
+
+s32
+brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
+                        u32 len)
+{
+       struct brcmf_pub *drvr = ifp->drvr;
+       s32 err;
+       u32 buflen;
+
+       mutex_lock(&drvr->proto_block);
+
+       brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+
+       buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
+                                   sizeof(drvr->proto_buf));
+       if (buflen) {
+               err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
+                                        buflen, true);
+       } else {
+               err = -EPERM;
+               brcmf_dbg(ERROR, "Creating iovar failed\n");
+       }
+
+       mutex_unlock(&drvr->proto_block);
+       return err;
+}
+
+s32
+brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
+                        u32 len)
+{
+       struct brcmf_pub *drvr = ifp->drvr;
+       s32 err;
+       u32 buflen;
+
+       mutex_lock(&drvr->proto_block);
+
+       buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
+                                   sizeof(drvr->proto_buf));
+       if (buflen) {
+               err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
+                                        buflen, false);
+               if (err == 0)
+                       memcpy(data, drvr->proto_buf, len);
+       } else {
+               err = -EPERM;
+               brcmf_dbg(ERROR, "Creating iovar failed\n");
+       }
+
+       brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+
+       mutex_unlock(&drvr->proto_block);
+       return err;
+}
+
+s32
+brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data)
+{
+       __le32 data_le = cpu_to_le32(data);
+
+       return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le));
+}
+
+s32
+brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data)
+{
+       __le32 data_le = cpu_to_le32(*data);
+       s32 err;
+
+       err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le));
+       if (err == 0)
+               *data = le32_to_cpu(data_le);
+       return err;
+}
+
+static u32
+brcmf_create_bsscfg(s32 bssidx, char *name, char *data, u32 datalen, char *buf,
+                   u32 buflen)
+{
+       const s8 *prefix = "bsscfg:";
+       s8 *p;
+       u32 prefixlen;
+       u32 namelen;
+       u32 iolen;
+       __le32 bssidx_le;
+
+       if (bssidx == 0)
+               return brcmf_create_iovar(name, data, datalen, buf, buflen);
+
+       prefixlen = strlen(prefix);
+       namelen = strlen(name) + 1; /* lengh of iovar  name + null */
+       iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen;
+
+       if (buflen < iolen) {
+               brcmf_dbg(ERROR, "buffer is too short\n");
+               return 0;
+       }
+
+       p = buf;
+
+       /* copy prefix, no null */
+       memcpy(p, prefix, prefixlen);
+       p += prefixlen;
+
+       /* copy iovar name including null */
+       memcpy(p, name, namelen);
+       p += namelen;
+
+       /* bss config index as first data */
+       bssidx_le = cpu_to_le32(bssidx);
+       memcpy(p, &bssidx_le, sizeof(bssidx_le));
+       p += sizeof(bssidx_le);
+
+       /* parameter buffer follows */
+       if (datalen)
+               memcpy(p, data, datalen);
+
+       return iolen;
+}
+
+s32
+brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
+                         void *data, u32 len)
+{
+       struct brcmf_pub *drvr = ifp->drvr;
+       s32 err;
+       u32 buflen;
+
+       mutex_lock(&drvr->proto_block);
+
+       brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+
+       buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
+                                    drvr->proto_buf, sizeof(drvr->proto_buf));
+       if (buflen) {
+               err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
+                                        buflen, true);
+       } else {
+               err = -EPERM;
+               brcmf_dbg(ERROR, "Creating bsscfg failed\n");
+       }
+
+       mutex_unlock(&drvr->proto_block);
+       return err;
+}
+
+s32
+brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
+                         void *data, u32 len)
+{
+       struct brcmf_pub *drvr = ifp->drvr;
+       s32 err;
+       u32 buflen;
+
+       mutex_lock(&drvr->proto_block);
+
+       buflen = brcmf_create_bsscfg(ifp->bssidx, name, NULL, len,
+                                    drvr->proto_buf, sizeof(drvr->proto_buf));
+       if (buflen) {
+               err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
+                                        buflen, false);
+               if (err == 0)
+                       memcpy(data, drvr->proto_buf, len);
+       } else {
+               err = -EPERM;
+               brcmf_dbg(ERROR, "Creating bsscfg failed\n");
+       }
+       brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+
+       mutex_unlock(&drvr->proto_block);
+       return err;
+
+}
+
+s32
+brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data)
+{
+       __le32 data_le = cpu_to_le32(data);
+
+       return brcmf_fil_bsscfg_data_set(ifp, name, &data_le,
+                                        sizeof(data_le));
+}
+
+s32
+brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data)
+{
+       __le32 data_le = cpu_to_le32(*data);
+       s32 err;
+
+       err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le,
+                                       sizeof(data_le));
+       if (err == 0)
+               *data = le32_to_cpu(data_le);
+       return err;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
new file mode 100644 (file)
index 0000000..16eb820
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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_h_
+#define _fwil_h_
+
+s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
+s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
+s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data);
+s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data);
+
+s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
+                            u32 len);
+s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
+                            u32 len);
+s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data);
+s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data);
+
+s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, void *data,
+                             u32 len);
+s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, void *data,
+                             u32 len);
+s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data);
+s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data);
+
+#endif /* _fwil_h_ */
index 7a6dfdc..484a6e4 100644 (file)
@@ -42,7 +42,6 @@
 
 #define IOCTL_RESP_TIMEOUT  2000
 
-#define BRCMF_USB_SYNC_TIMEOUT         300     /* ms */
 #define BRCMF_USB_DLIMAGE_SPINWAIT     100     /* in unit of ms */
 #define BRCMF_USB_DLIMAGE_LIMIT                500     /* spinwait limit (ms) */
 
@@ -116,10 +115,6 @@ struct brcmf_usbdev_info {
        u8 *image;      /* buffer for combine fw and nvram */
        int image_len;
 
-       wait_queue_head_t wait;
-       bool waitdone;
-       int sync_urb_status;
-
        struct usb_device *usbdev;
        struct device *dev;
 
@@ -131,7 +126,6 @@ struct brcmf_usbdev_info {
        int ctl_urb_status;
        int ctl_completed;
        wait_queue_head_t ioctl_resp_wait;
-       wait_queue_head_t ctrl_wait;
        ulong ctl_op;
 
        struct urb *bulk_urb; /* used for FW download */
@@ -754,34 +748,14 @@ static void brcmf_usb_down(struct device *dev)
        brcmf_usb_free_q(&devinfo->rx_postq, true);
 }
 
-static int
-brcmf_usb_sync_wait(struct brcmf_usbdev_info *devinfo, u16 time)
-{
-       int ret;
-       int err = 0;
-       int ms = time;
-
-       ret = wait_event_interruptible_timeout(devinfo->wait,
-               devinfo->waitdone == true, (ms * HZ / 1000));
-
-       if ((devinfo->waitdone == false) || (devinfo->sync_urb_status)) {
-               brcmf_dbg(ERROR, "timeout(%d) or urb err=%d\n",
-                         ret, devinfo->sync_urb_status);
-               err = -EINVAL;
-       }
-       devinfo->waitdone = false;
-       return err;
-}
-
 static void
 brcmf_usb_sync_complete(struct urb *urb)
 {
        struct brcmf_usbdev_info *devinfo =
                        (struct brcmf_usbdev_info *)urb->context;
 
-       devinfo->waitdone = true;
-       wake_up_interruptible(&devinfo->wait);
-       devinfo->sync_urb_status = urb->status;
+       devinfo->ctl_completed = true;
+       brcmf_usb_ioctl_resp_wake(devinfo);
 }
 
 static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
@@ -813,6 +787,7 @@ static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
                (void *) tmpbuf, size,
                (usb_complete_t)brcmf_usb_sync_complete, devinfo);
 
+       devinfo->ctl_completed = false;
        ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
        if (ret < 0) {
                brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
@@ -820,11 +795,11 @@ static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
                return false;
        }
 
-       ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
+       ret = brcmf_usb_ioctl_resp_wait(devinfo);
        memcpy(buffer, tmpbuf, buflen);
        kfree(tmpbuf);
 
-       return (ret == 0);
+       return ret;
 }
 
 static bool
@@ -918,13 +893,14 @@ brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info *devinfo, void *buffer, int len)
 
        devinfo->bulk_urb->transfer_flags |= URB_ZERO_PACKET;
 
+       devinfo->ctl_completed = false;
        ret = usb_submit_urb(devinfo->bulk_urb, GFP_ATOMIC);
        if (ret) {
                brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret);
                return ret;
        }
-       ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT);
-       return ret;
+       ret = brcmf_usb_ioctl_resp_wait(devinfo);
+       return (ret == 0);
 }
 
 static int
@@ -1284,7 +1260,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
                goto error;
        }
 
-       init_waitqueue_head(&devinfo->wait);
        if (!brcmf_usb_dlneeded(devinfo))
                return &devinfo->bus_pub;
 
index a6f1e81..cb30fea 100644 (file)
@@ -35,6 +35,7 @@
 #include <brcmu_wifi.h>
 #include "dhd.h"
 #include "wl_cfg80211.h"
+#include "fwil.h"
 
 #define BRCMF_SCAN_IE_LEN_MAX          2048
 #define BRCMF_PNO_VERSION              2
@@ -48,6 +49,8 @@
 #define BRCMF_PNO_SCAN_COMPLETE                1
 #define BRCMF_PNO_SCAN_INCOMPLETE      0
 
+#define BRCMF_IFACE_MAX_CNT            2
+
 #define TLV_LEN_OFF                    1       /* length offset */
 #define TLV_HDR_LEN                    2       /* header length */
 #define TLV_BODY_OFF                   2       /* body offset */
 #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
        (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
 
-static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
-
 static u32 brcmf_dbg_level = WL_DBG_ERR;
 
-static bool check_sys_up(struct wiphy *wiphy)
+static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
 {
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       if (!test_bit(WL_STATUS_READY, &cfg->status)) {
-               WL_INFO("device is not ready : status (%d)\n",
-                       (int)cfg->status);
+       if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
+               WL_INFO("device is not ready : status (%lu)\n",
+                       vif->sme_state);
                return false;
        }
        return true;
@@ -391,55 +391,29 @@ static u8 brcmf_mw_to_qdbm(u16 mw)
        return qdbm;
 }
 
-/* function for reading/writing a single u32 from/to the dongle */
-static int
-brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par)
+static u16 channel_to_chanspec(struct ieee80211_channel *ch)
 {
-       int err;
-       __le32 par_le = cpu_to_le32(*par);
-
-       err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32));
-       *par = le32_to_cpu(par_le);
-
-       return err;
-}
-
-static s32
-brcmf_dev_iovar_setbuf_bsscfg(struct net_device *ndev, s8 *name,
-                             void *param, s32 paramlen,
-                             void *buf, s32 buflen, s32 bssidx)
-{
-       s32 err = -ENOMEM;
-       u32 len;
-
-       len = brcmf_c_mkiovar_bsscfg(name, param, paramlen,
-                                    buf, buflen, bssidx);
-       BUG_ON(!len);
-       if (len > 0)
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
-       if (err)
-               WL_ERR("error (%d)\n", err);
+       u16 chanspec;
 
-       return err;
-}
+       chanspec = ieee80211_frequency_to_channel(ch->center_freq);
+       chanspec &= WL_CHANSPEC_CHAN_MASK;
 
-static s32
-brcmf_dev_iovar_getbuf_bsscfg(struct net_device *ndev, s8 *name,
-                             void *param, s32 paramlen,
-                             void *buf, s32 buflen, s32 bssidx)
-{
-       s32 err = -ENOMEM;
-       u32 len;
-
-       len = brcmf_c_mkiovar_bsscfg(name, param, paramlen,
-                                    buf, buflen, bssidx);
-       BUG_ON(!len);
-       if (len > 0)
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, buf, len);
-       if (err)
-               WL_ERR("error (%d)\n", err);
+       if (ch->band == IEEE80211_BAND_2GHZ)
+               chanspec |= WL_CHANSPEC_BAND_2G;
+       else
+               chanspec |= WL_CHANSPEC_BAND_5G;
 
-       return err;
+       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;
+       }
+       return chanspec;
 }
 
 static void convert_key_from_CPU(struct brcmf_wsec_key *key,
@@ -457,18 +431,17 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key,
 }
 
 static int
-send_key_to_dongle(struct brcmf_cfg80211_info *cfg, s32 bssidx,
-                  struct net_device *ndev, struct brcmf_wsec_key *key)
+send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
 {
        int err;
        struct brcmf_wsec_key_le key_le;
 
        convert_key_from_CPU(key, &key_le);
 
-       err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le,
-                                            sizeof(key_le),
-                                            cfg->extra_buf,
-                                            WL_EXTRA_BUF_MAX, bssidx);
+       brcmf_netdev_wait_pend8021x(ndev);
+
+       err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
+                                       sizeof(key_le));
 
        if (err)
                WL_ERR("wsec_key error (%d)\n", err);
@@ -480,6 +453,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
                         enum nl80211_iftype type, u32 *flags,
                         struct vif_params *params)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        s32 infra = 0;
        s32 ap = 0;
@@ -511,7 +485,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        if (ap) {
-               set_bit(WL_STATUS_AP_CREATING, &cfg->status);
+               set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
                if (!cfg->ap_info)
                        cfg->ap_info = kzalloc(sizeof(*cfg->ap_info),
                                               GFP_KERNEL);
@@ -521,7 +495,8 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
                }
                WL_INFO("IF Type = AP\n");
        } else {
-               err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
+               err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
+                                           BRCMF_C_SET_INFRA, infra);
                if (err) {
                        WL_ERR("WLC_SET_INFRA error (%d)\n", err);
                        err = -EAGAIN;
@@ -539,99 +514,13 @@ done:
        return err;
 }
 
-static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val)
-{
-       s8 buf[BRCMF_DCMD_SMLEN];
-       u32 len;
-       s32 err = 0;
-       __le32 val_le;
-
-       val_le = cpu_to_le32(val);
-       len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf,
-                           sizeof(buf));
-       BUG_ON(!len);
-
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
-       if (err)
-               WL_ERR("error (%d)\n", err);
-
-       return err;
-}
-
-static s32
-brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval)
-{
-       union {
-               s8 buf[BRCMF_DCMD_SMLEN];
-               __le32 val;
-       } var;
-       u32 len;
-       u32 data_null;
-       s32 err = 0;
-
-       len =
-           brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
-                       sizeof(var.buf));
-       BUG_ON(!len);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len);
-       if (err)
-               WL_ERR("error (%d)\n", err);
-
-       *retval = le32_to_cpu(var.val);
-
-       return err;
-}
-
-static s32
-brcmf_dev_intvar_set_bsscfg(struct net_device *ndev, s8 *name, u32 val,
-                           s32 bssidx)
-{
-       s8 buf[BRCMF_DCMD_SMLEN];
-       __le32 val_le;
-
-       val_le = cpu_to_le32(val);
-
-       return brcmf_dev_iovar_setbuf_bsscfg(ndev, name, &val_le,
-                                            sizeof(val_le), buf, sizeof(buf),
-                                            bssidx);
-}
-
-static s32
-brcmf_dev_intvar_get_bsscfg(struct net_device *ndev, s8 *name, s32 *val,
-                           s32 bssidx)
-{
-       s8 buf[BRCMF_DCMD_SMLEN];
-       s32 err;
-       __le32 val_le;
-
-       memset(buf, 0, sizeof(buf));
-       err = brcmf_dev_iovar_getbuf_bsscfg(ndev, name, val, sizeof(*val), buf,
-                                           sizeof(buf), bssidx);
-       if (err == 0) {
-               memcpy(&val_le, buf, sizeof(val_le));
-               *val = le32_to_cpu(val_le);
-       }
-       return err;
-}
-
-
-/*
- * For now brcmf_find_bssidx will return 0. Once p2p gets implemented this
- * should return the ndev matching bssidx.
- */
-static s32
-brcmf_find_bssidx(struct brcmf_cfg80211_info *cfg, struct net_device *ndev)
-{
-       return 0;
-}
-
 static void brcmf_set_mpc(struct net_device *ndev, int mpc)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
 
-       if (test_bit(WL_STATUS_READY, &cfg->status)) {
-               err = brcmf_dev_intvar_set(ndev, "mpc", mpc);
+       if (check_vif_up(ifp->vif)) {
+               err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
                if (err) {
                        WL_ERR("fail to set mpc\n");
                        return;
@@ -643,7 +532,7 @@ static void brcmf_set_mpc(struct net_device *ndev, int mpc)
 static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le,
                             struct brcmf_ssid *ssid)
 {
-       memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
+       memset(params_le->bssid, 0xFF, ETH_ALEN);
        params_le->bss_type = DOT11_BSSTYPE_ANY;
        params_le->scan_type = 0;
        params_le->channel_num = 0;
@@ -658,30 +547,6 @@ static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le,
 }
 
 static s32
-brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param,
-                   s32 paramlen, void *bufptr, s32 buflen)
-{
-       s32 iolen;
-
-       iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
-       BUG_ON(!iolen);
-
-       return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen);
-}
-
-static s32
-brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param,
-                   s32 paramlen, void *bufptr, s32 buflen)
-{
-       s32 iolen;
-
-       iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
-       BUG_ON(!iolen);
-
-       return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen);
-}
-
-static s32
 brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
                struct brcmf_ssid *ssid, u16 action)
 {
@@ -703,8 +568,8 @@ brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
        params->action = cpu_to_le16(action);
        params->scan_duration = cpu_to_le16(0);
 
-       err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size,
-                                    iscan->dcmd_buf, BRCMF_DCMD_SMLEN);
+       err = brcmf_fil_iovar_data_set(netdev_priv(iscan->ndev), "iscan",
+                                      params, params_size);
        if (err) {
                if (err == -EBUSY)
                        WL_INFO("system busy : iscan canceled\n");
@@ -721,7 +586,7 @@ static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg)
        struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
        struct net_device *ndev = cfg_to_ndev(cfg);
        struct brcmf_ssid ssid;
-       __le32 passive_scan;
+       u32 passive_scan;
        s32 err = 0;
 
        /* Broadcast scan by default */
@@ -729,9 +594,9 @@ static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg)
 
        iscan->state = WL_ISCAN_STATE_SCANING;
 
-       passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
-       err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_SET_PASSIVE_SCAN,
-                       &passive_scan, sizeof(passive_scan));
+       passive_scan = cfg->active_scan ? 0 : 1;
+       err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
+                                   BRCMF_C_SET_PASSIVE_SCAN, passive_scan);
        if (err) {
                WL_ERR("error (%d)\n", err);
                return err;
@@ -754,27 +619,27 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev,
                     struct cfg80211_scan_request *request,
                     struct cfg80211_ssid *this_ssid)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
        struct cfg80211_ssid *ssids;
        struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
-       __le32 passive_scan;
+       u32 passive_scan;
        bool iscan_req;
        bool spec_scan;
        s32 err = 0;
        u32 SSID_len;
 
-       if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
-               WL_ERR("Scanning already : status (%lu)\n", cfg->status);
+       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+               WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
                return -EAGAIN;
        }
-       if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) {
-               WL_ERR("Scanning being aborted : status (%lu)\n",
-                      cfg->status);
+       if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
+               WL_ERR("Scanning being aborted: status (%lu)\n",
+                      cfg->scan_status);
                return -EAGAIN;
        }
-       if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) {
-               WL_ERR("Connecting : status (%lu)\n",
-                      cfg->status);
+       if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
+               WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
                return -EAGAIN;
        }
 
@@ -792,7 +657,7 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        cfg->scan_request = request;
-       set_bit(WL_STATUS_SCANNING, &cfg->status);
+       set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
        if (iscan_req) {
                err = brcmf_do_iscan(cfg);
                if (!err)
@@ -813,16 +678,16 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev,
                        WL_SCAN("Broadcast scan\n");
                }
 
-               passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
-                               &passive_scan, sizeof(passive_scan));
+               passive_scan = cfg->active_scan ? 0 : 1;
+               err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
+                                           passive_scan);
                if (err) {
                        WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
                        goto scan_out;
                }
                brcmf_set_mpc(ndev, 0);
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
-                                     sizeof(sr->ssid_le));
+               err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+                                            &sr->ssid_le, sizeof(sr->ssid_le));
                if (err) {
                        if (err == -EBUSY)
                                WL_INFO("system busy : scan for \"%s\" "
@@ -838,7 +703,7 @@ brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev,
        return 0;
 
 scan_out:
-       clear_bit(WL_STATUS_SCANNING, &cfg->status);
+       clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
        cfg->scan_request = NULL;
        return err;
 }
@@ -851,12 +716,10 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
        s32 i;
        s32 offset;
        u16 chanspec;
-       u16 channel;
-       struct ieee80211_channel *req_channel;
        char *ptr;
        struct brcmf_ssid_le ssid_le;
 
-       memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
+       memset(params_le->bssid, 0xFF, ETH_ALEN);
        params_le->bss_type = DOT11_BSSTYPE_ANY;
        params_le->scan_type = 0;
        params_le->channel_num = 0;
@@ -876,30 +739,9 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
        WL_SCAN("### List of channelspecs to scan ### %d\n", n_channels);
        if (n_channels > 0) {
                for (i = 0; i < n_channels; i++) {
-                       chanspec = 0;
-                       req_channel = request->channels[i];
-                       channel = ieee80211_frequency_to_channel(
-                                       req_channel->center_freq);
-                       if (req_channel->band == IEEE80211_BAND_2GHZ)
-                               chanspec |= WL_CHANSPEC_BAND_2G;
-                       else
-                               chanspec |= WL_CHANSPEC_BAND_5G;
-
-                       if (req_channel->flags & IEEE80211_CHAN_NO_HT40) {
-                               chanspec |= WL_CHANSPEC_BW_20;
-                               chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-                       } else {
-                               chanspec |= WL_CHANSPEC_BW_40;
-                               if (req_channel->flags &
-                                               IEEE80211_CHAN_NO_HT40PLUS)
-                                       chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
-                               else
-                                       chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
-                       }
-
-                       chanspec |= (channel & WL_CHANSPEC_CHAN_MASK);
+                       chanspec = channel_to_chanspec(request->channels[i]);
                        WL_SCAN("Chan : %d, Channel spec: %x\n",
-                               channel, chanspec);
+                               request->channels[i]->hw_value, chanspec);
                        params_le->channel_list[i] = cpu_to_le16(chanspec);
                }
        } else {
@@ -966,7 +808,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
                /* Do a scan abort to stop the driver's scan engine */
                WL_SCAN("ABORT scan in firmware\n");
                memset(&params_le, 0, sizeof(params_le));
-               memcpy(params_le.bssid, ether_bcast, ETH_ALEN);
+               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);
@@ -977,8 +819,8 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
                /* 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_exec_dcmd(ndev, BRCMF_C_SCAN, &params_le,
-                       sizeof(params_le));
+               err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
+                                            &params_le, sizeof(params_le));
                if (err)
                        WL_ERR("Scan abort  failed\n");
        }
@@ -998,7 +840,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
                cfg80211_scan_done(scan_request, aborted);
                brcmf_set_mpc(ndev, 1);
        }
-       if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) {
+       if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
                WL_ERR("Scan complete while device not scanning\n");
                return -EPERM;
        }
@@ -1036,8 +878,8 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
        params->action = cpu_to_le16(action);
        params->sync_id = cpu_to_le16(0x1234);
 
-       err = brcmf_dev_iovar_setbuf(ndev, "escan", params, params_size,
-                       cfg->escan_ioctl_buf, BRCMF_DCMD_MEDLEN);
+       err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
+                                      params, params_size);
        if (err) {
                if (err == -EBUSY)
                        WL_INFO("system busy : escan canceled\n");
@@ -1055,16 +897,16 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
               struct net_device *ndev, struct cfg80211_scan_request *request)
 {
        s32 err;
-       __le32 passive_scan;
+       u32 passive_scan;
        struct brcmf_scan_results *results;
 
        WL_SCAN("Enter\n");
        cfg->escan_info.ndev = ndev;
        cfg->escan_info.wiphy = wiphy;
        cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
-       passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
-                       &passive_scan, sizeof(passive_scan));
+       passive_scan = cfg->active_scan ? 0 : 1;
+       err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
+                                   passive_scan);
        if (err) {
                WL_ERR("error (%d)\n", err);
                return err;
@@ -1086,10 +928,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
                     struct cfg80211_scan_request *request,
                     struct cfg80211_ssid *this_ssid)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
        struct cfg80211_ssid *ssids;
        struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
-       __le32 passive_scan;
+       u32 passive_scan;
        bool escan_req;
        bool spec_scan;
        s32 err;
@@ -1097,18 +940,17 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
 
        WL_SCAN("START ESCAN\n");
 
-       if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
-               WL_ERR("Scanning already : status (%lu)\n", cfg->status);
+       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+               WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
                return -EAGAIN;
        }
-       if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg->status)) {
-               WL_ERR("Scanning being aborted : status (%lu)\n",
-                      cfg->status);
+       if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
+               WL_ERR("Scanning being aborted: status (%lu)\n",
+                      cfg->scan_status);
                return -EAGAIN;
        }
-       if (test_bit(WL_STATUS_CONNECTING, &cfg->status)) {
-               WL_ERR("Connecting : status (%lu)\n",
-                      cfg->status);
+       if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
+               WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
                return -EAGAIN;
        }
 
@@ -1128,7 +970,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        cfg->scan_request = request;
-       set_bit(WL_STATUS_SCANNING, &cfg->status);
+       set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
        if (escan_req) {
                err = brcmf_do_escan(cfg, wiphy, ndev, request);
                if (!err)
@@ -1149,16 +991,16 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
                } else
                        WL_SCAN("Broadcast scan\n");
 
-               passive_scan = cfg->active_scan ? 0 : cpu_to_le32(1);
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
-                               &passive_scan, sizeof(passive_scan));
+               passive_scan = cfg->active_scan ? 0 : 1;
+               err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
+                                           passive_scan);
                if (err) {
                        WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
                        goto scan_out;
                }
                brcmf_set_mpc(ndev, 0);
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
-                                     sizeof(sr->ssid_le));
+               err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+                                            &sr->ssid_le, sizeof(sr->ssid_le));
                if (err) {
                        if (err == -EBUSY)
                                WL_INFO("BUSY: scan for \"%s\" canceled\n",
@@ -1174,7 +1016,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
        return 0;
 
 scan_out:
-       clear_bit(WL_STATUS_SCANNING, &cfg->status);
+       clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
        if (timer_pending(&cfg->escan_timeout))
                del_timer_sync(&cfg->escan_timeout);
        cfg->scan_request = NULL;
@@ -1182,8 +1024,7 @@ scan_out:
 }
 
 static s32
-brcmf_cfg80211_scan(struct wiphy *wiphy,
-                struct cfg80211_scan_request *request)
+brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
 {
        struct net_device *ndev = request->wdev->netdev;
        struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
@@ -1191,7 +1032,8 @@ brcmf_cfg80211_scan(struct wiphy *wiphy,
 
        WL_TRACE("Enter\n");
 
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(container_of(request->wdev,
+                                      struct brcmf_cfg80211_vif, wdev)))
                return -EIO;
 
        if (cfg->iscan_on)
@@ -1210,7 +1052,8 @@ static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
 {
        s32 err = 0;
 
-       err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold);
+       err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
+                                     rts_threshold);
        if (err)
                WL_ERR("Error (%d)\n", err);
 
@@ -1221,7 +1064,8 @@ static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
 {
        s32 err = 0;
 
-       err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold);
+       err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
+                                     frag_threshold);
        if (err)
                WL_ERR("Error (%d)\n", err);
 
@@ -1233,7 +1077,7 @@ static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
        s32 err = 0;
        u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
 
-       err = brcmf_exec_dcmd_u32(ndev, cmd, &retry);
+       err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
        if (err) {
                WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
                return err;
@@ -1245,10 +1089,11 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
@@ -1327,7 +1172,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_info *cfg)
        if (cfg->link_up) {
                ndev = cfg_to_ndev(cfg);
                WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0);
+               err = brcmf_fil_cmd_data_set(netdev_priv(ndev),
+                                            BRCMF_C_DISASSOC, NULL, 0);
                if (err)
                        WL_ERR("WLC_DISASSOC failed (%d)\n", err);
                cfg->link_up = false;
@@ -1340,7 +1186,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
                      struct cfg80211_ibss_params *params)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct brcmf_join_params join_params;
        size_t join_params_size = 0;
        s32 err = 0;
@@ -1348,7 +1195,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
        s32 bcnprd;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        if (params->ssid)
@@ -1358,7 +1205,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
                return -EOPNOTSUPP;
        }
 
-       set_bit(WL_STATUS_CONNECTING, &cfg->status);
+       set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
 
        if (params->bssid)
                WL_CONN("BSSID: %pM\n", params->bssid);
@@ -1399,7 +1246,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
        if (params->privacy)
                wsec |= WEP_ENABLED;
 
-       err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
+       err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
        if (err) {
                WL_ERR("wsec failed (%d)\n", err);
                goto done;
@@ -1411,7 +1258,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
        else
                bcnprd = 100;
 
-       err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd);
+       err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd);
        if (err) {
                WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
                goto done;
@@ -1434,7 +1281,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
                                   BRCMF_ASSOC_PARAMS_FIXED_SIZE;
                memcpy(profile->bssid, params->bssid, ETH_ALEN);
        } else {
-               memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
+               memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
                memset(profile->bssid, 0, ETH_ALEN);
        }
 
@@ -1453,8 +1300,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
 
                /* set channel for starter */
                target_channel = cfg->channel;
-               err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL,
-                                         &target_channel);
+               err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL,
+                                           target_channel);
                if (err) {
                        WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
                        goto done;
@@ -1465,8 +1312,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
        cfg->ibss_starter = false;
 
 
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
-                          &join_params, join_params_size);
+       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+                                    &join_params, join_params_size);
        if (err) {
                WL_ERR("WLC_SET_SSID failed (%d)\n", err);
                goto done;
@@ -1474,7 +1321,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
 
 done:
        if (err)
-               clear_bit(WL_STATUS_CONNECTING, &cfg->status);
+               clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
        WL_TRACE("Exit\n");
        return err;
 }
@@ -1483,10 +1330,11 @@ static s32
 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        brcmf_link_down(cfg);
@@ -1499,8 +1347,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
 static s32 brcmf_set_wpa_version(struct net_device *ndev,
                                 struct cfg80211_connect_params *sme)
 {
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
        struct brcmf_cfg80211_security *sec;
        s32 val = 0;
        s32 err = 0;
@@ -1512,7 +1359,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
        else
                val = WPA_AUTH_DISABLED;
        WL_CONN("setting wpa_auth to 0x%0x\n", val);
-       err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
+       err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
        if (err) {
                WL_ERR("set wpa_auth failed (%d)\n", err);
                return err;
@@ -1525,8 +1372,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
 static s32 brcmf_set_auth_type(struct net_device *ndev,
                               struct cfg80211_connect_params *sme)
 {
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
        struct brcmf_cfg80211_security *sec;
        s32 val = 0;
        s32 err = 0;
@@ -1552,7 +1398,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
                break;
        }
 
-       err = brcmf_dev_intvar_set(ndev, "auth", val);
+       err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
        if (err) {
                WL_ERR("set auth failed (%d)\n", err);
                return err;
@@ -1566,8 +1412,7 @@ static s32
 brcmf_set_set_cipher(struct net_device *ndev,
                     struct cfg80211_connect_params *sme)
 {
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
        struct brcmf_cfg80211_security *sec;
        s32 pval = 0;
        s32 gval = 0;
@@ -1617,7 +1462,7 @@ brcmf_set_set_cipher(struct net_device *ndev,
        }
 
        WL_CONN("pval (%d) gval (%d)\n", pval, gval);
-       err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval);
+       err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
        if (err) {
                WL_ERR("error (%d)\n", err);
                return err;
@@ -1633,14 +1478,14 @@ brcmf_set_set_cipher(struct net_device *ndev,
 static s32
 brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
 {
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
        struct brcmf_cfg80211_security *sec;
        s32 val = 0;
        s32 err = 0;
 
        if (sme->crypto.n_akm_suites) {
-               err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val);
+               err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
+                                             "wpa_auth", &val);
                if (err) {
                        WL_ERR("could not get wpa_auth (%d)\n", err);
                        return err;
@@ -1674,7 +1519,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
                }
 
                WL_CONN("setting wpa_auth to %d\n", val);
-               err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
+               err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
+                                             "wpa_auth", val);
                if (err) {
                        WL_ERR("could not set wpa_auth (%d)\n", err);
                        return err;
@@ -1690,13 +1536,11 @@ static s32
 brcmf_set_sharedkey(struct net_device *ndev,
                    struct cfg80211_connect_params *sme)
 {
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
        struct brcmf_cfg80211_security *sec;
        struct brcmf_wsec_key key;
        s32 val;
        s32 err = 0;
-       s32 bssidx;
 
        WL_CONN("key len (%d)\n", sme->key_len);
 
@@ -1739,15 +1583,14 @@ brcmf_set_sharedkey(struct net_device *ndev,
        WL_CONN("key length (%d) key index (%d) algo (%d)\n",
                key.len, key.index, key.algo);
        WL_CONN("key \"%s\"\n", key.data);
-       bssidx = brcmf_find_bssidx(cfg, ndev);
-       err = send_key_to_dongle(cfg, bssidx, ndev, &key);
+       err = send_key_to_dongle(ndev, &key);
        if (err)
                return err;
 
        if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
                WL_CONN("set auth_type to shared key\n");
                val = WL_AUTH_SHARED_KEY;       /* shared key */
-               err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", val, bssidx);
+               err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
                if (err)
                        WL_ERR("set auth failed (%d)\n", err);
        }
@@ -1759,7 +1602,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                    struct cfg80211_connect_params *sme)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct ieee80211_channel *chan = sme->channel;
        struct brcmf_join_params join_params;
        size_t join_params_size;
@@ -1768,7 +1612,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
        s32 err = 0;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        if (!sme->ssid) {
@@ -1776,7 +1620,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                return -EOPNOTSUPP;
        }
 
-       set_bit(WL_STATUS_CONNECTING, &cfg->status);
+       set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
 
        if (chan) {
                cfg->channel =
@@ -1827,7 +1671,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
        memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
        join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
 
-       memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
+       memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
 
        if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
                WL_CONN("ssid \"%s\", len (%d)\n",
@@ -1835,14 +1679,14 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
 
        brcmf_ch_to_chanspec(cfg->channel,
                             &join_params, &join_params_size);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
-                          &join_params, join_params_size);
+       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+                                    &join_params, join_params_size);
        if (err)
                WL_ERR("WLC_SET_SSID failed (%d)\n", err);
 
 done:
        if (err)
-               clear_bit(WL_STATUS_CONNECTING, &cfg->status);
+               clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
        WL_TRACE("Exit\n");
        return err;
 }
@@ -1852,20 +1696,21 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
                       u16 reason_code)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct brcmf_scb_val_le scbval;
        s32 err = 0;
 
        WL_TRACE("Enter. Reason code = %d\n", reason_code);
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
-       clear_bit(WL_STATUS_CONNECTED, &cfg->status);
+       clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
 
        memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
        scbval.val = cpu_to_le32(reason_code);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval,
-                             sizeof(struct brcmf_scb_val_le));
+       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
+                                    &scbval, sizeof(scbval));
        if (err)
                WL_ERR("error (%d)\n", err);
 
@@ -1882,13 +1727,14 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
 
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        u16 txpwrmw;
        s32 err = 0;
        s32 disable = 0;
        s32 dbm = MBM_TO_DBM(mbm);
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        switch (type) {
@@ -1905,7 +1751,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
        }
        /* Make sure radio is off or on as far as software is concerned */
        disable = WL_RADIO_SW_DISABLE << 16;
-       err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
        if (err)
                WL_ERR("WLC_SET_RADIO error (%d)\n", err);
 
@@ -1913,8 +1759,8 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
                txpwrmw = 0xffff;
        else
                txpwrmw = (u16) dbm;
-       err = brcmf_dev_intvar_set(ndev, "qtxpower",
-                       (s32) (brcmf_mw_to_qdbm(txpwrmw)));
+       err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
+                                     (s32)brcmf_mw_to_qdbm(txpwrmw));
        if (err)
                WL_ERR("qtxpower error (%d)\n", err);
        cfg->conf->tx_power = dbm;
@@ -1927,16 +1773,16 @@ done:
 static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        s32 txpwrdbm;
        u8 result;
        s32 err = 0;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
-       err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
+       err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
        if (err) {
                WL_ERR("error (%d)\n", err);
                goto done;
@@ -1954,19 +1800,17 @@ static s32
 brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
                               u8 key_idx, bool unicast, bool multicast)
 {
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        u32 index;
        u32 wsec;
        s32 err = 0;
-       s32 bssidx;
 
        WL_TRACE("Enter\n");
        WL_CONN("key index (%d)\n", key_idx);
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
-       bssidx = brcmf_find_bssidx(cfg, ndev);
-       err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx);
+       err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
        if (err) {
                WL_ERR("WLC_GET_WSEC error (%d)\n", err);
                goto done;
@@ -1975,8 +1819,8 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
        if (wsec & WEP_ENABLED) {
                /* Just select a new current key */
                index = key_idx;
-               err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY,
-                                         &index);
+               err = brcmf_fil_cmd_int_set(ifp,
+                                           BRCMF_C_SET_KEY_PRIMARY, index);
                if (err)
                        WL_ERR("error (%d)\n", err);
        }
@@ -1989,11 +1833,8 @@ static s32
 brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
              u8 key_idx, const u8 *mac_addr, struct key_params *params)
 {
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_wsec_key key;
-       struct brcmf_wsec_key_le key_le;
        s32 err = 0;
-       s32 bssidx;
 
        memset(&key, 0, sizeof(key));
        key.index = (u32) key_idx;
@@ -2002,11 +1843,10 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
        if (!is_multicast_ether_addr(mac_addr))
                memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
        key.len = (u32) params->key_len;
-       bssidx = brcmf_find_bssidx(cfg, ndev);
        /* check for key index change */
        if (key.len == 0) {
                /* key delete */
-               err = send_key_to_dongle(cfg, bssidx, ndev, &key);
+               err = send_key_to_dongle(ndev, &key);
                if (err)
                        WL_ERR("key delete error (%d)\n", err);
        } else {
@@ -2061,13 +1901,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
                        WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
                        return -EINVAL;
                }
-               convert_key_from_CPU(&key, &key_le);
-
-               brcmf_netdev_wait_pend8021x(ndev);
-               err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "wsec_key", &key_le,
-                                                    sizeof(key_le),
-                                                    cfg->extra_buf,
-                                                    WL_EXTRA_BUF_MAX, bssidx);
+               err = send_key_to_dongle(ndev, &key);
                if (err)
                        WL_ERR("wsec_key error (%d)\n", err);
        }
@@ -2080,16 +1914,16 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                    struct key_params *params)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_wsec_key key;
        s32 val;
        s32 wsec;
        s32 err = 0;
        u8 keybuf[8];
-       s32 bssidx;
 
        WL_TRACE("Enter\n");
        WL_CONN("key index (%d)\n", key_idx);
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        if (mac_addr) {
@@ -2147,18 +1981,17 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                goto done;
        }
 
-       bssidx = brcmf_find_bssidx(cfg, ndev);
-       err = send_key_to_dongle(cfg, bssidx, ndev, &key);
+       err = send_key_to_dongle(ndev, &key);
        if (err)
                goto done;
 
-       err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx);
+       err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
        if (err) {
                WL_ERR("get wsec error (%d)\n", err);
                goto done;
        }
        wsec |= val;
-       err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx);
+       err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
        if (err) {
                WL_ERR("set wsec error (%d)\n", err);
                goto done;
@@ -2173,13 +2006,12 @@ static s32
 brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
                    u8 key_idx, bool pairwise, const u8 *mac_addr)
 {
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_wsec_key key;
        s32 err = 0;
-       s32 bssidx;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        memset(&key, 0, sizeof(key));
@@ -2191,8 +2023,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
        WL_CONN("key index (%d)\n", key_idx);
 
        /* Set the new key/index */
-       bssidx = brcmf_find_bssidx(cfg, ndev);
-       err = send_key_to_dongle(cfg, bssidx, ndev, &key);
+       err = send_key_to_dongle(ndev, &key);
        if (err) {
                if (err == -EINVAL) {
                        if (key.index >= DOT11_MAX_DEFAULT_KEYS)
@@ -2213,22 +2044,20 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
                    void (*callback) (void *cookie, struct key_params * params))
 {
        struct key_params params;
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct brcmf_cfg80211_security *sec;
        s32 wsec;
        s32 err = 0;
-       s32 bssidx;
 
        WL_TRACE("Enter\n");
        WL_CONN("key index (%d)\n", key_idx);
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        memset(&params, 0, sizeof(params));
 
-       bssidx = brcmf_find_bssidx(cfg, ndev);
-       err = brcmf_dev_intvar_get_bsscfg(ndev, "wsec", &wsec, bssidx);
+       err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
        if (err) {
                WL_ERR("WLC_GET_WSEC error (%d)\n", err);
                /* Ignore this error, may happen during DISASSOC */
@@ -2280,33 +2109,33 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                           u8 *mac, struct station_info *sinfo)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct brcmf_scb_val_le scb_val;
        int rssi;
        s32 rate;
        s32 err = 0;
        u8 *bssid = profile->bssid;
-       struct brcmf_sta_info_le *sta_info_le;
+       struct brcmf_sta_info_le sta_info_le;
 
        WL_TRACE("Enter, MAC %pM\n", mac);
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        if (cfg->conf->mode == WL_MODE_AP) {
-               err = brcmf_dev_iovar_getbuf(ndev, "sta_info", mac, ETH_ALEN,
-                                            cfg->dcmd_buf,
-                                            WL_DCMD_LEN_MAX);
+               memcpy(&sta_info_le, mac, ETH_ALEN);
+               err = brcmf_fil_iovar_data_get(ifp, "sta_info",
+                                              &sta_info_le,
+                                              sizeof(sta_info_le));
                if (err < 0) {
                        WL_ERR("GET STA INFO failed, %d\n", err);
                        goto done;
                }
-               sta_info_le = (struct brcmf_sta_info_le *)cfg->dcmd_buf;
-
                sinfo->filled = STATION_INFO_INACTIVE_TIME;
-               sinfo->inactive_time = le32_to_cpu(sta_info_le->idle) * 1000;
-               if (le32_to_cpu(sta_info_le->flags) & BRCMF_STA_ASSOC) {
+               sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
+               if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
                        sinfo->filled |= STATION_INFO_CONNECTED_TIME;
-                       sinfo->connected_time = le32_to_cpu(sta_info_le->in);
+                       sinfo->connected_time = le32_to_cpu(sta_info_le.in);
                }
                WL_TRACE("STA idle time : %d ms, connected time :%d sec\n",
                         sinfo->inactive_time, sinfo->connected_time);
@@ -2318,7 +2147,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                        goto done;
                }
                /* Report the current tx rate */
-               err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate);
+       err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
                if (err) {
                        WL_ERR("Could not get rate (%d)\n", err);
                        goto done;
@@ -2328,10 +2157,11 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                        WL_CONN("Rate %d Mbps\n", rate / 2);
                }
 
-               if (test_bit(WL_STATUS_CONNECTED, &cfg->status)) {
+               if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
+                            &ifp->vif->sme_state)) {
                        memset(&scb_val, 0, sizeof(scb_val));
-                       err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
-                                             sizeof(scb_val));
+                       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
+                                                    &scb_val, sizeof(scb_val));
                        if (err) {
                                WL_ERR("Could not get rssi (%d)\n", err);
                                goto done;
@@ -2356,6 +2186,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
        s32 pm;
        s32 err = 0;
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
 
        WL_TRACE("Enter\n");
 
@@ -2367,7 +2198,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
         * FW later while initializing the dongle
         */
        cfg->pwr_save = enabled;
-       if (!test_bit(WL_STATUS_READY, &cfg->status)) {
+       if (!check_vif_up(ifp->vif)) {
 
                WL_INFO("Device is not ready, storing the value in cfg_info struct\n");
                goto done;
@@ -2376,7 +2207,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
        pm = enabled ? PM_FAST : PM_OFF;
        WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
 
-       err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
        if (err) {
                if (err == -ENODEV)
                        WL_ERR("net_device is not ready yet\n");
@@ -2393,6 +2224,7 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
                             const u8 *addr,
                             const struct cfg80211_bitrate_mask *mask)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcm_rateset_le rateset_le;
        s32 rate;
        s32 val;
@@ -2402,13 +2234,13 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
        s32 err = 0;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        /* addr param is always NULL. ignore it */
        /* Get current rateset */
-       err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le,
-                             sizeof(rateset_le));
+       err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_CURR_RATESET,
+                                    &rateset_le, sizeof(rateset_le));
        if (err) {
                WL_ERR("could not get current rateset (%d)\n", err);
                goto done;
@@ -2435,8 +2267,8 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
         *      Set rate override,
         *      Since the is a/b/g-blind, both a/bg_rate are enforced.
         */
-       err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate);
-       err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate);
+       err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
+       err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
        if (err_bg && err_a) {
                WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
                err = err_bg | err_a;
@@ -2565,7 +2397,8 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
 
        *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
 
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
+       err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
+                                    buf, WL_BSS_INFO_MAX);
        if (err) {
                WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
                goto CleanUp;
@@ -2674,12 +2507,12 @@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
        return false;
 }
 
-struct brcmf_vs_tlv *
+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_WPA))) {
+       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;
@@ -2689,7 +2522,9 @@ brcmf_find_wpaie(u8 *parse, u32 len)
 
 static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
 {
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       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_bss_info_le *bi;
        struct brcmf_ssid *ssid;
        struct brcmf_tlv *tim;
@@ -2706,8 +2541,8 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
        ssid = &profile->ssid;
 
        *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
-       err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCMF_C_GET_BSS_INFO,
-                       cfg->extra_buf, WL_EXTRA_BUF_MAX);
+       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
+                                    cfg->extra_buf, WL_EXTRA_BUF_MAX);
        if (err) {
                WL_ERR("Could not get bss info %d\n", err);
                goto update_bss_info_out;
@@ -2732,8 +2567,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
                * so we speficially query dtim information to dongle.
                */
                u32 var;
-               err = brcmf_dev_intvar_get(cfg_to_ndev(cfg),
-                                          "dtim_assoc", &var);
+               err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
                if (err) {
                        WL_ERR("wl dtim_assoc failed (%d)\n", err);
                        goto update_bss_info_out;
@@ -2741,9 +2575,6 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
                dtim_period = (u8)var;
        }
 
-       profile->beacon_interval = beacon_interval;
-       profile->dtim_period = dtim_period;
-
 update_bss_info_out:
        WL_TRACE("Exit");
        return err;
@@ -2755,7 +2586,7 @@ static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
        struct escan_info *escan = &cfg->escan_info;
        struct brcmf_ssid ssid;
 
-       set_bit(WL_STATUS_SCAN_ABORTING, &cfg->status);
+       set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
        if (cfg->iscan_on) {
                iscan->state = WL_ISCAN_STATE_IDLE;
 
@@ -2781,8 +2612,8 @@ static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
                escan->escan_state = WL_ESCAN_STATE_IDLE;
                brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
        }
-       clear_bit(WL_STATUS_SCANNING, &cfg->status);
-       clear_bit(WL_STATUS_SCAN_ABORTING, &cfg->status);
+       clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+       clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
 }
 
 static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
@@ -2791,7 +2622,7 @@ static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
        struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
        struct net_device *ndev = cfg_to_ndev(cfg);
 
-       if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) {
+       if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
                WL_ERR("Scan complete while device not scanning\n");
                return;
        }
@@ -2820,7 +2651,6 @@ static s32
 brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
                     struct brcmf_scan_results **bss_list)
 {
-       struct brcmf_iscan_results list;
        struct brcmf_scan_results *results;
        struct brcmf_scan_results_le *results_le;
        struct brcmf_iscan_results *list_buf;
@@ -2830,15 +2660,13 @@ brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
        list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
        results = &list_buf->results;
        results_le = &list_buf->results_le;
-       results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE;
-       results->version = 0;
-       results->count = 0;
+       results_le->buflen = cpu_to_le32(sizeof(iscan->scan_buf));
+       results_le->version = 0;
+       results_le->count = 0;
 
-       memset(&list, 0, sizeof(list));
-       list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX);
-       err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list,
-                                    BRCMF_ISCAN_RESULTS_FIXED_SIZE,
-                                    iscan->scan_buf, WL_ISCAN_BUF_MAX);
+       err = brcmf_fil_iovar_data_get(netdev_priv(iscan->ndev), "iscanresults",
+                                      iscan->scan_buf,
+                                      sizeof(iscan->scan_buf));
        if (err) {
                WL_ERR("error (%d)\n", err);
                return err;
@@ -3052,10 +2880,10 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg,
        status = be32_to_cpu(e->status);
 
        if (!ndev || !cfg->escan_on ||
-                       !test_bit(WL_STATUS_SCANNING, &cfg->status)) {
+                       !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
                WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n",
                        ndev, cfg->escan_on,
-                       !test_bit(WL_STATUS_SCANNING, &cfg->status));
+                       !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
                return -EPERM;
        }
 
@@ -3159,16 +2987,17 @@ static __always_inline void brcmf_delay(u32 ms)
 static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
 
        /*
-        * Check for WL_STATUS_READY before any function call which
+        * Check for BRCMF_VIF_STATUS_READY before any function call which
         * could result is bus access. Don't block the resume for
         * any driver error conditions
         */
        WL_TRACE("Enter\n");
 
-       if (test_bit(WL_STATUS_READY, &cfg->status))
-               brcmf_invoke_iscan(wiphy_to_cfg(wiphy));
+       if (check_vif_up(ifp->vif))
+               brcmf_invoke_iscan(cfg);
 
        WL_TRACE("Exit\n");
        return 0;
@@ -3179,85 +3008,53 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_cfg80211_vif *vif;
 
        WL_TRACE("Enter\n");
 
        /*
-        * Check for WL_STATUS_READY before any function call which
-        * could result is bus access. Don't block the suspend for
-        * any driver error conditions
-        */
-
-       /*
-        * While going to suspend if associated with AP disassociate
-        * from AP to save power while system is in suspended state
+        * if the primary net_device is not READY there is nothing
+        * we can do but pray resume goes smoothly.
         */
-       if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) ||
-            test_bit(WL_STATUS_CONNECTING, &cfg->status)) &&
-            test_bit(WL_STATUS_READY, &cfg->status)) {
-               WL_INFO("Disassociating from AP"
-                       " while entering suspend state\n");
-               brcmf_link_down(cfg);
+       vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
+       if (!check_vif_up(vif))
+               goto exit;
 
+       list_for_each_entry(vif, &cfg->vif_list, list) {
+               if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
+                       continue;
                /*
-                * Make sure WPA_Supplicant receives all the event
-                * generated due to DISASSOC call to the fw to keep
-                * the state fw and WPA_Supplicant state consistent
+                * While going to suspend if associated with AP disassociate
+                * from AP to save power while system is in suspended state
                 */
-               brcmf_delay(500);
+               if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) ||
+                   test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) {
+                       WL_INFO("Disassociating from AP before suspend\n");
+                       brcmf_link_down(cfg);
+
+                       /* Make sure WPA_Supplicant receives all the event
+                        * generated due to DISASSOC call to the fw to keep
+                        * the state fw and WPA_Supplicant state consistent
+                        */
+                       brcmf_delay(500);
+               }
        }
 
-       if (test_bit(WL_STATUS_READY, &cfg->status))
+       /* end any scanning */
+       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
                brcmf_abort_scanning(cfg);
-       else
-               clear_bit(WL_STATUS_SCANNING, &cfg->status);
 
        /* Turn off watchdog timer */
-       if (test_bit(WL_STATUS_READY, &cfg->status))
-               brcmf_set_mpc(ndev, 1);
+       brcmf_set_mpc(ndev, 1);
 
+exit:
        WL_TRACE("Exit\n");
-
+       /* clear any scanning activity */
+       cfg->scan_status = 0;
        return 0;
 }
 
 static __used s32
-brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len)
-{
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       u32 buflen;
-
-       buflen = brcmf_c_mkiovar(name, buf, len, cfg->dcmd_buf,
-                              WL_DCMD_LEN_MAX);
-       BUG_ON(!buflen);
-
-       return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg->dcmd_buf,
-                              buflen);
-}
-
-static s32
-brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf,
-                 s32 buf_len)
-{
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       u32 len;
-       s32 err = 0;
-
-       len = brcmf_c_mkiovar(name, NULL, 0, cfg->dcmd_buf,
-                           WL_DCMD_LEN_MAX);
-       BUG_ON(!len);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg->dcmd_buf,
-                             WL_DCMD_LEN_MAX);
-       if (err) {
-               WL_ERR("error (%d)\n", err);
-               return err;
-       }
-       memcpy(buf, cfg->dcmd_buf, buf_len);
-
-       return err;
-}
-
-static __used s32
 brcmf_update_pmklist(struct net_device *ndev,
                     struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
 {
@@ -3275,8 +3072,8 @@ brcmf_update_pmklist(struct net_device *ndev,
        }
 
        if (!err)
-               brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list,
-                                       sizeof(*pmk_list));
+               brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
+                                        (char *)pmk_list, sizeof(*pmk_list));
 
        return err;
 }
@@ -3286,13 +3083,14 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
                         struct cfg80211_pmksa *pmksa)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
        s32 err = 0;
        int i;
        int pmkid_len;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        pmkid_len = le32_to_cpu(pmkids->npmkid);
@@ -3325,12 +3123,13 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
                      struct cfg80211_pmksa *pmksa)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct pmkid_list pmkid;
        s32 err = 0;
        int i, pmkid_len;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
@@ -3375,10 +3174,11 @@ static s32
 brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
 
        WL_TRACE("Enter\n");
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
@@ -3478,15 +3278,15 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg,
                if (request->n_ssids)
                        request->ssids = &ssid[0];
 
-               if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
+               if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
                        /* Abort any on-going scan */
                        brcmf_abort_scanning(cfg);
                }
 
-               set_bit(WL_STATUS_SCANNING, &cfg->status);
+               set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
                err = brcmf_do_escan(cfg, wiphy, ndev, request);
                if (err) {
-                       clear_bit(WL_STATUS_SCANNING, &cfg->status);
+                       clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
                        goto out_err;
                }
                cfg->sched_escan = true;
@@ -3512,15 +3312,14 @@ out_err:
 #ifndef CONFIG_BRCMISCAN
 static int brcmf_dev_pno_clean(struct net_device *ndev)
 {
-       char iovbuf[128];
        int ret;
 
        /* Disable pfn */
-       ret = brcmf_dev_intvar_set(ndev, "pfn", 0);
+       ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
        if (ret == 0) {
                /* clear pfn */
-               ret = brcmf_dev_iovar_setbuf(ndev, "pfnclear", NULL, 0,
-                                            iovbuf, sizeof(iovbuf));
+               ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
+                                              NULL, 0);
        }
        if (ret < 0)
                WL_ERR("failed code %d\n", ret);
@@ -3531,7 +3330,6 @@ static int brcmf_dev_pno_clean(struct net_device *ndev)
 static int brcmf_dev_pno_config(struct net_device *ndev)
 {
        struct brcmf_pno_param_le pfn_param;
-       char iovbuf[128];
 
        memset(&pfn_param, 0, sizeof(pfn_param));
        pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
@@ -3544,9 +3342,8 @@ static int brcmf_dev_pno_config(struct net_device *ndev)
        /* set up pno scan fr */
        pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
 
-       return brcmf_dev_iovar_setbuf(ndev, "pfn_set",
-                                     &pfn_param, sizeof(pfn_param),
-                                     iovbuf, sizeof(iovbuf));
+       return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
+                                       &pfn_param, sizeof(pfn_param));
 }
 
 static int
@@ -3554,7 +3351,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
                                struct net_device *ndev,
                                struct cfg80211_sched_scan_request *request)
 {
-       char iovbuf[128];
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
        struct brcmf_pno_net_param_le pfn;
        int i;
@@ -3562,8 +3359,8 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
 
        WL_SCAN("Enter n_match_sets:%d   n_ssids:%d\n",
                request->n_match_sets, request->n_ssids);
-       if (test_bit(WL_STATUS_SCANNING, &cfg->status)) {
-               WL_ERR("Scanning already : status (%lu)\n", cfg->status);
+       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+               WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
                return -EAGAIN;
        }
 
@@ -3620,15 +3417,14 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
                        pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
                        pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
                        memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
-                       ret = brcmf_dev_iovar_setbuf(ndev, "pfn_add",
-                                                    &pfn, sizeof(pfn),
-                                                    iovbuf, sizeof(iovbuf));
+                       ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
+                                                      sizeof(pfn));
                        WL_SCAN(">>> PNO filter %s for ssid (%s)\n",
                                ret == 0 ? "set" : "failed",
                                ssid->ssid);
                }
                /* Enable the PNO */
-               if (brcmf_dev_intvar_set(ndev, "pfn", 1) < 0) {
+               if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
                        WL_ERR("PNO enable failed!! ret=%d\n", ret);
                        return -EINVAL;
                }
@@ -3656,12 +3452,20 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
 static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct net_device *ndev = cfg->wdev->netdev;
+       struct net_device *ndev = cfg_to_ndev(cfg);
        struct brcmf_dcmd *dcmd = data;
        struct sk_buff *reply;
        int ret;
 
-       ret = brcmf_netlink_dcmd(ndev, dcmd);
+       WL_TRACE("cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
+                dcmd->buf, dcmd->len);
+
+       if (dcmd->set)
+               ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
+                                            dcmd->buf, dcmd->len);
+       else
+               ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
+                                            dcmd->buf, dcmd->len);
        if (ret == 0) {
                reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
                nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
@@ -3673,23 +3477,23 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
 
 static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err;
 
        /* set auth */
-       err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", 0, bssidx);
+       err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
        if (err < 0) {
                WL_ERR("auth error %d\n", err);
                return err;
        }
        /* set wsec */
-       err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", 0, bssidx);
+       err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
        if (err < 0) {
                WL_ERR("wsec error %d\n", err);
                return err;
        }
        /* set upper-layer auth */
-       err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth",
-                                         WPA_AUTH_NONE, bssidx);
+       err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
        if (err < 0) {
                WL_ERR("wpa_auth error %d\n", err);
                return err;
@@ -3710,6 +3514,7 @@ static s32
 brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
                     bool is_rsn_ie, s32 bssidx)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        u32 auth = 0; /* d11 open authentication */
        u16 count;
        s32 err = 0;
@@ -3850,8 +3655,8 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
                                wme_bss_disable = 0;
                }
                /* set wme_bss_disable to sync RSN Capabilities */
-               err = brcmf_dev_intvar_set_bsscfg(ndev, "wme_bss_disable",
-                                                 wme_bss_disable, bssidx);
+               err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
+                                              wme_bss_disable);
                if (err < 0) {
                        WL_ERR("wme_bss_disable error %d\n", err);
                        goto exit;
@@ -3861,19 +3666,19 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
        wsec = (pval | gval | SES_OW_ENABLED);
 
        /* set auth */
-       err = brcmf_dev_intvar_set_bsscfg(ndev, "auth", auth, bssidx);
+       err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
        if (err < 0) {
                WL_ERR("auth error %d\n", err);
                goto exit;
        }
        /* set wsec */
-       err = brcmf_dev_intvar_set_bsscfg(ndev, "wsec", wsec, bssidx);
+       err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
        if (err < 0) {
                WL_ERR("wsec error %d\n", err);
                goto exit;
        }
        /* set upper-layer auth */
-       err = brcmf_dev_intvar_set_bsscfg(ndev, "wpa_auth", wpa_auth, bssidx);
+       err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
        if (err < 0) {
                WL_ERR("wpa_auth error %d\n", err);
                goto exit;
@@ -3963,17 +3768,19 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
        return ie_len + VNDR_IE_HDR_SIZE;
 }
 
-s32
+static s32
 brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
-                       struct net_device *ndev, s32 bssidx, s32 pktflag,
+                       struct net_device *ndev, s32 pktflag,
                        u8 *vndr_ie_buf, u32 vndr_ie_len)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct vif_saved_ie *saved_ie = &ifp->vif->saved_ie;
        s32 err = 0;
        u8  *iovar_ie_buf;
        u8  *curr_ie_buf;
        u8  *mgmt_ie_buf = NULL;
        int mgmt_ie_buf_len;
-       u32 *mgmt_ie_len = 0;
+       u32 *mgmt_ie_len;
        u32 del_add_ie_buf_len = 0;
        u32 total_ie_buf_len = 0;
        u32 parsed_ie_buf_len = 0;
@@ -3984,31 +3791,29 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
        u8 *ptr;
        int remained_buf_len;
 
-       WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag);
+       WL_TRACE("bssidx %d, pktflag : 0x%02X\n",
+                brcmf_ndev_bssidx(ndev), pktflag);
        iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
        if (!iovar_ie_buf)
                return -ENOMEM;
        curr_ie_buf = iovar_ie_buf;
-       if (test_bit(WL_STATUS_AP_CREATING, &cfg->status) ||
-           test_bit(WL_STATUS_AP_CREATED, &cfg->status)) {
+       if (ifp->vif->mode == WL_MODE_AP) {
                switch (pktflag) {
                case VNDR_IE_PRBRSP_FLAG:
-                       mgmt_ie_buf = cfg->ap_info->probe_res_ie;
-                       mgmt_ie_len = &cfg->ap_info->probe_res_ie_len;
-                       mgmt_ie_buf_len =
-                               sizeof(cfg->ap_info->probe_res_ie);
+                       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 = cfg->ap_info->beacon_ie;
-                       mgmt_ie_len = &cfg->ap_info->beacon_ie_len;
-                       mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie);
+                       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;
                        WL_ERR("not suitable type\n");
                        goto exit;
                }
-               bssidx = 0;
        } else {
                err = -EPERM;
                WL_ERR("not suitable type\n");
@@ -4104,11 +3909,8 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
                }
        }
        if (total_ie_buf_len) {
-               err  = brcmf_dev_iovar_setbuf_bsscfg(ndev, "vndr_ie",
-                                                    iovar_ie_buf,
-                                                    total_ie_buf_len,
-                                                    cfg->extra_buf,
-                                                    WL_EXTRA_BUF_MAX, bssidx);
+               err  = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
+                                                total_ie_buf_len);
                if (err)
                        WL_ERR("vndr ie set error : %d\n", err);
        }
@@ -4123,9 +3925,9 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
                        struct cfg80211_ap_settings *settings)
 {
        s32 ie_offset;
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_tlv *ssid_ie;
        struct brcmf_ssid_le ssid_le;
-       s32 ioctl_value;
        s32 err = -EPERM;
        struct brcmf_tlv *rsn_ie;
        struct brcmf_vs_tlv *wpa_ie;
@@ -4140,7 +3942,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
                 settings->ssid, settings->ssid_len, settings->auth_type,
                 settings->inactivity_timeout);
 
-       if (!test_bit(WL_STATUS_AP_CREATING, &cfg->status)) {
+       if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
                WL_ERR("Not in AP creation mode\n");
                return -EPERM;
        }
@@ -4164,20 +3966,17 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        brcmf_set_mpc(ndev, 0);
-       ioctl_value = 1;
-       err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_DOWN, &ioctl_value);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
        if (err < 0) {
                WL_ERR("BRCMF_C_DOWN error %d\n", err);
                goto exit;
        }
-       ioctl_value = 1;
-       err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &ioctl_value);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
        if (err < 0) {
                WL_ERR("SET INFRA error %d\n", err);
                goto exit;
        }
-       ioctl_value = 1;
-       err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
        if (err < 0) {
                WL_ERR("setting AP mode failed %d\n", err);
                goto exit;
@@ -4226,7 +4025,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
                cfg->ap_info->security_mode = false;
        }
        /* Set Beacon IEs to FW */
-       err = brcmf_set_management_ie(cfg, ndev, bssidx,
+       err = brcmf_set_management_ie(cfg, ndev,
                                      VNDR_IE_BEACON_FLAG,
                                      (u8 *)settings->beacon.tail,
                                      settings->beacon.tail_len);
@@ -4236,7 +4035,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
                WL_TRACE("Applied Vndr IEs for Beacon\n");
 
        /* Set Probe Response IEs to FW */
-       err = brcmf_set_management_ie(cfg, ndev, bssidx,
+       err = brcmf_set_management_ie(cfg, ndev,
                                      VNDR_IE_PRBRSP_FLAG,
                                      (u8 *)settings->beacon.proberesp_ies,
                                      settings->beacon.proberesp_ies_len);
@@ -4246,25 +4045,22 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
                WL_TRACE("Applied Vndr IEs for Probe Resp\n");
 
        if (settings->beacon_interval) {
-               ioctl_value = settings->beacon_interval;
-               err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_BCNPRD,
-                                         &ioctl_value);
+               err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
+                                           settings->beacon_interval);
                if (err < 0) {
                        WL_ERR("Beacon Interval Set Error, %d\n", err);
                        goto exit;
                }
        }
        if (settings->dtim_period) {
-               ioctl_value = settings->dtim_period;
-               err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_DTIMPRD,
-                                         &ioctl_value);
+               err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
+                                           settings->dtim_period);
                if (err < 0) {
                        WL_ERR("DTIM Interval Set Error, %d\n", err);
                        goto exit;
                }
        }
-       ioctl_value = 1;
-       err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
        if (err < 0) {
                WL_ERR("BRCMF_C_UP error (%d)\n", err);
                goto exit;
@@ -4274,14 +4070,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        /* join parameters starts with ssid */
        memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
        /* create softap */
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, &join_params,
-                             sizeof(join_params));
+       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+                                    &join_params, sizeof(join_params));
        if (err < 0) {
                WL_ERR("SET SSID error (%d)\n", err);
                goto exit;
        }
-       clear_bit(WL_STATUS_AP_CREATING, &cfg->status);
-       set_bit(WL_STATUS_AP_CREATED, &cfg->status);
+       clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+       set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
 
 exit:
        if (err)
@@ -4291,8 +4087,8 @@ exit:
 
 static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       s32 ioctl_value;
        s32 err = -EPERM;
 
        WL_TRACE("Enter\n");
@@ -4301,21 +4097,20 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
                /* Due to most likely deauths outstanding we sleep */
                /* first to make sure they get processed by fw. */
                msleep(400);
-               ioctl_value = 0;
-               err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AP, &ioctl_value);
+               err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
+                                           BRCMF_C_SET_AP, 0);
                if (err < 0) {
                        WL_ERR("setting AP mode failed %d\n", err);
                        goto exit;
                }
-               ioctl_value = 0;
-               err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_UP, &ioctl_value);
+               err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0);
                if (err < 0) {
                        WL_ERR("BRCMF_C_UP error %d\n", err);
                        goto exit;
                }
                brcmf_set_mpc(ndev, 1);
-               clear_bit(WL_STATUS_AP_CREATING, &cfg->status);
-               clear_bit(WL_STATUS_AP_CREATED, &cfg->status);
+               clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+               clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
        }
 exit:
        return err;
@@ -4326,6 +4121,7 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
                           u8 *mac)
 {
        struct brcmf_scb_val_le scbval;
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err;
 
        if (!mac)
@@ -4333,13 +4129,13 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
 
        WL_TRACE("Enter %pM\n", mac);
 
-       if (!check_sys_up(wiphy))
+       if (!check_vif_up(ifp->vif))
                return -EIO;
 
        memcpy(&scbval.ea, mac, ETH_ALEN);
        scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
-                             &scbval, sizeof(scbval));
+       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
+                                    &scbval, sizeof(scbval));
        if (err)
                WL_ERR("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
 
@@ -4410,72 +4206,97 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
 #endif
 }
 
-static struct wireless_dev *brcmf_alloc_wdev(struct device *ndev)
+static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 {
-       struct wireless_dev *wdev;
+       struct wiphy *wiphy;
        s32 err = 0;
 
-       wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
-       if (!wdev)
-               return ERR_PTR(-ENOMEM);
-
-       wdev->wiphy = wiphy_new(&wl_cfg80211_ops,
-                               sizeof(struct brcmf_cfg80211_info));
-       if (!wdev->wiphy) {
+       wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
+       if (!wiphy) {
                WL_ERR("Could not allocate wiphy device\n");
-               err = -ENOMEM;
-               goto wiphy_new_out;
-       }
-       set_wiphy_dev(wdev->wiphy, ndev);
-       wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
-       wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
-       wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                      BIT(NL80211_IFTYPE_ADHOC) |
-                                      BIT(NL80211_IFTYPE_AP);
-       wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
-       wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;    /* Set
+               return ERR_PTR(-ENOMEM);
+       }
+       set_wiphy_dev(wiphy, phydev);
+       wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+       wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_ADHOC) |
+                                BIT(NL80211_IFTYPE_AP);
+       wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
+       wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;  /* Set
                                                * it as 11a by default.
                                                * This will be updated with
                                                * 11n phy tables in
                                                * "ifconfig up"
                                                * if phy has 11n capability
                                                */
-       wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-       wdev->wiphy->cipher_suites = __wl_cipher_suites;
-       wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
-       wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;      /* enable power
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+       wiphy->cipher_suites = __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
                                                                 */
-       brcmf_wiphy_pno_params(wdev->wiphy);
-       err = wiphy_register(wdev->wiphy);
+       brcmf_wiphy_pno_params(wiphy);
+       err = wiphy_register(wiphy);
        if (err < 0) {
                WL_ERR("Could not register wiphy device (%d)\n", err);
-               goto wiphy_register_out;
+               wiphy_free(wiphy);
+               return ERR_PTR(err);
+       }
+       return wiphy;
+}
+
+static
+struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
+                                          struct net_device *netdev,
+                                          s32 mode, bool pm_block)
+{
+       struct brcmf_cfg80211_vif *vif;
+
+       if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
+               return ERR_PTR(-ENOSPC);
+
+       vif = kzalloc(sizeof(*vif), GFP_KERNEL);
+       if (!vif)
+               return ERR_PTR(-ENOMEM);
+
+       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));
        }
-       return wdev;
 
-wiphy_register_out:
-       wiphy_free(wdev->wiphy);
+       vif->mode = mode;
+       vif->pm_block = pm_block;
+       vif->roam_off = -1;
 
-wiphy_new_out:
-       kfree(wdev);
+       brcmf_init_prof(&vif->profile);
 
-       return ERR_PTR(err);
+       list_add_tail(&vif->list, &cfg->vif_list);
+       cfg->vif_cnt++;
+       return vif;
 }
 
-static void brcmf_free_wdev(struct brcmf_cfg80211_info *cfg)
+static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
 {
-       struct wireless_dev *wdev = cfg->wdev;
+       struct brcmf_cfg80211_info *cfg;
+       struct wiphy *wiphy;
 
-       if (!wdev) {
-               WL_ERR("wdev is invalid\n");
-               return;
+       wiphy = vif->wdev.wiphy;
+       cfg = wiphy_priv(wiphy);
+       list_del(&vif->list);
+       cfg->vif_cnt--;
+
+       kfree(vif);
+       if (!cfg->vif_cnt) {
+               wiphy_unregister(wiphy);
+               wiphy_free(wiphy);
        }
-       wiphy_unregister(wdev->wiphy);
-       wiphy_free(wdev->wiphy);
-       kfree(wdev);
-       cfg->wdev = NULL;
 }
 
 static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
@@ -4541,7 +4362,7 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
 
 static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
 {
-       struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
        struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
        u32 req_len;
@@ -4550,8 +4371,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
 
        brcmf_clear_assoc_ies(cfg);
 
-       err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg->extra_buf,
-                               WL_ASSOC_INFO_MAX);
+       err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
+                                      cfg->extra_buf, WL_ASSOC_INFO_MAX);
        if (err) {
                WL_ERR("could not get assoc info (%d)\n", err);
                return err;
@@ -4561,9 +4382,9 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
        req_len = le32_to_cpu(assoc_info->req_len);
        resp_len = le32_to_cpu(assoc_info->resp_len);
        if (req_len) {
-               err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies",
-                                          cfg->extra_buf,
-                                          WL_ASSOC_INFO_MAX);
+               err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
+                                              cfg->extra_buf,
+                                              WL_ASSOC_INFO_MAX);
                if (err) {
                        WL_ERR("could not get assoc req (%d)\n", err);
                        return err;
@@ -4577,9 +4398,9 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
                conn_info->req_ie = NULL;
        }
        if (resp_len) {
-               err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies",
-                                          cfg->extra_buf,
-                                          WL_ASSOC_INFO_MAX);
+               err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
+                                              cfg->extra_buf,
+                                              WL_ASSOC_INFO_MAX);
                if (err) {
                        WL_ERR("could not get assoc resp (%d)\n", err);
                        return err;
@@ -4603,7 +4424,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
                       struct net_device *ndev,
                       const struct brcmf_event_msg *e)
 {
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
        struct wiphy *wiphy = cfg_to_wiphy(cfg);
        struct ieee80211_channel *notify_channel = NULL;
@@ -4628,7 +4450,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
 
        /* data sent to dongle has to be little endian */
        *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
+       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
+                                    buf, WL_BSS_INFO_MAX);
 
        if (err)
                goto done;
@@ -4652,7 +4475,7 @@ done:
                        conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
        WL_CONN("Report roaming result\n");
 
-       set_bit(WL_STATUS_CONNECTED, &cfg->status);
+       set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
        WL_TRACE("Exit\n");
        return err;
 }
@@ -4662,13 +4485,15 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
                       struct net_device *ndev, const struct brcmf_event_msg *e,
                       bool completed)
 {
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
        s32 err = 0;
 
        WL_TRACE("Enter\n");
 
-       if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg->status)) {
+       if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+                              &ifp->vif->sme_state)) {
                if (completed) {
                        brcmf_get_assoc_ies(cfg);
                        memcpy(profile->bssid, e->addr, ETH_ALEN);
@@ -4684,7 +4509,8 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
                                                    WLAN_STATUS_AUTH_TIMEOUT,
                                        GFP_KERNEL);
                if (completed)
-                       set_bit(WL_STATUS_CONNECTED, &cfg->status);
+                       set_bit(BRCMF_VIF_STATUS_CONNECTED,
+                               &ifp->vif->sme_state);
                WL_CONN("Report connect result - connection %s\n",
                                completed ? "succeeded" : "failed");
        }
@@ -4736,7 +4562,8 @@ brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,
                            struct net_device *ndev,
                            const struct brcmf_event_msg *e, void *data)
 {
-       struct brcmf_cfg80211_profile *profile = cfg->profile;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        s32 err = 0;
 
        if (cfg->conf->mode == WL_MODE_AP) {
@@ -4747,30 +4574,34 @@ brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,
                        memcpy(profile->bssid, e->addr, ETH_ALEN);
                        wl_inform_ibss(cfg, ndev, e->addr);
                        cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
-                       clear_bit(WL_STATUS_CONNECTING, &cfg->status);
-                       set_bit(WL_STATUS_CONNECTED, &cfg->status);
+                       clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+                                 &ifp->vif->sme_state);
+                       set_bit(BRCMF_VIF_STATUS_CONNECTED,
+                               &ifp->vif->sme_state);
                } else
                        brcmf_bss_connect_done(cfg, ndev, e, true);
        } else if (brcmf_is_linkdown(cfg, e)) {
                WL_CONN("Linkdown\n");
                if (brcmf_is_ibssmode(cfg)) {
-                       clear_bit(WL_STATUS_CONNECTING, &cfg->status);
-                       if (test_and_clear_bit(WL_STATUS_CONNECTED,
-                               &cfg->status))
+                       clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+                                 &ifp->vif->sme_state);
+                       if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
+                                              &ifp->vif->sme_state))
                                brcmf_link_down(cfg);
                } else {
                        brcmf_bss_connect_done(cfg, ndev, e, false);
-                       if (test_and_clear_bit(WL_STATUS_CONNECTED,
-                               &cfg->status)) {
+                       if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
+                                              &ifp->vif->sme_state)) {
                                cfg80211_disconnected(ndev, 0, NULL, 0,
-                                       GFP_KERNEL);
+                                                     GFP_KERNEL);
                                brcmf_link_down(cfg);
                        }
                }
-               brcmf_init_prof(cfg->profile);
+               brcmf_init_prof(ndev_to_prof(ndev));
        } else if (brcmf_is_nonetwork(cfg, e)) {
                if (brcmf_is_ibssmode(cfg))
-                       clear_bit(WL_STATUS_CONNECTING, &cfg->status);
+                       clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+                                 &ifp->vif->sme_state);
                else
                        brcmf_bss_connect_done(cfg, ndev, e, false);
        }
@@ -4783,12 +4614,13 @@ brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg,
                            struct net_device *ndev,
                            const struct brcmf_event_msg *e, void *data)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
        u32 event = be32_to_cpu(e->event_type);
        u32 status = be32_to_cpu(e->status);
 
        if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
-               if (test_bit(WL_STATUS_CONNECTED, &cfg->status))
+               if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
                        brcmf_bss_roaming_done(cfg, ndev, e);
                else
                        brcmf_bss_connect_done(cfg, ndev, e, true);
@@ -4821,6 +4653,7 @@ brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg,
                         struct net_device *ndev,
                         const struct brcmf_event_msg *e, void *data)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_channel_info_le channel_inform_le;
        struct brcmf_scan_results_le *bss_list_le;
        u32 len = WL_SCAN_BUF_MAX;
@@ -4835,15 +4668,16 @@ brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg,
                return brcmf_wakeup_iscan(cfg_to_iscan(cfg));
        }
 
-       if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg->status)) {
+       if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
                WL_ERR("Scan complete while device not scanning\n");
                scan_abort = true;
                err = -EINVAL;
                goto scan_done_out;
        }
 
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le,
-                             sizeof(channel_inform_le));
+       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL,
+                                    &channel_inform_le,
+                                    sizeof(channel_inform_le));
        if (err) {
                WL_ERR("scan busy (%d)\n", err);
                scan_abort = true;
@@ -4857,8 +4691,8 @@ brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg,
 
        memset(cfg->scan_results, 0, len);
        bss_list_le->buflen = cpu_to_le32(len);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS,
-                             cfg->scan_results, len);
+       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_SCAN_RESULTS,
+                                    cfg->scan_results, len);
        if (err) {
                WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
                err = -EINVAL;
@@ -4920,8 +4754,6 @@ static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
        cfg->bss_info = NULL;
        kfree(cfg->conf);
        cfg->conf = NULL;
-       kfree(cfg->profile);
-       cfg->profile = NULL;
        kfree(cfg->scan_req_int);
        cfg->scan_req_int = NULL;
        kfree(cfg->escan_ioctl_buf);
@@ -4950,9 +4782,6 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
        cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
        if (!cfg->conf)
                goto init_priv_mem_out;
-       cfg->profile = kzalloc(sizeof(*cfg->profile), GFP_KERNEL);
-       if (!cfg->profile)
-               goto init_priv_mem_out;
        cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
        if (!cfg->bss_info)
                goto init_priv_mem_out;
@@ -5129,7 +4958,6 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
                return err;
        brcmf_init_escan(cfg);
        brcmf_init_conf(cfg->conf);
-       brcmf_init_prof(cfg->profile);
        brcmf_link_down(cfg);
 
        return err;
@@ -5145,12 +4973,14 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
        brcmf_deinit_priv_mem(cfg);
 }
 
-struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev,
-                                                 struct device *busdev,
-                                                 struct brcmf_pub *drvr)
+struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr)
 {
-       struct wireless_dev *wdev;
+       struct net_device *ndev = drvr->iflist[0]->ndev;
+       struct device *busdev = drvr->dev;
        struct brcmf_cfg80211_info *cfg;
+       struct wiphy *wiphy;
+       struct brcmf_cfg80211_vif *vif;
+       struct brcmf_if *ifp;
        s32 err = 0;
 
        if (!ndev) {
@@ -5158,35 +4988,45 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev,
                return NULL;
        }
 
-       wdev = brcmf_alloc_wdev(busdev);
-       if (IS_ERR(wdev)) {
+       ifp = netdev_priv(ndev);
+       wiphy = brcmf_setup_wiphy(busdev);
+       if (IS_ERR(wiphy))
                return NULL;
-       }
 
-       wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS);
-       cfg = wdev_to_cfg(wdev);
-       cfg->wdev = wdev;
+       cfg = wiphy_priv(wiphy);
+       cfg->wiphy = wiphy;
        cfg->pub = drvr;
-       ndev->ieee80211_ptr = wdev;
-       SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
-       wdev->netdev = ndev;
+       INIT_LIST_HEAD(&cfg->vif_list);
+
+       vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
+       if (IS_ERR(vif)) {
+               wiphy_free(wiphy);
+               return NULL;
+       }
+
        err = wl_init_priv(cfg);
        if (err) {
                WL_ERR("Failed to init iwm_priv (%d)\n", err);
                goto cfg80211_attach_out;
        }
 
+       ifp->vif = vif;
        return cfg;
 
 cfg80211_attach_out:
-       brcmf_free_wdev(cfg);
+       brcmf_free_vif(vif);
        return NULL;
 }
 
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 {
+       struct brcmf_cfg80211_vif *vif;
+       struct brcmf_cfg80211_vif *tmp;
+
        wl_deinit_priv(cfg);
-       brcmf_free_wdev(cfg);
+       list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
+               brcmf_free_vif(vif);
+       }
 }
 
 void
@@ -5202,22 +5042,18 @@ brcmf_cfg80211_event(struct net_device *ndev,
 
 static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
 {
-       /* Room for "event_msgs" + '\0' + bitvec */
-       s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
        s8 eventmask[BRCMF_EVENTING_MASK_LEN];
        s32 err = 0;
 
        WL_TRACE("Enter\n");
 
        /* Setup event_msgs */
-       brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
-                       iovbuf, sizeof(iovbuf));
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf));
+       err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
+                                      eventmask, BRCMF_EVENTING_MASK_LEN);
        if (err) {
                WL_ERR("Get event_msgs error (%d)\n", err);
                goto dongle_eventmsg_out;
        }
-       memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
 
        setbit(eventmask, BRCMF_E_SET_SSID);
        setbit(eventmask, BRCMF_E_ROAM);
@@ -5241,9 +5077,8 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
        setbit(eventmask, BRCMF_E_ESCAN_RESULT);
        setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
 
-       brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
-                       iovbuf, sizeof(iovbuf));
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
+       err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
+                                      eventmask, BRCMF_EVENTING_MASK_LEN);
        if (err) {
                WL_ERR("Set event_msgs error (%d)\n", err);
                goto dongle_eventmsg_out;
@@ -5257,23 +5092,17 @@ dongle_eventmsg_out:
 static s32
 brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
 {
-       s8 iovbuf[32];
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
        __le32 roamtrigger[2];
        __le32 roam_delta[2];
-       __le32 bcn_to_le;
-       __le32 roamvar_le;
 
        /*
         * Setup timeout if Beacons are lost and roam is
         * off to report link down
         */
        if (roamvar) {
-               bcn_to_le = cpu_to_le32(bcn_timeout);
-               brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le,
-                       sizeof(bcn_to_le), iovbuf, sizeof(iovbuf));
-               err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR,
-                                  iovbuf, sizeof(iovbuf));
+               err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
                if (err) {
                        WL_ERR("bcn_timeout error (%d)\n", err);
                        goto dongle_rom_out;
@@ -5285,10 +5114,7 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
         * to take care of roaming
         */
        WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
-       roamvar_le = cpu_to_le32(roamvar);
-       brcmf_c_mkiovar("roam_off", (char *)&roamvar_le,
-                               sizeof(roamvar_le), iovbuf, sizeof(iovbuf));
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
+       err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
        if (err) {
                WL_ERR("roam_off error (%d)\n", err);
                goto dongle_rom_out;
@@ -5296,8 +5122,8 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
 
        roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
        roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER,
-                       (void *)roamtrigger, sizeof(roamtrigger));
+       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
+                                    (void *)roamtrigger, sizeof(roamtrigger));
        if (err) {
                WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
                goto dongle_rom_out;
@@ -5305,8 +5131,8 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
 
        roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
        roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA,
-                               (void *)roam_delta, sizeof(roam_delta));
+       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
+                                    (void *)roam_delta, sizeof(roam_delta));
        if (err) {
                WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
                goto dongle_rom_out;
@@ -5320,13 +5146,11 @@ static s32
 brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
                      s32 scan_unassoc_time, s32 scan_passive_time)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err = 0;
-       __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time);
-       __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time);
-       __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time);
 
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME,
-                          &scan_assoc_tm_le, sizeof(scan_assoc_tm_le));
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+                                   scan_assoc_time);
        if (err) {
                if (err == -EOPNOTSUPP)
                        WL_INFO("Scan assoc time is not supported\n");
@@ -5334,8 +5158,8 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
                        WL_ERR("Scan assoc time error (%d)\n", err);
                goto dongle_scantime_out;
        }
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME,
-                          &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le));
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+                                   scan_unassoc_time);
        if (err) {
                if (err == -EOPNOTSUPP)
                        WL_INFO("Scan unassoc time is not supported\n");
@@ -5344,8 +5168,8 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
                goto dongle_scantime_out;
        }
 
-       err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME,
-                          &scan_passive_tm_le, sizeof(scan_passive_tm_le));
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
+                                   scan_passive_time);
        if (err) {
                if (err == -EOPNOTSUPP)
                        WL_INFO("Scan passive time is not supported\n");
@@ -5360,13 +5184,14 @@ dongle_scantime_out:
 
 static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
 {
+       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        struct wiphy *wiphy;
        s32 phy_list;
        s8 phy;
        s32 err = 0;
 
-       err = brcmf_exec_dcmd(cfg_to_ndev(cfg), BRCM_GET_PHYLIST,
-                             &phy_list, sizeof(phy_list));
+       err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST,
+                                    &phy_list, sizeof(phy_list));
        if (err) {
                WL_ERR("error (%d)\n", err);
                return err;
@@ -5408,7 +5233,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
                goto default_conf_out;
 
        power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
-       err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode);
+       err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
+                                   power_mode);
        if (err)
                goto default_conf_out;
        WL_INFO("power save set to %s\n",
@@ -5436,47 +5262,12 @@ default_conf_out:
 
 }
 
-static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_info *cfg)
-{
-       char buf[10+IFNAMSIZ];
-       struct dentry *fd;
-       s32 err = 0;
-
-       sprintf(buf, "netdev:%s", cfg_to_ndev(cfg)->name);
-       cfg->debugfsdir = debugfs_create_dir(buf,
-                                       cfg_to_wiphy(cfg)->debugfsdir);
-
-       fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg->debugfsdir,
-               (u16 *)&cfg->profile->beacon_interval);
-       if (!fd) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-       fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg->debugfsdir,
-               (u8 *)&cfg->profile->dtim_period);
-       if (!fd) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-err_out:
-       return err;
-}
-
-static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_info *cfg)
-{
-       debugfs_remove_recursive(cfg->debugfsdir);
-       cfg->debugfsdir = NULL;
-}
-
 static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
 {
+       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        s32 err = 0;
 
-       set_bit(WL_STATUS_READY, &cfg->status);
-
-       brcmf_debugfs_add_netdev_params(cfg);
+       set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
 
        err = brcmf_config_dongle(cfg);
        if (err)
@@ -5489,13 +5280,16 @@ static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
 
 static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
 {
+       struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+
        /*
         * While going down, if associated with AP disassociate
         * from AP to save power
         */
-       if ((test_bit(WL_STATUS_CONNECTED, &cfg->status) ||
-            test_bit(WL_STATUS_CONNECTING, &cfg->status)) &&
-            test_bit(WL_STATUS_READY, &cfg->status)) {
+       if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) ||
+            test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) &&
+            check_vif_up(ifp->vif)) {
                WL_INFO("Disassociating from AP");
                brcmf_link_down(cfg);
 
@@ -5507,9 +5301,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
        }
 
        brcmf_abort_scanning(cfg);
-       clear_bit(WL_STATUS_READY, &cfg->status);
-
-       brcmf_debugfs_remove_netdev(cfg);
+       clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
 
        return 0;
 }
index 71ced17..1dd96f1 100644 (file)
@@ -127,15 +127,15 @@ do {                                                              \
 #define WL_AUTH_SHARED_KEY             1       /* d11 shared authentication */
 #define IE_MAX_LEN                     512
 
-/* dongle status */
-enum wl_status {
-       WL_STATUS_READY,
-       WL_STATUS_SCANNING,
-       WL_STATUS_SCAN_ABORTING,
-       WL_STATUS_CONNECTING,
-       WL_STATUS_CONNECTED,
-       WL_STATUS_AP_CREATING,
-       WL_STATUS_AP_CREATED
+/**
+ * enum brcmf_scan_status - dongle scan status
+ *
+ * @BRCMF_SCAN_STATUS_BUSY: scanning in progress on dongle.
+ * @BRCMF_SCAN_STATUS_ABORT: scan being aborted on dongle.
+ */
+enum brcmf_scan_status {
+       BRCMF_SCAN_STATUS_BUSY,
+       BRCMF_SCAN_STATUS_ABORT,
 };
 
 /* wi-fi mode */
@@ -145,19 +145,6 @@ enum wl_mode {
        WL_MODE_AP
 };
 
-/* dongle profile list */
-enum wl_prof_list {
-       WL_PROF_MODE,
-       WL_PROF_SSID,
-       WL_PROF_SEC,
-       WL_PROF_IBSS,
-       WL_PROF_BAND,
-       WL_PROF_BSSID,
-       WL_PROF_ACT,
-       WL_PROF_BEACONINT,
-       WL_PROF_DTIMPERIOD
-};
-
 /* dongle iscan state */
 enum wl_iscan_state {
        WL_ISCAN_STATE_IDLE,
@@ -214,25 +201,73 @@ struct brcmf_cfg80211_security {
        u32 wpa_auth;
 };
 
-/* ibss information for currently joined ibss network */
-struct brcmf_cfg80211_ibss {
-       u8 beacon_interval;     /* in millisecond */
-       u8 atim;                /* in millisecond */
-       s8 join_only;
-       u8 band;
-       u8 channel;
-};
-
-/* dongle profile */
+/**
+ * struct brcmf_cfg80211_profile - profile information.
+ *
+ * @ssid: ssid of associated/associating ap.
+ * @bssid: bssid of joined/joining ibss.
+ * @sec: security information.
+ */
 struct brcmf_cfg80211_profile {
-       u32 mode;
        struct brcmf_ssid ssid;
        u8 bssid[ETH_ALEN];
-       u16 beacon_interval;
-       u8 dtim_period;
        struct brcmf_cfg80211_security sec;
-       struct brcmf_cfg80211_ibss ibss;
-       s32 band;
+};
+
+/**
+ * enum brcmf_vif_status - bit indices for vif status.
+ *
+ * @BRCMF_VIF_STATUS_READY: ready for operation.
+ * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
+ * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
+ * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
+ */
+enum brcmf_vif_status {
+       BRCMF_VIF_STATUS_READY,
+       BRCMF_VIF_STATUS_CONNECTING,
+       BRCMF_VIF_STATUS_CONNECTED,
+       BRCMF_VIF_STATUS_AP_CREATING,
+       BRCMF_VIF_STATUS_AP_CREATED
+};
+
+/**
+ * struct vif_saved_ie - holds saved IEs for a virtual interface.
+ *
+ * @probe_res_ie: IE info for probe response.
+ * @beacon_ie: IE info for beacon frame.
+ * @probe_res_ie_len: IE info length for probe response.
+ * @beacon_ie_len: IE info length for beacon frame.
+ */
+struct vif_saved_ie {
+       u8  probe_res_ie[IE_MAX_LEN];
+       u8  beacon_ie[IE_MAX_LEN];
+       u32 probe_res_ie_len;
+       u32 beacon_ie_len;
+};
+
+/**
+ * struct brcmf_cfg80211_vif - virtual interface specific information.
+ *
+ * @ifp: lower layer interface pointer
+ * @wdev: wireless device.
+ * @profile: profile information.
+ * @mode: operating mode.
+ * @roam_off: roaming state.
+ * @sme_state: SME state using enum brcmf_vif_status bits.
+ * @pm_block: power-management blocked.
+ * @list: linked list.
+ */
+struct brcmf_cfg80211_vif {
+       struct brcmf_if *ifp;
+       struct wireless_dev wdev;
+       struct brcmf_cfg80211_profile profile;
+       s32 mode;
+       s32 roam_off;
+       unsigned long sme_state;
+       bool pm_block;
+       struct vif_saved_ie saved_ie;
+       struct list_head list;
 };
 
 /* dongle iscan event loop */
@@ -383,7 +418,7 @@ struct brcmf_pno_scanresults_le {
 /**
  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
  *
- * @wdev: representing wl cfg80211 device.
+ * @wiphy: wiphy object for cfg80211 interface.
  * @conf: dongle configuration.
  * @scan_request: cfg80211 scan request object.
  * @el: main event loop.
@@ -395,12 +430,11 @@ struct brcmf_pno_scanresults_le {
  * @scan_req_int: internal scan request object.
  * @bss_info: bss information for cfg80211 layer.
  * @ie: information element object for internal purpose.
- * @profile: holding dongle profile.
  * @iscan: iscan controller information.
  * @conn_info: association info.
  * @pmk_list: wpa2 pmk list.
  * @event_work: event handler work struct.
- * @status: current dongle status.
+ * @scan_status: scan activity on the dongle.
  * @pub: common driver information.
  * @channel: current channel.
  * @iscan_on: iscan on/off switch.
@@ -422,10 +456,11 @@ struct brcmf_pno_scanresults_le {
  * @escan_timeout_work: scan timeout worker.
  * @escan_ioctl_buf: dongle command buffer for escan commands.
  * @ap_info: host ap information.
- * @ci: used to link this structure to netdev private data.
+ * @vif_list: linked list of vif instances.
+ * @vif_cnt: number of vif instances.
  */
 struct brcmf_cfg80211_info {
-       struct wireless_dev *wdev;
+       struct wiphy *wiphy;
        struct brcmf_cfg80211_conf *conf;
        struct cfg80211_scan_request *scan_request;
        struct brcmf_cfg80211_event_loop el;
@@ -437,12 +472,11 @@ struct brcmf_cfg80211_info {
        struct brcmf_cfg80211_scan_req *scan_req_int;
        struct wl_cfg80211_bss_info *bss_info;
        struct brcmf_cfg80211_ie ie;
-       struct brcmf_cfg80211_profile *profile;
        struct brcmf_cfg80211_iscan_ctrl *iscan;
        struct brcmf_cfg80211_connect_info conn_info;
        struct brcmf_cfg80211_pmk_list *pmk_list;
        struct work_struct event_work;
-       unsigned long status;
+       unsigned long scan_status;
        struct brcmf_pub *pub;
        u32 channel;
        bool iscan_on;
@@ -464,11 +498,13 @@ struct brcmf_cfg80211_info {
        struct work_struct escan_timeout_work;
        u8 *escan_ioctl_buf;
        struct ap_info *ap_info;
+       struct list_head vif_list;
+       u8 vif_cnt;
 };
 
-static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *w)
+static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
 {
-       return w->wdev->wiphy;
+       return cfg->wiphy;
 }
 
 static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w)
@@ -481,9 +517,12 @@ static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd)
        return (struct brcmf_cfg80211_info *)(wdev_priv(wd));
 }
 
-static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
+static inline
+struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
 {
-       return cfg->wdev->netdev;
+       struct brcmf_cfg80211_vif *vif;
+       vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list);
+       return vif->wdev.netdev;
 }
 
 static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)
@@ -491,6 +530,12 @@ static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)
        return wdev_to_cfg(ndev->ieee80211_ptr);
 }
 
+static inline struct brcmf_cfg80211_profile *ndev_to_prof(struct net_device *nd)
+{
+       struct brcmf_if *ifp = netdev_priv(nd);
+       return &ifp->vif->profile;
+}
+
 #define iscan_to_cfg(i) ((struct brcmf_cfg80211_info *)(i->data))
 #define cfg_to_iscan(w) (w->iscan)
 
@@ -500,9 +545,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
        return &cfg->conn_info;
 }
 
-struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev,
-                                                 struct device *busdev,
-                                                 struct brcmf_pub *drvr);
+struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
 
 /* event handler from dongle */
index b89f127..de96290 100644 (file)
@@ -692,7 +692,7 @@ void ai_pci_up(struct si_pub *sih)
        sii = container_of(sih, struct si_info, pub);
 
        if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
-               bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true);
+               bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], true);
 }
 
 /* Unconfigure and/or apply various WARs when going down */
@@ -703,7 +703,7 @@ void ai_pci_down(struct si_pub *sih)
        sii = container_of(sih, struct si_info, pub);
 
        if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
-               bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false);
+               bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], false);
 }
 
 /* Enable BT-COEX & Ex-PA for 4313 */
index 75086b3..565c15a 100644 (file)
@@ -5077,7 +5077,7 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
         * Configure pci/pcmcia here instead of in brcms_c_attach()
         * to allow mfg hotswap:  down, hotswap (chip power cycle), up.
         */
-       bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core,
+       bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core,
                              true);
 
        /*
index df7050a..d39e3e2 100644 (file)
@@ -415,7 +415,7 @@ static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb,
                        ssid = pos + 2;
                        ssid_len = pos[1];
                        break;
-               case WLAN_EID_GENERIC:
+               case WLAN_EID_VENDOR_SPECIFIC:
                        if (pos[1] >= 4 &&
                            pos[2] == 0x00 && pos[3] == 0x50 &&
                            pos[4] == 0xf2 && pos[5] == 1) {
index 02e0579..95a1ca1 100644 (file)
@@ -1108,7 +1108,7 @@ static const char *get_info_element_string(u16 id)
                MFIE_STRING(ERP_INFO);
                MFIE_STRING(RSN);
                MFIE_STRING(EXT_SUPP_RATES);
-               MFIE_STRING(GENERIC);
+               MFIE_STRING(VENDOR_SPECIFIC);
                MFIE_STRING(QOS_PARAMETER);
        default:
                return "UNKNOWN";
@@ -1248,8 +1248,8 @@ static int libipw_parse_info_param(struct libipw_info_element
                        LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
                        break;
 
-               case WLAN_EID_GENERIC:
-                       LIBIPW_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n",
+               case WLAN_EID_VENDOR_SPECIFIC:
+                       LIBIPW_DEBUG_MGMT("WLAN_EID_VENDOR_SPECIFIC: %d bytes\n",
                                             info_element->len);
                        if (!libipw_parse_qos_info_param_IE(info_element,
                                                               network))
index 7ff3f14..475df45 100644 (file)
@@ -1191,8 +1191,6 @@ static void iwl_option_config(struct iwl_priv *priv)
 
 static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
 {
-       u16 radio_cfg;
-
        priv->eeprom_data->sku = priv->eeprom_data->sku;
 
        if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE &&
@@ -1208,8 +1206,6 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
 
        IWL_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku);
 
-       radio_cfg = priv->eeprom_data->radio_cfg;
-
        priv->hw_params.tx_chains_num =
                num_of_ant(priv->eeprom_data->valid_tx_ant);
        if (priv->cfg->rx_with_siso_diversity)
@@ -1334,6 +1330,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        /* Configure transport layer */
        iwl_trans_configure(priv->trans, &trans_cfg);
 
+       trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
+       trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
+
        /* At this point both hw and priv are allocated. */
 
        SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
@@ -2152,8 +2151,6 @@ static int __init iwl_init(void)
 {
 
        int ret;
-       pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
-       pr_info(DRV_COPYRIGHT "\n");
 
        ret = iwlagn_rate_control_register();
        if (ret) {
index 59a5f78..678717b 100644 (file)
  *****************************************************************************/
 
 #if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#include <linux/skbuff.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "iwl-trans.h"
+#if !defined(__IWLWIFI_DEVICE_TRACE)
+static inline bool iwl_trace_data(struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+
+       if (ieee80211_is_data(hdr->frame_control))
+               return skb->protocol != cpu_to_be16(ETH_P_PAE);
+       return false;
+}
+
+static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans,
+                                     void *rxbuf, size_t len)
+{
+       struct iwl_cmd_header *cmd = (void *)((u8 *)rxbuf + sizeof(__le32));
+       struct ieee80211_hdr *hdr;
+
+       if (cmd->cmd != trans->rx_mpdu_cmd)
+               return len;
+
+       hdr = (void *)((u8 *)cmd + sizeof(struct iwl_cmd_header) +
+                       trans->rx_mpdu_cmd_hdr_size);
+       if (!ieee80211_is_data(hdr->frame_control))
+               return len;
+       /* maybe try to identify EAPOL frames? */
+       return sizeof(__le32) + sizeof(*cmd) + trans->rx_mpdu_cmd_hdr_size +
+               ieee80211_hdrlen(hdr->frame_control);
+}
+#endif
+
 #define __IWLWIFI_DEVICE_TRACE
 
 #include <linux/tracepoint.h>
@@ -235,6 +268,48 @@ TRACE_EVENT(iwlwifi_dbg,
 );
 
 #undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi_data
+
+TRACE_EVENT(iwlwifi_dev_tx_data,
+       TP_PROTO(const struct device *dev,
+                struct sk_buff *skb,
+                void *data, size_t data_len),
+       TP_ARGS(dev, skb, data, data_len),
+       TP_STRUCT__entry(
+               DEV_ENTRY
+
+               __dynamic_array(u8, data, iwl_trace_data(skb) ? data_len : 0)
+       ),
+       TP_fast_assign(
+               DEV_ASSIGN;
+               if (iwl_trace_data(skb))
+                       memcpy(__get_dynamic_array(data), data, data_len);
+       ),
+       TP_printk("[%s] TX frame data", __get_str(dev))
+);
+
+TRACE_EVENT(iwlwifi_dev_rx_data,
+       TP_PROTO(const struct device *dev,
+                const struct iwl_trans *trans,
+                void *rxbuf, size_t len),
+       TP_ARGS(dev, trans, rxbuf, len),
+       TP_STRUCT__entry(
+               DEV_ENTRY
+
+               __dynamic_array(u8, data,
+                               len - iwl_rx_trace_len(trans, rxbuf, len))
+       ),
+       TP_fast_assign(
+               size_t offs = iwl_rx_trace_len(trans, rxbuf, len);
+               DEV_ASSIGN;
+               if (offs < len)
+                       memcpy(__get_dynamic_array(data),
+                              ((u8 *)rxbuf) + offs, len - offs);
+       ),
+       TP_printk("[%s] TX frame data", __get_str(dev))
+);
+
+#undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
@@ -270,25 +345,28 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
 );
 
 TRACE_EVENT(iwlwifi_dev_rx,
-       TP_PROTO(const struct device *dev, void *rxbuf, size_t len),
-       TP_ARGS(dev, rxbuf, len),
+       TP_PROTO(const struct device *dev, const struct iwl_trans *trans,
+                void *rxbuf, size_t len),
+       TP_ARGS(dev, trans, rxbuf, len),
        TP_STRUCT__entry(
                DEV_ENTRY
-               __dynamic_array(u8, rxbuf, len)
+               __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, rxbuf, len))
        ),
        TP_fast_assign(
                DEV_ASSIGN;
-               memcpy(__get_dynamic_array(rxbuf), rxbuf, len);
+               memcpy(__get_dynamic_array(rxbuf), rxbuf,
+                      iwl_rx_trace_len(trans, rxbuf, len));
        ),
        TP_printk("[%s] RX cmd %#.2x",
                  __get_str(dev), ((u8 *)__get_dynamic_array(rxbuf))[4])
 );
 
 TRACE_EVENT(iwlwifi_dev_tx,
-       TP_PROTO(const struct device *dev, void *tfd, size_t tfdlen,
+       TP_PROTO(const struct device *dev, struct sk_buff *skb,
+                void *tfd, size_t tfdlen,
                 void *buf0, size_t buf0_len,
                 void *buf1, size_t buf1_len),
-       TP_ARGS(dev, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
+       TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
        TP_STRUCT__entry(
                DEV_ENTRY
 
@@ -301,14 +379,15 @@ TRACE_EVENT(iwlwifi_dev_tx,
                 * for the possible padding).
                 */
                __dynamic_array(u8, buf0, buf0_len)
-               __dynamic_array(u8, buf1, buf1_len)
+               __dynamic_array(u8, buf1, iwl_trace_data(skb) ? 0 : buf1_len)
        ),
        TP_fast_assign(
                DEV_ASSIGN;
                __entry->framelen = buf0_len + buf1_len;
                memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
                memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
-               memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
+               if (!iwl_trace_data(skb))
+                       memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
        ),
        TP_printk("[%s] TX %.2x (%zu bytes)",
                  __get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0],
index 3dfebfb..54c41b4 100644 (file)
@@ -327,11 +327,11 @@ u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
 EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
 
 int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-                              void *buf, int dwords)
+                              const void *buf, int dwords)
 {
        unsigned long flags;
        int offs, result = 0;
-       u32 *vals = buf;
+       const u32 *vals = buf;
 
        spin_lock_irqsave(&trans->reg_lock, flags);
        if (likely(iwl_grab_nic_access(trans))) {
index 50d3819..e1aa69f 100644 (file)
@@ -87,7 +87,7 @@ void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
        } while (0)
 
 int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-                              void *buf, int dwords);
+                              const void *buf, int dwords);
 
 u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
 int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
index 9253ef1..c3a4bb4 100644 (file)
 #define SCD_CONTEXT_QUEUE_OFFSET(x)\
        (SCD_CONTEXT_MEM_LOWER_BOUND + ((x) * 8))
 
+#define SCD_TX_STTS_QUEUE_OFFSET(x)\
+       (SCD_TX_STTS_MEM_LOWER_BOUND + ((x) * 16))
+
 #define SCD_TRANS_TBL_OFFSET_QUEUE(x) \
        ((SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc)
 
index ff11542..f75ea6d 100644 (file)
@@ -444,6 +444,10 @@ enum iwl_trans_state {
  * @dev_cmd_headroom: room needed for the transport's private use before the
  *     device_cmd for Tx - for internal use only
  *     The user should use iwl_trans_{alloc,free}_tx_cmd.
+ * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before
+ *     starting the firmware, used for tracing
+ * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
+ *     start of the 802.11 header in the @rx_mpdu_cmd
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
@@ -457,6 +461,8 @@ struct iwl_trans {
        u32 hw_id;
        char hw_id_str[52];
 
+       u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
+
        bool pm_support;
 
        wait_queue_head_t wait_command_queue;
@@ -516,6 +522,8 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans,
 {
        might_sleep();
 
+       WARN_ON_ONCE(!trans->rx_mpdu_cmd);
+
        return trans->ops->start_fw(trans, fw);
 }
 
index 17c8e5d..137af4c 100644 (file)
@@ -411,7 +411,8 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
 
                len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
                len += sizeof(u32); /* account for status word */
-               trace_iwlwifi_dev_rx(trans->dev, pkt, len);
+               trace_iwlwifi_dev_rx(trans->dev, trans, pkt, len);
+               trace_iwlwifi_dev_rx_data(trans->dev, trans, pkt, len);
 
                /* Reclaim a command buffer only if this packet is a response
                 *   to a (driver-originated) command.
index fe0fffd..f95d88d 100644 (file)
@@ -300,7 +300,7 @@ static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
        struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
        struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
        u32 scd_sram_addr = trans_pcie->scd_base_addr +
-               SCD_TX_STTS_MEM_LOWER_BOUND + (16 * txq->q.id);
+                               SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
        u8 buf[16];
        int i;
 
@@ -1385,11 +1385,13 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
                                   DMA_BIDIRECTIONAL);
 
-       trace_iwlwifi_dev_tx(trans->dev,
+       trace_iwlwifi_dev_tx(trans->dev, skb,
                             &txq->tfds[txq->q.write_ptr],
                             sizeof(struct iwl_tfd),
                             &dev_cmd->hdr, firstlen,
                             skb->data + hdr_len, secondlen);
+       trace_iwlwifi_dev_tx_data(trans->dev, skb,
+                                 skb->data + hdr_len, secondlen);
 
        /* start timer if queue currently empty */
        if (txq->need_update && q->read_ptr == q->write_ptr &&
@@ -1514,14 +1516,13 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
        struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
        /* n_bd is usually 256 => n_bd - 1 = 0xff */
        int tfd_num = ssn & (txq->q.n_bd - 1);
-       int freed = 0;
 
        spin_lock(&txq->lock);
 
        if (txq->q.read_ptr != tfd_num) {
                IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
                                   txq_id, txq->q.read_ptr, tfd_num, ssn);
-               freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
+               iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
                if (iwl_queue_space(&txq->q) > txq->q.low_mark)
                        iwl_wake_queue(trans, txq);
        }
index 105e3af..db3efbb 100644 (file)
@@ -480,21 +480,20 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
 void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u16 rd_ptr, wr_ptr;
-       int n_bd = trans_pcie->txq[txq_id].q.n_bd;
+       u32 stts_addr = trans_pcie->scd_base_addr +
+                       SCD_TX_STTS_QUEUE_OFFSET(txq_id);
+       static const u32 zero_val[4] = {};
 
        if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
                WARN_ONCE(1, "queue %d not used", txq_id);
                return;
        }
 
-       rd_ptr = iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (n_bd - 1);
-       wr_ptr = iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id));
+       iwl_txq_set_inactive(trans, txq_id);
 
-       WARN_ONCE(rd_ptr != wr_ptr, "queue %d isn't empty: [%d,%d]",
-                 txq_id, rd_ptr, wr_ptr);
+       _iwl_write_targ_mem_dwords(trans, stts_addr,
+                                  zero_val, ARRAY_SIZE(zero_val));
 
-       iwl_txq_set_inactive(trans, txq_id);
        IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
 }
 
@@ -549,7 +548,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
         * allocated into separate TFDs, then we will need to
         * increase the size of the buffers.
         */
-       if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
+       if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE,
+                "Command %s (%#x) is too large (%d bytes)\n",
+                trans_pcie_get_cmd_string(trans_pcie, cmd->id),
+                cmd->id, copy_size))
                return -EINVAL;
 
        spin_lock_bh(&txq->lock);
index 9780775..3e81264 100644 (file)
@@ -101,7 +101,7 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
 
        switch (action) {
        case CMD_ACT_MESH_CONFIG_START:
-               ie->id = WLAN_EID_GENERIC;
+               ie->id = WLAN_EID_VENDOR_SPECIFIC;
                ie->val.oui[0] = 0x00;
                ie->val.oui[1] = 0x50;
                ie->val.oui[2] = 0x43;
index 9402b93..4a97acd 100644 (file)
@@ -58,8 +58,7 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
                        if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
                                mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
                        else
-                               mwifiex_process_rx_packet(priv->adapter,
-                                                         rx_tmp_ptr);
+                               mwifiex_process_rx_packet(priv, rx_tmp_ptr);
                }
        }
 
@@ -106,7 +105,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
                if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
                        mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
                else
-                       mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+                       mwifiex_process_rx_packet(priv, rx_tmp_ptr);
        }
 
        spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -442,8 +441,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
                        if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
                                mwifiex_handle_uap_rx_forward(priv, payload);
                        else
-                               mwifiex_process_rx_packet(priv->adapter,
-                                                         payload);
+                               mwifiex_process_rx_packet(priv, payload);
                }
                return 0;
        }
index 780d3e1..fdb1eb8 100644 (file)
@@ -471,13 +471,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
                        flag = 1;
                        first_chan = (u32) ch->hw_value;
                        next_chan = first_chan;
-                       max_pwr = ch->max_reg_power;
+                       max_pwr = ch->max_power;
                        no_of_parsed_chan = 1;
                        continue;
                }
 
                if (ch->hw_value == next_chan + 1 &&
-                   ch->max_reg_power == max_pwr) {
+                   ch->max_power == max_pwr) {
                        next_chan++;
                        no_of_parsed_chan++;
                } else {
@@ -488,7 +488,7 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
                        no_of_triplet++;
                        first_chan = (u32) ch->hw_value;
                        next_chan = first_chan;
-                       max_pwr = ch->max_reg_power;
+                       max_pwr = ch->max_power;
                        no_of_parsed_chan = 1;
                }
        }
@@ -1819,12 +1819,18 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
 
        wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
 
-       if (atomic_read(&priv->wmm.tx_pkts_queued) >=
+       if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+           atomic_read(&priv->wmm.tx_pkts_queued) >=
            MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) {
                dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n");
                return -EBUSY;
        }
 
+       if (priv->user_scan_cfg) {
+               dev_err(priv->adapter->dev, "cmd: Scan already in process..\n");
+               return -EBUSY;
+       }
+
        priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
                                      GFP_KERNEL);
        if (!priv->user_scan_cfg) {
@@ -2116,7 +2122,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
        }
 
        sema_init(&priv->async_sem, 1);
-       priv->scan_pending_on_block = false;
 
        dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
 
@@ -2253,8 +2258,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
        wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;
 
-       wiphy->features = NL80211_FEATURE_HT_IBSS |
-                         NL80211_FEATURE_INACTIVITY_TIMER;
+       wiphy->features |= NL80211_FEATURE_HT_IBSS |
+                          NL80211_FEATURE_INACTIVITY_TIMER |
+                          NL80211_FEATURE_LOW_PRIORITY_SCAN;
 
        /* Reserve space for mwifiex specific private data for BSS */
        wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
index 8d46510..da6c491 100644 (file)
@@ -917,21 +917,24 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
 
                dev_err(adapter->dev, "last_cmd_index = %d\n",
                        adapter->dbg.last_cmd_index);
-               print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET,
-                                    adapter->dbg.last_cmd_id, DBG_CMD_NUM);
-               print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET,
-                                    adapter->dbg.last_cmd_act, DBG_CMD_NUM);
+               dev_err(adapter->dev, "last_cmd_id: %*ph\n",
+                       (int)sizeof(adapter->dbg.last_cmd_id),
+                       adapter->dbg.last_cmd_id);
+               dev_err(adapter->dev, "last_cmd_act: %*ph\n",
+                       (int)sizeof(adapter->dbg.last_cmd_act),
+                       adapter->dbg.last_cmd_act);
 
                dev_err(adapter->dev, "last_cmd_resp_index = %d\n",
                        adapter->dbg.last_cmd_resp_index);
-               print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET,
-                                    adapter->dbg.last_cmd_resp_id,
-                                    DBG_CMD_NUM);
+               dev_err(adapter->dev, "last_cmd_resp_id: %*ph\n",
+                       (int)sizeof(adapter->dbg.last_cmd_resp_id),
+                       adapter->dbg.last_cmd_resp_id);
 
                dev_err(adapter->dev, "last_event_index = %d\n",
                        adapter->dbg.last_event_index);
-               print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET,
-                                    adapter->dbg.last_event, DBG_CMD_NUM);
+               dev_err(adapter->dev, "last_event: %*ph\n",
+                       (int)sizeof(adapter->dbg.last_event),
+                       adapter->dbg.last_event);
 
                dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n",
                        adapter->data_sent, adapter->cmd_sent);
index b5d37a8..482faac 100644 (file)
@@ -84,18 +84,19 @@ static void scan_delay_timer_fn(unsigned long data)
                spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
 
                if (priv->user_scan_cfg) {
-                       dev_dbg(priv->adapter->dev,
-                               "info: %s: scan aborted\n", __func__);
-                       cfg80211_scan_done(priv->scan_request, 1);
-                       priv->scan_request = NULL;
+                       if (priv->scan_request) {
+                               dev_dbg(priv->adapter->dev,
+                                       "info: aborting scan\n");
+                               cfg80211_scan_done(priv->scan_request, 1);
+                               priv->scan_request = NULL;
+                       } else {
+                               dev_dbg(priv->adapter->dev,
+                                       "info: scan already aborted\n");
+                       }
+
                        kfree(priv->user_scan_cfg);
                        priv->user_scan_cfg = NULL;
                }
-
-               if (priv->scan_pending_on_block) {
-                       priv->scan_pending_on_block = false;
-                       up(&priv->async_sem);
-               }
                goto done;
        }
 
index eb22dd2..1df767b 100644 (file)
@@ -472,6 +472,14 @@ mwifiex_open(struct net_device *dev)
 static int
 mwifiex_close(struct net_device *dev)
 {
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+       if (priv->scan_request) {
+               dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n");
+               cfg80211_scan_done(priv->scan_request, 1);
+               priv->scan_request = NULL;
+       }
+
        return 0;
 }
 
index c2d0ab1..81f8772 100644 (file)
@@ -115,8 +115,6 @@ enum {
 #define MWIFIEX_TYPE_DATA                              0
 #define MWIFIEX_TYPE_EVENT                             3
 
-#define DBG_CMD_NUM                                            5
-
 #define MAX_BITMAP_RATES_SIZE                  10
 
 #define MAX_CHANNEL_BAND_BG     14
@@ -484,7 +482,6 @@ struct mwifiex_private {
        u8 nick_name[16];
        u16 current_key_index;
        struct semaphore async_sem;
-       u8 scan_pending_on_block;
        u8 report_scan_result;
        struct cfg80211_scan_request *scan_request;
        struct mwifiex_user_scan_cfg *user_scan_cfg;
@@ -750,9 +747,9 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter);
 
 int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);
 
-int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
+int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb);
 
-int mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter,
+int mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
                                struct sk_buff *skb);
 
 int mwifiex_process_event(struct mwifiex_adapter *adapter);
@@ -809,7 +806,7 @@ void mwifiex_hs_activated_event(struct mwifiex_private *priv,
                                        u8 activated);
 int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
                              struct host_cmd_ds_command *resp);
-int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
+int mwifiex_process_rx_packet(struct mwifiex_private *priv,
                              struct sk_buff *skb);
 int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
                            u16 cmd_action, u32 cmd_oid,
@@ -819,9 +816,9 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
                            void *data_buf, void *cmd_buf);
 int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
                                struct host_cmd_ds_command *resp);
-int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
+int mwifiex_process_sta_rx_packet(struct mwifiex_private *,
                                  struct sk_buff *skb);
-int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
+int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
                                  struct sk_buff *skb);
 int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
                                  struct sk_buff *skb);
index 9171aae..9189a32 100644 (file)
@@ -153,7 +153,7 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
 
        if (((bss_desc->bcn_wpa_ie) &&
             ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id ==
-             WLAN_EID_WPA))) {
+             WLAN_EID_VENDOR_SPECIFIC))) {
                iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
                oui = &mwifiex_wpa_oui[cipher][0];
                ret = mwifiex_search_oui_in_ie(iebody, oui);
@@ -202,7 +202,7 @@ mwifiex_is_bss_no_sec(struct mwifiex_private *priv,
        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
            !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
                ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
-                WLAN_EID_WPA)) &&
+                WLAN_EID_VENDOR_SPECIFIC)) &&
            ((!bss_desc->bcn_rsn_ie) ||
                ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
                 WLAN_EID_RSN)) &&
@@ -237,7 +237,8 @@ mwifiex_is_bss_wpa(struct mwifiex_private *priv,
 {
        if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled &&
            !priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) &&
-           ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == WLAN_EID_WPA))
+           ((*(bss_desc->bcn_wpa_ie)).
+            vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC))
           /*
            * Privacy bit may NOT be set in some APs like
            * LinkSys WRT54G && bss_desc->privacy
@@ -309,7 +310,8 @@ mwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv,
        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
            !priv->sec_info.wpa2_enabled &&
            ((!bss_desc->bcn_wpa_ie) ||
-            ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) &&
+            ((*(bss_desc->bcn_wpa_ie)).
+             vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) &&
            ((!bss_desc->bcn_rsn_ie) ||
             ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
            !priv->sec_info.encryption_mode && bss_desc->privacy) {
@@ -329,7 +331,8 @@ mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv,
        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
            !priv->sec_info.wpa2_enabled &&
            ((!bss_desc->bcn_wpa_ie) ||
-            ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) &&
+            ((*(bss_desc->bcn_wpa_ie)).
+             vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) &&
            ((!bss_desc->bcn_rsn_ie) ||
             ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
            priv->sec_info.encryption_mode && bss_desc->privacy) {
@@ -938,6 +941,11 @@ mwifiex_config_scan(struct mwifiex_private *priv,
                                 chan_idx)->chan_scan_mode_bitmap
                                        &= ~MWIFIEX_PASSIVE_SCAN;
 
+                       if (*filtered_scan)
+                               (scan_chan_list +
+                                chan_idx)->chan_scan_mode_bitmap
+                                       |= MWIFIEX_DISABLE_CHAN_FILT;
+
                        if (user_scan_in->chan_list[chan_idx].scan_time) {
                                scan_dur = (u16) user_scan_in->
                                        chan_list[chan_idx].scan_time;
@@ -1759,26 +1767,39 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                }
                if (priv->report_scan_result)
                        priv->report_scan_result = false;
-               if (priv->scan_pending_on_block) {
-                       priv->scan_pending_on_block = false;
-                       up(&priv->async_sem);
-               }
 
                if (priv->user_scan_cfg) {
-                       dev_dbg(priv->adapter->dev,
-                               "info: %s: sending scan results\n", __func__);
-                       cfg80211_scan_done(priv->scan_request, 0);
-                       priv->scan_request = NULL;
+                       if (priv->scan_request) {
+                               dev_dbg(priv->adapter->dev,
+                                       "info: notifying scan done\n");
+                               cfg80211_scan_done(priv->scan_request, 0);
+                               priv->scan_request = NULL;
+                       } else {
+                               dev_dbg(priv->adapter->dev,
+                                       "info: scan already aborted\n");
+                       }
+
                        kfree(priv->user_scan_cfg);
                        priv->user_scan_cfg = NULL;
                }
        } else {
-               if (!mwifiex_wmm_lists_empty(adapter)) {
+               if (priv->user_scan_cfg && !priv->scan_request) {
+                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+                                              flags);
+                       adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT;
+                       mod_timer(&priv->scan_delay_timer, jiffies);
+                       dev_dbg(priv->adapter->dev,
+                               "info: %s: triggerring scan abort\n", __func__);
+               } else if (!mwifiex_wmm_lists_empty(adapter) &&
+                          (priv->scan_request && (priv->scan_request->flags &
+                                           NL80211_SCAN_FLAG_LOW_PRIORITY))) {
                        spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
                                               flags);
                        adapter->scan_delay_cnt = 1;
                        mod_timer(&priv->scan_delay_timer, jiffies +
                                  msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+                       dev_dbg(priv->adapter->dev,
+                               "info: %s: deferring scan\n", __func__);
                } else {
                        /* Get scan command from scan_pending_q and put to
                           cmd_pending_q */
@@ -1891,7 +1912,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
                        __func__);
                return -1;
        }
-       priv->scan_pending_on_block = true;
 
        priv->adapter->scan_wait_q_woken = false;
 
@@ -1905,10 +1925,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
        if (!ret)
                ret = mwifiex_wait_queue_complete(priv->adapter);
 
-       if (ret == -1) {
-               priv->scan_pending_on_block = false;
-               up(&priv->async_sem);
-       }
+       up(&priv->async_sem);
 
        return ret;
 }
index 09e6a26..65c12eb 100644 (file)
@@ -85,10 +85,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
                spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
                if (priv->report_scan_result)
                        priv->report_scan_result = false;
-               if (priv->scan_pending_on_block) {
-                       priv->scan_pending_on_block = false;
-                       up(&priv->async_sem);
-               }
                break;
 
        case HostCmd_CMD_MAC_CONTROL:
index 0c9f70b..552d72e 100644 (file)
@@ -713,7 +713,7 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
                dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
                        priv->wpa_ie_len, priv->wpa_ie[0]);
 
-               if (priv->wpa_ie[0] == WLAN_EID_WPA) {
+               if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
                        priv->sec_info.wpa_enabled = true;
                } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
                        priv->sec_info.wpa2_enabled = true;
@@ -1253,7 +1253,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
        }
        pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
        /* Test to see if it is a WPA IE, if not, then it is a gen IE */
-       if (((pvendor_ie->element_id == WLAN_EID_WPA) &&
+       if (((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) &&
             (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) ||
            (pvendor_ie->element_id == WLAN_EID_RSN)) {
 
index 07d32b7..b5c1095 100644 (file)
  *
  * The completion callback is called after processing in complete.
  */
-int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
+int mwifiex_process_rx_packet(struct mwifiex_private *priv,
                              struct sk_buff *skb)
 {
        int ret;
-       struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
-       struct mwifiex_private *priv =
-                       mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
-                                              rx_info->bss_type);
        struct rx_packet_hdr *rx_pkt_hdr;
        struct rxpd *local_rx_pd;
        int hdr_chop;
@@ -98,9 +94,9 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
 
        priv->rxpd_htinfo = local_rx_pd->ht_info;
 
-       ret = mwifiex_recv_packet(adapter, skb);
+       ret = mwifiex_recv_packet(priv, skb);
        if (ret == -1)
-               dev_err(adapter->dev, "recv packet failed\n");
+               dev_err(priv->adapter->dev, "recv packet failed\n");
 
        return ret;
 }
@@ -117,21 +113,15 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
  *
  * The completion callback is called after processing in complete.
  */
-int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
+int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
                                  struct sk_buff *skb)
 {
+       struct mwifiex_adapter *adapter = priv->adapter;
        int ret = 0;
        struct rxpd *local_rx_pd;
-       struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
        struct rx_packet_hdr *rx_pkt_hdr;
        u8 ta[ETH_ALEN];
        u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num;
-       struct mwifiex_private *priv =
-                       mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
-                                              rx_info->bss_type);
-
-       if (!priv)
-               return -1;
 
        local_rx_pd = (struct rxpd *) (skb->data);
        rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type);
@@ -169,13 +159,13 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
 
                while (!skb_queue_empty(&list)) {
                        rx_skb = __skb_dequeue(&list);
-                       ret = mwifiex_recv_packet(adapter, rx_skb);
+                       ret = mwifiex_recv_packet(priv, rx_skb);
                        if (ret == -1)
                                dev_err(adapter->dev, "Rx of A-MSDU failed");
                }
                return 0;
        } else if (rx_pkt_type == PKT_TYPE_MGMT) {
-               ret = mwifiex_process_mgmt_packet(adapter, skb);
+               ret = mwifiex_process_mgmt_packet(priv, skb);
                if (ret)
                        dev_err(adapter->dev, "Rx of mgmt packet failed");
                dev_kfree_skb_any(skb);
@@ -188,7 +178,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
         */
        if (!IS_11N_ENABLED(priv) ||
            memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) {
-               mwifiex_process_rx_packet(adapter, skb);
+               mwifiex_process_rx_packet(priv, skb);
                return ret;
        }
 
index 2af2639..5cb3f7a 100644 (file)
@@ -48,13 +48,19 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
        if (!priv)
                priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
 
+       if (!priv) {
+               dev_err(adapter->dev, "data: priv not found. Drop RX packet\n");
+               dev_kfree_skb_any(skb);
+               return -1;
+       }
+
        rx_info->bss_num = priv->bss_num;
        rx_info->bss_type = priv->bss_type;
 
        if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
-               return mwifiex_process_uap_rx_packet(adapter, skb);
+               return mwifiex_process_uap_rx_packet(priv, skb);
 
-       return mwifiex_process_sta_rx_packet(adapter, skb);
+       return mwifiex_process_sta_rx_packet(priv, skb);
 }
 EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
 
index d95a2d5..8dd7224 100644 (file)
@@ -188,10 +188,19 @@ mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
        int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
        const u8 *var_pos = params->beacon.head + var_offset;
        int len = params->beacon.head_len - var_offset;
+       u8 rate_len = 0;
 
        rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
-       if (rate_ie)
+       if (rate_ie) {
                memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
+               rate_len = rate_ie->len;
+       }
+
+       rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
+                                          params->beacon.tail,
+                                          params->beacon.tail_len);
+       if (rate_ie)
+               memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len);
 
        return;
 }
index 0966ac2..a018e42 100644 (file)
@@ -146,7 +146,7 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
        }
 
        /* Forward unicat/Inter-BSS packets to kernel. */
-       return mwifiex_process_rx_packet(adapter, skb);
+       return mwifiex_process_rx_packet(priv, skb);
 }
 
 /*
@@ -159,24 +159,17 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
  *
  * The completion callback is called after processing is complete.
  */
-int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
+int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
                                  struct sk_buff *skb)
 {
+       struct mwifiex_adapter *adapter = priv->adapter;
        int ret;
        struct uap_rxpd *uap_rx_pd;
-       struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
        struct rx_packet_hdr *rx_pkt_hdr;
        u16 rx_pkt_type;
        u8 ta[ETH_ALEN], pkt_type;
        struct mwifiex_sta_node *node;
 
-       struct mwifiex_private *priv =
-                       mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
-                                              rx_info->bss_type);
-
-       if (!priv)
-               return -1;
-
        uap_rx_pd = (struct uap_rxpd *)(skb->data);
        rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
        rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
@@ -210,7 +203,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
 
                while (!skb_queue_empty(&list)) {
                        rx_skb = __skb_dequeue(&list);
-                       ret = mwifiex_recv_packet(adapter, rx_skb);
+                       ret = mwifiex_recv_packet(priv, rx_skb);
                        if (ret)
                                dev_err(adapter->dev,
                                        "AP:Rx A-MSDU failed");
@@ -218,7 +211,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
 
                return 0;
        } else if (rx_pkt_type == PKT_TYPE_MGMT) {
-               ret = mwifiex_process_mgmt_packet(adapter, skb);
+               ret = mwifiex_process_mgmt_packet(priv, skb);
                if (ret)
                        dev_err(adapter->dev, "Rx of mgmt packet failed");
                dev_kfree_skb_any(skb);
index ae88f80..0982375 100644 (file)
@@ -146,20 +146,16 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
  * to the kernel.
  */
 int
-mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter,
+mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
                            struct sk_buff *skb)
 {
        struct rxpd *rx_pd;
-       struct mwifiex_private *priv;
        u16 pkt_len;
 
        if (!skb)
                return -1;
 
        rx_pd = (struct rxpd *)skb->data;
-       priv = mwifiex_get_priv_by_id(adapter, rx_pd->bss_num, rx_pd->bss_type);
-       if (!priv)
-               return -1;
 
        skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));
        skb_pull(skb, sizeof(pkt_len));
@@ -190,20 +186,11 @@ mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter,
  * the function creates a blank SKB, fills it with the data from the
  * received buffer and then sends this new SKB to the kernel.
  */
-int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
 {
-       struct mwifiex_rxinfo *rx_info;
-       struct mwifiex_private *priv;
-
        if (!skb)
                return -1;
 
-       rx_info = MWIFIEX_SKB_RXCB(skb);
-       priv = mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
-                                     rx_info->bss_type);
-       if (!priv)
-               return -1;
-
        skb->dev = priv->netdev;
        skb->protocol = eth_type_trans(skb, priv->netdev);
        skb->ip_summed = CHECKSUM_NONE;
@@ -225,7 +212,7 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
         * fragments. Currently we fail the Filesndl-ht.scr script
         * for UDP, hence this fix
         */
-       if ((adapter->iface_type == MWIFIEX_USB) &&
+       if ((priv->adapter->iface_type == MWIFIEX_USB) &&
            (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
                skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
 
index 4dadf98..5a8fec2 100644 (file)
@@ -39,7 +39,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
 {
        u8 *p = data;
        while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
-               if ((p[0] == WLAN_EID_GENERIC) &&
+               if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) &&
                    (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
                        return p;
                p += p[1] + 2;
index 7f53cea..01624dc 100644 (file)
@@ -865,7 +865,7 @@ static int ezusb_firmware_download(struct ezusb_priv *upriv,
 static int ezusb_access_ltv(struct ezusb_priv *upriv,
                            struct request_context *ctx,
                            u16 length, const void *data, u16 frame_type,
-                           void *ans_buff, int ans_size, u16 *ans_length)
+                           void *ans_buff, unsigned ans_size, u16 *ans_length)
 {
        int req_size;
        int retval = 0;
@@ -933,7 +933,7 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv,
        }
        if (ctx->in_rid) {
                struct ezusb_packet *ans = ctx->buf;
-               int exp_len;
+               unsigned exp_len;
 
                if (ans->hermes_len != 0)
                        exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12;
@@ -949,8 +949,7 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv,
                }
 
                if (ans_buff)
-                       memcpy(ans_buff, ans->data,
-                              min_t(int, exp_len, ans_size));
+                       memcpy(ans_buff, ans->data, min(exp_len, ans_size));
                if (ans_length)
                        *ans_length = le16_to_cpu(ans->hermes_len);
        }
@@ -995,7 +994,7 @@ static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
        struct ezusb_priv *upriv = hw->priv;
        struct request_context *ctx;
 
-       if ((bufsize < 0) || (bufsize % 2))
+       if (bufsize % 2)
                return -EINVAL;
 
        ctx = ezusb_alloc_ctx(upriv, rid, rid);
index 59474ae..c0441a7 100644 (file)
@@ -2520,20 +2520,37 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev,
        return comp_value;
 }
 
+static int rt2800_get_txpower_reg_delta(struct rt2x00_dev *rt2x00dev,
+                                       int power_level, int max_power)
+{
+       int delta;
+
+       if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags))
+               return 0;
+
+       /*
+        * XXX: We don't know the maximum transmit power of our hardware since
+        * the EEPROM doesn't expose it. We only know that we are calibrated
+        * to 100% tx power.
+        *
+        * Hence, we assume the regulatory limit that cfg80211 calulated for
+        * the current channel is our maximum and if we are requested to lower
+        * the value we just reduce our tx power accordingly.
+        */
+       delta = power_level - max_power;
+       return min(delta, 0);
+}
+
 static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
                                   enum ieee80211_band band, int power_level,
                                   u8 txpower, int delta)
 {
-       u32 reg;
        u16 eeprom;
        u8 criterion;
        u8 eirp_txpower;
        u8 eirp_txpower_criterion;
        u8 reg_limit;
 
-       if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b))
-               return txpower;
-
        if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) {
                /*
                 * Check if eirp txpower exceed txpower_limit.
@@ -2542,11 +2559,13 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
                 * .11b data rate need add additional 4dbm
                 * when calculating eirp txpower.
                 */
-               rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, &reg);
-               criterion = rt2x00_get_field32(reg, TX_PWR_CFG_0_6MBS);
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + 1,
+                                  &eeprom);
+               criterion = rt2x00_get_field16(eeprom,
+                                              EEPROM_TXPOWER_BYRATE_RATE0);
 
-               rt2x00_eeprom_read(rt2x00dev,
-                                  EEPROM_EIRP_MAX_TX_POWER, &eeprom);
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER,
+                                  &eeprom);
 
                if (band == IEEE80211_BAND_2GHZ)
                        eirp_txpower_criterion = rt2x00_get_field16(eeprom,
@@ -2563,36 +2582,71 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
        } else
                reg_limit = 0;
 
-       return txpower + delta - reg_limit;
+       txpower = max(0, txpower + delta - reg_limit);
+       return min_t(u8, txpower, 0xc);
 }
 
+/*
+ * We configure transmit power using MAC TX_PWR_CFG_{0,...,N} registers and
+ * BBP R1 register. TX_PWR_CFG_X allow to configure per rate TX power values,
+ * 4 bits for each rate (tune from 0 to 15 dBm). BBP_R1 controls transmit power
+ * for all rates, but allow to set only 4 discrete values: -12, -6, 0 and 6 dBm.
+ * Reference per rate transmit power values are located in the EEPROM at
+ * EEPROM_TXPOWER_BYRATE offset. We adjust them and BBP R1 settings according to
+ * current conditions (i.e. band, bandwidth, temperature, user settings).
+ */
 static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
-                                 enum ieee80211_band band,
+                                 struct ieee80211_channel *chan,
                                  int power_level)
 {
-       u8 txpower;
+       u8 txpower, r1;
        u16 eeprom;
-       int i, is_rate_b;
-       u32 reg;
-       u8 r1;
-       u32 offset;
-       int delta;
+       u32 reg, offset;
+       int i, is_rate_b, delta, power_ctrl;
+       enum ieee80211_band band = chan->band;
 
        /*
-        * Calculate HT40 compensation delta
+        * Calculate HT40 compensation. For 40MHz we need to add or subtract
+        * value read from EEPROM (different for 2GHz and for 5GHz).
         */
        delta = rt2800_get_txpower_bw_comp(rt2x00dev, band);
 
        /*
-        * calculate temperature compensation delta
+        * Calculate temperature compensation. Depends on measurement of current
+        * TSSI (Transmitter Signal Strength Indication) we know TX power (due
+        * to temperature or maybe other factors) is smaller or bigger than
+        * expected. We adjust it, based on TSSI reference and boundaries values
+        * provided in EEPROM.
         */
        delta += rt2800_get_gain_calibration_delta(rt2x00dev);
 
        /*
-        * set to normal bbp tx power control mode: +/- 0dBm
+        * Decrease power according to user settings, on devices with unknown
+        * maximum tx power. For other devices we take user power_level into
+        * consideration on rt2800_compensate_txpower().
+        */
+       delta += rt2800_get_txpower_reg_delta(rt2x00dev, power_level,
+                                             chan->max_power);
+
+       /*
+        * BBP_R1 controls TX power for all rates, it allow to set the following
+        * gains -12, -6, 0, +6 dBm by setting values 2, 1, 0, 3 respectively.
+        *
+        * TODO: we do not use +6 dBm option to do not increase power beyond
+        * regulatory limit, however this could be utilized for devices with
+        * CAPABILITY_POWER_LIMIT.
         */
        rt2800_bbp_read(rt2x00dev, 1, &r1);
-       rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, 0);
+       if (delta <= -12) {
+               power_ctrl = 2;
+               delta += 12;
+       } else if (delta <= -6) {
+               power_ctrl = 1;
+               delta += 6;
+       } else {
+               power_ctrl = 0;
+       }
+       rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl);
        rt2800_bbp_write(rt2x00dev, 1, r1);
        offset = TX_PWR_CFG_0;
 
@@ -2710,7 +2764,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
 
 void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
 {
-       rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band,
+       rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.channel,
                              rt2x00dev->tx_power);
 }
 EXPORT_SYMBOL_GPL(rt2800_gain_calibration);
@@ -2845,11 +2899,11 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev,
        if (flags & IEEE80211_CONF_CHANGE_CHANNEL) {
                rt2800_config_channel(rt2x00dev, libconf->conf,
                                      &libconf->rf, &libconf->channel);
-               rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
+               rt2800_config_txpower(rt2x00dev, libconf->conf->channel,
                                      libconf->conf->power_level);
        }
        if (flags & IEEE80211_CONF_CHANGE_POWER)
-               rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
+               rt2800_config_txpower(rt2x00dev, libconf->conf->channel,
                                      libconf->conf->power_level);
        if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
                rt2800_config_retry_limit(rt2x00dev, libconf);
index 5b4b4d4..ca69e35 100644 (file)
@@ -52,11 +52,8 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
        u32 target_content = 0;
        u8 entry_i;
 
-       RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
-                "key_cont_128:\n %x:%x:%x:%x:%x:%x\n",
-                key_cont_128[0], key_cont_128[1],
-                key_cont_128[2], key_cont_128[3],
-                key_cont_128[4], key_cont_128[5]);
+       RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "key_cont_128: %6phC\n",
+                key_cont_128);
 
        for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
                target_command = entry_i + CAM_CONTENT_COUNT * entry_no;
index 1ca4e25..1cdf5a2 100644 (file)
@@ -43,8 +43,8 @@
 #define GET_UNDECORATED_AVERAGE_RSSI(_priv)    \
        ((RTLPRIV(_priv))->mac80211.opmode == \
                             NL80211_IFTYPE_ADHOC) ?    \
-       ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \
-       ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb)
+       ((RTLPRIV(_priv))->dm.entry_min_undec_sm_pwdb) : \
+       ((RTLPRIV(_priv))->dm.undec_sm_pwdb)
 
 static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
        0x7f8001fe,
@@ -167,18 +167,18 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
        dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
        dm_digtable->cur_igvalue = 0x20;
        dm_digtable->pre_igvalue = 0x0;
-       dm_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
-       dm_digtable->presta_connectstate = DIG_STA_DISCONNECT;
-       dm_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT;
+       dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
+       dm_digtable->presta_cstate = DIG_STA_DISCONNECT;
+       dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
        dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
        dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
        dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
        dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
        dm_digtable->rx_gain_range_max = DM_DIG_MAX;
        dm_digtable->rx_gain_range_min = DM_DIG_MIN;
-       dm_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT;
-       dm_digtable->backoff_val_range_max = DM_DIG_BACKOFF_MAX;
-       dm_digtable->backoff_val_range_min = DM_DIG_BACKOFF_MIN;
+       dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+       dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
+       dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
        dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;
        dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
 }
@@ -189,22 +189,21 @@ static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
        struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
        long rssi_val_min = 0;
 
-       if ((dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) &&
-           (dm_digtable->cursta_connectstate == DIG_STA_CONNECT)) {
-               if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb != 0)
+       if ((dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) &&
+           (dm_digtable->cursta_cstate == DIG_STA_CONNECT)) {
+               if (rtlpriv->dm.entry_min_undec_sm_pwdb != 0)
                        rssi_val_min =
-                           (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb >
-                            rtlpriv->dm.undecorated_smoothed_pwdb) ?
-                           rtlpriv->dm.undecorated_smoothed_pwdb :
-                           rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                           (rtlpriv->dm.entry_min_undec_sm_pwdb >
+                            rtlpriv->dm.undec_sm_pwdb) ?
+                           rtlpriv->dm.undec_sm_pwdb :
+                           rtlpriv->dm.entry_min_undec_sm_pwdb;
                else
-                       rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb;
-       } else if (dm_digtable->cursta_connectstate == DIG_STA_CONNECT ||
-                  dm_digtable->cursta_connectstate == DIG_STA_BEFORE_CONNECT) {
-               rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb;
-       } else if (dm_digtable->curmultista_connectstate ==
-                  DIG_MULTISTA_CONNECT) {
-               rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                       rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+       } else if (dm_digtable->cursta_cstate == DIG_STA_CONNECT ||
+                  dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT) {
+               rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+       } else if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) {
+               rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
        }
 
        return (u8) rssi_val_min;
@@ -286,37 +285,33 @@ static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw)
 static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+       struct dig_t *digtable = &rtlpriv->dm_digtable;
 
-       if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable->fa_highthresh) {
-               if ((dm_digtable->backoff_val - 2) <
-                   dm_digtable->backoff_val_range_min)
-                       dm_digtable->backoff_val =
-                           dm_digtable->backoff_val_range_min;
+       if (rtlpriv->falsealm_cnt.cnt_all > digtable->fa_highthresh) {
+               if ((digtable->back_val - 2) < digtable->back_range_min)
+                       digtable->back_val = digtable->back_range_min;
                else
-                       dm_digtable->backoff_val -= 2;
-       } else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable->fa_lowthresh) {
-               if ((dm_digtable->backoff_val + 2) >
-                   dm_digtable->backoff_val_range_max)
-                       dm_digtable->backoff_val =
-                           dm_digtable->backoff_val_range_max;
+                       digtable->back_val -= 2;
+       } else if (rtlpriv->falsealm_cnt.cnt_all < digtable->fa_lowthresh) {
+               if ((digtable->back_val + 2) > digtable->back_range_max)
+                       digtable->back_val = digtable->back_range_max;
                else
-                       dm_digtable->backoff_val += 2;
+                       digtable->back_val += 2;
        }
 
-       if ((dm_digtable->rssi_val_min + 10 - dm_digtable->backoff_val) >
-           dm_digtable->rx_gain_range_max)
-               dm_digtable->cur_igvalue = dm_digtable->rx_gain_range_max;
-       else if ((dm_digtable->rssi_val_min + 10 -
-                 dm_digtable->backoff_val) < dm_digtable->rx_gain_range_min)
-               dm_digtable->cur_igvalue = dm_digtable->rx_gain_range_min;
+       if ((digtable->rssi_val_min + 10 - digtable->back_val) >
+           digtable->rx_gain_range_max)
+               digtable->cur_igvalue = digtable->rx_gain_range_max;
+       else if ((digtable->rssi_val_min + 10 -
+                 digtable->back_val) < digtable->rx_gain_range_min)
+               digtable->cur_igvalue = digtable->rx_gain_range_min;
        else
-               dm_digtable->cur_igvalue = dm_digtable->rssi_val_min + 10 -
-                   dm_digtable->backoff_val;
+               digtable->cur_igvalue = digtable->rssi_val_min + 10 -
+                   digtable->back_val;
 
        RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-                "rssi_val_min = %x backoff_val %x\n",
-                dm_digtable->rssi_val_min, dm_digtable->backoff_val);
+                "rssi_val_min = %x back_val %x\n",
+                digtable->rssi_val_min, digtable->back_val);
 
        rtl92c_dm_write_dig(hw);
 }
@@ -327,14 +322,14 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+       long rssi_strength = rtlpriv->dm.entry_min_undec_sm_pwdb;
        bool multi_sta = false;
 
        if (mac->opmode == NL80211_IFTYPE_ADHOC)
                multi_sta = true;
 
        if (!multi_sta ||
-           dm_digtable->cursta_connectstate != DIG_STA_DISCONNECT) {
+           dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
                initialized = false;
                dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
                return;
@@ -345,7 +340,7 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
                rtl92c_dm_write_dig(hw);
        }
 
-       if (dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) {
+       if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) {
                if ((rssi_strength < dm_digtable->rssi_lowthresh) &&
                    (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) {
 
@@ -367,8 +362,8 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
        }
 
        RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-                "curmultista_connectstate = %x dig_ext_port_stage %x\n",
-                dm_digtable->curmultista_connectstate,
+                "curmultista_cstate = %x dig_ext_port_stage %x\n",
+                dm_digtable->curmultista_cstate,
                 dm_digtable->dig_ext_port_stage);
 }
 
@@ -378,15 +373,14 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
        struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
        RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-                "presta_connectstate = %x, cursta_connectstate = %x\n",
-                dm_digtable->presta_connectstate,
-                dm_digtable->cursta_connectstate);
+                "presta_cstate = %x, cursta_cstate = %x\n",
+                dm_digtable->presta_cstate, dm_digtable->cursta_cstate);
 
-       if (dm_digtable->presta_connectstate == dm_digtable->cursta_connectstate
-           || dm_digtable->cursta_connectstate == DIG_STA_BEFORE_CONNECT
-           || dm_digtable->cursta_connectstate == DIG_STA_CONNECT) {
+       if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate ||
+           dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT ||
+           dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
 
-               if (dm_digtable->cursta_connectstate != DIG_STA_DISCONNECT) {
+               if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
                        dm_digtable->rssi_val_min =
                            rtl92c_dm_initial_gain_min_pwdb(hw);
                        rtl92c_dm_ctrl_initgain_by_rssi(hw);
@@ -394,7 +388,7 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
        } else {
                dm_digtable->rssi_val_min = 0;
                dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
-               dm_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT;
+               dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
                dm_digtable->cur_igvalue = 0x20;
                dm_digtable->pre_igvalue = 0;
                rtl92c_dm_write_dig(hw);
@@ -407,7 +401,7 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
-       if (dm_digtable->cursta_connectstate == DIG_STA_CONNECT) {
+       if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
                dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw);
 
                if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
@@ -484,15 +478,15 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
                return;
 
        if (mac->link_state >= MAC80211_LINKED)
-               dm_digtable->cursta_connectstate = DIG_STA_CONNECT;
+               dm_digtable->cursta_cstate = DIG_STA_CONNECT;
        else
-               dm_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
+               dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
 
        rtl92c_dm_initial_gain_sta(hw);
        rtl92c_dm_initial_gain_multi_sta(hw);
        rtl92c_dm_cck_packet_detection_thresh(hw);
 
-       dm_digtable->presta_connectstate = dm_digtable->cursta_connectstate;
+       dm_digtable->presta_cstate = dm_digtable->cursta_cstate;
 
 }
 
@@ -526,9 +520,9 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw)
        struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
-                "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n",
+                "cur_igvalue = 0x%x, pre_igvalue = 0x%x, back_val = %d\n",
                 dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
-                dm_digtable->backoff_val);
+                dm_digtable->back_val);
 
        dm_digtable->cur_igvalue += 2;
        if (dm_digtable->cur_igvalue > 0x3f)
@@ -555,20 +549,18 @@ static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw)
        return;
 
        if (tmpentry_max_pwdb != 0) {
-               rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb =
-                   tmpentry_max_pwdb;
+               rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb;
        } else {
-               rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = 0;
+               rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
        }
 
        if (tmpentry_min_pwdb != 0xff) {
-               rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb =
-                   tmpentry_min_pwdb;
+               rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb;
        } else {
-               rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = 0;
+               rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
        }
 
-       h2c_parameter[2] = (u8) (rtlpriv->dm.undecorated_smoothed_pwdb & 0xFF);
+       h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF);
        h2c_parameter[0] = 0;
 
        rtl92c_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);
@@ -1160,7 +1152,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rate_adaptive *p_ra = &(rtlpriv->ra);
-       u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
+       u32 low_rssi_thresh, high_rssi_thresh;
        struct ieee80211_sta *sta = NULL;
 
        if (is_hal_stop(rtlhal)) {
@@ -1179,35 +1171,33 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
            mac->opmode == NL80211_IFTYPE_STATION) {
                switch (p_ra->pre_ratr_state) {
                case DM_RATR_STA_HIGH:
-                       high_rssithresh_for_ra = 50;
-                       low_rssithresh_for_ra = 20;
+                       high_rssi_thresh = 50;
+                       low_rssi_thresh = 20;
                        break;
                case DM_RATR_STA_MIDDLE:
-                       high_rssithresh_for_ra = 55;
-                       low_rssithresh_for_ra = 20;
+                       high_rssi_thresh = 55;
+                       low_rssi_thresh = 20;
                        break;
                case DM_RATR_STA_LOW:
-                       high_rssithresh_for_ra = 50;
-                       low_rssithresh_for_ra = 25;
+                       high_rssi_thresh = 50;
+                       low_rssi_thresh = 25;
                        break;
                default:
-                       high_rssithresh_for_ra = 50;
-                       low_rssithresh_for_ra = 20;
+                       high_rssi_thresh = 50;
+                       low_rssi_thresh = 20;
                        break;
                }
 
-               if (rtlpriv->dm.undecorated_smoothed_pwdb >
-                   (long)high_rssithresh_for_ra)
+               if (rtlpriv->dm.undec_sm_pwdb > (long)high_rssi_thresh)
                        p_ra->ratr_state = DM_RATR_STA_HIGH;
-               else if (rtlpriv->dm.undecorated_smoothed_pwdb >
-                        (long)low_rssithresh_for_ra)
+               else if (rtlpriv->dm.undec_sm_pwdb > (long)low_rssi_thresh)
                        p_ra->ratr_state = DM_RATR_STA_MIDDLE;
                else
                        p_ra->ratr_state = DM_RATR_STA_LOW;
 
                if (p_ra->pre_ratr_state != p_ra->ratr_state) {
                        RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, "RSSI = %ld\n",
-                                rtlpriv->dm.undecorated_smoothed_pwdb);
+                                rtlpriv->dm.undec_sm_pwdb);
                        RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
                                 "RSSI_LEVEL = %d\n", p_ra->ratr_state);
                        RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
@@ -1315,7 +1305,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
        if (((mac->link_state == MAC80211_NOLINK)) &&
-           (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
                dm_pstable->rssi_val_min = 0;
                RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, "Not connected to any\n");
        }
@@ -1323,20 +1313,19 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
        if (mac->link_state == MAC80211_LINKED) {
                if (mac->opmode == NL80211_IFTYPE_ADHOC) {
                        dm_pstable->rssi_val_min =
-                           rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                           rtlpriv->dm.entry_min_undec_sm_pwdb;
                        RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
                                 "AP Client PWDB = 0x%lx\n",
                                 dm_pstable->rssi_val_min);
                } else {
-                       dm_pstable->rssi_val_min =
-                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       dm_pstable->rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
                        RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
                                 "STA Default Port PWDB = 0x%lx\n",
                                 dm_pstable->rssi_val_min);
                }
        } else {
                dm_pstable->rssi_val_min =
-                   rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                   rtlpriv->dm.entry_min_undec_sm_pwdb;
 
                RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
                         "AP Ext Port PWDB = 0x%lx\n",
@@ -1368,7 +1357,7 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
 
        if (!rtlpriv->dm.dynamic_txpower_enable)
                return;
@@ -1379,7 +1368,7 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
        }
 
        if ((mac->link_state < MAC80211_LINKED) &&
-           (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
                         "Not connected to any\n");
 
@@ -1391,41 +1380,35 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
 
        if (mac->link_state >= MAC80211_LINKED) {
                if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "AP Client PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                } else {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "STA Default Port PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                }
        } else {
-               undecorated_smoothed_pwdb =
-                   rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+               undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
 
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "AP Ext Port PWDB = 0x%lx\n",
-                        undecorated_smoothed_pwdb);
+                        undec_sm_pwdb);
        }
 
-       if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+       if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
-       } else if ((undecorated_smoothed_pwdb <
-                   (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
-                  (undecorated_smoothed_pwdb >=
-                   TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+       } else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+                  (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
 
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n");
-       } else if (undecorated_smoothed_pwdb <
-                  (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+       } else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_NORMAL\n");
@@ -1473,48 +1456,46 @@ u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
        u8 curr_bt_rssi_state = 0x00;
 
        if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
-               undecorated_smoothed_pwdb =
-                                GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
+               undec_sm_pwdb = GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
        } else {
-               if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)
-                       undecorated_smoothed_pwdb = 100;
+               if (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)
+                       undec_sm_pwdb = 100;
                else
-                       undecorated_smoothed_pwdb =
-                               rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
        }
 
        /* Check RSSI to determine HighPower/NormalPower state for
         * BT coexistence. */
-       if (undecorated_smoothed_pwdb >= 67)
+       if (undec_sm_pwdb >= 67)
                curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER);
-       else if (undecorated_smoothed_pwdb < 62)
+       else if (undec_sm_pwdb < 62)
                curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER;
 
        /* Check RSSI to determine AMPDU setting for BT coexistence. */
-       if (undecorated_smoothed_pwdb >= 40)
+       if (undec_sm_pwdb >= 40)
                curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF);
-       else if (undecorated_smoothed_pwdb <= 32)
+       else if (undec_sm_pwdb <= 32)
                curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF;
 
        /* Marked RSSI state. It will be used to determine BT coexistence
         * setting later. */
-       if (undecorated_smoothed_pwdb < 35)
+       if (undec_sm_pwdb < 35)
                curr_bt_rssi_state |=  BT_RSSI_STATE_SPECIAL_LOW;
        else
                curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW);
 
        /* Set Tx Power according to BT status. */
-       if (undecorated_smoothed_pwdb >= 30)
+       if (undec_sm_pwdb >= 30)
                curr_bt_rssi_state |=  BT_RSSI_STATE_TXPOWER_LOW;
-       else if (undecorated_smoothed_pwdb < 25)
+       else if (undec_sm_pwdb < 25)
                curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW);
 
        /* Check BT state related to BT_Idle in B/G mode. */
-       if (undecorated_smoothed_pwdb < 15)
+       if (undec_sm_pwdb < 15)
                curr_bt_rssi_state |=  BT_RSSI_STATE_BG_EDCA_LOW;
        else
                curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW);
index cdcad7d..1d5d360 100644 (file)
@@ -34,9 +34,6 @@
 #include "dm_common.h"
 #include "phy_common.h"
 
-/* Define macro to shorten lines */
-#define MCS_TXPWR      mcs_txpwrlevel_origoffset
-
 u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -138,13 +135,13 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
                rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
                                                 BIT(8));
        if (rfpi_enable)
-               retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi,
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
                                         BLSSIREADBACKDATA);
        else
-               retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
                                         BLSSIREADBACKDATA);
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
-                rfpath, pphyreg->rflssi_readback, retvalue);
+                rfpath, pphyreg->rf_rb, retvalue);
        return retvalue;
 }
 EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read);
@@ -290,11 +287,11 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
        else
                return;
 
-       rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index] = data;
+       rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;
        RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
                 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
                 rtlphy->pwrgroup_cnt, index,
-                rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][index]);
+                rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);
 
        if (index == 13)
                rtlphy->pwrgroup_cnt++;
@@ -374,14 +371,10 @@ void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
        rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
 
-       rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control =
-           RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control =
-           RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control =
-           RFPGA0_XCD_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control =
-           RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
 
        rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
        rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
@@ -393,47 +386,33 @@ void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
        rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
 
-       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance =
-           ROFDM0_XARXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance =
-           ROFDM0_XBRXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance =
-           ROFDM0_XCRXIQIMBANLANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance =
-           ROFDM0_XDRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
 
        rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
        rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
        rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
        rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
 
-       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance =
-           ROFDM0_XATXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance =
-           ROFDM0_XBTXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance =
-           ROFDM0_XCTXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance =
-           ROFDM0_XDTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
 
        rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
        rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
        rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
        rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
 
-       rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback =
-           RFPGA0_XA_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback =
-           RFPGA0_XB_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback =
-           RFPGA0_XC_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback =
-           RFPGA0_XD_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
 
-       rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi =
-           TRANSCEIVEA_HSPI_READBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi =
-           TRANSCEIVEB_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
 
 }
 EXPORT_SYMBOL(_rtl92c_phy_init_bb_rf_register_definition);
@@ -724,6 +703,26 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(rtl92c_phy_sw_chnl);
 
+static void _rtl92c_phy_sw_rf_setting(struct ieee80211_hw *hw, u8 channel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
+               if (channel == 6 && rtlphy->current_chan_bw ==
+                   HT_CHANNEL_WIDTH_20)
+                       rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
+                                     0x00255);
+               else{
+                       u32 backupRF0x1A = (u32)rtl_get_rfreg(hw, RF90_PATH_A,
+                                           RF_RX_G1, RFREG_OFFSET_MASK);
+                       rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
+                                     backupRF0x1A);
+               }
+       }
+}
+
 static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
                                             u32 cmdtableidx, u32 cmdtablesz,
                                             enum swchnlcmd_id cmdid,
@@ -837,6 +836,7 @@ bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
                                              currentcmd->para1,
                                              RFREG_OFFSET_MASK,
                                              rtlphy->rfreg_chnlval[rfpath]);
+                       _rtl92c_phy_sw_rf_setting(hw, channel);
                        }
                        break;
                default:
index 2925094..3cfa1bb 100644 (file)
        LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
 
 #define CHIP_VER_B                     BIT(4)
+#define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3)
+#define CHIP_BONDING_92C_1T2R          0x1
+#define RF_TYPE_1T2R                   BIT(1)
 #define CHIP_92C_BITMASK               BIT(0)
 #define CHIP_UNKNOWN                   BIT(7)
 #define CHIP_92C_1T2R                  0x03
index 27b3af8..74f9c08 100644 (file)
@@ -41,7 +41,7 @@ void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
 
        if (!rtlpriv->dm.dynamic_txpower_enable)
                return;
@@ -52,7 +52,7 @@ void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)
        }
 
        if ((mac->link_state < MAC80211_LINKED) &&
-           (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
                         "Not connected to any\n");
 
@@ -64,41 +64,35 @@ void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)
 
        if (mac->link_state >= MAC80211_LINKED) {
                if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "AP Client PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                } else {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "STA Default Port PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                }
        } else {
-               undecorated_smoothed_pwdb =
-                   rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+               undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
 
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "AP Ext Port PWDB = 0x%lx\n",
-                        undecorated_smoothed_pwdb);
+                        undec_sm_pwdb);
        }
 
-       if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+       if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
-       } else if ((undecorated_smoothed_pwdb <
-                   (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
-                  (undecorated_smoothed_pwdb >=
-                   TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+       } else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+                  (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
 
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n");
-       } else if (undecorated_smoothed_pwdb <
-                  (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+       } else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_NORMAL\n");
index 86d73b3..d1f34f6 100644 (file)
@@ -896,7 +896,6 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-       static bool iqk_initialized; /* initialized to false */
        bool rtstatus = true;
        bool is92c;
        int err;
@@ -921,9 +920,28 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
 
        rtlhal->last_hmeboxnum = 0;
        rtl92c_phy_mac_config(hw);
+       /* because last function modify RCR, so we update
+        * rcr var here, or TP will unstable for receive_config
+        * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+        * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252*/
+       rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR);
+       rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+       rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
        rtl92c_phy_bb_config(hw);
        rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
        rtl92c_phy_rf_config(hw);
+       if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
+           !IS_92C_SERIAL(rtlhal->version)) {
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, 0x30255);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G2, MASKDWORD, 0x50a00);
+       } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x0C, MASKDWORD, 0x894AE);
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x0A, MASKDWORD, 0x1AF31);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_IPA, MASKDWORD, 0x8F425);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_SYN_G2, MASKDWORD, 0x4F200);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK1, MASKDWORD, 0x44053);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK2, MASKDWORD, 0x80201);
+       }
        rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
                                                 RF_CHNLBW, RFREG_OFFSET_MASK);
        rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1,
@@ -945,11 +963,11 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
 
        if (ppsc->rfpwr_state == ERFON) {
                rtl92c_phy_set_rfpath_switch(hw, 1);
-               if (iqk_initialized) {
+               if (rtlphy->iqk_initialized) {
                        rtl92c_phy_iq_calibrate(hw, true);
                } else {
                        rtl92c_phy_iq_calibrate(hw, false);
-                       iqk_initialized = true;
+                       rtlphy->iqk_initialized = true;
                }
 
                rtl92c_dm_check_txpower_tracking(hw);
@@ -1004,6 +1022,13 @@ static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw)
                                   ? CHIP_VENDOR_UMC_B_CUT : CHIP_UNKNOWN) |
                                   CHIP_VENDOR_UMC));
                }
+               if (IS_92C_SERIAL(version)) {
+                       value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM);
+                       version = (enum version_8192c)(version |
+                                  ((CHIP_BONDING_IDENTIFIER(value32)
+                                  == CHIP_BONDING_92C_1T2R) ?
+                                  RF_TYPE_1T2R : 0));
+               }
        }
 
        switch (version) {
@@ -1019,12 +1044,30 @@ static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw)
        case VERSION_A_CHIP_88C:
                versionid = "A_CHIP_88C";
                break;
+       case VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT:
+               versionid = "A_CUT_92C_1T2R";
+               break;
+       case VERSION_NORMAL_UMC_CHIP_92C_A_CUT:
+               versionid = "A_CUT_92C";
+               break;
+       case VERSION_NORMAL_UMC_CHIP_88C_A_CUT:
+               versionid = "A_CUT_88C";
+               break;
+       case VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT:
+               versionid = "B_CUT_92C_1T2R";
+               break;
+       case VERSION_NORMAL_UMC_CHIP_92C_B_CUT:
+               versionid = "B_CUT_92C";
+               break;
+       case VERSION_NORMAL_UMC_CHIP_88C_B_CUT:
+               versionid = "B_CUT_88C";
+               break;
        default:
                versionid = "Unknown. Bug?";
                break;
        }
 
-       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
                 "Chip Version ID: %s\n", versionid);
 
        switch (version & 0x3) {
@@ -1197,6 +1240,7 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
        u8 u1b_tmp;
        u32 u4b_tmp;
 
@@ -1225,7 +1269,8 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
        rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790);
        rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080);
        rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80);
-       rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23);
+       if (!IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+               rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23);
        if (rtlpcipriv->bt_coexist.bt_coexistence) {
                u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL);
                u4b_tmp |= 0x03824800;
@@ -1254,6 +1299,9 @@ void rtl92ce_card_disable(struct ieee80211_hw *hw)
                rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
        RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
        _rtl92ce_poweroff_adapter(hw);
+
+       /* after power off we should do iqk again */
+       rtlpriv->phy.iqk_initialized = false;
 }
 
 void rtl92ce_interrupt_recognized(struct ieee80211_hw *hw,
@@ -1355,9 +1403,9 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
                        tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i];
                else
                        tempval = EEPROM_DEFAULT_HT40_2SDIFF;
-               rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] =
+               rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_A][i] =
                    (tempval & 0xf);
-               rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] =
+               rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_B][i] =
                    ((tempval & 0xf0) >> 4);
        }
 
@@ -1381,7 +1429,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
                                "RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
                                rf_path, i,
                                rtlefuse->
-                               eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]);
+                               eprom_chnl_txpwr_ht40_2sdf[rf_path][i]);
 
        for (rf_path = 0; rf_path < 2; rf_path++) {
                for (i = 0; i < 14; i++) {
@@ -1396,14 +1444,14 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
                        if ((rtlefuse->
                             eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] -
                             rtlefuse->
-                            eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index])
+                            eprom_chnl_txpwr_ht40_2sdf[rf_path][index])
                            > 0) {
                                rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
                                    rtlefuse->
                                    eeprom_chnlarea_txpwr_ht40_1s[rf_path]
                                    [index] -
                                    rtlefuse->
-                                   eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path]
+                                   eprom_chnl_txpwr_ht40_2sdf[rf_path]
                                    [index];
                        } else {
                                rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0;
@@ -1912,16 +1960,16 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
                        ratr_bitmap &= 0x0f0ff0ff;
                break;
        }
+       sta_entry->ratr_index = ratr_index;
+
        RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
                 "ratr_bitmap :%x\n", ratr_bitmap);
        *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
                                     (ratr_index << 28);
        rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
        RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
-                "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x\n",
-                ratr_index, ratr_bitmap,
-                rate_mask[0], rate_mask[1], rate_mask[2], rate_mask[3],
-                rate_mask[4]);
+                "Rate_index:%x, ratr_val:%x, %5phC\n",
+                ratr_index, ratr_bitmap, rate_mask);
        rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
 
        if (macid != 0)
@@ -2176,7 +2224,7 @@ static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw)
 
        if (rtlpcipriv->bt_coexist.reg_bt_iso == 2)
                rtlpcipriv->bt_coexist.bt_ant_isolation =
-                       rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation;
+                       rtlpcipriv->bt_coexist.eeprom_bt_ant_isol;
        else
                rtlpcipriv->bt_coexist.bt_ant_isolation =
                        rtlpcipriv->bt_coexist.reg_bt_iso;
@@ -2207,23 +2255,22 @@ void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
                                              bool auto_load_fail, u8 *hwinfo)
 {
        struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-       u8 value;
+       u8 val;
 
        if (!auto_load_fail) {
                rtlpcipriv->bt_coexist.eeprom_bt_coexist =
                                        ((hwinfo[RF_OPTION1] & 0xe0) >> 5);
-               value = hwinfo[RF_OPTION4];
-               rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1);
-               rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1);
-               rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation =
-                                                        ((value & 0x10) >> 4);
+               val = hwinfo[RF_OPTION4];
+               rtlpcipriv->bt_coexist.eeprom_bt_type = ((val & 0xe) >> 1);
+               rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (val & 0x1);
+               rtlpcipriv->bt_coexist.eeprom_bt_ant_isol = ((val & 0x10) >> 4);
                rtlpcipriv->bt_coexist.eeprom_bt_radio_shared =
-                                                        ((value & 0x20) >> 5);
+                                                        ((val & 0x20) >> 5);
        } else {
                rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0;
                rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE;
                rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2;
-               rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0;
+               rtlpcipriv->bt_coexist.eeprom_bt_ant_isol = 0;
                rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;
        }
 
index 88deae6..73262ca 100644 (file)
@@ -82,6 +82,8 @@ bool rtl92c_phy_mac_config(struct ieee80211_hw *hw)
 
        if (is92c)
                rtl_write_byte(rtlpriv, 0x14, 0x71);
+       else
+               rtl_write_byte(rtlpriv, 0x04CA, 0x0A);
        return rtstatus;
 }
 
index 54c7614..a9c406f 100644 (file)
@@ -97,15 +97,12 @@ void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
                }
 
                if (rtlefuse->eeprom_regulatory == 0) {
-                       tmpval =
-                           (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
-                           (rtlphy->mcs_txpwrlevel_origoffset[0][7] <<
-                            8);
+                       tmpval = (rtlphy->mcs_offset[0][6]) +
+                           (rtlphy->mcs_offset[0][7] << 8);
                        tx_agc[RF90_PATH_A] += tmpval;
 
-                       tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
-                                (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
-                                24);
+                       tmpval = (rtlphy->mcs_offset[0][14]) +
+                                (rtlphy->mcs_offset[0][15] << 24);
                        tx_agc[RF90_PATH_B] += tmpval;
                }
        }
@@ -209,8 +206,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                case 0:
                        chnlgroup = 0;
 
-                       writeVal =
-                           rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index +
+                       writeVal = rtlphy->mcs_offset[chnlgroup][index +
                            (rf ? 8 : 0)]
                            + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
 
@@ -240,8 +236,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                                                chnlgroup++;
                                }
 
-                               writeVal =
-                                   rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+                               writeVal = rtlphy->mcs_offset[chnlgroup]
                                    [index + (rf ? 8 : 0)] + ((index < 2) ?
                                                              powerBase0[rf] :
                                                              powerBase1[rf]);
@@ -276,8 +271,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                                                                    1]);
                        }
                        for (i = 0; i < 4; i++) {
-                               pwr_diff_limit[i] =
-                                   (u8) ((rtlphy->mcs_txpwrlevel_origoffset
+                               pwr_diff_limit[i] = (u8) ((rtlphy->mcs_offset
                                          [chnlgroup][index +
                                          (rf ? 8 : 0)] & (0x7f << (i * 8))) >>
                                          (i * 8));
@@ -317,8 +311,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                        break;
                default:
                        chnlgroup = 0;
-                       writeVal =
-                           rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+                       writeVal = rtlphy->mcs_offset[chnlgroup]
                            [index + (rf ? 8 : 0)]
                            + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
 
index ea2e1bd..60451ee 100644 (file)
@@ -162,12 +162,10 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
 
        /* request fw */
        if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
-           !IS_92C_SERIAL(rtlhal->version)) {
+           !IS_92C_SERIAL(rtlhal->version))
                rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin";
-       } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
+       else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
                rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
-               pr_info("****** This B_CUT device may not work with kernels 3.6 and earlier\n");
-       }
 
        rtlpriv->max_fw_size = 0x4000;
        pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
index 390d6d4..d7e1f0a 100644 (file)
@@ -127,11 +127,11 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct phy_sts_cck_8192s_t *cck_buf;
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
        s8 rx_pwr_all = 0, rx_pwr[4];
        u8 evm, pwdb_all, rf_rx_num = 0;
        u8 i, max_spatial_stream;
        u32 rssi, total_rssi = 0;
-       bool in_powersavemode = false;
        bool is_cck_rate;
 
        is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
@@ -140,14 +140,14 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
        pstats->is_cck = is_cck_rate;
        pstats->packet_beacon = packet_beacon;
        pstats->is_cck = is_cck_rate;
-       pstats->rx_mimo_signalquality[0] = -1;
-       pstats->rx_mimo_signalquality[1] = -1;
+       pstats->rx_mimo_sig_qual[0] = -1;
+       pstats->rx_mimo_sig_qual[1] = -1;
 
        if (is_cck_rate) {
                u8 report, cck_highpwr;
                cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
 
-               if (!in_powersavemode)
+               if (ppsc->rfpwr_state == ERFON)
                        cck_highpwr = (u8) rtl_get_bbreg(hw,
                                                 RFPGA0_XA_HSSIPARAMETER2,
                                                 BIT(9));
@@ -211,8 +211,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
                        }
 
                        pstats->signalquality = sq;
-                       pstats->rx_mimo_signalquality[0] = sq;
-                       pstats->rx_mimo_signalquality[1] = -1;
+                       pstats->rx_mimo_sig_qual[0] = sq;
+                       pstats->rx_mimo_sig_qual[1] = -1;
                }
        } else {
                rtlpriv->dm.rfpath_rxenable[0] =
@@ -251,8 +251,7 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
                                if (i == 0)
                                        pstats->signalquality =
                                            (u8) (evm & 0xff);
-                               pstats->rx_mimo_signalquality[i] =
-                                   (u8) (evm & 0xff);
+                               pstats->rx_mimo_sig_qual[i] = (u8) (evm & 0xff);
                        }
                }
        }
@@ -362,36 +361,31 @@ static void _rtl92ce_process_pwdb(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
 
        if (mac->opmode == NL80211_IFTYPE_ADHOC) {
                return;
        } else {
-               undecorated_smoothed_pwdb =
-                   rtlpriv->dm.undecorated_smoothed_pwdb;
+               undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
        }
 
        if (pstats->packet_toself || pstats->packet_beacon) {
-               if (undecorated_smoothed_pwdb < 0)
-                       undecorated_smoothed_pwdb = pstats->rx_pwdb_all;
+               if (undec_sm_pwdb < 0)
+                       undec_sm_pwdb = pstats->rx_pwdb_all;
 
-               if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) {
-                       undecorated_smoothed_pwdb =
-                           (((undecorated_smoothed_pwdb) *
+               if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
+                       undec_sm_pwdb = (((undec_sm_pwdb) *
                              (RX_SMOOTH_FACTOR - 1)) +
                             (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
 
-                       undecorated_smoothed_pwdb = undecorated_smoothed_pwdb
-                           + 1;
+                       undec_sm_pwdb += 1;
                } else {
-                       undecorated_smoothed_pwdb =
-                           (((undecorated_smoothed_pwdb) *
+                       undec_sm_pwdb = (((undec_sm_pwdb) *
                              (RX_SMOOTH_FACTOR - 1)) +
                             (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
                }
 
-               rtlpriv->dm.undecorated_smoothed_pwdb =
-                   undecorated_smoothed_pwdb;
+               rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
                _rtl92ce_update_rxsignalstatistics(hw, pstats);
        }
 }
@@ -438,15 +432,14 @@ static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw,
                        for (n_spatialstream = 0; n_spatialstream < 2;
                             n_spatialstream++) {
                                if (pstats->
-                                   rx_mimo_signalquality[n_spatialstream] !=
-                                   -1) {
+                                   rx_mimo_sig_qual[n_spatialstream] != -1) {
                                        if (rtlpriv->stats.
                                            rx_evm_percentage[n_spatialstream]
                                            == 0) {
                                                rtlpriv->stats.
                                                   rx_evm_percentage
                                                   [n_spatialstream] =
-                                                  pstats->rx_mimo_signalquality
+                                                  pstats->rx_mimo_sig_qual
                                                   [n_spatialstream];
                                        }
 
@@ -456,8 +449,7 @@ static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw,
                                              stats.rx_evm_percentage
                                              [n_spatialstream] *
                                              (RX_SMOOTH_FACTOR - 1)) +
-                                            (pstats->
-                                             rx_mimo_signalquality
+                                            (pstats->rx_mimo_sig_qual
                                              [n_spatialstream] * 1)) /
                                            (RX_SMOOTH_FACTOR);
                                }
index 6fd39ea..16a0b9e 100644 (file)
@@ -39,7 +39,7 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
 
        if (!rtlpriv->dm.dynamic_txpower_enable)
                return;
@@ -50,7 +50,7 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)
        }
 
        if ((mac->link_state < MAC80211_LINKED) &&
-           (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
                         "Not connected to any\n");
 
@@ -62,41 +62,35 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)
 
        if (mac->link_state >= MAC80211_LINKED) {
                if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "AP Client PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                } else {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "STA Default Port PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                }
        } else {
-               undecorated_smoothed_pwdb =
-                   rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+               undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
 
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "AP Ext Port PWDB = 0x%lx\n",
-                        undecorated_smoothed_pwdb);
+                        undec_sm_pwdb);
        }
 
-       if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+       if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
-       } else if ((undecorated_smoothed_pwdb <
-                   (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
-                  (undecorated_smoothed_pwdb >=
-                   TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+       } else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+                  (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
 
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n");
-       } else if (undecorated_smoothed_pwdb <
-                  (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+       } else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
                rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_NORMAL\n");
index 4bbb711..b1ccff4 100644 (file)
@@ -152,9 +152,9 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
                        tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i];
                else
                        tempval = EEPROM_DEFAULT_HT40_2SDIFF;
-               rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] =
+               rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_A][i] =
                    (tempval & 0xf);
-               rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] =
+               rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_B][i] =
                    ((tempval & 0xf0) >> 4);
        }
        for (rf_path = 0; rf_path < 2; rf_path++)
@@ -177,7 +177,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
                                "RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
                                rf_path, i,
                                rtlefuse->
-                               eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]);
+                               eprom_chnl_txpwr_ht40_2sdf[rf_path][i]);
        for (rf_path = 0; rf_path < 2; rf_path++) {
                for (i = 0; i < 14; i++) {
                        index = _rtl92c_get_chnl_group((u8) i);
@@ -189,13 +189,13 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
                        if ((rtlefuse->
                             eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] -
                             rtlefuse->
-                            eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index])
+                            eprom_chnl_txpwr_ht40_2sdf[rf_path][index])
                            > 0) {
                                rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
                                    rtlefuse->
                                    eeprom_chnlarea_txpwr_ht40_1s[rf_path]
                                    [index] - rtlefuse->
-                                   eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path]
+                                   eprom_chnl_txpwr_ht40_2sdf[rf_path]
                                    [index];
                        } else {
                                rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0;
@@ -2169,10 +2169,8 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
                                      ratr_index << 28);
        rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
        RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
-                "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x\n",
-                ratr_index, ratr_bitmap,
-                rate_mask[0], rate_mask[1], rate_mask[2], rate_mask[3],
-                rate_mask[4]);
+                "Rate_index:%x, ratr_val:%x, %5phC\n",
+                ratr_index, ratr_bitmap, rate_mask);
        rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
 }
 
index 7e91c76..32ff959 100644 (file)
@@ -46,7 +46,7 @@
 
 #define LINK_Q ui_link_quality
 #define RX_EVM rx_evm_percentage
-#define RX_SIGQ        rx_mimo_signalquality
+#define RX_SIGQ        rx_mimo_sig_qual
 
 
 void rtl92c_read_chip_version(struct ieee80211_hw *hw)
@@ -982,32 +982,27 @@ static void _rtl92c_process_pwdb(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb = 0;
+       long undec_sm_pwdb = 0;
 
        if (mac->opmode == NL80211_IFTYPE_ADHOC) {
                return;
        } else {
-               undecorated_smoothed_pwdb =
-                   rtlpriv->dm.undecorated_smoothed_pwdb;
+               undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
        }
        if (pstats->packet_toself || pstats->packet_beacon) {
-               if (undecorated_smoothed_pwdb < 0)
-                       undecorated_smoothed_pwdb = pstats->rx_pwdb_all;
-               if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) {
-                       undecorated_smoothed_pwdb =
-                           (((undecorated_smoothed_pwdb) *
+               if (undec_sm_pwdb < 0)
+                       undec_sm_pwdb = pstats->rx_pwdb_all;
+               if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
+                       undec_sm_pwdb = (((undec_sm_pwdb) *
                              (RX_SMOOTH_FACTOR - 1)) +
                             (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-                       undecorated_smoothed_pwdb = undecorated_smoothed_pwdb
-                           + 1;
+                       undec_sm_pwdb += 1;
                } else {
-                       undecorated_smoothed_pwdb =
-                           (((undecorated_smoothed_pwdb) *
+                       undec_sm_pwdb = (((undec_sm_pwdb) *
                              (RX_SMOOTH_FACTOR - 1)) +
                             (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
                }
-               rtlpriv->dm.undecorated_smoothed_pwdb =
-                   undecorated_smoothed_pwdb;
+               rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
                _rtl92c_update_rxsignalstatistics(hw, pstats);
        }
 }
index 506b9a0..953f1a0 100644 (file)
@@ -115,15 +115,11 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
                                    (ppowerlevel[idx1] << 24);
                        }
                        if (rtlefuse->eeprom_regulatory == 0) {
-                               tmpval = (rtlphy->mcs_txpwrlevel_origoffset
-                                       [0][6]) +
-                                       (rtlphy->mcs_txpwrlevel_origoffset
-                                       [0][7] <<  8);
+                               tmpval = (rtlphy->mcs_offset[0][6]) +
+                                       (rtlphy->mcs_offset[0][7] <<  8);
                                tx_agc[RF90_PATH_A] += tmpval;
-                               tmpval = (rtlphy->mcs_txpwrlevel_origoffset
-                                       [0][14]) +
-                                       (rtlphy->mcs_txpwrlevel_origoffset
-                                       [0][15] << 24);
+                               tmpval = (rtlphy->mcs_offset[0][14]) +
+                                       (rtlphy->mcs_offset[0][15] << 24);
                                tx_agc[RF90_PATH_B] += tmpval;
                        }
                }
@@ -215,7 +211,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                switch (rtlefuse->eeprom_regulatory) {
                case 0:
                        chnlgroup = 0;
-                       writeVal = rtlphy->mcs_txpwrlevel_origoffset
+                       writeVal = rtlphy->mcs_offset
                            [chnlgroup][index + (rf ? 8 : 0)]
                            + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
                        RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
@@ -238,8 +234,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                                else
                                        chnlgroup += 4;
                        }
-                       writeVal = rtlphy->mcs_txpwrlevel_origoffset
-                                       [chnlgroup][index +
+                       writeVal = rtlphy->mcs_offset[chnlgroup][index +
                                        (rf ? 8 : 0)] +
                                        ((index < 2) ? powerBase0[rf] :
                                        powerBase1[rf]);
@@ -271,8 +266,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                                        [channel - 1]);
                        }
                        for (i = 0; i < 4; i++) {
-                               pwr_diff_limit[i] =
-                                   (u8) ((rtlphy->mcs_txpwrlevel_origoffset
+                               pwr_diff_limit[i] = (u8) ((rtlphy->mcs_offset
                                    [chnlgroup][index + (rf ? 8 : 0)]
                                    & (0x7f << (i * 8))) >> (i * 8));
                                if (rtlphy->current_chan_bw ==
@@ -306,7 +300,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                        break;
                default:
                        chnlgroup = 0;
-                       writeVal = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+                       writeVal = rtlphy->mcs_offset[chnlgroup]
                                   [index + (rf ? 8 : 0)] + ((index < 2) ?
                                   powerBase0[rf] : powerBase1[rf]);
                        RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
index ed868c3..fd8df23 100644 (file)
@@ -35,7 +35,7 @@
 #include "dm.h"
 #include "fw.h"
 
-#define UNDEC_SM_PWDB  entry_min_undecoratedsmoothed_pwdb
+#define UNDEC_SM_PWDB  entry_min_undec_sm_pwdb
 
 static const u32 ofdmswing_table[OFDM_TABLE_SIZE_92D] = {
        0x7f8001fe,             /* 0, +6.0dB */
@@ -164,18 +164,18 @@ static void rtl92d_dm_diginit(struct ieee80211_hw *hw)
        de_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
        de_digtable->cur_igvalue = 0x20;
        de_digtable->pre_igvalue = 0x0;
-       de_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
-       de_digtable->presta_connectstate = DIG_STA_DISCONNECT;
-       de_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT;
+       de_digtable->cursta_cstate = DIG_STA_DISCONNECT;
+       de_digtable->presta_cstate = DIG_STA_DISCONNECT;
+       de_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
        de_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
        de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
        de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
        de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
        de_digtable->rx_gain_range_max = DM_DIG_FA_UPPER;
        de_digtable->rx_gain_range_min = DM_DIG_FA_LOWER;
-       de_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT;
-       de_digtable->backoff_val_range_max = DM_DIG_BACKOFF_MAX;
-       de_digtable->backoff_val_range_min = DM_DIG_BACKOFF_MIN;
+       de_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+       de_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
+       de_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
        de_digtable->pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI;
        de_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
        de_digtable->large_fa_hit = 0;
@@ -273,35 +273,34 @@ static void rtl92d_dm_find_minimum_rssi(struct ieee80211_hw *hw)
        /* Determine the minimum RSSI  */
        if ((mac->link_state < MAC80211_LINKED) &&
            (rtlpriv->dm.UNDEC_SM_PWDB == 0)) {
-               de_digtable->min_undecorated_pwdb_for_dm = 0;
+               de_digtable->min_undec_pwdb_for_dm = 0;
                RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
                         "Not connected to any\n");
        }
        if (mac->link_state >= MAC80211_LINKED) {
                if (mac->opmode == NL80211_IFTYPE_AP ||
                    mac->opmode == NL80211_IFTYPE_ADHOC) {
-                       de_digtable->min_undecorated_pwdb_for_dm =
+                       de_digtable->min_undec_pwdb_for_dm =
                            rtlpriv->dm.UNDEC_SM_PWDB;
                        RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
                                 "AP Client PWDB = 0x%lx\n",
                                 rtlpriv->dm.UNDEC_SM_PWDB);
                } else {
-                       de_digtable->min_undecorated_pwdb_for_dm =
-                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       de_digtable->min_undec_pwdb_for_dm =
+                           rtlpriv->dm.undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
                                 "STA Default Port PWDB = 0x%x\n",
-                                de_digtable->min_undecorated_pwdb_for_dm);
+                                de_digtable->min_undec_pwdb_for_dm);
                }
        } else {
-               de_digtable->min_undecorated_pwdb_for_dm =
-                   rtlpriv->dm.UNDEC_SM_PWDB;
+               de_digtable->min_undec_pwdb_for_dm = rtlpriv->dm.UNDEC_SM_PWDB;
                RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
                         "AP Ext Port or disconnect PWDB = 0x%x\n",
-                        de_digtable->min_undecorated_pwdb_for_dm);
+                        de_digtable->min_undec_pwdb_for_dm);
        }
 
        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n",
-                de_digtable->min_undecorated_pwdb_for_dm);
+                de_digtable->min_undec_pwdb_for_dm);
 }
 
 static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
@@ -310,16 +309,16 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
        struct dig_t *de_digtable = &rtlpriv->dm_digtable;
        unsigned long flag = 0;
 
-       if (de_digtable->cursta_connectstate == DIG_STA_CONNECT) {
+       if (de_digtable->cursta_cstate == DIG_STA_CONNECT) {
                if (de_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) {
-                       if (de_digtable->min_undecorated_pwdb_for_dm <= 25)
+                       if (de_digtable->min_undec_pwdb_for_dm <= 25)
                                de_digtable->cur_cck_pd_state =
                                                         CCK_PD_STAGE_LOWRSSI;
                        else
                                de_digtable->cur_cck_pd_state =
                                                         CCK_PD_STAGE_HIGHRSSI;
                } else {
-                       if (de_digtable->min_undecorated_pwdb_for_dm <= 20)
+                       if (de_digtable->min_undec_pwdb_for_dm <= 20)
                                de_digtable->cur_cck_pd_state =
                                                         CCK_PD_STAGE_LOWRSSI;
                        else
@@ -342,7 +341,7 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
                de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state;
        }
        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CurSTAConnectState=%s\n",
-                de_digtable->cursta_connectstate == DIG_STA_CONNECT ?
+                de_digtable->cursta_cstate == DIG_STA_CONNECT ?
                 "DIG_STA_CONNECT " : "DIG_STA_DISCONNECT");
        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CCKPDStage=%s\n",
                 de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI ?
@@ -358,9 +357,9 @@ void rtl92d_dm_write_dig(struct ieee80211_hw *hw)
        struct dig_t *de_digtable = &rtlpriv->dm_digtable;
 
        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
-                "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n",
+                "cur_igvalue = 0x%x, pre_igvalue = 0x%x, back_val = %d\n",
                 de_digtable->cur_igvalue, de_digtable->pre_igvalue,
-                de_digtable->backoff_val);
+                de_digtable->back_val);
        if (de_digtable->dig_enable_flag == false) {
                RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "DIG is disabled\n");
                de_digtable->pre_igvalue = 0x17;
@@ -382,13 +381,13 @@ static void rtl92d_early_mode_enabled(struct rtl_priv *rtlpriv)
        if ((rtlpriv->mac80211.link_state >= MAC80211_LINKED) &&
            (rtlpriv->mac80211.vendor == PEER_CISCO)) {
                RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "IOT_PEER = CISCO\n");
-               if (de_digtable->last_min_undecorated_pwdb_for_dm >= 50
-                   && de_digtable->min_undecorated_pwdb_for_dm < 50) {
+               if (de_digtable->last_min_undec_pwdb_for_dm >= 50
+                   && de_digtable->min_undec_pwdb_for_dm < 50) {
                        rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x00);
                        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
                                 "Early Mode Off\n");
-               } else if (de_digtable->last_min_undecorated_pwdb_for_dm <= 55 &&
-                          de_digtable->min_undecorated_pwdb_for_dm > 55) {
+               } else if (de_digtable->last_min_undec_pwdb_for_dm <= 55 &&
+                          de_digtable->min_undec_pwdb_for_dm > 55) {
                        rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x0f);
                        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
                                 "Early Mode On\n");
@@ -409,8 +408,8 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "==>\n");
        if (rtlpriv->rtlhal.earlymode_enable) {
                rtl92d_early_mode_enabled(rtlpriv);
-               de_digtable->last_min_undecorated_pwdb_for_dm =
-                                de_digtable->min_undecorated_pwdb_for_dm;
+               de_digtable->last_min_undec_pwdb_for_dm =
+                                de_digtable->min_undec_pwdb_for_dm;
        }
        if (!rtlpriv->dm.dm_initialgain_enable)
                return;
@@ -428,9 +427,9 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
        RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "progress\n");
        /* Decide the current status and if modify initial gain or not */
        if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
-               de_digtable->cursta_connectstate = DIG_STA_CONNECT;
+               de_digtable->cursta_cstate = DIG_STA_CONNECT;
        else
-               de_digtable->cursta_connectstate = DIG_STA_DISCONNECT;
+               de_digtable->cursta_cstate = DIG_STA_DISCONNECT;
 
        /* adjust initial gain according to false alarm counter */
        if (falsealm_cnt->cnt_all < DM_DIG_FA_TH0)
@@ -522,7 +521,7 @@ static void rtl92d_dm_dynamic_txpower(struct ieee80211_hw *hw)
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
 
        if ((!rtlpriv->dm.dynamic_txpower_enable)
            || rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
@@ -539,62 +538,62 @@ static void rtl92d_dm_dynamic_txpower(struct ieee80211_hw *hw)
        }
        if (mac->link_state >= MAC80211_LINKED) {
                if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-                       undecorated_smoothed_pwdb =
+                       undec_sm_pwdb =
                            rtlpriv->dm.UNDEC_SM_PWDB;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "IBSS Client PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                } else {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       undec_sm_pwdb =
+                           rtlpriv->dm.undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "STA Default Port PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                }
        } else {
-               undecorated_smoothed_pwdb =
+               undec_sm_pwdb =
                    rtlpriv->dm.UNDEC_SM_PWDB;
 
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "AP Ext Port PWDB = 0x%lx\n",
-                        undecorated_smoothed_pwdb);
+                        undec_sm_pwdb);
        }
        if (rtlhal->current_bandtype == BAND_ON_5G) {
-               if (undecorated_smoothed_pwdb >= 0x33) {
+               if (undec_sm_pwdb >= 0x33) {
                        rtlpriv->dm.dynamic_txhighpower_lvl =
                                                 TXHIGHPWRLEVEL_LEVEL2;
                        RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD,
                                 "5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n");
-               } else if ((undecorated_smoothed_pwdb < 0x33)
-                          && (undecorated_smoothed_pwdb >= 0x2b)) {
+               } else if ((undec_sm_pwdb < 0x33)
+                          && (undec_sm_pwdb >= 0x2b)) {
                        rtlpriv->dm.dynamic_txhighpower_lvl =
                                                 TXHIGHPWRLEVEL_LEVEL1;
                        RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD,
                                 "5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n");
-               } else if (undecorated_smoothed_pwdb < 0x2b) {
+               } else if (undec_sm_pwdb < 0x2b) {
                        rtlpriv->dm.dynamic_txhighpower_lvl =
                                                 TXHIGHPWRLEVEL_NORMAL;
                        RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD,
                                 "5G:TxHighPwrLevel_Normal\n");
                }
        } else {
-               if (undecorated_smoothed_pwdb >=
+               if (undec_sm_pwdb >=
                    TX_POWER_NEAR_FIELD_THRESH_LVL2) {
                        rtlpriv->dm.dynamic_txhighpower_lvl =
                                                 TXHIGHPWRLEVEL_LEVEL2;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
                } else
-                   if ((undecorated_smoothed_pwdb <
+                   if ((undec_sm_pwdb <
                         (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3))
-                       && (undecorated_smoothed_pwdb >=
+                       && (undec_sm_pwdb >=
                            TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
 
                        rtlpriv->dm.dynamic_txhighpower_lvl =
                                                 TXHIGHPWRLEVEL_LEVEL1;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n");
-               } else if (undecorated_smoothed_pwdb <
+               } else if (undec_sm_pwdb <
                           (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
                        rtlpriv->dm.dynamic_txhighpower_lvl =
                                                 TXHIGHPWRLEVEL_NORMAL;
@@ -620,7 +619,7 @@ static void rtl92d_dm_pwdb_monitor(struct ieee80211_hw *hw)
                return;
        /* Indicate Rx signal strength to FW. */
        if (rtlpriv->dm.useramask) {
-               u32 temp = rtlpriv->dm.undecorated_smoothed_pwdb;
+               u32 temp = rtlpriv->dm.undec_sm_pwdb;
 
                temp <<= 16;
                temp |= 0x100;
@@ -629,7 +628,7 @@ static void rtl92d_dm_pwdb_monitor(struct ieee80211_hw *hw)
                rtl92d_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, (u8 *) (&temp));
        } else {
                rtl_write_byte(rtlpriv, 0x4fe,
-                              (u8) rtlpriv->dm.undecorated_smoothed_pwdb);
+                              (u8) rtlpriv->dm.undec_sm_pwdb);
        }
 }
 
index db00860..33041bd 100644 (file)
@@ -298,13 +298,13 @@ static u32 _rtl92d_phy_rf_serial_read(struct ieee80211_hw *hw,
                rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
                              BIT(8));
        if (rfpi_enable)
-               retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi,
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
                        BLSSIREADBACKDATA);
        else
-               retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
                        BLSSIREADBACKDATA);
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x] = 0x%x\n",
-                rfpath, pphyreg->rflssi_readback, retvalue);
+                rfpath, pphyreg->rf_rb, retvalue);
        return retvalue;
 }
 
@@ -478,14 +478,10 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
 
        /* RF switch Control */
        /* TR/Ant switch control */
-       rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control =
-               RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control =
-           RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control =
-           RFPGA0_XCD_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control =
-           RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
 
        /* AGC control 1 */
        rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
@@ -500,14 +496,10 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
 
        /* RX AFE control 1 */
-       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance =
-           ROFDM0_XARXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance =
-           ROFDM0_XBRXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance =
-           ROFDM0_XCRXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance =
-           ROFDM0_XDRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
 
        /*RX AFE control 1 */
        rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
@@ -516,14 +508,10 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
 
        /* Tx AFE control 1 */
-       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance =
-           ROFDM0_XATxIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance =
-           ROFDM0_XBTxIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance =
-           ROFDM0_XCTxIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance =
-           ROFDM0_XDTxIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATxIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTxIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTxIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTxIQIMBALANCE;
 
        /* Tx AFE control 2 */
        rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATxAFE;
@@ -532,20 +520,14 @@ static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTxAFE;
 
        /* Tranceiver LSSI Readback SI mode */
-       rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback =
-           RFPGA0_XA_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback =
-           RFPGA0_XB_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback =
-           RFPGA0_XC_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback =
-           RFPGA0_XD_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
 
        /* Tranceiver LSSI Readback PI mode */
-       rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi =
-           TRANSCEIVERA_HSPI_READBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi =
-           TRANSCEIVERB_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVERA_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVERB_HSPI_READBACK;
 }
 
 static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
@@ -702,12 +684,11 @@ static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
        else
                return;
 
-       rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+       rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;
        RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
                 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",
                 rtlphy->pwrgroup_cnt, index,
-                rtlphy->mcs_txpwrlevel_origoffset
-                [rtlphy->pwrgroup_cnt][index]);
+                rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);
        if (index == 13)
                rtlphy->pwrgroup_cnt++;
 }
index 3066a7f..20144e0 100644 (file)
@@ -106,11 +106,11 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
                            (ppowerlevel[idx1] << 24);
                }
                if (rtlefuse->eeprom_regulatory == 0) {
-                       tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
-                           (rtlphy->mcs_txpwrlevel_origoffset[0][7] << 8);
+                       tmpval = (rtlphy->mcs_offset[0][6]) +
+                           (rtlphy->mcs_offset[0][7] << 8);
                        tx_agc[RF90_PATH_A] += tmpval;
-                       tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
-                           (rtlphy->mcs_txpwrlevel_origoffset[0][15] << 24);
+                       tmpval = (rtlphy->mcs_offset[0][14]) +
+                           (rtlphy->mcs_offset[0][15] << 24);
                        tx_agc[RF90_PATH_B] += tmpval;
                }
        }
@@ -227,7 +227,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                switch (rtlefuse->eeprom_regulatory) {
                case 0:
                        chnlgroup = 0;
-                       writeval = rtlphy->mcs_txpwrlevel_origoffset
+                       writeval = rtlphy->mcs_offset
                                        [chnlgroup][index +
                                        (rf ? 8 : 0)] + ((index < 2) ?
                                        powerbase0[rf] :
@@ -247,7 +247,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                                        chnlgroup++;
                                else
                                        chnlgroup += 4;
-                               writeval = rtlphy->mcs_txpwrlevel_origoffset
+                               writeval = rtlphy->mcs_offset
                                                [chnlgroup][index +
                                                (rf ? 8 : 0)] + ((index < 2) ?
                                                powerbase0[rf] :
@@ -280,8 +280,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                                        [channel - 1]);
                        }
                        for (i = 0; i < 4; i++) {
-                               pwr_diff_limit[i] =
-                                       (u8)((rtlphy->mcs_txpwrlevel_origoffset
+                               pwr_diff_limit[i] = (u8)((rtlphy->mcs_offset
                                        [chnlgroup][index + (rf ? 8 : 0)] &
                                        (0x7f << (i * 8))) >> (i * 8));
                                if (rtlphy->current_chan_bw ==
@@ -316,8 +315,7 @@ static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
                        break;
                default:
                        chnlgroup = 0;
-                       writeval = rtlphy->mcs_txpwrlevel_origoffset
-                                  [chnlgroup][index +
+                       writeval = rtlphy->mcs_offset[chnlgroup][index +
                                   (rf ? 8 : 0)] + ((index < 2) ?
                                   powerbase0[rf] : powerbase1[rf]);
                        RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
index 4686f34..35bb9da 100644 (file)
@@ -132,8 +132,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,
        pstats->packet_toself = packet_toself;
        pstats->packet_beacon = packet_beacon;
        pstats->is_cck = is_cck_rate;
-       pstats->rx_mimo_signalquality[0] = -1;
-       pstats->rx_mimo_signalquality[1] = -1;
+       pstats->rx_mimo_sig_qual[0] = -1;
+       pstats->rx_mimo_sig_qual[1] = -1;
 
        if (is_cck_rate) {
                u8 report, cck_highpwr;
@@ -212,8 +212,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,
                                        sq = ((64 - sq) * 100) / 44;
                        }
                        pstats->signalquality = sq;
-                       pstats->rx_mimo_signalquality[0] = sq;
-                       pstats->rx_mimo_signalquality[1] = -1;
+                       pstats->rx_mimo_sig_qual[0] = sq;
+                       pstats->rx_mimo_sig_qual[1] = -1;
                }
        } else {
                rtlpriv->dm.rfpath_rxenable[0] = true;
@@ -246,7 +246,7 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,
                                if (i == 0)
                                        pstats->signalquality =
                                                 (u8)(evm & 0xff);
-                               pstats->rx_mimo_signalquality[i] =
+                               pstats->rx_mimo_sig_qual[i] =
                                                 (u8)(evm & 0xff);
                        }
                }
@@ -345,33 +345,28 @@ static void _rtl92de_process_pwdb(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
 
        if (mac->opmode == NL80211_IFTYPE_ADHOC ||
                mac->opmode == NL80211_IFTYPE_AP)
                return;
        else
-               undecorated_smoothed_pwdb =
-                   rtlpriv->dm.undecorated_smoothed_pwdb;
+               undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
 
        if (pstats->packet_toself || pstats->packet_beacon) {
-               if (undecorated_smoothed_pwdb < 0)
-                       undecorated_smoothed_pwdb = pstats->rx_pwdb_all;
-               if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) {
-                       undecorated_smoothed_pwdb =
-                             (((undecorated_smoothed_pwdb) *
+               if (undec_sm_pwdb < 0)
+                       undec_sm_pwdb = pstats->rx_pwdb_all;
+               if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
+                       undec_sm_pwdb = (((undec_sm_pwdb) *
                              (RX_SMOOTH_FACTOR - 1)) +
                              (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-                       undecorated_smoothed_pwdb =
-                             undecorated_smoothed_pwdb + 1;
+                       undec_sm_pwdb = undec_sm_pwdb + 1;
                } else {
-                       undecorated_smoothed_pwdb =
-                             (((undecorated_smoothed_pwdb) *
+                       undec_sm_pwdb = (((undec_sm_pwdb) *
                              (RX_SMOOTH_FACTOR - 1)) +
                              (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
                }
-               rtlpriv->dm.undecorated_smoothed_pwdb =
-                                undecorated_smoothed_pwdb;
+               rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
                _rtl92de_update_rxsignalstatistics(hw, pstats);
        }
 }
@@ -383,15 +378,15 @@ static void rtl92d_loop_over_streams(struct ieee80211_hw *hw,
        int stream;
 
        for (stream = 0; stream < 2; stream++) {
-               if (pstats->rx_mimo_signalquality[stream] != -1) {
+               if (pstats->rx_mimo_sig_qual[stream] != -1) {
                        if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {
                                rtlpriv->stats.rx_evm_percentage[stream] =
-                                   pstats->rx_mimo_signalquality[stream];
+                                   pstats->rx_mimo_sig_qual[stream];
                        }
                        rtlpriv->stats.rx_evm_percentage[stream] =
                            ((rtlpriv->stats.rx_evm_percentage[stream]
                              * (RX_SMOOTH_FACTOR - 1)) +
-                            (pstats->rx_mimo_signalquality[stream] * 1)) /
+                            (pstats->rx_mimo_sig_qual[stream] * 1)) /
                            (RX_SMOOTH_FACTOR);
                }
        }
index 465f581..bf79a52 100644 (file)
@@ -267,13 +267,12 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
                        break;
                }
 
-               if (rtlpriv->dm.undecorated_smoothed_pwdb >
-                   (long)high_rssi_thresh) {
+               if (rtlpriv->dm.undec_sm_pwdb > (long)high_rssi_thresh) {
                        ra->ratr_state = DM_RATR_STA_HIGH;
-               } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
+               } else if (rtlpriv->dm.undec_sm_pwdb >
                           (long)middle_rssi_thresh) {
                        ra->ratr_state = DM_RATR_STA_LOW;
-               } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
+               } else if (rtlpriv->dm.undec_sm_pwdb >
                           (long)low_rssi_thresh) {
                        ra->ratr_state = DM_RATR_STA_LOW;
                } else {
@@ -283,8 +282,7 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
                if (ra->pre_ratr_state != ra->ratr_state) {
                        RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
                                 "RSSI = %ld RSSI_LEVEL = %d PreState = %d, CurState = %d\n",
-                                rtlpriv->dm.undecorated_smoothed_pwdb,
-                                ra->ratr_state,
+                                rtlpriv->dm.undec_sm_pwdb, ra->ratr_state,
                                 ra->pre_ratr_state, ra->ratr_state);
 
                        rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
@@ -316,7 +314,7 @@ static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw)
        rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(&current_mrc));
 
        if (mac->link_state >= MAC80211_LINKED) {
-               if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) {
+               if (rtlpriv->dm.undec_sm_pwdb > tmpentry_maxpwdb) {
                        rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A];
                        rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B];
                }
@@ -424,18 +422,18 @@ static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw)
        struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
 
        if (falsealm_cnt->cnt_all > digtable->fa_highthresh) {
-               if ((digtable->backoff_val - 6) <
+               if ((digtable->back_val - 6) <
                        digtable->backoffval_range_min)
-                       digtable->backoff_val = digtable->backoffval_range_min;
+                       digtable->back_val = digtable->backoffval_range_min;
                else
-                       digtable->backoff_val -= 6;
+                       digtable->back_val -= 6;
        } else if (falsealm_cnt->cnt_all < digtable->fa_lowthresh) {
-               if ((digtable->backoff_val + 6) >
+               if ((digtable->back_val + 6) >
                        digtable->backoffval_range_max)
-                       digtable->backoff_val =
+                       digtable->back_val =
                                 digtable->backoffval_range_max;
                else
-                       digtable->backoff_val += 6;
+                       digtable->back_val += 6;
        }
 }
 
@@ -447,28 +445,28 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
        static u8 initialized, force_write;
        u8 initial_gain = 0;
 
-       if ((digtable->pre_sta_connectstate == digtable->cur_sta_connectstate) ||
-               (digtable->cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) {
-               if (digtable->cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) {
+       if ((digtable->pre_sta_cstate == digtable->cur_sta_cstate) ||
+           (digtable->cur_sta_cstate == DIG_STA_BEFORE_CONNECT)) {
+               if (digtable->cur_sta_cstate == DIG_STA_BEFORE_CONNECT) {
                        if (rtlpriv->psc.rfpwr_state != ERFON)
                                return;
 
                        if (digtable->backoff_enable_flag)
                                rtl92s_backoff_enable_flag(hw);
                        else
-                               digtable->backoff_val = DM_DIG_BACKOFF;
+                               digtable->back_val = DM_DIG_BACKOFF;
 
-                       if ((digtable->rssi_val + 10 - digtable->backoff_val) >
+                       if ((digtable->rssi_val + 10 - digtable->back_val) >
                                digtable->rx_gain_range_max)
                                digtable->cur_igvalue =
                                                digtable->rx_gain_range_max;
-                       else if ((digtable->rssi_val + 10 - digtable->backoff_val)
+                       else if ((digtable->rssi_val + 10 - digtable->back_val)
                                 < digtable->rx_gain_range_min)
                                digtable->cur_igvalue =
                                                digtable->rx_gain_range_min;
                        else
                                digtable->cur_igvalue = digtable->rssi_val + 10 -
-                                               digtable->backoff_val;
+                                               digtable->back_val;
 
                        if (falsealm_cnt->cnt_all > 10000)
                                digtable->cur_igvalue =
@@ -490,7 +488,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
                digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
                rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE);
 
-               digtable->backoff_val = DM_DIG_BACKOFF;
+               digtable->back_val = DM_DIG_BACKOFF;
                digtable->cur_igvalue = rtlpriv->phy.default_initialgain[0];
                digtable->pre_igvalue = 0;
                return;
@@ -528,14 +526,14 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw)
        /* Decide the current status and if modify initial gain or not */
        if (rtlpriv->mac80211.link_state >= MAC80211_LINKED ||
            rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
-               digtable->cur_sta_connectstate = DIG_STA_CONNECT;
+               digtable->cur_sta_cstate = DIG_STA_CONNECT;
        else
-               digtable->cur_sta_connectstate = DIG_STA_DISCONNECT;
+               digtable->cur_sta_cstate = DIG_STA_DISCONNECT;
 
-       digtable->rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb;
+       digtable->rssi_val = rtlpriv->dm.undec_sm_pwdb;
 
        /* Change dig mode to rssi */
-       if (digtable->cur_sta_connectstate != DIG_STA_DISCONNECT) {
+       if (digtable->cur_sta_cstate != DIG_STA_DISCONNECT) {
                if (digtable->dig_twoport_algorithm ==
                    DIG_TWO_PORT_ALGO_FALSE_ALARM) {
                        digtable->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI;
@@ -546,7 +544,7 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw)
        _rtl92s_dm_false_alarm_counter_statistics(hw);
        _rtl92s_dm_initial_gain_sta_beforeconnect(hw);
 
-       digtable->pre_sta_connectstate = digtable->cur_sta_connectstate;
+       digtable->pre_sta_cstate = digtable->cur_sta_cstate;
 }
 
 static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw)
@@ -573,7 +571,7 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
        long txpwr_threshold_lv1, txpwr_threshold_lv2;
 
        /* 2T2R TP issue */
@@ -587,7 +585,7 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)
        }
 
        if ((mac->link_state < MAC80211_LINKED) &&
-           (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
                         "Not connected to any\n");
 
@@ -599,25 +597,22 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)
 
        if (mac->link_state >= MAC80211_LINKED) {
                if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "AP Client PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                } else {
-                       undecorated_smoothed_pwdb =
-                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                                 "STA Default Port PWDB = 0x%lx\n",
-                                undecorated_smoothed_pwdb);
+                                undec_sm_pwdb);
                }
        } else {
-               undecorated_smoothed_pwdb =
-                   rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+               undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
 
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "AP Ext Port PWDB = 0x%lx\n",
-                        undecorated_smoothed_pwdb);
+                        undec_sm_pwdb);
        }
 
        txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2;
@@ -625,12 +620,12 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)
 
        if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1)
                rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
-       else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2)
+       else if (undec_sm_pwdb >= txpwr_threshold_lv2)
                rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2;
-       else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) &&
-               (undecorated_smoothed_pwdb >= txpwr_threshold_lv1))
+       else if ((undec_sm_pwdb < (txpwr_threshold_lv2 - 3)) &&
+               (undec_sm_pwdb >= txpwr_threshold_lv1))
                rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1;
-       else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3))
+       else if (undec_sm_pwdb < (txpwr_threshold_lv1 - 3))
                rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
 
        if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl))
@@ -665,10 +660,10 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
        digtable->dig_state = DM_STA_DIG_MAX;
        digtable->dig_highpwrstate = DM_STA_DIG_MAX;
 
-       digtable->cur_sta_connectstate = DIG_STA_DISCONNECT;
-       digtable->pre_sta_connectstate = DIG_STA_DISCONNECT;
-       digtable->cur_ap_connectstate = DIG_AP_DISCONNECT;
-       digtable->pre_ap_connectstate = DIG_AP_DISCONNECT;
+       digtable->cur_sta_cstate = DIG_STA_DISCONNECT;
+       digtable->pre_sta_cstate = DIG_STA_DISCONNECT;
+       digtable->cur_ap_cstate = DIG_AP_DISCONNECT;
+       digtable->pre_ap_cstate = DIG_AP_DISCONNECT;
 
        digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
        digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
@@ -681,7 +676,7 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
 
        /* for dig debug rssi value */
        digtable->rssi_val = 50;
-       digtable->backoff_val = DM_DIG_BACKOFF;
+       digtable->back_val = DM_DIG_BACKOFF;
        digtable->rx_gain_range_max = DM_DIG_MAX;
 
        digtable->rx_gain_range_min = DM_DIG_MIN;
@@ -709,7 +704,7 @@ void rtl92s_dm_init(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
        rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
-       rtlpriv->dm.undecorated_smoothed_pwdb = -1;
+       rtlpriv->dm.undec_sm_pwdb = -1;
 
        _rtl92s_dm_init_dynamic_txpower(hw);
        rtl92s_dm_init_edca_turbo(hw);
index 4542e69..1d72779 100644 (file)
@@ -1697,7 +1697,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
                        hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i];
 
                        /* Read OFDM RF A & B Tx power for 2T */
-                       rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]
+                       rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][i]
                                 = hwinfo[EEPROM_TXPOWERBASE + 12 +
                                   rf_path * 3 + i];
                }
@@ -1722,7 +1722,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
                        RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
                                "RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
                                rf_path, i,
-                               rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif
+                               rtlefuse->eprom_chnl_txpwr_ht40_2sdf
                                [rf_path][i]);
 
        for (rf_path = 0; rf_path < 2; rf_path++) {
@@ -1748,7 +1748,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
                                rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
                                                        [rf_path][index];
                        rtlefuse->txpwrlevel_ht40_2s[rf_path][i]  =
-                               rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif
+                               rtlefuse->eprom_chnl_txpwr_ht40_2sdf
                                                        [rf_path][index];
                }
 
index b917a2a..6740497 100644 (file)
@@ -139,17 +139,17 @@ static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw,
                                                BIT(8));
 
        if (rfpi_enable)
-               retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi,
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
                                         BLSSI_READBACK_DATA);
        else
-               retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
                                         BLSSI_READBACK_DATA);
 
-       retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+       retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
                                 BLSSI_READBACK_DATA);
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
-                rfpath, pphyreg->rflssi_readback, retvalue);
+                rfpath, pphyreg->rf_rb, retvalue);
 
        return retvalue;
 
@@ -696,7 +696,7 @@ static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
        else
                return;
 
-       rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][index] = data;
+       rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;
        if (index == 5)
                rtlphy->pwrgroup_cnt++;
 }
@@ -765,14 +765,10 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2;
 
        /* RF switch Control */
-       rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control =
-                                                RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control =
-                                                RFPGA0_XAB_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control =
-                                                RFPGA0_XCD_SWITCHCONTROL;
-       rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control =
-                                                RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
 
        /* AGC control 1  */
        rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
@@ -787,14 +783,10 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
 
        /* RX AFE control 1  */
-       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance =
-                                                ROFDM0_XARXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance =
-                                                ROFDM0_XBRXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance =
-                                                ROFDM0_XCRXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance =
-                                                ROFDM0_XDRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
 
        /* RX AFE control 1   */
        rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
@@ -803,14 +795,10 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
 
        /* Tx AFE control 1  */
-       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance =
-                                                ROFDM0_XATXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance =
-                                                ROFDM0_XBTXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance =
-                                                ROFDM0_XCTXIQIMBALANCE;
-       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance =
-                                                ROFDM0_XDTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
 
        /* Tx AFE control 2  */
        rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
@@ -819,20 +807,14 @@ static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
        rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
 
        /* Tranceiver LSSI Readback */
-       rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback =
-                        RFPGA0_XA_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback =
-                        RFPGA0_XB_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback =
-                        RFPGA0_XC_LSSIREADBACK;
-       rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback =
-                        RFPGA0_XD_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
 
        /* Tranceiver LSSI Readback PI mode  */
-       rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi =
-                        TRANSCEIVERA_HSPI_READBACK;
-       rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi =
-                        TRANSCEIVERB_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVERA_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVERB_HSPI_READBACK;
 }
 
 
index 08c2f56..5061f1d 100644 (file)
@@ -192,8 +192,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
                 * defined by Realtek for large power */
                chnlgroup = 0;
 
-               writeval = rtlphy->mcs_txpwrlevel_origoffset
-                               [chnlgroup][index] +
+               writeval = rtlphy->mcs_offset[chnlgroup][index] +
                                ((index < 2) ? pwrbase0 : pwrbase1);
 
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
@@ -223,8 +222,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
                                        chnlgroup++;
                        }
 
-                       writeval = rtlphy->mcs_txpwrlevel_origoffset
-                                       [chnlgroup][index]
+                       writeval = rtlphy->mcs_offset[chnlgroup][index]
                                        + ((index < 2) ?
                                        pwrbase0 : pwrbase1);
 
@@ -257,8 +255,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
                }
 
                for (i = 0; i < 4; i++) {
-                       pwrdiff_limit[i] =
-                               (u8)((rtlphy->mcs_txpwrlevel_origoffset
+                       pwrdiff_limit[i] = (u8)((rtlphy->mcs_offset
                                [chnlgroup][index] & (0x7f << (i * 8)))
                                >> (i * 8));
 
@@ -296,7 +293,7 @@ static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
                break;
        default:
                chnlgroup = 0;
-               writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] +
+               writeval = rtlphy->mcs_offset[chnlgroup][index] +
                                ((index < 2) ? pwrbase0 : pwrbase1);
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "RTK better performance, writeval = 0x%x\n", writeval);
index e3cf4c0..1ad51e7 100644 (file)
@@ -129,8 +129,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
        pstats->packet_matchbssid = packet_match_bssid;
        pstats->packet_toself = packet_toself;
        pstats->packet_beacon = packet_beacon;
-       pstats->rx_mimo_signalquality[0] = -1;
-       pstats->rx_mimo_signalquality[1] = -1;
+       pstats->rx_mimo_sig_qual[0] = -1;
+       pstats->rx_mimo_sig_qual[1] = -1;
 
        if (is_cck) {
                u8 report, cck_highpwr;
@@ -216,8 +216,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
                        }
 
                        pstats->signalquality = sq;
-                       pstats->rx_mimo_signalquality[0] = sq;
-                       pstats->rx_mimo_signalquality[1] = -1;
+                       pstats->rx_mimo_sig_qual[0] = sq;
+                       pstats->rx_mimo_sig_qual[1] = -1;
                }
        } else {
                rtlpriv->dm.rfpath_rxenable[0] =
@@ -256,8 +256,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
                                if (i == 0)
                                        pstats->signalquality = (u8)(evm &
                                                                 0xff);
-                               pstats->rx_mimo_signalquality[i] =
-                                                        (u8) (evm & 0xff);
+                               pstats->rx_mimo_sig_qual[i] = (u8) (evm & 0xff);
                        }
                }
        }
@@ -366,7 +365,7 @@ static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,
                return;
        } else {
                undec_sm_pwdb =
-                   rtlpriv->dm.undecorated_smoothed_pwdb;
+                   rtlpriv->dm.undec_sm_pwdb;
        }
 
        if (pstats->packet_toself || pstats->packet_beacon) {
@@ -386,7 +385,7 @@ static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,
                              (RX_SMOOTH_FACTOR);
                }
 
-               rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb;
+               rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
                _rtl92se_update_rxsignalstatistics(hw, pstats);
        }
 }
@@ -398,16 +397,16 @@ static void rtl_92s_process_streams(struct ieee80211_hw *hw,
        u32 stream;
 
        for (stream = 0; stream < 2; stream++) {
-               if (pstats->rx_mimo_signalquality[stream] != -1) {
+               if (pstats->rx_mimo_sig_qual[stream] != -1) {
                        if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {
                                rtlpriv->stats.rx_evm_percentage[stream] =
-                                   pstats->rx_mimo_signalquality[stream];
+                                   pstats->rx_mimo_sig_qual[stream];
                        }
 
                        rtlpriv->stats.rx_evm_percentage[stream] =
                            ((rtlpriv->stats.rx_evm_percentage[stream] *
                                        (RX_SMOOTH_FACTOR - 1)) +
-                            (pstats->rx_mimo_signalquality[stream] *
+                            (pstats->rx_mimo_sig_qual[stream] *
                                        1)) / (RX_SMOOTH_FACTOR);
                }
        }
index f1b6bc6..6794b68 100644 (file)
@@ -198,15 +198,15 @@ struct bb_reg_def {
        u32 rftxgain_stage;
        u32 rfhssi_para1;
        u32 rfhssi_para2;
-       u32 rfswitch_control;
+       u32 rfsw_ctrl;
        u32 rfagc_control1;
        u32 rfagc_control2;
-       u32 rfrxiq_imbalance;
+       u32 rfrxiq_imbal;
        u32 rfrx_afe;
-       u32 rftxiq_imbalance;
+       u32 rftxiq_imbal;
        u32 rftx_afe;
-       u32 rflssi_readback;
-       u32 rflssi_readbackpi;
+       u32 rf_rb;              /* rflssi_readback */
+       u32 rf_rbpi;            /* rflssi_readbackpi */
 };
 
 enum io_type {
@@ -885,7 +885,7 @@ struct rtl_phy {
        u8 pwrgroup_cnt;
        u8 cck_high_power;
        /* MAX_PG_GROUP groups of pwr diff by rates */
-       u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16];
+       u32 mcs_offset[MAX_PG_GROUP][16];
        u8 default_initialgain[4];
 
        /* the current Tx power level */
@@ -933,7 +933,7 @@ struct rtl_tid_data {
 };
 
 struct rssi_sta {
-       long undecorated_smoothed_pwdb;
+       long undec_sm_pwdb;
 };
 
 struct rtl_sta_info {
@@ -1131,9 +1131,9 @@ struct rtl_security {
 
 struct rtl_dm {
        /*PHY status for Dynamic Management */
-       long entry_min_undecoratedsmoothed_pwdb;
-       long undecorated_smoothed_pwdb; /*out dm */
-       long entry_max_undecoratedsmoothed_pwdb;
+       long entry_min_undec_sm_pwdb;
+       long undec_sm_pwdb;     /*out dm */
+       long entry_max_undec_sm_pwdb;
        bool dm_initialgain_enable;
        bool dynamic_txpower_enable;
        bool current_turbo_edca;
@@ -1209,7 +1209,7 @@ struct rtl_efuse {
        u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX];
        u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G];
        u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX];
-       u8 eeprom_chnlarea_txpwr_ht40_2sdiif[2][CHANNEL_GROUP_MAX];
+       u8 eprom_chnl_txpwr_ht40_2sdf[2][CHANNEL_GROUP_MAX];
        u8 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G];
        u8 txpwrlevel_ht40_1s[2][CHANNEL_MAX_NUMBER];   /*For HT 40MHZ pwr */
        u8 txpwrlevel_ht40_2s[2][CHANNEL_MAX_NUMBER];   /*For HT 40MHZ pwr */
@@ -1351,7 +1351,7 @@ struct rtl_stats {
        bool rx_is40Mhzpacket;
        u32 rx_pwdb_all;
        u8 rx_mimo_signalstrength[4];   /*in 0~100 index */
-       s8 rx_mimo_signalquality[2];
+       s8 rx_mimo_sig_qual[2];
        bool packet_matchbssid;
        bool is_cck;
        bool is_ht;
@@ -1503,6 +1503,9 @@ struct rtl_hal_ops {
        void (*phy_lc_calibrate) (struct ieee80211_hw *hw, bool is2t);
        void (*phy_set_bw_mode_callback) (struct ieee80211_hw *hw);
        void (*dm_dynamic_txpower) (struct ieee80211_hw *hw);
+       void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw,
+                                            bool mstate);
+       void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
 };
 
 struct rtl_intf_ops {
@@ -1679,7 +1682,7 @@ struct dig_t {
        u32 rssi_highthresh;
        u32 fa_lowthresh;
        u32 fa_highthresh;
-       long last_min_undecorated_pwdb_for_dm;
+       long last_min_undec_pwdb_for_dm;
        long rssi_highpower_lowthresh;
        long rssi_highpower_highthresh;
        u32 recover_cnt;
@@ -1692,15 +1695,15 @@ struct dig_t {
        u8 dig_twoport_algorithm;
        u8 dig_dbgmode;
        u8 dig_slgorithm_switch;
-       u8 cursta_connectstate;
-       u8 presta_connectstate;
-       u8 curmultista_connectstate;
-       char backoff_val;
-       char backoff_val_range_max;
-       char backoff_val_range_min;
+       u8 cursta_cstate;
+       u8 presta_cstate;
+       u8 curmultista_cstate;
+       char back_val;
+       char back_range_max;
+       char back_range_min;
        u8 rx_gain_range_max;
        u8 rx_gain_range_min;
-       u8 min_undecorated_pwdb_for_dm;
+       u8 min_undec_pwdb_for_dm;
        u8 rssi_val_min;
        u8 pre_cck_pd_state;
        u8 cur_cck_pd_state;
@@ -1712,10 +1715,10 @@ struct dig_t {
        u8 forbidden_igi;
        u8 dig_state;
        u8 dig_highpwrstate;
-       u8 cur_sta_connectstate;
-       u8 pre_sta_connectstate;
-       u8 cur_ap_connectstate;
-       u8 pre_ap_connectstate;
+       u8 cur_sta_cstate;
+       u8 pre_sta_cstate;
+       u8 cur_ap_cstate;
+       u8 pre_ap_cstate;
        u8 cur_pd_thstate;
        u8 pre_pd_thstate;
        u8 cur_cs_ratiostate;
@@ -1846,7 +1849,7 @@ struct bt_coexist_info {
        u8 eeprom_bt_coexist;
        u8 eeprom_bt_type;
        u8 eeprom_bt_ant_num;
-       u8 eeprom_bt_ant_isolation;
+       u8 eeprom_bt_ant_isol;
        u8 eeprom_bt_radio_shared;
 
        u8 bt_coexistence;
index bf05831..36c3590 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for nfc devices
 #
 
-obj-$(CONFIG_PN544_HCI_NFC)    += pn544_hci.o
+obj-$(CONFIG_PN544_HCI_NFC)    += pn544/
 obj-$(CONFIG_NFC_PN533)                += pn533.o
 obj-$(CONFIG_NFC_WILINK)       += nfcwilink.o
 
index 97c440a..18e279d 100644 (file)
@@ -84,6 +84,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_LISTEN_TIME 2
 
 /* frame definitions */
+#define PN533_NORMAL_FRAME_MAX_LEN 262  /* 6   (PREAMBLE, SOF, LEN, LCS, TFI)
+                                          254 (DATA)
+                                          2   (DCS, postamble) */
+
 #define PN533_FRAME_TAIL_SIZE 2
 #define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
                                PN533_FRAME_TAIL_SIZE)
@@ -1165,8 +1169,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,
                pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
 }
 
-static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
-                                    u8 *params, int params_len)
+static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len)
 {
        struct pn533_poll_response *resp;
        int rc;
@@ -1304,8 +1307,7 @@ static void pn533_wq_tg_get_data(struct work_struct *work)
 }
 
 #define ATR_REQ_GB_OFFSET 17
-static int pn533_init_target_complete(struct pn533 *dev, void *arg,
-                                     u8 *params, int params_len)
+static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len)
 {
        struct pn533_cmd_init_target_response *resp;
        u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
@@ -1402,9 +1404,9 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
        if (cur_mod->len == 0) {
                del_timer(&dev->listen_timer);
 
-               return pn533_init_target_complete(dev, arg, params, params_len);
+               return pn533_init_target_complete(dev, params, params_len);
        } else {
-               rc = pn533_start_poll_complete(dev, arg, params, params_len);
+               rc = pn533_start_poll_complete(dev, params, params_len);
                if (!rc)
                        return rc;
        }
@@ -2373,9 +2375,9 @@ static int pn533_probe(struct usb_interface *interface,
                goto error;
        }
 
-       dev->in_frame = kmalloc(dev->in_maxlen, GFP_KERNEL);
+       dev->in_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
        dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);
-       dev->out_frame = kmalloc(dev->out_maxlen, GFP_KERNEL);
+       dev->out_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
        dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
 
        if (!dev->in_frame || !dev->out_frame ||
diff --git a/drivers/nfc/pn544/Makefile b/drivers/nfc/pn544/Makefile
new file mode 100644 (file)
index 0000000..7257338
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for PN544 HCI based NFC driver
+#
+
+obj-$(CONFIG_PN544_HCI_NFC)    += pn544_i2c.o
+
+pn544_i2c-y            := pn544.o i2c.o
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
new file mode 100644 (file)
index 0000000..fb430d8
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * I2C Link Layer for PN544 HCI based Driver
+ *
+ * Copyright (C) 2012  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/crc-ccitt.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <linux/nfc/pn544.h>
+
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "pn544.h"
+
+#define PN544_I2C_FRAME_HEADROOM 1
+#define PN544_I2C_FRAME_TAILROOM 2
+
+/* framing in HCI mode */
+#define PN544_HCI_I2C_LLC_LEN          1
+#define PN544_HCI_I2C_LLC_CRC          2
+#define PN544_HCI_I2C_LLC_LEN_CRC      (PN544_HCI_I2C_LLC_LEN + \
+                                        PN544_HCI_I2C_LLC_CRC)
+#define PN544_HCI_I2C_LLC_MIN_SIZE     (1 + PN544_HCI_I2C_LLC_LEN_CRC)
+#define PN544_HCI_I2C_LLC_MAX_PAYLOAD  29
+#define PN544_HCI_I2C_LLC_MAX_SIZE     (PN544_HCI_I2C_LLC_LEN_CRC + 1 + \
+                                        PN544_HCI_I2C_LLC_MAX_PAYLOAD)
+
+static struct i2c_device_id pn544_hci_i2c_id_table[] = {
+       {"pn544", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
+
+#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
+
+struct pn544_i2c_phy {
+       struct i2c_client *i2c_dev;
+       struct nfc_hci_dev *hdev;
+
+       unsigned int gpio_en;
+       unsigned int gpio_irq;
+       unsigned int gpio_fw;
+       unsigned int en_polarity;
+
+       int powered;
+
+       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 pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
+{
+       int polarity, retry, ret;
+       char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 };
+       int count = sizeof(rset_cmd);
+
+       pr_info(DRIVER_DESC ": %s\n", __func__);
+       dev_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
+
+       /* Disable fw download */
+       gpio_set_value(phy->gpio_fw, 0);
+
+       for (polarity = 0; polarity < 2; polarity++) {
+               phy->en_polarity = polarity;
+               retry = 3;
+               while (retry--) {
+                       /* power off */
+                       gpio_set_value(phy->gpio_en, !phy->en_polarity);
+                       usleep_range(10000, 15000);
+
+                       /* power on */
+                       gpio_set_value(phy->gpio_en, phy->en_polarity);
+                       usleep_range(10000, 15000);
+
+                       /* send reset */
+                       dev_dbg(&phy->i2c_dev->dev, "Sending reset cmd\n");
+                       ret = i2c_master_send(phy->i2c_dev, rset_cmd, count);
+                       if (ret == count) {
+                               dev_info(&phy->i2c_dev->dev,
+                                        "nfc_en polarity : active %s\n",
+                                        (polarity == 0 ? "low" : "high"));
+                               goto out;
+                       }
+               }
+       }
+
+       dev_err(&phy->i2c_dev->dev,
+               "Could not detect nfc_en polarity, fallback to active high\n");
+
+out:
+       gpio_set_value(phy->gpio_en, !phy->en_polarity);
+}
+
+static int pn544_hci_i2c_enable(void *phy_id)
+{
+       struct pn544_i2c_phy *phy = phy_id;
+
+       pr_info(DRIVER_DESC ": %s\n", __func__);
+
+       gpio_set_value(phy->gpio_fw, 0);
+       gpio_set_value(phy->gpio_en, phy->en_polarity);
+       usleep_range(10000, 15000);
+
+       phy->powered = 1;
+
+       return 0;
+}
+
+static void pn544_hci_i2c_disable(void *phy_id)
+{
+       struct pn544_i2c_phy *phy = phy_id;
+
+       pr_info(DRIVER_DESC ": %s\n", __func__);
+
+       gpio_set_value(phy->gpio_fw, 0);
+       gpio_set_value(phy->gpio_en, !phy->en_polarity);
+       usleep_range(10000, 15000);
+
+       gpio_set_value(phy->gpio_en, phy->en_polarity);
+       usleep_range(10000, 15000);
+
+       gpio_set_value(phy->gpio_en, !phy->en_polarity);
+       usleep_range(10000, 15000);
+
+       phy->powered = 0;
+}
+
+static void pn544_hci_i2c_add_len_crc(struct sk_buff *skb)
+{
+       u16 crc;
+       int len;
+
+       len = skb->len + 2;
+       *skb_push(skb, 1) = len;
+
+       crc = crc_ccitt(0xffff, skb->data, skb->len);
+       crc = ~crc;
+       *skb_put(skb, 1) = crc & 0xff;
+       *skb_put(skb, 1) = crc >> 8;
+}
+
+static void pn544_hci_i2c_remove_len_crc(struct sk_buff *skb)
+{
+       skb_pull(skb, PN544_I2C_FRAME_HEADROOM);
+       skb_trim(skb, PN544_I2C_FRAME_TAILROOM);
+}
+
+/*
+ * 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 pn544_hci_i2c_write(void *phy_id, struct sk_buff *skb)
+{
+       int r;
+       struct pn544_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);
+
+       pn544_hci_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;
+       }
+
+       pn544_hci_i2c_remove_len_crc(skb);
+
+       return r;
+}
+
+static int check_crc(u8 *buf, int buflen)
+{
+       int len;
+       u16 crc;
+
+       len = buf[0] + 1;
+       crc = crc_ccitt(0xffff, buf, len - 2);
+       crc = ~crc;
+
+       if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) {
+               pr_err(PN544_HCI_I2C_DRIVER_NAME
+                      ": CRC error 0x%x != 0x%x 0x%x\n",
+                      crc, buf[len - 1], buf[len - 2]);
+
+               pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
+               print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
+                              16, 2, buf, buflen, false);
+               return -EPERM;
+       }
+       return 0;
+}
+
+/*
+ * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees
+ * that i2c bus will be flushed and that next read will start on a new frame.
+ * returned skb contains only LLC header and payload.
+ * returns:
+ * -EREMOTEIO : i2c read error (fatal)
+ * -EBADMSG : frame was incorrect and discarded
+ * -ENOMEM : cannot allocate skb, frame dropped
+ */
+static int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb)
+{
+       int r;
+       u8 len;
+       u8 tmp[PN544_HCI_I2C_LLC_MAX_SIZE - 1];
+       struct i2c_client *client = phy->i2c_dev;
+
+       r = i2c_master_recv(client, &len, 1);
+       if (r != 1) {
+               dev_err(&client->dev, "cannot read len byte\n");
+               return -EREMOTEIO;
+       }
+
+       if ((len < (PN544_HCI_I2C_LLC_MIN_SIZE - 1)) ||
+           (len > (PN544_HCI_I2C_LLC_MAX_SIZE - 1))) {
+               dev_err(&client->dev, "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("i2c frame read", *skb);
+
+       r = check_crc((*skb)->data, (*skb)->len);
+       if (r != 0) {
+               kfree_skb(*skb);
+               r = -EBADMSG;
+               goto flush;
+       }
+
+       skb_pull(*skb, 1);
+       skb_trim(*skb, (*skb)->len - 2);
+
+       usleep_range(3000, 6000);
+
+       return 0;
+
+flush:
+       if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
+               r = -EREMOTEIO;
+
+       usleep_range(3000, 6000);
+
+       return r;
+}
+
+/*
+ * Reads an shdlc frame from the chip. This is not as straightforward as it
+ * seems. There are cases where we could loose the frame start synchronization.
+ * The frame format is len-data-crc, and corruption can occur anywhere while
+ * transiting on i2c bus, such that we could read an invalid len.
+ * In order to recover synchronization with the next frame, we must be sure
+ * to read the real amount of data without using the len byte. We do this by
+ * assuming the following:
+ * - the chip will always present only one single complete frame on the bus
+ *   before triggering the interrupt
+ * - the chip will not present a new frame until we have completely read
+ *   the previous one (or until we have handled the interrupt).
+ * The tricky case is when we read a corrupted len that is less than the real
+ * len. We must detect this here in order to determine that we need to flush
+ * the bus. This is the reason why we check the crc here.
+ */
+static irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id)
+{
+       struct pn544_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 = pn544_hci_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 = pn544_hci_i2c_write,
+       .enable = pn544_hci_i2c_enable,
+       .disable = pn544_hci_i2c_disable,
+};
+
+static int __devinit pn544_hci_i2c_probe(struct i2c_client *client,
+                                    const struct i2c_device_id *id)
+{
+       struct pn544_i2c_phy *phy;
+       struct pn544_nfc_platform_data *pdata;
+       int r = 0;
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+       dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "Need I2C_FUNC_I2C\n");
+               return -ENODEV;
+       }
+
+       phy = kzalloc(sizeof(struct pn544_i2c_phy), GFP_KERNEL);
+       if (!phy) {
+               dev_err(&client->dev,
+                       "Cannot allocate memory for pn544 i2c phy.\n");
+               r = -ENOMEM;
+               goto err_phy_alloc;
+       }
+
+       phy->i2c_dev = client;
+       i2c_set_clientdata(client, phy);
+
+       pdata = client->dev.platform_data;
+       if (pdata == NULL) {
+               dev_err(&client->dev, "No platform data\n");
+               r = -EINVAL;
+               goto err_pdata;
+       }
+
+       if (pdata->request_resources == NULL) {
+               dev_err(&client->dev, "request_resources() missing\n");
+               r = -EINVAL;
+               goto err_pdata;
+       }
+
+       r = pdata->request_resources(client);
+       if (r) {
+               dev_err(&client->dev, "Cannot get platform resources\n");
+               goto err_pdata;
+       }
+
+       phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
+       phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
+       phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ);
+
+       pn544_hci_i2c_platform_init(phy);
+
+       r = request_threaded_irq(client->irq, NULL, pn544_hci_i2c_irq_thread_fn,
+                                IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                PN544_HCI_I2C_DRIVER_NAME, phy);
+       if (r < 0) {
+               dev_err(&client->dev, "Unable to register IRQ handler\n");
+               goto err_rti;
+       }
+
+       r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
+                           PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM,
+                           PN544_HCI_I2C_LLC_MAX_PAYLOAD, &phy->hdev);
+       if (r < 0)
+               goto err_hci;
+
+       return 0;
+
+err_hci:
+       free_irq(client->irq, phy);
+
+err_rti:
+       if (pdata->free_resources != NULL)
+               pdata->free_resources();
+
+err_pdata:
+       kfree(phy);
+
+err_phy_alloc:
+       return r;
+}
+
+static __devexit int pn544_hci_i2c_remove(struct i2c_client *client)
+{
+       struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
+       struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+
+       pn544_hci_remove(phy->hdev);
+
+       if (phy->powered)
+               pn544_hci_i2c_disable(phy);
+
+       free_irq(client->irq, phy);
+       if (pdata->free_resources)
+               pdata->free_resources();
+
+       kfree(phy);
+
+       return 0;
+}
+
+static struct i2c_driver pn544_hci_i2c_driver = {
+       .driver = {
+                  .name = PN544_HCI_I2C_DRIVER_NAME,
+                 },
+       .probe = pn544_hci_i2c_probe,
+       .id_table = pn544_hci_i2c_id_table,
+       .remove = __devexit_p(pn544_hci_i2c_remove),
+};
+
+static int __init pn544_hci_i2c_init(void)
+{
+       int r;
+
+       pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+       r = i2c_add_driver(&pn544_hci_i2c_driver);
+       if (r) {
+               pr_err(PN544_HCI_I2C_DRIVER_NAME
+                      ": driver registration failed\n");
+               return r;
+       }
+
+       return 0;
+}
+
+static void __exit pn544_hci_i2c_exit(void)
+{
+       i2c_del_driver(&pn544_hci_i2c_driver);
+}
+
+module_init(pn544_hci_i2c_init);
+module_exit(pn544_hci_i2c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
similarity index 58%
rename from drivers/nfc/pn544_hci.c
rename to drivers/nfc/pn544/pn544.c
index c9c8570..cc666de 100644 (file)
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <linux/crc-ccitt.h>
-#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/miscdevice.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
 
 #include <linux/nfc.h>
 #include <net/nfc/hci.h>
 #include <net/nfc/llc.h>
 
-#include <linux/nfc/pn544.h>
-
-#define DRIVER_DESC "HCI NFC driver for PN544"
-
-#define PN544_HCI_DRIVER_NAME "pn544_hci"
+#include "pn544.h"
 
 /* Timing restrictions (ms) */
 #define PN544_HCI_RESETVEN_TIME                30
 
-static struct i2c_device_id pn544_hci_id_table[] = {
-       {"pn544", 0},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, pn544_hci_id_table);
-
 #define HCI_MODE 0
 #define FW_MODE 1
 
-/* framing in HCI mode */
-#define PN544_HCI_LLC_LEN              1
-#define PN544_HCI_LLC_CRC              2
-#define PN544_HCI_LLC_LEN_CRC          (PN544_HCI_LLC_LEN + PN544_HCI_LLC_CRC)
-#define PN544_HCI_LLC_MIN_SIZE         (1 + PN544_HCI_LLC_LEN_CRC)
-#define PN544_HCI_LLC_MAX_PAYLOAD      29
-#define PN544_HCI_LLC_MAX_SIZE         (PN544_HCI_LLC_LEN_CRC + 1 + \
-                                        PN544_HCI_LLC_MAX_PAYLOAD)
-
 enum pn544_state {
        PN544_ST_COLD,
        PN544_ST_FW_READY,
@@ -100,6 +74,10 @@ enum pn544_state {
 #define PN544_SYS_MGMT_INFO_NOTIFICATION       0x02
 
 #define PN544_POLLING_LOOP_MGMT_GATE           0x94
+#define PN544_DEP_MODE                         0x01
+#define PN544_DEP_ATR_REQ                      0x02
+#define PN544_DEP_ATR_RES                      0x03
+#define PN544_DEP_MERGE                                0x0D
 #define PN544_PL_RDPHASES                      0x06
 #define PN544_PL_EMULATION                     0x07
 #define PN544_PL_NFCT_DEACTIVATED              0x09
@@ -108,6 +86,15 @@ enum pn544_state {
 
 #define PN544_NFC_WI_MGMT_GATE                 0xA1
 
+#define PN544_HCI_EVT_SND_DATA                 0x01
+#define PN544_HCI_EVT_ACTIVATED                        0x02
+#define PN544_HCI_EVT_DEACTIVATED              0x03
+#define PN544_HCI_EVT_RCV_DATA                 0x04
+#define PN544_HCI_EVT_CONTINUE_MI              0x05
+
+#define PN544_HCI_CMD_ATTREQUEST               0x12
+#define PN544_HCI_CMD_CONTINUE_ACTIVATION      0x13
+
 static struct nfc_hci_gate pn544_gates[] = {
        {NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE},
        {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
@@ -128,259 +115,22 @@ static struct nfc_hci_gate pn544_gates[] = {
 
 /* Largest headroom needed for outgoing custom commands */
 #define PN544_CMDS_HEADROOM    2
-#define PN544_FRAME_HEADROOM 1
-#define PN544_FRAME_TAILROOM 2
 
 struct pn544_hci_info {
-       struct i2c_client *i2c_dev;
+       struct nfc_phy_ops *phy_ops;
+       void *phy_id;
+
        struct nfc_hci_dev *hdev;
 
        enum pn544_state state;
 
        struct mutex info_lock;
 
-       unsigned int gpio_en;
-       unsigned int gpio_irq;
-       unsigned int gpio_fw;
-       unsigned int en_polarity;
-
-       int hard_fault;         /*
-                                * < 0 if hardware error occured (e.g. i2c err)
-                                * and prevents normal operation.
-                                */
        int async_cb_type;
        data_exchange_cb_t async_cb;
        void *async_cb_context;
 };
 
-static void pn544_hci_platform_init(struct pn544_hci_info *info)
-{
-       int polarity, retry, ret;
-       char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 };
-       int count = sizeof(rset_cmd);
-
-       pr_info(DRIVER_DESC ": %s\n", __func__);
-       dev_info(&info->i2c_dev->dev, "Detecting nfc_en polarity\n");
-
-       /* Disable fw download */
-       gpio_set_value(info->gpio_fw, 0);
-
-       for (polarity = 0; polarity < 2; polarity++) {
-               info->en_polarity = polarity;
-               retry = 3;
-               while (retry--) {
-                       /* power off */
-                       gpio_set_value(info->gpio_en, !info->en_polarity);
-                       usleep_range(10000, 15000);
-
-                       /* power on */
-                       gpio_set_value(info->gpio_en, info->en_polarity);
-                       usleep_range(10000, 15000);
-
-                       /* send reset */
-                       dev_dbg(&info->i2c_dev->dev, "Sending reset cmd\n");
-                       ret = i2c_master_send(info->i2c_dev, rset_cmd, count);
-                       if (ret == count) {
-                               dev_info(&info->i2c_dev->dev,
-                                        "nfc_en polarity : active %s\n",
-                                        (polarity == 0 ? "low" : "high"));
-                               goto out;
-                       }
-               }
-       }
-
-       dev_err(&info->i2c_dev->dev,
-               "Could not detect nfc_en polarity, fallback to active high\n");
-
-out:
-       gpio_set_value(info->gpio_en, !info->en_polarity);
-}
-
-static int pn544_hci_enable(struct pn544_hci_info *info, int mode)
-{
-       pr_info(DRIVER_DESC ": %s\n", __func__);
-
-       gpio_set_value(info->gpio_fw, 0);
-       gpio_set_value(info->gpio_en, info->en_polarity);
-       usleep_range(10000, 15000);
-
-       return 0;
-}
-
-static void pn544_hci_disable(struct pn544_hci_info *info)
-{
-       pr_info(DRIVER_DESC ": %s\n", __func__);
-
-       gpio_set_value(info->gpio_fw, 0);
-       gpio_set_value(info->gpio_en, !info->en_polarity);
-       usleep_range(10000, 15000);
-
-       gpio_set_value(info->gpio_en, info->en_polarity);
-       usleep_range(10000, 15000);
-
-       gpio_set_value(info->gpio_en, !info->en_polarity);
-       usleep_range(10000, 15000);
-}
-
-static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len)
-{
-       int r;
-
-       usleep_range(3000, 6000);
-
-       r = i2c_master_send(client, buf, len);
-
-       if (r == -EREMOTEIO) {  /* Retry, chip was in standby */
-               usleep_range(6000, 10000);
-               r = i2c_master_send(client, buf, len);
-       }
-
-       if (r >= 0) {
-               if (r != len)
-                       return -EREMOTEIO;
-               else
-                       return 0;
-       }
-
-       return r;
-}
-
-static int check_crc(u8 *buf, int buflen)
-{
-       int len;
-       u16 crc;
-
-       len = buf[0] + 1;
-       crc = crc_ccitt(0xffff, buf, len - 2);
-       crc = ~crc;
-
-       if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) {
-               pr_err(PN544_HCI_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n",
-                      crc, buf[len - 1], buf[len - 2]);
-
-               pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
-               print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
-                              16, 2, buf, buflen, false);
-               return -EPERM;
-       }
-       return 0;
-}
-
-/*
- * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees
- * that i2c bus will be flushed and that next read will start on a new frame.
- * returned skb contains only LLC header and payload.
- * returns:
- * -EREMOTEIO : i2c read error (fatal)
- * -EBADMSG : frame was incorrect and discarded
- * -ENOMEM : cannot allocate skb, frame dropped
- */
-static int pn544_hci_i2c_read(struct i2c_client *client, struct sk_buff **skb)
-{
-       int r;
-       u8 len;
-       u8 tmp[PN544_HCI_LLC_MAX_SIZE - 1];
-
-       r = i2c_master_recv(client, &len, 1);
-       if (r != 1) {
-               dev_err(&client->dev, "cannot read len byte\n");
-               return -EREMOTEIO;
-       }
-
-       if ((len < (PN544_HCI_LLC_MIN_SIZE - 1)) ||
-           (len > (PN544_HCI_LLC_MAX_SIZE - 1))) {
-               dev_err(&client->dev, "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;
-       }
-
-       r = check_crc((*skb)->data, (*skb)->len);
-       if (r != 0) {
-               kfree_skb(*skb);
-               r = -EBADMSG;
-               goto flush;
-       }
-
-       skb_pull(*skb, 1);
-       skb_trim(*skb, (*skb)->len - 2);
-
-       usleep_range(3000, 6000);
-
-       return 0;
-
-flush:
-       if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
-               r = -EREMOTEIO;
-
-       usleep_range(3000, 6000);
-
-       return r;
-}
-
-/*
- * Reads an shdlc frame from the chip. This is not as straightforward as it
- * seems. There are cases where we could loose the frame start synchronization.
- * The frame format is len-data-crc, and corruption can occur anywhere while
- * transiting on i2c bus, such that we could read an invalid len.
- * In order to recover synchronization with the next frame, we must be sure
- * to read the real amount of data without using the len byte. We do this by
- * assuming the following:
- * - the chip will always present only one single complete frame on the bus
- *   before triggering the interrupt
- * - the chip will not present a new frame until we have completely read
- *   the previous one (or until we have handled the interrupt).
- * The tricky case is when we read a corrupted len that is less than the real
- * len. We must detect this here in order to determine that we need to flush
- * the bus. This is the reason why we check the crc here.
- */
-static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id)
-{
-       struct pn544_hci_info *info = dev_id;
-       struct i2c_client *client;
-       struct sk_buff *skb = NULL;
-       int r;
-
-       if (!info || irq != info->i2c_dev->irq) {
-               WARN_ON_ONCE(1);
-               return IRQ_NONE;
-       }
-
-       client = info->i2c_dev;
-       dev_dbg(&client->dev, "IRQ\n");
-
-       if (info->hard_fault != 0)
-               return IRQ_HANDLED;
-
-       r = pn544_hci_i2c_read(client, &skb);
-       if (r == -EREMOTEIO) {
-               info->hard_fault = r;
-
-               nfc_hci_recv_frame(info->hdev, NULL);
-
-               return IRQ_HANDLED;
-       } else if ((r == -ENOMEM) || (r == -EBADMSG)) {
-               return IRQ_HANDLED;
-       }
-
-       nfc_hci_recv_frame(info->hdev, skb);
-
-       return IRQ_HANDLED;
-}
-
 static int pn544_hci_open(struct nfc_hci_dev *hdev)
 {
        struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
@@ -393,7 +143,7 @@ static int pn544_hci_open(struct nfc_hci_dev *hdev)
                goto out;
        }
 
-       r = pn544_hci_enable(info, HCI_MODE);
+       r = info->phy_ops->enable(info->phy_id);
 
        if (r == 0)
                info->state = PN544_ST_READY;
@@ -412,7 +162,7 @@ static void pn544_hci_close(struct nfc_hci_dev *hdev)
        if (info->state == PN544_ST_COLD)
                goto out;
 
-       pn544_hci_disable(info);
+       info->phy_ops->disable(info->phy_id);
 
        info->state = PN544_ST_COLD;
 
@@ -587,40 +337,11 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
        return 0;
 }
 
-static void pn544_hci_add_len_crc(struct sk_buff *skb)
-{
-       u16 crc;
-       int len;
-
-       len = skb->len + 2;
-       *skb_push(skb, 1) = len;
-
-       crc = crc_ccitt(0xffff, skb->data, skb->len);
-       crc = ~crc;
-       *skb_put(skb, 1) = crc & 0xff;
-       *skb_put(skb, 1) = crc >> 8;
-}
-
-static void pn544_hci_remove_len_crc(struct sk_buff *skb)
-{
-       skb_pull(skb, PN544_FRAME_HEADROOM);
-       skb_trim(skb, PN544_FRAME_TAILROOM);
-}
-
 static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
 {
        struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
-       struct i2c_client *client = info->i2c_dev;
-       int r;
 
-       if (info->hard_fault != 0)
-               return info->hard_fault;
-
-       pn544_hci_add_len_crc(skb);
-       r = pn544_hci_i2c_write(client, skb->data, skb->len);
-       pn544_hci_remove_len_crc(skb);
-
-       return r;
+       return info->phy_ops->write(info->phy_id, skb);
 }
 
 static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
@@ -630,6 +351,9 @@ static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
        int r;
        u8 duration[2];
        u8 activated;
+       u8 i_mode = 0x3f; /* Enable all supported modes */
+       u8 t_mode = 0x0f;
+       u8 t_merge = 0x01; /* Enable merge by default */
 
        pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
                __func__, im_protocols, tm_protocols);
@@ -667,6 +391,61 @@ static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
        if (r < 0)
                return r;
 
+       if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
+               hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
+                                                       &hdev->gb_len);
+               pr_debug("generate local bytes %p", hdev->gb);
+               if (hdev->gb == NULL || hdev->gb_len == 0) {
+                       im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+                       tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+               }
+       }
+
+       if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+               r = nfc_hci_send_event(hdev,
+                               PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                               NFC_HCI_EVT_END_OPERATION, NULL, 0);
+               if (r < 0)
+                       return r;
+
+               r = nfc_hci_set_param(hdev,
+                               PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                               PN544_DEP_MODE, &i_mode, 1);
+               if (r < 0)
+                       return r;
+
+               r = nfc_hci_set_param(hdev,
+                               PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                               PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len);
+               if (r < 0)
+                       return r;
+
+               r = nfc_hci_send_event(hdev,
+                               PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                               NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
+               if (r < 0)
+                       nfc_hci_send_event(hdev,
+                                       PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                                       NFC_HCI_EVT_END_OPERATION, NULL, 0);
+       }
+
+       if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
+               r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
+                               PN544_DEP_MODE, &t_mode, 1);
+               if (r < 0)
+                       return r;
+
+               r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
+                               PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len);
+               if (r < 0)
+                       return r;
+
+               r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
+                               PN544_DEP_MERGE, &t_merge, 1);
+               if (r < 0)
+                       return r;
+       }
+
        r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
                               NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
        if (r < 0)
@@ -676,6 +455,43 @@ static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
        return r;
 }
 
+static int pn544_hci_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,
+                               PN544_DEP_ATR_RES, &rgb_skb);
+       if (r < 0)
+               return r;
+
+       if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
+               r = -EPROTO;
+               goto exit;
+       }
+       print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET,
+                       16, 1, rgb_skb->data, rgb_skb->len, true);
+
+       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 pn544_hci_dep_link_down(struct nfc_hci_dev *hdev)
+{
+
+       return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                                       NFC_HCI_EVT_END_OPERATION, NULL, 0);
+}
+
 static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
                                      struct nfc_target *target)
 {
@@ -687,6 +503,9 @@ static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
                target->supported_protocols = NFC_PROTO_JEWEL_MASK;
                target->sens_res = 0x0c00;
                break;
+       case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
+               target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+               break;
        default:
                return -EPROTO;
        }
@@ -701,7 +520,18 @@ static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
        struct sk_buff *uid_skb;
        int r = 0;
 
-       if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
+       if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
+               return r;
+
+       if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
+               r = nfc_hci_send_cmd(hdev,
+                       PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                       PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL);
+               if (r < 0)
+                       return r;
+
+               target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
+       } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
                if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
                    target->nfcid1_len != 10)
                        return -EPROTO;
@@ -724,6 +554,16 @@ static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
                                     PN544_RF_READER_CMD_ACTIVATE_NEXT,
                                     uid_skb->data, uid_skb->len, NULL);
                kfree_skb(uid_skb);
+
+               r = nfc_hci_send_cmd(hdev,
+                                       PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+                                       PN544_HCI_CMD_CONTINUE_ACTIVATION,
+                                       NULL, 0, NULL);
+               if (r < 0)
+                       return r;
+
+               target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
+               target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
        } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {
                /*
                 * TODO: maybe other ISO 14443 require some kind of continue
@@ -769,7 +609,7 @@ static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
  * <= 0: driver handled the data exchange
  *    1: driver doesn't especially handle, please do standard processing
  */
-static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev,
+static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
                                   struct nfc_target *target,
                                   struct sk_buff *skb, data_exchange_cb_t cb,
                                   void *cb_context)
@@ -822,17 +662,110 @@ static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev,
                return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
                                              PN544_JEWEL_RAW_CMD, skb->data,
                                              skb->len, cb, cb_context);
+       case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
+               *skb_push(skb, 1) = 0;
+
+               return nfc_hci_send_event(hdev, target->hci_reader_gate,
+                                       PN544_HCI_EVT_SND_DATA, skb->data,
+                                       skb->len);
        default:
                return 1;
        }
 }
 
+static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+       /* Set default false for multiple information chaining */
+       *skb_push(skb, 1) = 0;
+
+       return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
+                               PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
+}
+
 static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
                                   struct nfc_target *target)
 {
-       return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
-                               PN544_RF_READER_CMD_PRESENCE_CHECK,
-                               NULL, 0, NULL);
+       pr_debug("supported protocol %d", target->supported_protocols);
+       if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK |
+                                       NFC_PROTO_ISO14443_B_MASK)) {
+               return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+                                       PN544_RF_READER_CMD_PRESENCE_CHECK,
+                                       NULL, 0, NULL);
+       } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
+               if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
+                   target->nfcid1_len != 10)
+                       return -EOPNOTSUPP;
+
+                return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
+                                    PN544_RF_READER_CMD_ACTIVATE_NEXT,
+                                    target->nfcid1, target->nfcid1_len, NULL);
+       } else if (target->supported_protocols & NFC_PROTO_JEWEL_MASK) {
+               return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+                                       PN544_JEWEL_RAW_CMD, NULL, 0, NULL);
+       } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
+               return nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
+                                       PN544_FELICA_RAW, NULL, 0, NULL);
+       } else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
+               return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+                                       PN544_HCI_CMD_ATTREQUEST,
+                                       NULL, 0, NULL);
+       }
+
+       return 0;
+}
+
+static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
+                                       u8 event, struct sk_buff *skb)
+{
+       struct sk_buff *rgb_skb = NULL;
+       int r = 0;
+
+       pr_debug("hci event %d", event);
+       switch (event) {
+       case PN544_HCI_EVT_ACTIVATED:
+               if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
+                       nfc_hci_target_discovered(hdev, gate);
+               else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
+                       r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
+                                               &rgb_skb);
+
+                       if (r < 0)
+                               goto exit;
+
+                       nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+                                       NFC_COMM_PASSIVE, rgb_skb->data,
+                                       rgb_skb->len);
+
+                       kfree_skb(rgb_skb);
+               }
+
+               break;
+       case PN544_HCI_EVT_DEACTIVATED:
+               nfc_hci_send_event(hdev, gate,
+                       NFC_HCI_EVT_END_OPERATION, NULL, 0);
+               break;
+       case PN544_HCI_EVT_RCV_DATA:
+               if (skb->len < 2) {
+                       r = -EPROTO;
+                       goto exit;
+               }
+
+               if (skb->data[0] != 0) {
+                       pr_debug("data0 %d", skb->data[0]);
+                       r = -EPROTO;
+                       goto exit;
+               }
+
+               skb_pull(skb, 2);
+               nfc_tm_data_received(hdev->ndev, skb);
+
+               return;
+       default:
+               break;
+       }
+
+exit:
+       kfree_skb(skb);
 }
 
 static struct nfc_hci_ops pn544_hci_ops = {
@@ -841,74 +774,36 @@ static struct nfc_hci_ops pn544_hci_ops = {
        .hci_ready = pn544_hci_ready,
        .xmit = pn544_hci_xmit,
        .start_poll = pn544_hci_start_poll,
+       .dep_link_up = pn544_hci_dep_link_up,
+       .dep_link_down = pn544_hci_dep_link_down,
        .target_from_gate = pn544_hci_target_from_gate,
        .complete_target_discovered = pn544_hci_complete_target_discovered,
-       .data_exchange = pn544_hci_data_exchange,
+       .im_transceive = pn544_hci_im_transceive,
+       .tm_send = pn544_hci_tm_send,
        .check_presence = pn544_hci_check_presence,
+       .event_received = pn544_hci_event_received,
 };
 
-static int __devinit pn544_hci_probe(struct i2c_client *client,
-                                    const struct i2c_device_id *id)
+int pn544_hci_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 pn544_hci_info *info;
-       struct pn544_nfc_platform_data *pdata;
-       int r = 0;
        u32 protocols;
        struct nfc_hci_init_data init_data;
-
-       dev_dbg(&client->dev, "%s\n", __func__);
-       dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
-
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-               dev_err(&client->dev, "Need I2C_FUNC_I2C\n");
-               return -ENODEV;
-       }
+       int r;
 
        info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);
        if (!info) {
-               dev_err(&client->dev,
-                       "Cannot allocate memory for pn544_hci_info.\n");
+               pr_err("Cannot allocate memory for pn544_hci_info.\n");
                r = -ENOMEM;
                goto err_info_alloc;
        }
 
-       info->i2c_dev = client;
+       info->phy_ops = phy_ops;
+       info->phy_id = phy_id;
        info->state = PN544_ST_COLD;
        mutex_init(&info->info_lock);
-       i2c_set_clientdata(client, info);
-
-       pdata = client->dev.platform_data;
-       if (pdata == NULL) {
-               dev_err(&client->dev, "No platform data\n");
-               r = -EINVAL;
-               goto err_pdata;
-       }
-
-       if (pdata->request_resources == NULL) {
-               dev_err(&client->dev, "request_resources() missing\n");
-               r = -EINVAL;
-               goto err_pdata;
-       }
-
-       r = pdata->request_resources(client);
-       if (r) {
-               dev_err(&client->dev, "Cannot get platform resources\n");
-               goto err_pdata;
-       }
-
-       info->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
-       info->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
-       info->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ);
-
-       pn544_hci_platform_init(info);
-
-       r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn,
-                                IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                PN544_HCI_DRIVER_NAME, info);
-       if (r < 0) {
-               dev_err(&client->dev, "Unable to register IRQ handler\n");
-               goto err_rti;
-       }
 
        init_data.gate_count = ARRAY_SIZE(pn544_gates);
 
@@ -928,13 +823,11 @@ static int __devinit pn544_hci_probe(struct i2c_client *client,
                    NFC_PROTO_NFC_DEP_MASK;
 
        info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
-                                            protocols, LLC_SHDLC_NAME,
-                                            PN544_FRAME_HEADROOM +
-                                            PN544_CMDS_HEADROOM,
-                                            PN544_FRAME_TAILROOM,
-                                            PN544_HCI_LLC_MAX_PAYLOAD);
+                                            protocols, llc_name,
+                                            phy_headroom + PN544_CMDS_HEADROOM,
+                                            phy_tailroom, phy_payload);
        if (!info->hdev) {
-               dev_err(&client->dev, "Cannot allocate nfc hdev.\n");
+               pr_err("Cannot allocate nfc hdev.\n");
                r = -ENOMEM;
                goto err_alloc_hdev;
        }
@@ -945,79 +838,25 @@ static int __devinit pn544_hci_probe(struct i2c_client *client,
        if (r)
                goto err_regdev;
 
+       *hdev = info->hdev;
+
        return 0;
 
 err_regdev:
        nfc_hci_free_device(info->hdev);
 
 err_alloc_hdev:
-       free_irq(client->irq, info);
-
-err_rti:
-       if (pdata->free_resources != NULL)
-               pdata->free_resources();
-
-err_pdata:
        kfree(info);
 
 err_info_alloc:
        return r;
 }
 
-static __devexit int pn544_hci_remove(struct i2c_client *client)
+void pn544_hci_remove(struct nfc_hci_dev *hdev)
 {
-       struct pn544_hci_info *info = i2c_get_clientdata(client);
-       struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
-
-       dev_dbg(&client->dev, "%s\n", __func__);
-
-       nfc_hci_free_device(info->hdev);
-
-       if (info->state != PN544_ST_COLD) {
-               if (pdata->disable)
-                       pdata->disable();
-       }
-
-       free_irq(client->irq, info);
-       if (pdata->free_resources)
-               pdata->free_resources();
+       struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
 
+       nfc_hci_unregister_device(hdev);
+       nfc_hci_free_device(hdev);
        kfree(info);
-
-       return 0;
 }
-
-static struct i2c_driver pn544_hci_driver = {
-       .driver = {
-                  .name = PN544_HCI_DRIVER_NAME,
-                 },
-       .probe = pn544_hci_probe,
-       .id_table = pn544_hci_id_table,
-       .remove = __devexit_p(pn544_hci_remove),
-};
-
-static int __init pn544_hci_init(void)
-{
-       int r;
-
-       pr_debug(DRIVER_DESC ": %s\n", __func__);
-
-       r = i2c_add_driver(&pn544_hci_driver);
-       if (r) {
-               pr_err(PN544_HCI_DRIVER_NAME ": driver registration failed\n");
-               return r;
-       }
-
-       return 0;
-}
-
-static void __exit pn544_hci_exit(void)
-{
-       i2c_del_driver(&pn544_hci_driver);
-}
-
-module_init(pn544_hci_init);
-module_exit(pn544_hci_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h
new file mode 100644 (file)
index 0000000..f47c645
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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_PN544_H_
+#define __LOCAL_PN544_H_
+
+#include <net/nfc/hci.h>
+
+#define DRIVER_DESC "HCI NFC driver for PN544"
+
+int pn544_hci_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 pn544_hci_remove(struct nfc_hci_dev *hdev);
+
+#endif /* __LOCAL_PN544_H_ */
index 266aa16..19396dc 100644 (file)
@@ -37,6 +37,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4350) },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
index b58fef7..d7d5804 100644 (file)
@@ -346,6 +346,8 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
                        chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
                }
                break;
+       case 43222:
+               break;
        default:
                ssb_printk(KERN_ERR PFX
                           "ERROR: PLL init unknown for device %04X\n",
@@ -434,6 +436,7 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
                 min_msk = 0xCBB;
                 break;
        case 0x4322:
+       case 43222:
                /* We keep the default settings:
                 * min_msk = 0xCBB
                 * max_msk = 0x7FFFF
index c625086..b918ba9 100644 (file)
@@ -192,9 +192,10 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
 
        /* When there is no chipcommon on the bus there is 4MB flash */
        if (!bus->chipco.dev) {
-               mcore->flash_buswidth = 2;
-               mcore->flash_window = SSB_FLASH1;
-               mcore->flash_window_size = SSB_FLASH1_SZ;
+               mcore->pflash.present = true;
+               mcore->pflash.buswidth = 2;
+               mcore->pflash.window = SSB_FLASH1;
+               mcore->pflash.window_size = SSB_FLASH1_SZ;
                return;
        }
 
@@ -206,13 +207,14 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
                break;
        case SSB_CHIPCO_FLASHT_PARA:
                pr_debug("Found parallel flash\n");
-               mcore->flash_window = SSB_FLASH2;
-               mcore->flash_window_size = SSB_FLASH2_SZ;
+               mcore->pflash.present = true;
+               mcore->pflash.window = SSB_FLASH2;
+               mcore->pflash.window_size = SSB_FLASH2_SZ;
                if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
                               & SSB_CHIPCO_CFG_DS16) == 0)
-                       mcore->flash_buswidth = 1;
+                       mcore->pflash.buswidth = 1;
                else
-                       mcore->flash_buswidth = 2;
+                       mcore->pflash.buswidth = 2;
                break;
        }
 }
index 4180eb7..fd15d98 100644 (file)
@@ -251,7 +251,7 @@ struct bcma_bus {
        u8 num;
 
        struct bcma_drv_cc drv_cc;
-       struct bcma_drv_pci drv_pci;
+       struct bcma_drv_pci drv_pci[2];
        struct bcma_drv_mips drv_mips;
        struct bcma_drv_gmac_cmn drv_gmac_cmn;
 
index 1cf1749..145f3c5 100644 (file)
@@ -510,6 +510,7 @@ struct bcma_chipcommon_pmu {
 
 #ifdef CONFIG_BCMA_DRIVER_MIPS
 struct bcma_pflash {
+       bool present;
        u8 buswidth;
        u32 window;
        u32 window_size;
@@ -532,6 +533,7 @@ struct mtd_info;
 
 struct bcma_nflash {
        bool present;
+       bool boot;              /* This is the flash the SoC boots from */
 
        struct mtd_info *mtd;
 };
@@ -552,6 +554,7 @@ struct bcma_drv_cc {
        u32 capabilities;
        u32 capabilities_ext;
        u8 setup_done:1;
+       u8 early_setup_done:1;
        /* Fast Powerup Delay constant */
        u16 fast_pwrup_delay;
        struct bcma_chipcommon_pmu pmu;
@@ -583,6 +586,7 @@ struct bcma_drv_cc {
        bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
 
 extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
+extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
 
 extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
@@ -606,6 +610,7 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
 
 /* PMU support */
 extern void bcma_pmu_init(struct bcma_drv_cc *cc);
+extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
 
 extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
                                  u32 value);
index c004364..0baf8a5 100644 (file)
@@ -35,13 +35,16 @@ struct bcma_device;
 struct bcma_drv_mips {
        struct bcma_device *core;
        u8 setup_done:1;
+       u8 early_setup_done:1;
        unsigned int assigned_irqs;
 };
 
 #ifdef CONFIG_BCMA_DRIVER_MIPS
 extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
 #else
 static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
+static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
 #endif
 
 extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
index 6c9cb93..7e8104b 100644 (file)
@@ -85,6 +85,9 @@
                                                         * (2 ZettaBytes), high 32 bits
                                                         */
 
-#define BCMA_SFLASH                    0x1c000000
+#define BCMA_SOC_FLASH1                        0x1fc00000      /* MIPS Flash Region 1 */
+#define BCMA_SOC_FLASH1_SZ             0x00400000      /* MIPS Size of Flash Region 1 */
+#define BCMA_SOC_FLASH2                        0x1c000000      /* Flash Region 2 (region 1 shadowed here) */
+#define BCMA_SOC_FLASH2_SZ             0x02000000      /* Size of Flash Region 2 */
 
 #endif /* LINUX_BCMA_REGS_H_ */
index 2385119..85764a9 100644 (file)
@@ -1107,20 +1107,6 @@ struct ieee80211_ht_operation {
 #define WLAN_HT_SMPS_CONTROL_STATIC    1
 #define WLAN_HT_SMPS_CONTROL_DYNAMIC   3
 
-#define VHT_MCS_SUPPORTED_SET_SIZE      8
-
-struct ieee80211_vht_capabilities {
-       __le32 vht_capabilities_info;
-       u8 vht_supported_mcs_set[VHT_MCS_SUPPORTED_SET_SIZE];
-} __packed;
-
-struct ieee80211_vht_operation {
-       u8 vht_op_info_chwidth;
-       u8 vht_op_info_chan_center_freq_seg1_idx;
-       u8 vht_op_info_chan_center_freq_seg2_idx;
-       __le16 vht_basic_mcs_set;
-} __packed;
-
 /**
  * struct ieee80211_vht_mcs_info - VHT MCS information
  * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams
@@ -1141,6 +1127,37 @@ struct ieee80211_vht_mcs_info {
        __le16 tx_highest;
 } __packed;
 
+/**
+ * struct ieee80211_vht_cap - VHT capabilities
+ *
+ * This structure is the "VHT capabilities element" as
+ * described in 802.11ac D3.0 8.4.2.160
+ * @vht_cap_info: VHT capability info
+ * @supp_mcs: VHT MCS supported rates
+ */
+struct ieee80211_vht_cap {
+       __le32 vht_cap_info;
+       struct ieee80211_vht_mcs_info supp_mcs;
+} __packed;
+
+/**
+ * struct ieee80211_vht_operation - VHT operation IE
+ *
+ * This structure is the "VHT operation element" as
+ * described in 802.11ac D3.0 8.4.2.161
+ * @chan_width: Operating channel width
+ * @center_freq_seg1_idx: center freq segment 1 index
+ * @center_freq_seg2_idx: center freq segment 2 index
+ * @basic_mcs_set: VHT Basic MCS rate set
+ */
+struct ieee80211_vht_operation {
+       u8 chan_width;
+       u8 center_freq_seg1_idx;
+       u8 center_freq_seg2_idx;
+       __le16 basic_mcs_set;
+} __packed;
+
+
 #define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0
 #define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1
 #define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT  2
@@ -1440,8 +1457,6 @@ enum ieee80211_eid {
 
        WLAN_EID_RSN = 48,
        WLAN_EID_MMIE = 76,
-       WLAN_EID_WPA = 221,
-       WLAN_EID_GENERIC = 221,
        WLAN_EID_VENDOR_SPECIFIC = 221,
        WLAN_EID_QOS_PARAMETER = 222,
 
index 1cc595a..f4e56ec 100644 (file)
@@ -4,5 +4,22 @@
 #include <linux/ip.h>
 #include <linux/in6.h>
 #include <uapi/linux/if_tunnel.h>
+#include <linux/u64_stats_sync.h>
+
+/*
+ * Locking : hash tables are protected by RCU and RTNL
+ */
+
+#define for_each_ip_tunnel_rcu(pos, start) \
+       for (pos = rcu_dereference(start); pos; pos = rcu_dereference(pos->next))
+
+/* often modified stats are per cpu, other are shared (netdev->stats) */
+struct pcpu_tstats {
+       u64     rx_packets;
+       u64     rx_bytes;
+       u64     tx_packets;
+       u64     tx_bytes;
+       struct u64_stats_sync   syncp;
+};
 
 #endif /* _IF_TUNNEL_H_ */
index ee21795..9cbd670 100644 (file)
@@ -604,6 +604,20 @@ struct pci_driver {
        .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
 
 /**
+ * PCI_DEVICE_SUB - macro used to describe a specific pci device with subsystem
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ * @subvend: the 16 bit PCI Subvendor ID
+ * @subdev: the 16 bit PCI Subdevice ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device with subsystem information.
+ */
+#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
+       .vendor = (vend), .device = (dev), \
+       .subvendor = (subvend), .subdevice = (subdev)
+
+/**
  * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
  * @dev_class: the class, subclass, prog-if triple for this device
  * @dev_class_mask: the class mask for this device
index b5c16c3..24368a2 100644 (file)
@@ -18,9 +18,7 @@
 #include <linux/if_ether.h>
 
 struct cpsw_slave_data {
-       u32             slave_reg_ofs;
-       u32             sliver_reg_ofs;
-       const char      *phy_id;
+       char            phy_id[MII_BUS_ID_SIZE];
        int             phy_if;
        u8              mac_addr[ETH_ALEN];
 };
@@ -28,31 +26,14 @@ struct cpsw_slave_data {
 struct cpsw_platform_data {
        u32     ss_reg_ofs;     /* Subsystem control register offset */
        u32     channels;       /* number of cpdma channels (symmetric) */
-       u32     cpdma_reg_ofs;  /* cpdma register offset */
-       u32     cpdma_sram_ofs; /* cpdma sram offset */
-
        u32     slaves;         /* number of slave cpgmac ports */
        struct cpsw_slave_data  *slave_data;
        u32     cpts_active_slave; /* time stamping slave */
        u32     cpts_clock_mult;  /* convert input clock ticks to nanoseconds */
        u32     cpts_clock_shift; /* convert input clock ticks to nanoseconds */
-
-       u32     ale_reg_ofs;    /* address lookup engine reg offset */
        u32     ale_entries;    /* ale table size */
-
-       u32     host_port_reg_ofs; /* cpsw cpdma host port registers */
-       u32     host_port_num; /* The port number for the host port */
-
-       u32     hw_stats_reg_ofs;  /* cpsw hardware statistics counters */
-       u32     cpts_reg_ofs;      /* cpts registers */
-
-       u32     bd_ram_ofs;   /* embedded buffer descriptor RAM offset*/
        u32     bd_ram_size;  /*buffer descriptor ram size */
-       u32     hw_ram_addr; /*if the HW address for BD RAM is different */
-       bool    no_bd_ram; /* no embedded BD ram*/
-
        u32     rx_descs;       /* Number of Rx Descriptios */
-
        u32     mac_control;    /* Mac control register */
 };
 
index 5f44e97..07a9c7a 100644 (file)
@@ -13,6 +13,12 @@ struct ssb_serial_port {
        unsigned int reg_shift;
 };
 
+struct ssb_pflash {
+       bool present;
+       u8 buswidth;
+       u32 window;
+       u32 window_size;
+};
 
 struct ssb_mipscore {
        struct ssb_device *dev;
@@ -20,9 +26,7 @@ struct ssb_mipscore {
        int nr_serial_ports;
        struct ssb_serial_port serial_ports[4];
 
-       u8 flash_buswidth;
-       u32 flash_window;
-       u32 flash_window_size;
+       struct ssb_pflash pflash;
 };
 
 extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
index 6a76e0a..42f2176 100644 (file)
 
 #define A2MP_FEAT_EXT  0x8000
 
+enum amp_mgr_state {
+       READ_LOC_AMP_INFO,
+       READ_LOC_AMP_ASSOC,
+       READ_LOC_AMP_ASSOC_FINAL,
+};
+
 struct amp_mgr {
+       struct list_head        list;
        struct l2cap_conn       *l2cap_conn;
        struct l2cap_chan       *a2mp_chan;
+       struct l2cap_chan       *bredr_chan;
        struct kref             kref;
        __u8                    ident;
        __u8                    handle;
+       enum amp_mgr_state      state;
        unsigned long           flags;
+
+       struct list_head        amp_ctrls;
+       struct mutex            amp_ctrls_lock;
 };
 
 struct a2mp_cmd {
@@ -118,9 +130,19 @@ struct a2mp_physlink_rsp {
 #define A2MP_STATUS_PHYS_LINK_EXISTS           0x05
 #define A2MP_STATUS_SECURITY_VIOLATION         0x06
 
-void amp_mgr_get(struct amp_mgr *mgr);
+extern struct list_head amp_mgr_list;
+extern struct mutex amp_mgr_list_lock;
+
+struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
+u8 __next_ident(struct amp_mgr *mgr);
 struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
                                       struct sk_buff *skb);
+struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
+void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
+void a2mp_discover_amp(struct l2cap_chan *chan);
+void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
+void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
+void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
 
 #endif /* __A2MP_H */
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
new file mode 100644 (file)
index 0000000..2e7c79e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only 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.
+*/
+
+#ifndef __AMP_H
+#define __AMP_H
+
+struct amp_ctrl {
+       struct list_head        list;
+       struct kref             kref;
+       __u8                    id;
+       __u16                   assoc_len_so_far;
+       __u16                   assoc_rem_len;
+       __u16                   assoc_len;
+       __u8                    *assoc;
+};
+
+int amp_ctrl_put(struct amp_ctrl *ctrl);
+void amp_ctrl_get(struct amp_ctrl *ctrl);
+struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id);
+struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id);
+void amp_ctrl_list_flush(struct amp_mgr *mgr);
+
+struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
+                            u8 remote_id, bool out);
+
+int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type);
+
+void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
+void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
+                                  struct hci_conn *hcon);
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon);
+void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon);
+void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
+void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
+
+#endif /* __AMP_H */
index ede0369..2554b3f 100644 (file)
@@ -180,7 +180,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src)
 }
 
 void baswap(bdaddr_t *dst, bdaddr_t *src);
-char *batostr(bdaddr_t *ba);
 
 /* Common socket structures and functions */
 
index 76b2b6b..88cbbda 100644 (file)
@@ -33,6 +33,8 @@
 #define HCI_LINK_KEY_SIZE      16
 #define HCI_AMP_LINK_KEY_SIZE  (2 * HCI_LINK_KEY_SIZE)
 
+#define HCI_MAX_AMP_ASSOC_SIZE 672
+
 /* HCI dev events */
 #define HCI_DEV_REG                    1
 #define HCI_DEV_UNREG                  2
@@ -196,6 +198,7 @@ enum {
 #define ACL_START_NO_FLUSH     0x00
 #define ACL_CONT               0x01
 #define ACL_START              0x02
+#define ACL_COMPLETE           0x03
 #define ACL_ACTIVE_BCAST       0x04
 #define ACL_PICO_BCAST         0x08
 
@@ -205,6 +208,7 @@ enum {
 #define ESCO_LINK      0x02
 /* Low Energy links do not have defined link type. Use invented one */
 #define LE_LINK                0x80
+#define AMP_LINK       0x81
 
 /* LMP features */
 #define LMP_3SLOT      0x01
@@ -556,12 +560,46 @@ struct hci_cp_accept_phy_link {
        __u8     key[HCI_AMP_LINK_KEY_SIZE];
 } __packed;
 
-#define HCI_OP_DISCONN_PHY_LINK        0x0437
+#define HCI_OP_DISCONN_PHY_LINK                0x0437
 struct hci_cp_disconn_phy_link {
        __u8     phy_handle;
        __u8     reason;
 } __packed;
 
+struct ext_flow_spec {
+       __u8       id;
+       __u8       stype;
+       __le16     msdu;
+       __le32     sdu_itime;
+       __le32     acc_lat;
+       __le32     flush_to;
+} __packed;
+
+#define HCI_OP_CREATE_LOGICAL_LINK     0x0438
+#define HCI_OP_ACCEPT_LOGICAL_LINK     0x0439
+struct hci_cp_create_accept_logical_link {
+       __u8                  phy_handle;
+       struct ext_flow_spec  tx_flow_spec;
+       struct ext_flow_spec  rx_flow_spec;
+} __packed;
+
+#define HCI_OP_DISCONN_LOGICAL_LINK    0x043a
+struct hci_cp_disconn_logical_link {
+       __le16   log_handle;
+} __packed;
+
+#define HCI_OP_LOGICAL_LINK_CANCEL     0x043b
+struct hci_cp_logical_link_cancel {
+       __u8     phy_handle;
+       __u8     flow_spec_id;
+} __packed;
+
+struct hci_rp_logical_link_cancel {
+       __u8     status;
+       __u8     phy_handle;
+       __u8     flow_spec_id;
+} __packed;
+
 #define HCI_OP_SNIFF_MODE              0x0803
 struct hci_cp_sniff_mode {
        __le16   handle;
index e7d4546..9fe8e2d 100644 (file)
@@ -73,6 +73,7 @@ struct discovery_state {
 struct hci_conn_hash {
        struct list_head list;
        unsigned int     acl_num;
+       unsigned int     amp_num;
        unsigned int     sco_num;
        unsigned int     le_num;
 };
@@ -124,6 +125,14 @@ struct le_scan_params {
 
 #define HCI_MAX_SHORT_NAME_LENGTH      10
 
+struct amp_assoc {
+       __u16   len;
+       __u16   offset;
+       __u16   rem_len;
+       __u16   len_so_far;
+       __u8    data[HCI_MAX_AMP_ASSOC_SIZE];
+};
+
 #define NUM_REASSEMBLY 4
 struct hci_dev {
        struct list_head list;
@@ -177,6 +186,8 @@ struct hci_dev {
        __u32           amp_max_flush_to;
        __u32           amp_be_flush_to;
 
+       struct amp_assoc        loc_assoc;
+
        __u8            flow_ctl_mode;
 
        unsigned int    auto_accept_delay;
@@ -252,8 +263,6 @@ struct hci_dev {
 
        struct sk_buff_head     driver_init;
 
-       void                    *core_data;
-
        atomic_t                promisc;
 
        struct dentry           *debugfs;
@@ -277,6 +286,8 @@ struct hci_dev {
        int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
 };
 
+#define HCI_PHY_HANDLE(handle) (handle & 0xff)
+
 struct hci_conn {
        struct list_head list;
 
@@ -310,6 +321,7 @@ struct hci_conn {
 
        __u8            remote_cap;
        __u8            remote_auth;
+       __u8            remote_id;
        bool            flush_key;
 
        unsigned int    sent;
@@ -339,7 +351,7 @@ struct hci_conn {
 
 struct hci_chan {
        struct list_head list;
-
+       __u16 handle;
        struct hci_conn *conn;
        struct sk_buff_head data_q;
        unsigned int    sent;
@@ -438,6 +450,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
        case ACL_LINK:
                h->acl_num++;
                break;
+       case AMP_LINK:
+               h->amp_num++;
+               break;
        case LE_LINK:
                h->le_num++;
                break;
@@ -459,6 +474,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
        case ACL_LINK:
                h->acl_num--;
                break;
+       case AMP_LINK:
+               h->amp_num--;
+               break;
        case LE_LINK:
                h->le_num--;
                break;
@@ -475,6 +493,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
        switch (type) {
        case ACL_LINK:
                return h->acl_num;
+       case AMP_LINK:
+               return h->amp_num;
        case LE_LINK:
                return h->le_num;
        case SCO_LINK:
@@ -556,6 +576,7 @@ void hci_conn_check_pending(struct hci_dev *hdev);
 struct hci_chan *hci_chan_create(struct hci_conn *conn);
 void hci_chan_del(struct hci_chan *chan);
 void hci_chan_list_flush(struct hci_conn *conn);
+struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
 
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                             __u8 dst_type, __u8 sec_level, __u8 auth_type);
@@ -584,7 +605,10 @@ static inline void hci_conn_put(struct hci_conn *conn)
 
        if (atomic_dec_and_test(&conn->refcnt)) {
                unsigned long timeo;
-               if (conn->type == ACL_LINK || conn->type == LE_LINK) {
+
+               switch (conn->type) {
+               case ACL_LINK:
+               case LE_LINK:
                        del_timer(&conn->idle_timer);
                        if (conn->state == BT_CONNECTED) {
                                timeo = conn->disc_timeout;
@@ -593,12 +617,20 @@ static inline void hci_conn_put(struct hci_conn *conn)
                        } else {
                                timeo = msecs_to_jiffies(10);
                        }
-               } else {
+                       break;
+
+               case AMP_LINK:
+                       timeo = conn->disc_timeout;
+                       break;
+
+               default:
                        timeo = msecs_to_jiffies(10);
+                       break;
                }
+
                cancel_delayed_work(&conn->disc_work);
                queue_delayed_work(conn->hdev->workqueue,
-                                       &conn->disc_work, timeo);
+                                  &conn->disc_work, timeo);
        }
 }
 
@@ -789,6 +821,10 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
                sco_disconn_cfm(conn, reason);
                break;
 
+       /* L2CAP would be handled for BREDR chan */
+       case AMP_LINK:
+               break;
+
        default:
                BT_ERR("unknown link type %d", conn->type);
                break;
index 7ed8e35..6e23afd 100644 (file)
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU              672
 #define L2CAP_DEFAULT_MIN_MTU          48
-#define L2CAP_DEFAULT_FLUSH_TO         0xffff
+#define L2CAP_DEFAULT_FLUSH_TO         0xFFFF
+#define L2CAP_EFS_DEFAULT_FLUSH_TO     0xFFFFFFFF
 #define L2CAP_DEFAULT_TX_WINDOW                63
 #define L2CAP_DEFAULT_EXT_WINDOW       0x3FFF
 #define L2CAP_DEFAULT_MAX_TX           3
 #define L2CAP_DEFAULT_RETRANS_TO       2000    /* 2 seconds */
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
-#define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
+#define L2CAP_DEFAULT_MAX_PDU_SIZE     1492    /* Sized for AMP packet */
 #define L2CAP_DEFAULT_ACK_TO           200
 #define L2CAP_DEFAULT_MAX_SDU_SIZE     0xFFFF
 #define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
@@ -508,6 +509,8 @@ struct l2cap_chan {
        __u32           remote_acc_lat;
        __u32           remote_flush_to;
 
+       __u8            ctrl_id;
+
        struct delayed_work     chan_timer;
        struct delayed_work     retrans_timer;
        struct delayed_work     monitor_timer;
@@ -538,6 +541,7 @@ struct l2cap_ops {
        void                    (*state_change) (struct l2cap_chan *chan,
                                                 int state);
        void                    (*ready) (struct l2cap_chan *chan);
+       void                    (*defer) (struct l2cap_chan *chan);
        struct sk_buff          *(*alloc_skb) (struct l2cap_chan *chan,
                                               unsigned long len, int nb);
 };
@@ -745,6 +749,10 @@ static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
 {
 }
 
+static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
+{
+}
+
 extern bool disable_ertm;
 
 int l2cap_init_sockets(void);
@@ -767,6 +775,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
 int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
+void l2cap_send_conn_req(struct l2cap_chan *chan);
 
 #endif /* __L2CAP_H */
index 7d5b600..c696457 100644 (file)
@@ -498,6 +498,7 @@ enum station_parameters_apply_mask {
  * @plink_action: plink action to take
  * @plink_state: set the peer link state for a station
  * @ht_capa: HT capabilities of station
+ * @vht_capa: VHT capabilities of station
  * @uapsd_queues: bitmap of queues configured for uapsd. same format
  *     as the AC bitmap in the QoS info field
  * @max_sp: max Service Period. same format as the MAX_SP in the
@@ -517,6 +518,7 @@ struct station_parameters {
        u8 plink_action;
        u8 plink_state;
        struct ieee80211_ht_cap *ht_capa;
+       struct ieee80211_vht_cap *vht_capa;
        u8 uapsd_queues;
        u8 max_sp;
 };
@@ -1000,8 +1002,10 @@ struct cfg80211_ssid {
  * @n_channels: total number of channels to scan
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
+ * @flags: bit field of flags controlling operation
  * @rates: bitmap of rates to advertise for each band
  * @wiphy: the wiphy this was for
+ * @scan_start: time (in jiffies) when the scan started
  * @wdev: the wireless device to scan for
  * @aborted: (internal) scan request was notified as aborted
  * @no_cck: used to send probe requests at non CCK rate in 2GHz band
@@ -1012,6 +1016,7 @@ struct cfg80211_scan_request {
        u32 n_channels;
        const u8 *ie;
        size_t ie_len;
+       u32 flags;
 
        u32 rates[IEEE80211_NUM_BANDS];
 
@@ -1019,6 +1024,7 @@ struct cfg80211_scan_request {
 
        /* internal */
        struct wiphy *wiphy;
+       unsigned long scan_start;
        bool aborted;
        bool no_cck;
 
@@ -1044,6 +1050,7 @@ struct cfg80211_match_set {
  * @interval: interval between each scheduled scan cycle
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
+ * @flags: bit field of flags controlling operation
  * @match_sets: sets of parameters to be matched for a scan result
  *     entry to be considered valid and to be passed to the host
  *     (others are filtered out).
@@ -1061,6 +1068,7 @@ struct cfg80211_sched_scan_request {
        u32 interval;
        const u8 *ie;
        size_t ie_len;
+       u32 flags;
        struct cfg80211_match_set *match_sets;
        int n_match_sets;
        s32 rssi_thold;
@@ -1068,6 +1076,7 @@ struct cfg80211_sched_scan_request {
        /* internal */
        struct wiphy *wiphy;
        struct net_device *dev;
+       unsigned long scan_start;
 
        /* keep last */
        struct ieee80211_channel *channels[0];
@@ -1152,6 +1161,9 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
  * @key: WEP key for shared key authentication
+ * @sae_data: Non-IE data to use with SAE or %NULL. This starts with
+ *     Authentication transaction sequence number field.
+ * @sae_data_len: Length of sae_data buffer in octets
  */
 struct cfg80211_auth_request {
        struct cfg80211_bss *bss;
@@ -1160,6 +1172,8 @@ struct cfg80211_auth_request {
        enum nl80211_auth_type auth_type;
        const u8 *key;
        u8 key_len, key_idx;
+       const u8 *sae_data;
+       size_t sae_data_len;
 };
 
 /**
index ddc077c..21947cf 100644 (file)
@@ -48,25 +48,27 @@ struct ip_tunnel_prl_entry {
        struct rcu_head                 rcu_head;
 };
 
-#define __IPTUNNEL_XMIT(stats1, stats2) do {                           \
-       int err;                                                        \
-       int pkt_len = skb->len - skb_transport_offset(skb);             \
-                                                                       \
-       skb->ip_summed = CHECKSUM_NONE;                                 \
-       ip_select_ident(iph, &rt->dst, NULL);                           \
-                                                                       \
-       err = ip_local_out(skb);                                        \
-       if (likely(net_xmit_eval(err) == 0)) {                          \
-               u64_stats_update_begin(&(stats1)->syncp);               \
-               (stats1)->tx_bytes += pkt_len;                          \
-               (stats1)->tx_packets++;                                 \
-               u64_stats_update_end(&(stats1)->syncp);                 \
-       } else {                                                        \
-               (stats2)->tx_errors++;                                  \
-               (stats2)->tx_aborted_errors++;                          \
-       }                                                               \
-} while (0)
+static inline void iptunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       int err;
+       struct iphdr *iph = ip_hdr(skb);
+       int pkt_len = skb->len - skb_transport_offset(skb);
+       struct pcpu_tstats *tstats = this_cpu_ptr(dev->tstats);
 
-#define IPTUNNEL_XMIT() __IPTUNNEL_XMIT(txq, stats)
+       nf_reset(skb);
+       skb->ip_summed = CHECKSUM_NONE;
+       ip_select_ident(iph, skb_dst(skb), NULL);
+
+       err = ip_local_out(skb);
+       if (likely(net_xmit_eval(err) == 0)) {
+               u64_stats_update_begin(&tstats->syncp);
+               tstats->tx_bytes += pkt_len;
+               tstats->tx_packets++;
+               u64_stats_update_end(&tstats->syncp);
+       } else {
+               dev->stats.tx_errors++;
+               dev->stats.tx_aborted_errors++;
+       }
+}
 
 #endif
index 82558c8..00b7204 100644 (file)
@@ -144,6 +144,41 @@ struct ieee80211_low_level_stats {
 };
 
 /**
+ * enum ieee80211_chanctx_change - change flag for channel context
+ * @IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE: The channel type was changed
+ * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed
+ */
+enum ieee80211_chanctx_change {
+       IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE   = BIT(0),
+       IEEE80211_CHANCTX_CHANGE_RX_CHAINS      = BIT(1),
+};
+
+/**
+ * struct ieee80211_chanctx_conf - channel context that vifs may be tuned to
+ *
+ * This is the driver-visible part. The ieee80211_chanctx
+ * that contains it is visible in mac80211 only.
+ *
+ * @channel: the channel to tune to
+ * @channel_type: the channel (HT) type
+ * @rx_chains_static: The number of RX chains that must always be
+ *     active on the channel to receive MIMO transmissions
+ * @rx_chains_dynamic: The number of RX chains that must be enabled
+ *     after RTS/CTS handshake to receive SMPS MIMO transmissions;
+ *     this will always be >= @rx_chains_always.
+ * @drv_priv: data area for driver use, will always be aligned to
+ *     sizeof(void *), size is determined in hw information.
+ */
+struct ieee80211_chanctx_conf {
+       struct ieee80211_channel *channel;
+       enum nl80211_channel_type channel_type;
+
+       u8 rx_chains_static, rx_chains_dynamic;
+
+       u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
+/**
  * enum ieee80211_bss_change - BSS change notification flags
  *
  * These flags are used with the bss_info_changed() callback
@@ -223,6 +258,7 @@ enum ieee80211_rssi_event {
  * @assoc: association status
  * @ibss_joined: indicates whether this station is part of an IBSS
  *     or not
+ * @ibss_creator: indicates if a new IBSS network is being created
  * @aid: association ID number, valid only when @assoc is true
  * @use_cts_prot: use CTS protection
  * @use_short_preamble: use 802.11b short preamble;
@@ -278,6 +314,7 @@ struct ieee80211_bss_conf {
        const u8 *bssid;
        /* association related data */
        bool assoc, ibss_joined;
+       bool ibss_creator;
        u16 aid;
        /* erp related data */
        bool use_cts_prot;
@@ -794,6 +831,8 @@ enum ieee80211_conf_flags {
  * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
  * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
  * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
+ *     Note that this is only valid if channel contexts are not used,
+ *     otherwise each channel context has the number of chains listed.
  */
 enum ieee80211_conf_changed {
        IEEE80211_CONF_CHANGE_SMPS              = BIT(1),
@@ -859,7 +898,9 @@ enum ieee80211_smps_mode {
  *
  * @smps_mode: spatial multiplexing powersave mode; note that
  *     %IEEE80211_SMPS_STATIC is used when the device is not
- *     configured for an HT channel
+ *     configured for an HT channel.
+ *     Note that this is only valid if channel contexts are not used,
+ *     otherwise each channel context has the number of chains listed.
  */
 struct ieee80211_conf {
        u32 flags;
@@ -931,6 +972,11 @@ enum ieee80211_vif_flags {
  *     at runtime, mac80211 will never touch this field
  * @hw_queue: hardware queue for each AC
  * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
+ * @chanctx_conf: The channel context this interface is assigned to, or %NULL
+ *     when it is not assigned. This pointer is RCU-protected due to the TX
+ *     path needing to access it; even though the netdev carrier will always
+ *     be off when it is %NULL there can still be races and packets could be
+ *     processed after it switches back to %NULL.
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *).
  */
@@ -943,6 +989,8 @@ struct ieee80211_vif {
        u8 cab_queue;
        u8 hw_queue[IEEE80211_NUM_ACS];
 
+       struct ieee80211_chanctx_conf __rcu *chanctx_conf;
+
        u32 driver_flags;
 
        /* must be last */
@@ -1076,6 +1124,8 @@ enum ieee80211_sta_state {
  * @aid: AID we assigned to the station if we're an AP
  * @supp_rates: Bitmap of supported rates (per band)
  * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
+ * @vht_cap: VHT capabilities of this STA; Not restricting any capabilities
+ *     of remote STA. Taking as is.
  * @wme: indicates whether the STA supports WME. Only valid during AP-mode.
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *), size is determined in hw information.
@@ -1088,6 +1138,7 @@ struct ieee80211_sta {
        u8 addr[ETH_ALEN];
        u16 aid;
        struct ieee80211_sta_ht_cap ht_cap;
+       struct ieee80211_sta_vht_cap vht_cap;
        bool wme;
        u8 uapsd_queues;
        u8 max_sp;
@@ -1325,6 +1376,8 @@ enum ieee80211_hw_flags {
  *     within &struct ieee80211_vif.
  * @sta_data_size: size (in bytes) of the drv_priv data area
  *     within &struct ieee80211_sta.
+ * @chanctx_data_size: size (in bytes) of the drv_priv data area
+ *     within &struct ieee80211_chanctx_conf.
  *
  * @max_rates: maximum number of alternate rate retry stages the hw
  *     can handle.
@@ -1369,6 +1422,7 @@ struct ieee80211_hw {
        int channel_change_time;
        int vif_data_size;
        int sta_data_size;
+       int chanctx_data_size;
        int napi_weight;
        u16 queues;
        u16 max_listen_interval;
@@ -2317,6 +2371,16 @@ enum ieee80211_rate_control_changed {
  *     The callback will be called before each transmission and upon return
  *     mac80211 will transmit the frame right away.
  *     The callback is optional and can (should!) sleep.
+ *
+ * @add_chanctx: Notifies device driver about new channel context creation.
+ * @remove_chanctx: Notifies device driver about channel context destruction.
+ * @change_chanctx: Notifies device driver about channel context changes that
+ *     may happen when combining different virtual interfaces on the same
+ *     channel context with different settings
+ * @assign_vif_chanctx: Notifies device driver about channel context being bound
+ *     to vif. Possible use is for hw queue remapping.
+ * @unassign_vif_chanctx: Notifies device driver about channel context being
+ *     unbound from vif.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -2461,6 +2525,20 @@ struct ieee80211_ops {
 
        void    (*mgd_prepare_tx)(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif);
+
+       int (*add_chanctx)(struct ieee80211_hw *hw,
+                          struct ieee80211_chanctx_conf *ctx);
+       void (*remove_chanctx)(struct ieee80211_hw *hw,
+                              struct ieee80211_chanctx_conf *ctx);
+       void (*change_chanctx)(struct ieee80211_hw *hw,
+                              struct ieee80211_chanctx_conf *ctx,
+                              u32 changed);
+       int (*assign_vif_chanctx)(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_chanctx_conf *ctx);
+       void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
+                                    struct ieee80211_chanctx_conf *ctx);
 };
 
 /**
@@ -3145,6 +3223,19 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
                            struct sk_buff *skb, u8 *p2k);
 
 /**
+ * ieee80211_aes_cmac_calculate_k1_k2 - calculate the AES-CMAC sub keys
+ *
+ * This function computes the two AES-CMAC sub-keys, based on the
+ * previously installed master key.
+ *
+ * @keyconf: the parameter passed with the set key
+ * @k1: a buffer to be filled with the 1st sub-key
+ * @k2: a buffer to be filled with the 2nd sub-key
+ */
+void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf,
+                                       u8 *k1, u8 *k2);
+
+/**
  * struct ieee80211_key_seq - key sequence counter
  *
  * @tkip: TKIP data, containing IV32 and IV16 in host byte order
@@ -3524,6 +3615,27 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
                         void *iter_data);
 
 /**
+ * ieee80211_iter_chan_contexts_atomic - iterate channel contexts
+ * @hw: pointre obtained from ieee80211_alloc_hw().
+ * @iter: iterator function
+ * @iter_data: data passed to iterator function
+ *
+ * Iterate all active channel contexts. This function is atomic and
+ * doesn't acquire any locks internally that might be held in other
+ * places while calling into the driver.
+ *
+ * The iterator will not find a context that's being added (during
+ * the driver callback to add it) but will find it while it's being
+ * removed.
+ */
+void ieee80211_iter_chan_contexts_atomic(
+       struct ieee80211_hw *hw,
+       void (*iter)(struct ieee80211_hw *hw,
+                    struct ieee80211_chanctx_conf *chanctx_conf,
+                    void *data),
+       void *iter_data);
+
+/**
  * ieee80211_ap_probereq_get - retrieve a Probe Request template
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
index e900072..639f50a 100644 (file)
 
 #include <net/nfc/nfc.h>
 
+struct nfc_phy_ops {
+       int (*write)(void *dev_id, struct sk_buff *skb);
+       int (*enable)(void *dev_id);
+       void (*disable)(void *dev_id);
+};
+
 struct nfc_hci_dev;
 
 struct nfc_hci_ops {
@@ -38,15 +44,21 @@ struct nfc_hci_ops {
        int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
        int (*start_poll) (struct nfc_hci_dev *hdev,
                           u32 im_protocols, u32 tm_protocols);
+       int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
+                          u8 comm_mode, u8 *gb, size_t gb_len);
+       int (*dep_link_down)(struct nfc_hci_dev *hdev);
        int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
                                 struct nfc_target *target);
        int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
                                           struct nfc_target *target);
-       int (*data_exchange) (struct nfc_hci_dev *hdev,
+       int (*im_transceive) (struct nfc_hci_dev *hdev,
                              struct nfc_target *target, struct sk_buff *skb,
                              data_exchange_cb_t cb, void *cb_context);
+       int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_hci_dev *hdev,
                              struct nfc_target *target);
+       void (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+                               struct sk_buff *skb);
 };
 
 /* Pipes */
@@ -114,6 +126,9 @@ struct nfc_hci_dev {
        int async_cb_type;
        data_exchange_cb_t async_cb;
        void *async_cb_context;
+
+       u8 *gb;
+       size_t gb_len;
 };
 
 /* hci device allocation */
@@ -219,5 +234,6 @@ int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,
                          const u8 *param, size_t param_len);
 int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
                       const u8 *param, size_t param_len);
+int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate);
 
 #endif /* __NET_HCI_H */
index f05b106..fce80b2 100644 (file)
@@ -95,7 +95,7 @@ struct nfc_genl_data {
 };
 
 struct nfc_dev {
-       unsigned int idx;
+       int idx;
        u32 target_next_idx;
        struct nfc_target *targets;
        int n_targets;
index 5c80cb1..7aae017 100644 (file)
@@ -205,6 +205,23 @@ enum {
 
 #define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
 
+enum {
+       BRIDGE_MODE_UNSPEC,
+       BRIDGE_MODE_HAIRPIN,
+};
+
+enum {
+       IFLA_BRPORT_UNSPEC,
+       IFLA_BRPORT_STATE,      /* Spanning tree state     */
+       IFLA_BRPORT_PRIORITY,   /* "             priority  */
+       IFLA_BRPORT_COST,       /* "             cost      */
+       IFLA_BRPORT_MODE,       /* mode (hairpin)          */
+       IFLA_BRPORT_GUARD,      /* bpdu guard              */
+       IFLA_BRPORT_PROTECT,    /* root port protection    */
+       __IFLA_BRPORT_MAX
+};
+#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+
 struct ifla_cacheinfo {
        __u32   max_reasm_len;
        __u32   tstamp;         /* ipv6InterfaceTable updated timestamp */
index c1bf0b5..5ab0c8d 100644 (file)
@@ -47,6 +47,8 @@ enum {
        IFLA_IPTUN_ENCAP_LIMIT,
        IFLA_IPTUN_FLOWINFO,
        IFLA_IPTUN_FLAGS,
+       IFLA_IPTUN_PROTO,
+       IFLA_IPTUN_PMTUDISC,
        __IFLA_IPTUN_MAX,
 };
 #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
index d908d17..0e63cee 100644 (file)
  *      target mode.
  * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated
  *      from target mode.
+ * @NFC_CMD_LLC_GET_PARAMS: request LTO, RW, and MIUX parameters for a device
+ * @NFC_CMD_LLC_SET_PARAMS: set one or more of LTO, RW, and MIUX parameters for
+ *     a device. LTO must be set before the link is up otherwise -EINPROGRESS
+ *     is returned. RW and MIUX can be set at anytime and will be passed in
+ *     subsequent CONNECT and CC messages.
+ *     If one of the passed parameters is wrong none is set and -EINVAL is
+ *     returned.
  */
 enum nfc_commands {
        NFC_CMD_UNSPEC,
@@ -77,6 +84,8 @@ enum nfc_commands {
        NFC_EVENT_TARGET_LOST,
        NFC_EVENT_TM_ACTIVATED,
        NFC_EVENT_TM_DEACTIVATED,
+       NFC_CMD_LLC_GET_PARAMS,
+       NFC_CMD_LLC_SET_PARAMS,
 /* private: internal use only */
        __NFC_CMD_AFTER_LAST
 };
@@ -102,6 +111,9 @@ enum nfc_commands {
  * @NFC_ATTR_RF_MODE: Initiator or target
  * @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for
  * @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen for
+ * @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter
+ * @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter
+ * @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter
  */
 enum nfc_attrs {
        NFC_ATTR_UNSPEC,
@@ -119,6 +131,9 @@ enum nfc_attrs {
        NFC_ATTR_DEVICE_POWERED,
        NFC_ATTR_IM_PROTOCOLS,
        NFC_ATTR_TM_PROTOCOLS,
+       NFC_ATTR_LLC_PARAM_LTO,
+       NFC_ATTR_LLC_PARAM_RW,
+       NFC_ATTR_LLC_PARAM_MIUX,
 /* private: internal use only */
        __NFC_ATTR_AFTER_LAST
 };
index 7df9b50..617d0fb 100644 (file)
@@ -1273,6 +1273,14 @@ enum nl80211_commands {
  *     the connection request from a station. nl80211_connect_failed_reason
  *     enum has different reasons of connection failure.
  *
+ * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
+ *     with the Authentication transaction sequence number field.
+ *
+ * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
+ *     association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32)
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1530,6 +1538,12 @@ enum nl80211_attrs {
 
        NL80211_ATTR_CONN_FAILED_REASON,
 
+       NL80211_ATTR_SAE_DATA,
+
+       NL80211_ATTR_VHT_CAPABILITY,
+
+       NL80211_ATTR_SCAN_FLAGS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1573,6 +1587,7 @@ enum nl80211_attrs {
 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY    16
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY    24
 #define NL80211_HT_CAPABILITY_LEN              26
+#define NL80211_VHT_CAPABILITY_LEN             12
 
 #define NL80211_MAX_NR_CIPHER_SUITES           5
 #define NL80211_MAX_NR_AKM_SUITES              2
@@ -2489,6 +2504,7 @@ enum nl80211_bss_status {
  * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
  * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
  * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
  * @__NL80211_AUTHTYPE_NUM: internal
  * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
  * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -2500,6 +2516,7 @@ enum nl80211_auth_type {
        NL80211_AUTHTYPE_SHARED_KEY,
        NL80211_AUTHTYPE_FT,
        NL80211_AUTHTYPE_NETWORK_EAP,
+       NL80211_AUTHTYPE_SAE,
 
        /* keep last */
        __NL80211_AUTHTYPE_NUM,
@@ -3028,6 +3045,12 @@ enum nl80211_ap_sme_features {
  *     in the interface combinations, even when it's only used for scan
  *     and remain-on-channel. This could be due to, for example, the
  *     remain-on-channel implementation requiring a channel context.
+ * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
+ *     equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
+ *     mode
+ * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
+ * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
+ * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -3035,6 +3058,10 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_INACTIVITY_TIMER                = 1 << 2,
        NL80211_FEATURE_CELL_BASE_REG_HINTS             = 1 << 3,
        NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL        = 1 << 4,
+       NL80211_FEATURE_SAE                             = 1 << 5,
+       NL80211_FEATURE_LOW_PRIORITY_SCAN               = 1 << 6,
+       NL80211_FEATURE_SCAN_FLUSH                      = 1 << 7,
+       NL80211_FEATURE_AP_SCAN                         = 1 << 8,
 };
 
 /**
@@ -3069,4 +3096,25 @@ enum nl80211_connect_failed_reason {
        NL80211_CONN_FAIL_BLOCKED_CLIENT,
 };
 
+/**
+ * enum nl80211_scan_flags -  scan request control flags
+ *
+ * Scan request control flags are used to control the handling
+ * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
+ * requests.
+ *
+ * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
+ * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
+ * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
+ *     as AP and the beaconing has already been configured. This attribute is
+ *     dangerous because will destroy stations performance as a lot of frames
+ *     will be lost while scanning off-channel, therefore it must be used only
+ *     when really needed
+ */
+enum nl80211_scan_flags {
+       NL80211_SCAN_FLAG_LOW_PRIORITY                  = 1<<0,
+       NL80211_SCAN_FLAG_FLUSH                         = 1<<1,
+       NL80211_SCAN_FLAG_AP                            = 1<<2,
+};
+
 #endif /* __LINUX_NL80211_H */
index 3537d38..1c11d0d 100644 (file)
@@ -11,6 +11,7 @@ menuconfig BT
        select CRYPTO_BLKCIPHER
        select CRYPTO_AES
        select CRYPTO_ECB
+       select CRYPTO_SHA256
        help
          Bluetooth is low-cost, low-power, short-range wireless technology.
          It was designed as a replacement for cables and other short-range
index fa6d94a..dea6a28 100644 (file)
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
        hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
-       a2mp.o
+       a2mp.o amp.o
index 0760d1f..d5136cf 100644 (file)
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
+
+/* Global AMP Manager list */
+LIST_HEAD(amp_mgr_list);
+DEFINE_MUTEX(amp_mgr_list_lock);
 
 /* A2MP build & send command helper functions */
 static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
@@ -37,8 +42,7 @@ static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
        return cmd;
 }
 
-static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
-                     void *data)
+void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
 {
        struct l2cap_chan *chan = mgr->a2mp_chan;
        struct a2mp_cmd *cmd;
@@ -63,6 +67,14 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
        kfree(cmd);
 }
 
+u8 __next_ident(struct amp_mgr *mgr)
+{
+       if (++mgr->ident == 0)
+               mgr->ident = 1;
+
+       return mgr->ident;
+}
+
 static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
 {
        cl->id = 0;
@@ -161,6 +173,83 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
        return 0;
 }
 
+static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                            struct a2mp_cmd *hdr)
+{
+       struct a2mp_discov_rsp *rsp = (void *) skb->data;
+       u16 len = le16_to_cpu(hdr->len);
+       struct a2mp_cl *cl;
+       u16 ext_feat;
+       bool found = false;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       len -= sizeof(*rsp);
+       skb_pull(skb, sizeof(*rsp));
+
+       ext_feat = le16_to_cpu(rsp->ext_feat);
+
+       BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(rsp->mtu), ext_feat);
+
+       /* check that packet is not broken for now */
+       while (ext_feat & A2MP_FEAT_EXT) {
+               if (len < sizeof(ext_feat))
+                       return -EINVAL;
+
+               ext_feat = get_unaligned_le16(skb->data);
+               BT_DBG("efm 0x%4.4x", ext_feat);
+               len -= sizeof(ext_feat);
+               skb_pull(skb, sizeof(ext_feat));
+       }
+
+       cl = (void *) skb->data;
+       while (len >= sizeof(*cl)) {
+               BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type,
+                      cl->status);
+
+               if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) {
+                       struct a2mp_info_req req;
+
+                       found = true;
+                       req.id = cl->id;
+                       a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr),
+                                 sizeof(req), &req);
+               }
+
+               len -= sizeof(*cl);
+               cl = (void *) skb_pull(skb, sizeof(*cl));
+       }
+
+       /* Fall back to L2CAP init sequence */
+       if (!found) {
+               struct l2cap_conn *conn = mgr->l2cap_conn;
+               struct l2cap_chan *chan;
+
+               mutex_lock(&conn->chan_lock);
+
+               list_for_each_entry(chan, &conn->chan_l, list) {
+
+                       BT_DBG("chan %p state %s", chan,
+                              state_to_string(chan->state));
+
+                       if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
+                               continue;
+
+                       l2cap_chan_lock(chan);
+
+                       if (chan->state == BT_CONNECT)
+                               l2cap_send_conn_req(chan);
+
+                       l2cap_chan_unlock(chan);
+               }
+
+               mutex_unlock(&conn->chan_lock);
+       }
+
+       return 0;
+}
+
 static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
                              struct a2mp_cmd *hdr)
 {
@@ -181,7 +270,6 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
                            struct a2mp_cmd *hdr)
 {
        struct a2mp_info_req *req  = (void *) skb->data;
-       struct a2mp_info_rsp rsp;
        struct hci_dev *hdev;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
@@ -189,53 +277,93 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
 
        BT_DBG("id %d", req->id);
 
-       rsp.id = req->id;
-       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
-
        hdev = hci_dev_get(req->id);
-       if (hdev && hdev->amp_type != HCI_BREDR) {
-               rsp.status = 0;
-               rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
-               rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
-               rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
-               rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
-               rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+       if (!hdev || hdev->dev_type != HCI_AMP) {
+               struct a2mp_info_rsp rsp;
+
+               rsp.id = req->id;
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+               a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp),
+                         &rsp);
+
+               goto done;
        }
 
+       mgr->state = READ_LOC_AMP_INFO;
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+
+done:
        if (hdev)
                hci_dev_put(hdev);
 
-       a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
-
        skb_pull(skb, sizeof(*req));
        return 0;
 }
 
+static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                           struct a2mp_cmd *hdr)
+{
+       struct a2mp_info_rsp *rsp = (struct a2mp_info_rsp *) skb->data;
+       struct a2mp_amp_assoc_req req;
+       struct amp_ctrl *ctrl;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*rsp))
+               return -EINVAL;
+
+       BT_DBG("id %d status 0x%2.2x", rsp->id, rsp->status);
+
+       if (rsp->status)
+               return -EINVAL;
+
+       ctrl = amp_ctrl_add(mgr, rsp->id);
+       if (!ctrl)
+               return -ENOMEM;
+
+       req.id = rsp->id;
+       a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req),
+                 &req);
+
+       skb_pull(skb, sizeof(*rsp));
+       return 0;
+}
+
 static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
                                struct a2mp_cmd *hdr)
 {
        struct a2mp_amp_assoc_req *req = (void *) skb->data;
        struct hci_dev *hdev;
+       struct amp_mgr *tmp;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
                return -EINVAL;
 
        BT_DBG("id %d", req->id);
 
+       /* Make sure that other request is not processed */
+       tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
+
        hdev = hci_dev_get(req->id);
-       if (!hdev || hdev->amp_type == HCI_BREDR) {
+       if (!hdev || hdev->amp_type == HCI_BREDR || tmp) {
                struct a2mp_amp_assoc_rsp rsp;
                rsp.id = req->id;
-               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+               if (tmp) {
+                       rsp.status = A2MP_STATUS_COLLISION_OCCURED;
+                       amp_mgr_put(tmp);
+               } else {
+                       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+               }
 
                a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
                          &rsp);
-               goto clean;
+
+               goto done;
        }
 
-       /* Placeholder for HCI Read AMP Assoc */
+       amp_read_loc_assoc(hdev, mgr);
 
-clean:
+done:
        if (hdev)
                hci_dev_put(hdev);
 
@@ -243,6 +371,68 @@ clean:
        return 0;
 }
 
+static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                               struct a2mp_cmd *hdr)
+{
+       struct a2mp_amp_assoc_rsp *rsp = (void *) skb->data;
+       u16 len = le16_to_cpu(hdr->len);
+       struct hci_dev *hdev;
+       struct amp_ctrl *ctrl;
+       struct hci_conn *hcon;
+       size_t assoc_len;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       assoc_len = len - sizeof(*rsp);
+
+       BT_DBG("id %d status 0x%2.2x assoc len %zu", rsp->id, rsp->status,
+              assoc_len);
+
+       if (rsp->status)
+               return -EINVAL;
+
+       /* Save remote ASSOC data */
+       ctrl = amp_ctrl_lookup(mgr, rsp->id);
+       if (ctrl) {
+               u8 *assoc;
+
+               assoc = kzalloc(assoc_len, GFP_KERNEL);
+               if (!assoc) {
+                       amp_ctrl_put(ctrl);
+                       return -ENOMEM;
+               }
+
+               memcpy(assoc, rsp->amp_assoc, assoc_len);
+               ctrl->assoc = assoc;
+               ctrl->assoc_len = assoc_len;
+               ctrl->assoc_rem_len = assoc_len;
+               ctrl->assoc_len_so_far = 0;
+
+               amp_ctrl_put(ctrl);
+       }
+
+       /* Create Phys Link */
+       hdev = hci_dev_get(rsp->id);
+       if (!hdev)
+               return -EINVAL;
+
+       hcon = phylink_add(hdev, mgr, rsp->id, true);
+       if (!hcon)
+               goto done;
+
+       BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id);
+
+       mgr->bredr_chan->ctrl_id = rsp->id;
+
+       amp_create_phylink(hdev, mgr, hcon);
+
+done:
+       hci_dev_put(hdev);
+       skb_pull(skb, len);
+       return 0;
+}
+
 static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
                                   struct a2mp_cmd *hdr)
 {
@@ -250,6 +440,8 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
 
        struct a2mp_physlink_rsp rsp;
        struct hci_dev *hdev;
+       struct hci_conn *hcon;
+       struct amp_ctrl *ctrl;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
                return -EINVAL;
@@ -265,9 +457,43 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
                goto send_rsp;
        }
 
-       /* TODO process physlink create */
+       ctrl = amp_ctrl_lookup(mgr, rsp.remote_id);
+       if (!ctrl) {
+               ctrl = amp_ctrl_add(mgr, rsp.remote_id);
+               if (ctrl) {
+                       amp_ctrl_get(ctrl);
+               } else {
+                       rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
+                       goto send_rsp;
+               }
+       }
 
-       rsp.status = A2MP_STATUS_SUCCESS;
+       if (ctrl) {
+               size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req);
+               u8 *assoc;
+
+               assoc = kzalloc(assoc_len, GFP_KERNEL);
+               if (!assoc) {
+                       amp_ctrl_put(ctrl);
+                       return -ENOMEM;
+               }
+
+               memcpy(assoc, req->amp_assoc, assoc_len);
+               ctrl->assoc = assoc;
+               ctrl->assoc_len = assoc_len;
+               ctrl->assoc_rem_len = assoc_len;
+               ctrl->assoc_len_so_far = 0;
+
+               amp_ctrl_put(ctrl);
+       }
+
+       hcon = phylink_add(hdev, mgr, req->local_id, false);
+       if (hcon) {
+               amp_accept_phylink(hdev, mgr, hcon);
+               rsp.status = A2MP_STATUS_SUCCESS;
+       } else {
+               rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
+       }
 
 send_rsp:
        if (hdev)
@@ -286,6 +512,7 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
        struct a2mp_physlink_req *req = (void *) skb->data;
        struct a2mp_physlink_rsp rsp;
        struct hci_dev *hdev;
+       struct hci_conn *hcon;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
                return -EINVAL;
@@ -296,14 +523,22 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
        rsp.remote_id = req->local_id;
        rsp.status = A2MP_STATUS_SUCCESS;
 
-       hdev = hci_dev_get(req->local_id);
+       hdev = hci_dev_get(req->remote_id);
        if (!hdev) {
                rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
                goto send_rsp;
        }
 
+       hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, mgr->l2cap_conn->dst);
+       if (!hcon) {
+               BT_ERR("No phys link exist");
+               rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS;
+               goto clean;
+       }
+
        /* TODO Disconnect Phys Link here */
 
+clean:
        hci_dev_put(hdev);
 
 send_rsp:
@@ -377,10 +612,19 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
                        err = a2mp_discphyslink_req(mgr, skb, hdr);
                        break;
 
-               case A2MP_CHANGE_RSP:
                case A2MP_DISCOVER_RSP:
+                       err = a2mp_discover_rsp(mgr, skb, hdr);
+                       break;
+
                case A2MP_GETINFO_RSP:
+                       err = a2mp_getinfo_rsp(mgr, skb, hdr);
+                       break;
+
                case A2MP_GETAMPASSOC_RSP:
+                       err = a2mp_getampassoc_rsp(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CHANGE_RSP:
                case A2MP_CREATEPHYSLINK_RSP:
                case A2MP_DISCONNPHYSLINK_RSP:
                        err = a2mp_cmd_rsp(mgr, skb, hdr);
@@ -455,9 +699,10 @@ static struct l2cap_ops a2mp_chan_ops = {
        .new_connection = l2cap_chan_no_new_connection,
        .teardown = l2cap_chan_no_teardown,
        .ready = l2cap_chan_no_ready,
+       .defer = l2cap_chan_no_defer,
 };
 
-static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
 {
        struct l2cap_chan *chan;
        int err;
@@ -492,7 +737,10 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
        chan->conf_state = 0;
 
-       l2cap_chan_add(conn, chan);
+       if (locked)
+               __l2cap_chan_add(conn, chan);
+       else
+               l2cap_chan_add(conn, chan);
 
        chan->remote_mps = chan->omtu;
        chan->mps = chan->omtu;
@@ -503,11 +751,13 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 }
 
 /* AMP Manager functions */
-void amp_mgr_get(struct amp_mgr *mgr)
+struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr)
 {
        BT_DBG("mgr %p orig refcnt %d", mgr, atomic_read(&mgr->kref.refcount));
 
        kref_get(&mgr->kref);
+
+       return mgr;
 }
 
 static void amp_mgr_destroy(struct kref *kref)
@@ -516,6 +766,11 @@ static void amp_mgr_destroy(struct kref *kref)
 
        BT_DBG("mgr %p", mgr);
 
+       mutex_lock(&amp_mgr_list_lock);
+       list_del(&mgr->list);
+       mutex_unlock(&amp_mgr_list_lock);
+
+       amp_ctrl_list_flush(mgr);
        kfree(mgr);
 }
 
@@ -526,7 +781,7 @@ int amp_mgr_put(struct amp_mgr *mgr)
        return kref_put(&mgr->kref, &amp_mgr_destroy);
 }
 
-static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
 {
        struct amp_mgr *mgr;
        struct l2cap_chan *chan;
@@ -539,7 +794,7 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
        mgr->l2cap_conn = conn;
 
-       chan = a2mp_chan_open(conn);
+       chan = a2mp_chan_open(conn, locked);
        if (!chan) {
                kfree(mgr);
                return NULL;
@@ -552,6 +807,14 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
        kref_init(&mgr->kref);
 
+       /* Remote AMP ctrl list initialization */
+       INIT_LIST_HEAD(&mgr->amp_ctrls);
+       mutex_init(&mgr->amp_ctrls_lock);
+
+       mutex_lock(&amp_mgr_list_lock);
+       list_add(&mgr->list, &amp_mgr_list);
+       mutex_unlock(&amp_mgr_list_lock);
+
        return mgr;
 }
 
@@ -560,7 +823,7 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
 {
        struct amp_mgr *mgr;
 
-       mgr = amp_mgr_create(conn);
+       mgr = amp_mgr_create(conn, false);
        if (!mgr) {
                BT_ERR("Could not create AMP manager");
                return NULL;
@@ -570,3 +833,139 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
 
        return mgr->a2mp_chan;
 }
+
+struct amp_mgr *amp_mgr_lookup_by_state(u8 state)
+{
+       struct amp_mgr *mgr;
+
+       mutex_lock(&amp_mgr_list_lock);
+       list_for_each_entry(mgr, &amp_mgr_list, list) {
+               if (mgr->state == state) {
+                       amp_mgr_get(mgr);
+                       mutex_unlock(&amp_mgr_list_lock);
+                       return mgr;
+               }
+       }
+       mutex_unlock(&amp_mgr_list_lock);
+
+       return NULL;
+}
+
+void a2mp_send_getinfo_rsp(struct hci_dev *hdev)
+{
+       struct amp_mgr *mgr;
+       struct a2mp_info_rsp rsp;
+
+       mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_INFO);
+       if (!mgr)
+               return;
+
+       BT_DBG("%s mgr %p", hdev->name, mgr);
+
+       rsp.id = hdev->id;
+       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+       if (hdev->amp_type != HCI_BREDR) {
+               rsp.status = 0;
+               rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+               rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+               rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+               rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+               rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+       }
+
+       a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp);
+       amp_mgr_put(mgr);
+}
+
+void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status)
+{
+       struct amp_mgr *mgr;
+       struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+       struct a2mp_amp_assoc_rsp *rsp;
+       size_t len;
+
+       mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
+       if (!mgr)
+               return;
+
+       BT_DBG("%s mgr %p", hdev->name, mgr);
+
+       len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len;
+       rsp = kzalloc(len, GFP_KERNEL);
+       if (!rsp) {
+               amp_mgr_put(mgr);
+               return;
+       }
+
+       rsp->id = hdev->id;
+
+       if (status) {
+               rsp->status = A2MP_STATUS_INVALID_CTRL_ID;
+       } else {
+               rsp->status = A2MP_STATUS_SUCCESS;
+               memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len);
+       }
+
+       a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp);
+       amp_mgr_put(mgr);
+       kfree(rsp);
+}
+
+void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status)
+{
+       struct amp_mgr *mgr;
+       struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+       struct a2mp_physlink_req *req;
+       struct l2cap_chan *bredr_chan;
+       size_t len;
+
+       mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC_FINAL);
+       if (!mgr)
+               return;
+
+       len = sizeof(*req) + loc_assoc->len;
+
+       BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len);
+
+       req = kzalloc(len, GFP_KERNEL);
+       if (!req) {
+               amp_mgr_put(mgr);
+               return;
+       }
+
+       bredr_chan = mgr->bredr_chan;
+       if (!bredr_chan)
+               goto clean;
+
+       req->local_id = hdev->id;
+       req->remote_id = bredr_chan->ctrl_id;
+       memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len);
+
+       a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req);
+
+clean:
+       amp_mgr_put(mgr);
+       kfree(req);
+}
+
+void a2mp_discover_amp(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
+       struct amp_mgr *mgr = conn->hcon->amp_mgr;
+       struct a2mp_discov_req req;
+
+       BT_DBG("chan %p conn %p mgr %p", chan, conn, mgr);
+
+       if (!mgr) {
+               mgr = amp_mgr_create(conn, true);
+               if (!mgr)
+                       return;
+       }
+
+       mgr->bredr_chan = chan;
+
+       req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+       req.ext_feat = 0;
+       a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
+}
index ba033f0..5355df6 100644 (file)
@@ -569,7 +569,6 @@ static int bt_seq_show(struct seq_file *seq, void *v)
 {
        struct bt_seq_state *s = seq->private;
        struct bt_sock_list *l = s->l;
-       bdaddr_t src_baswapped, dst_baswapped;
 
        if (v == SEQ_START_TOKEN) {
                seq_puts(seq ,"sk               RefCnt Rmem   Wmem   User   Inode  Src Dst Parent");
@@ -583,18 +582,17 @@ static int bt_seq_show(struct seq_file *seq, void *v)
        } else {
                struct sock *sk = sk_entry(v);
                struct bt_sock *bt = bt_sk(sk);
-               baswap(&src_baswapped, &bt->src);
-               baswap(&dst_baswapped, &bt->dst);
 
-               seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu",
+               seq_printf(seq,
+                          "%pK %-6d %-6u %-6u %-6u %-6lu %pMR %pMR %-6lu",
                           sk,
                           atomic_read(&sk->sk_refcnt),
                           sk_rmem_alloc_get(sk),
                           sk_wmem_alloc_get(sk),
                           from_kuid(seq_user_ns(seq), sock_i_uid(sk)),
                           sock_i_ino(sk),
-                          &src_baswapped,
-                          &dst_baswapped,
+                          &bt->src,
+                          &bt->dst,
                           bt->parent? sock_i_ino(bt->parent): 0LU);
 
                if (l->custom_seq_show) {
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
new file mode 100644 (file)
index 0000000..231d7ef
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only 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.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
+#include <crypto/hash.h>
+
+/* Remote AMP Controllers interface */
+void amp_ctrl_get(struct amp_ctrl *ctrl)
+{
+       BT_DBG("ctrl %p orig refcnt %d", ctrl,
+              atomic_read(&ctrl->kref.refcount));
+
+       kref_get(&ctrl->kref);
+}
+
+static void amp_ctrl_destroy(struct kref *kref)
+{
+       struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref);
+
+       BT_DBG("ctrl %p", ctrl);
+
+       kfree(ctrl->assoc);
+       kfree(ctrl);
+}
+
+int amp_ctrl_put(struct amp_ctrl *ctrl)
+{
+       BT_DBG("ctrl %p orig refcnt %d", ctrl,
+              atomic_read(&ctrl->kref.refcount));
+
+       return kref_put(&ctrl->kref, &amp_ctrl_destroy);
+}
+
+struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id)
+{
+       struct amp_ctrl *ctrl;
+
+       ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+       if (!ctrl)
+               return NULL;
+
+       kref_init(&ctrl->kref);
+       ctrl->id = id;
+
+       mutex_lock(&mgr->amp_ctrls_lock);
+       list_add(&ctrl->list, &mgr->amp_ctrls);
+       mutex_unlock(&mgr->amp_ctrls_lock);
+
+       BT_DBG("mgr %p ctrl %p", mgr, ctrl);
+
+       return ctrl;
+}
+
+void amp_ctrl_list_flush(struct amp_mgr *mgr)
+{
+       struct amp_ctrl *ctrl, *n;
+
+       BT_DBG("mgr %p", mgr);
+
+       mutex_lock(&mgr->amp_ctrls_lock);
+       list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) {
+               list_del(&ctrl->list);
+               amp_ctrl_put(ctrl);
+       }
+       mutex_unlock(&mgr->amp_ctrls_lock);
+}
+
+struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id)
+{
+       struct amp_ctrl *ctrl;
+
+       BT_DBG("mgr %p id %d", mgr, id);
+
+       mutex_lock(&mgr->amp_ctrls_lock);
+       list_for_each_entry(ctrl, &mgr->amp_ctrls, list) {
+               if (ctrl->id == id) {
+                       amp_ctrl_get(ctrl);
+                       mutex_unlock(&mgr->amp_ctrls_lock);
+                       return ctrl;
+               }
+       }
+       mutex_unlock(&mgr->amp_ctrls_lock);
+
+       return NULL;
+}
+
+/* Physical Link interface */
+static u8 __next_handle(struct amp_mgr *mgr)
+{
+       if (++mgr->handle == 0)
+               mgr->handle = 1;
+
+       return mgr->handle;
+}
+
+struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
+                            u8 remote_id, bool out)
+{
+       bdaddr_t *dst = mgr->l2cap_conn->dst;
+       struct hci_conn *hcon;
+
+       hcon = hci_conn_add(hdev, AMP_LINK, dst);
+       if (!hcon)
+               return NULL;
+
+       BT_DBG("hcon %p dst %pMR", hcon, dst);
+
+       hcon->state = BT_CONNECT;
+       hcon->attempt++;
+       hcon->handle = __next_handle(mgr);
+       hcon->remote_id = remote_id;
+       hcon->amp_mgr = amp_mgr_get(mgr);
+       hcon->out = out;
+
+       return hcon;
+}
+
+/* AMP crypto key generation interface */
+static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
+{
+       int ret = 0;
+       struct crypto_shash *tfm;
+
+       if (!ksize)
+               return -EINVAL;
+
+       tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+       if (IS_ERR(tfm)) {
+               BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+
+       ret = crypto_shash_setkey(tfm, key, ksize);
+       if (ret) {
+               BT_DBG("crypto_ahash_setkey failed: err %d", ret);
+       } else {
+               struct {
+                       struct shash_desc shash;
+                       char ctx[crypto_shash_descsize(tfm)];
+               } desc;
+
+               desc.shash.tfm = tfm;
+               desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+               ret = crypto_shash_digest(&desc.shash, plaintext, psize,
+                                         output);
+       }
+
+       crypto_free_shash(tfm);
+       return ret;
+}
+
+int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
+{
+       struct hci_dev *hdev = conn->hdev;
+       struct link_key *key;
+       u8 keybuf[HCI_AMP_LINK_KEY_SIZE];
+       u8 gamp_key[HCI_AMP_LINK_KEY_SIZE];
+       int err;
+
+       if (!hci_conn_check_link_mode(conn))
+               return -EACCES;
+
+       BT_DBG("conn %p key_type %d", conn, conn->key_type);
+
+       /* Legacy key */
+       if (conn->key_type < 3) {
+               BT_ERR("Legacy key type %d", conn->key_type);
+               return -EACCES;
+       }
+
+       *type = conn->key_type;
+       *len = HCI_AMP_LINK_KEY_SIZE;
+
+       key = hci_find_link_key(hdev, &conn->dst);
+       if (!key) {
+               BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst);
+               return -EACCES;
+       }
+
+       /* BR/EDR Link Key concatenated together with itself */
+       memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE);
+       memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE);
+
+       /* Derive Generic AMP Link Key (gamp) */
+       err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key);
+       if (err) {
+               BT_ERR("Could not derive Generic AMP Key: err %d", err);
+               return err;
+       }
+
+       if (conn->key_type == HCI_LK_DEBUG_COMBINATION) {
+               BT_DBG("Use Generic AMP Key (gamp)");
+               memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE);
+               return err;
+       }
+
+       /* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */
+       return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
+}
+
+void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
+{
+       struct hci_cp_read_local_amp_assoc cp;
+       struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+
+       BT_DBG("%s handle %d", hdev->name, phy_handle);
+
+       cp.phy_handle = phy_handle;
+       cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+       cp.len_so_far = cpu_to_le16(loc_assoc->offset);
+
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+}
+
+void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
+{
+       struct hci_cp_read_local_amp_assoc cp;
+
+       memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
+       memset(&cp, 0, sizeof(cp));
+
+       cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+
+       mgr->state = READ_LOC_AMP_ASSOC;
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+}
+
+void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
+                                  struct hci_conn *hcon)
+{
+       struct hci_cp_read_local_amp_assoc cp;
+       struct amp_mgr *mgr = hcon->amp_mgr;
+
+       cp.phy_handle = hcon->handle;
+       cp.len_so_far = cpu_to_le16(0);
+       cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+
+       mgr->state = READ_LOC_AMP_ASSOC_FINAL;
+
+       /* Read Local AMP Assoc final link information data */
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+}
+
+/* Write AMP Assoc data fragments, returns true with last fragment written*/
+static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
+                                    struct hci_conn *hcon)
+{
+       struct hci_cp_write_remote_amp_assoc *cp;
+       struct amp_mgr *mgr = hcon->amp_mgr;
+       struct amp_ctrl *ctrl;
+       u16 frag_len, len;
+
+       ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
+       if (!ctrl)
+               return false;
+
+       if (!ctrl->assoc_rem_len) {
+               BT_DBG("all fragments are written");
+               ctrl->assoc_rem_len = ctrl->assoc_len;
+               ctrl->assoc_len_so_far = 0;
+
+               amp_ctrl_put(ctrl);
+               return true;
+       }
+
+       frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
+       len = frag_len + sizeof(*cp);
+
+       cp = kzalloc(len, GFP_KERNEL);
+       if (!cp) {
+               amp_ctrl_put(ctrl);
+               return false;
+       }
+
+       BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u",
+              hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len);
+
+       cp->phy_handle = hcon->handle;
+       cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far);
+       cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len);
+       memcpy(cp->frag, ctrl->assoc, frag_len);
+
+       ctrl->assoc_len_so_far += frag_len;
+       ctrl->assoc_rem_len -= frag_len;
+
+       amp_ctrl_put(ctrl);
+
+       hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
+
+       kfree(cp);
+
+       return false;
+}
+
+void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle)
+{
+       struct hci_conn *hcon;
+
+       BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
+
+       hcon = hci_conn_hash_lookup_handle(hdev, handle);
+       if (!hcon)
+               return;
+
+       amp_write_rem_assoc_frag(hdev, hcon);
+}
+
+void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
+{
+       struct hci_conn *hcon;
+
+       BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
+
+       hcon = hci_conn_hash_lookup_handle(hdev, handle);
+       if (!hcon)
+               return;
+
+       BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon);
+
+       amp_write_rem_assoc_frag(hdev, hcon);
+}
+
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon)
+{
+       struct hci_cp_create_phy_link cp;
+
+       cp.phy_handle = hcon->handle;
+
+       BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
+              hcon->handle);
+
+       if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
+                           &cp.key_type)) {
+               BT_DBG("Cannot create link key");
+               return;
+       }
+
+       hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
+}
+
+void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon)
+{
+       struct hci_cp_accept_phy_link cp;
+
+       cp.phy_handle = hcon->handle;
+
+       BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
+              hcon->handle);
+
+       if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
+                           &cp.key_type)) {
+               BT_DBG("Cannot create link key");
+               return;
+       }
+
+       hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
+}
index 4a6620b..a5b6397 100644 (file)
@@ -182,8 +182,7 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
                        a2 = data;
                        data += ETH_ALEN;
 
-                       BT_DBG("mc filter %s -> %s",
-                               batostr((void *) a1), batostr((void *) a2));
+                       BT_DBG("mc filter %pMR -> %pMR", a1, a2);
 
                        /* Iterate from a1 to a2 */
                        set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
index 6c9c1fd..e0a6ebf 100644 (file)
@@ -353,7 +353,7 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
 
        BT_DBG("mtu %d", session->mtu);
 
-       sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst));
+       sprintf(session->name, "%pMR", &bt_sk(sock->sk)->dst);
 
        session->sock  = sock;
        session->state = BT_CONFIG;
index b9196a4..fe64621 100644 (file)
@@ -130,6 +130,20 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
        hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
+static void hci_amp_disconn(struct hci_conn *conn, __u8 reason)
+{
+       struct hci_cp_disconn_phy_link cp;
+
+       BT_DBG("hcon %p", conn);
+
+       conn->state = BT_DISCONN;
+
+       cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
+       cp.reason = reason;
+       hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK,
+                    sizeof(cp), &cp);
+}
+
 static void hci_add_sco(struct hci_conn *conn, __u16 handle)
 {
        struct hci_dev *hdev = conn->hdev;
@@ -230,11 +244,24 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
        }
 }
 
+static void hci_conn_disconnect(struct hci_conn *conn)
+{
+       __u8 reason = hci_proto_disconn_ind(conn);
+
+       switch (conn->type) {
+       case ACL_LINK:
+               hci_acl_disconn(conn, reason);
+               break;
+       case AMP_LINK:
+               hci_amp_disconn(conn, reason);
+               break;
+       }
+}
+
 static void hci_conn_timeout(struct work_struct *work)
 {
        struct hci_conn *conn = container_of(work, struct hci_conn,
                                             disc_work.work);
-       __u8 reason;
 
        BT_DBG("hcon %p state %s", conn, state_to_string(conn->state));
 
@@ -253,8 +280,7 @@ static void hci_conn_timeout(struct work_struct *work)
                break;
        case BT_CONFIG:
        case BT_CONNECTED:
-               reason = hci_proto_disconn_ind(conn);
-               hci_acl_disconn(conn, reason);
+               hci_conn_disconnect(conn);
                break;
        default:
                conn->state = BT_CLOSED;
@@ -320,7 +346,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 {
        struct hci_conn *conn;
 
-       BT_DBG("%s dst %s", hdev->name, batostr(dst));
+       BT_DBG("%s dst %pMR", hdev->name, dst);
 
        conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
        if (!conn)
@@ -437,7 +463,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
        int use_src = bacmp(src, BDADDR_ANY);
        struct hci_dev *hdev = NULL, *d;
 
-       BT_DBG("%s -> %s", batostr(src), batostr(dst));
+       BT_DBG("%pMR -> %pMR", src, dst);
 
        read_lock(&hci_dev_list_lock);
 
@@ -567,7 +593,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                             __u8 dst_type, __u8 sec_level, __u8 auth_type)
 {
-       BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type);
+       BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type);
 
        switch (type) {
        case LE_LINK:
@@ -963,3 +989,35 @@ void hci_chan_list_flush(struct hci_conn *conn)
        list_for_each_entry_safe(chan, n, &conn->chan_list, list)
                hci_chan_del(chan);
 }
+
+static struct hci_chan *__hci_chan_lookup_handle(struct hci_conn *hcon,
+                                                __u16 handle)
+{
+       struct hci_chan *hchan;
+
+       list_for_each_entry(hchan, &hcon->chan_list, list) {
+               if (hchan->handle == handle)
+                       return hchan;
+       }
+
+       return NULL;
+}
+
+struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_conn *hcon;
+       struct hci_chan *hchan = NULL;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(hcon, &h->list, list) {
+               hchan = __hci_chan_lookup_handle(hcon, handle);
+               if (hchan)
+                       break;
+       }
+
+       rcu_read_unlock();
+
+       return hchan;
+}
index 8a0ce70..5a3f941 100644 (file)
@@ -405,7 +405,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
-       BT_DBG("cache %p, %s", cache, batostr(bdaddr));
+       BT_DBG("cache %p, %pMR", cache, bdaddr);
 
        list_for_each_entry(e, &cache->all, all) {
                if (!bacmp(&e->data.bdaddr, bdaddr))
@@ -421,7 +421,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
-       BT_DBG("cache %p, %s", cache, batostr(bdaddr));
+       BT_DBG("cache %p, %pMR", cache, bdaddr);
 
        list_for_each_entry(e, &cache->unknown, list) {
                if (!bacmp(&e->data.bdaddr, bdaddr))
@@ -438,7 +438,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
-       BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state);
+       BT_DBG("cache %p bdaddr %pMR state %d", cache, bdaddr, state);
 
        list_for_each_entry(e, &cache->resolve, list) {
                if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
@@ -475,7 +475,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *ie;
 
-       BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
+       BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
 
        if (ssp)
                *ssp = data->ssp_mode;
@@ -1259,7 +1259,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                list_add(&key->list, &hdev->link_keys);
        }
 
-       BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
+       BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type);
 
        /* Some buggy controller combinations generate a changed
         * combination key for legacy pairing even when there's no
@@ -1338,7 +1338,7 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
        if (!key)
                return -ENOENT;
 
-       BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
        list_del(&key->list);
        kfree(key);
@@ -1354,7 +1354,7 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
                if (bacmp(bdaddr, &k->bdaddr))
                        continue;
 
-               BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+               BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
                list_del(&k->list);
                kfree(k);
@@ -1401,7 +1401,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
        if (!data)
                return -ENOENT;
 
-       BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
        list_del(&data->list);
        kfree(data);
@@ -1440,7 +1440,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
        memcpy(data->hash, hash, sizeof(data->hash));
        memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
 
-       BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
+       BT_DBG("%s for %pMR", hdev->name, bdaddr);
 
        return 0;
 }
@@ -2153,9 +2153,10 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        hdr->dlen   = cpu_to_le16(len);
 }
 
-static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
+static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
                          struct sk_buff *skb, __u16 flags)
 {
+       struct hci_conn *conn = chan->conn;
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
 
@@ -2163,7 +2164,18 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
        skb->data_len = 0;
 
        bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-       hci_add_acl_hdr(skb, conn->handle, flags);
+
+       switch (hdev->dev_type) {
+       case HCI_BREDR:
+               hci_add_acl_hdr(skb, conn->handle, flags);
+               break;
+       case HCI_AMP:
+               hci_add_acl_hdr(skb, chan->handle, flags);
+               break;
+       default:
+               BT_ERR("%s unknown dev_type %d", hdev->name, hdev->dev_type);
+               return;
+       }
 
        list = skb_shinfo(skb)->frag_list;
        if (!list) {
@@ -2202,14 +2214,13 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
 
 void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
 {
-       struct hci_conn *conn = chan->conn;
-       struct hci_dev *hdev = conn->hdev;
+       struct hci_dev *hdev = chan->conn->hdev;
 
        BT_DBG("%s chan %p flags 0x%4.4x", hdev->name, chan, flags);
 
        skb->dev = (void *) hdev;
 
-       hci_queue_acl(conn, &chan->data_q, skb, flags);
+       hci_queue_acl(chan, &chan->data_q, skb, flags);
 
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
@@ -2311,8 +2322,8 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
        /* Kill stalled connections */
        list_for_each_entry_rcu(c, &h->list, list) {
                if (c->type == type && c->sent) {
-                       BT_ERR("%s killing stalled connection %s",
-                              hdev->name, batostr(&c->dst));
+                       BT_ERR("%s killing stalled connection %pMR",
+                              hdev->name, &c->dst);
                        hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
                }
        }
@@ -2381,6 +2392,9 @@ static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
        case ACL_LINK:
                cnt = hdev->acl_cnt;
                break;
+       case AMP_LINK:
+               cnt = hdev->block_cnt;
+               break;
        case SCO_LINK:
        case ESCO_LINK:
                cnt = hdev->sco_cnt;
@@ -2510,11 +2524,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
        struct hci_chan *chan;
        struct sk_buff *skb;
        int quote;
+       u8 type;
 
        __check_timeout(hdev, cnt);
 
+       BT_DBG("%s", hdev->name);
+
+       if (hdev->dev_type == HCI_AMP)
+               type = AMP_LINK;
+       else
+               type = ACL_LINK;
+
        while (hdev->block_cnt > 0 &&
-              (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+              (chan = hci_chan_sent(hdev, type, &quote))) {
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
                        int blocks;
@@ -2547,14 +2569,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
        }
 
        if (cnt != hdev->block_cnt)
-               hci_prio_recalculate(hdev, ACL_LINK);
+               hci_prio_recalculate(hdev, type);
 }
 
 static void hci_sched_acl(struct hci_dev *hdev)
 {
        BT_DBG("%s", hdev->name);
 
-       if (!hci_conn_num(hdev, ACL_LINK))
+       /* No ACL link over BR/EDR controller */
+       if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_BREDR)
+               return;
+
+       /* No AMP link over AMP controller */
+       if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP)
                return;
 
        switch (hdev->flow_ctl_mode) {
index 2022b43..0383635 100644 (file)
@@ -30,6 +30,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/mgmt.h>
+#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
 
 /* Handle HCI Event packets */
 
@@ -846,7 +848,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
        BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
        if (rp->status)
-               return;
+               goto a2mp_rsp;
 
        hdev->amp_status = rp->amp_status;
        hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
@@ -860,6 +862,46 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
        hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
 
        hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
+
+a2mp_rsp:
+       a2mp_send_getinfo_rsp(hdev);
+}
+
+static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
+{
+       struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
+       struct amp_assoc *assoc = &hdev->loc_assoc;
+       size_t rem_len, frag_len;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (rp->status)
+               goto a2mp_rsp;
+
+       frag_len = skb->len - sizeof(*rp);
+       rem_len = __le16_to_cpu(rp->rem_len);
+
+       if (rem_len > frag_len) {
+               BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
+
+               memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
+               assoc->offset += frag_len;
+
+               /* Read other fragments */
+               amp_read_loc_assoc_frag(hdev, rp->phy_handle);
+
+               return;
+       }
+
+       memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
+       assoc->len = assoc->offset + rem_len;
+       assoc->offset = 0;
+
+a2mp_rsp:
+       /* Send A2MP Rsp when all fragments are received */
+       a2mp_send_getampassoc_rsp(hdev, rp->status);
+       a2mp_send_create_phy_link_req(hdev, rp->status);
 }
 
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
@@ -1174,6 +1216,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
        hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
 }
 
+static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
+                                         struct sk_buff *skb)
+{
+       struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
+              hdev->name, rp->status, rp->phy_handle);
+
+       if (rp->status)
+               return;
+
+       amp_write_rem_assoc_continue(hdev, rp->phy_handle);
+}
+
 static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -1210,7 +1266,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 
-       BT_DBG("%s bdaddr %s hcon %p", hdev->name, batostr(&cp->bdaddr), conn);
+       BT_DBG("%s bdaddr %pMR hcon %p", hdev->name, &cp->bdaddr, conn);
 
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
@@ -1639,8 +1695,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
                        return;
                }
 
-               BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&conn->dst),
-                      conn);
+               BT_DBG("%s bdaddr %pMR conn %p", hdev->name, &conn->dst, conn);
 
                conn->state = BT_CLOSED;
                mgmt_connect_failed(hdev, &conn->dst, conn->type,
@@ -1657,6 +1712,38 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
 }
 
+static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_create_phy_link *cp;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
+       if (!cp)
+               return;
+
+       amp_write_remote_assoc(hdev, cp->phy_handle);
+}
+
+static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_accept_phy_link *cp;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
+       if (!cp)
+               return;
+
+       amp_write_remote_assoc(hdev, cp->phy_handle);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -1822,7 +1909,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        struct hci_ev_conn_request *ev = (void *) skb->data;
        int mask = hdev->link_mode;
 
-       BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr),
+       BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
               ev->link_type);
 
        mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
@@ -2314,6 +2401,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_read_local_amp_info(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_AMP_ASSOC:
+               hci_cc_read_local_amp_assoc(hdev, skb);
+               break;
+
        case HCI_OP_DELETE_STORED_LINK_KEY:
                hci_cc_delete_stored_link_key(hdev, skb);
                break;
@@ -2386,6 +2477,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_write_le_host_supported(hdev, skb);
                break;
 
+       case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
+               hci_cc_write_remote_amp_assoc(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -2467,6 +2562,14 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_le_start_enc(hdev, ev->status);
                break;
 
+       case HCI_OP_CREATE_PHY_LINK:
+               hci_cs_create_phylink(hdev, ev->status);
+               break;
+
+       case HCI_OP_ACCEPT_PHY_LINK:
+               hci_cs_accept_phylink(hdev, ev->status);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -2574,6 +2677,27 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
 
+static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev,
+                                                __u16 handle)
+{
+       struct hci_chan *chan;
+
+       switch (hdev->dev_type) {
+       case HCI_BREDR:
+               return hci_conn_hash_lookup_handle(hdev, handle);
+       case HCI_AMP:
+               chan = hci_chan_lookup_handle(hdev, handle);
+               if (chan)
+                       return chan->conn;
+               break;
+       default:
+               BT_ERR("%s unknown dev_type %d", hdev->name, hdev->dev_type);
+               break;
+       }
+
+       return NULL;
+}
+
 static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
@@ -2595,13 +2719,13 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        for (i = 0; i < ev->num_hndl; i++) {
                struct hci_comp_blocks_info *info = &ev->handles[i];
-               struct hci_conn *conn;
+               struct hci_conn *conn = NULL;
                __u16  handle, block_count;
 
                handle = __le16_to_cpu(info->handle);
                block_count = __le16_to_cpu(info->blocks);
 
-               conn = hci_conn_hash_lookup_handle(hdev, handle);
+               conn = __hci_conn_lookup_handle(hdev, handle);
                if (!conn)
                        continue;
 
@@ -2609,6 +2733,7 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
                switch (conn->type) {
                case ACL_LINK:
+               case AMP_LINK:
                        hdev->block_cnt += block_count;
                        if (hdev->block_cnt > hdev->num_blocks)
                                hdev->block_cnt = hdev->num_blocks;
@@ -2705,13 +2830,13 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        key = hci_find_link_key(hdev, &ev->bdaddr);
        if (!key) {
-               BT_DBG("%s link key not found for %s", hdev->name,
-                      batostr(&ev->bdaddr));
+               BT_DBG("%s link key not found for %pMR", hdev->name,
+                      &ev->bdaddr);
                goto not_found;
        }
 
-       BT_DBG("%s found key type %u for %s", hdev->name, key->type,
-              batostr(&ev->bdaddr));
+       BT_DBG("%s found key type %u for %pMR", hdev->name, key->type,
+              &ev->bdaddr);
 
        if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
            key->type == HCI_LK_DEBUG_COMBINATION) {
@@ -3558,6 +3683,22 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
+static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_channel_selected *ev = (void *) skb->data;
+       struct hci_conn *hcon;
+
+       BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
+
+       skb_pull(skb, sizeof(*ev));
+
+       hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+       if (!hcon)
+               return;
+
+       amp_read_loc_assoc_final_data(hdev, hcon);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_event_hdr *hdr = (void *) skb->data;
@@ -3722,6 +3863,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_le_meta_evt(hdev, skb);
                break;
 
+       case HCI_EV_CHANNEL_SELECTED:
+               hci_chan_selected_evt(hdev, skb);
+               break;
+
        case HCI_EV_REMOTE_OOB_DATA_REQUEST:
                hci_remote_oob_data_request_evt(hdev, skb);
                break;
index a20e61c..55cceee 100644 (file)
@@ -38,7 +38,7 @@ static ssize_t show_link_address(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
-       return sprintf(buf, "%s\n", batostr(&conn->dst));
+       return sprintf(buf, "%pMR\n", &conn->dst);
 }
 
 static ssize_t show_link_features(struct device *dev,
@@ -224,7 +224,7 @@ static ssize_t show_address(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
-       return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
+       return sprintf(buf, "%pMR\n", &hdev->bdaddr);
 }
 
 static ssize_t show_features(struct device *dev,
@@ -406,8 +406,8 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
 
        list_for_each_entry(e, &cache->all, all) {
                struct inquiry_data *data = &e->data;
-               seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
-                          batostr(&data->bdaddr),
+               seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
+                          &data->bdaddr,
                           data->pscan_rep_mode, data->pscan_period_mode,
                           data->pscan_mode, data->dev_class[2],
                           data->dev_class[1], data->dev_class[0],
@@ -440,7 +440,7 @@ static int blacklist_show(struct seq_file *f, void *p)
        hci_dev_lock(hdev);
 
        list_for_each_entry(b, &hdev->blacklist, list)
-               seq_printf(f, "%s\n", batostr(&b->bdaddr));
+               seq_printf(f, "%pMR\n", &b->bdaddr);
 
        hci_dev_unlock(hdev);
 
index ccd985d..0c00284 100644 (file)
@@ -932,8 +932,12 @@ static int hidp_setup_hid(struct hidp_session *session,
        hid->country = req->country;
 
        strncpy(hid->name, req->name, 128);
-       strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
-       strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
+
+       snprintf(hid->phys, sizeof(hid->phys), "%pMR",
+                &bt_sk(session->ctrl_sock->sk)->src);
+
+       snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
+                &bt_sk(session->ctrl_sock->sk)->dst);
 
        hid->dev.parent = &session->conn->dev;
        hid->ll_driver = &hidp_hid_driver;
index a91239d..08efc25 100644 (file)
@@ -48,19 +48,20 @@ static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
 
 static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
-                               u8 code, u8 ident, u16 dlen, void *data);
+                                      u8 code, u8 ident, u16 dlen, void *data);
 static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
-                                                               void *data);
+                          void *data);
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
                                   struct l2cap_chan *chan, int err);
 
 static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
-                   struct sk_buff_head *skbs, u8 event);
+                    struct sk_buff_head *skbs, u8 event);
 
 /* ---- L2CAP channels ---- */
 
-static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
+static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
+                                                  u16 cid)
 {
        struct l2cap_chan *c;
 
@@ -71,7 +72,8 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16
        return NULL;
 }
 
-static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
+static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn,
+                                                  u16 cid)
 {
        struct l2cap_chan *c;
 
@@ -84,7 +86,8 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16
 
 /* Find channel with given SCID.
  * Returns locked channel. */
-static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
+static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
+                                                u16 cid)
 {
        struct l2cap_chan *c;
 
@@ -97,7 +100,8 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci
        return c;
 }
 
-static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
+static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
+                                                   u8 ident)
 {
        struct l2cap_chan *c;
 
@@ -178,7 +182,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 static void __l2cap_state_change(struct l2cap_chan *chan, int state)
 {
        BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
-                                               state_to_string(state));
+              state_to_string(state));
 
        chan->state = state;
        chan->ops->state_change(chan, state);
@@ -361,7 +365,7 @@ static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq)
 static void l2cap_chan_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-                                                       chan_timer.work);
+                                              chan_timer.work);
        struct l2cap_conn *conn = chan->conn;
        int reason;
 
@@ -373,7 +377,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
        if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
                reason = ECONNREFUSED;
        else if (chan->state == BT_CONNECT &&
-                                       chan->sec_level != BT_SECURITY_SDP)
+                chan->sec_level != BT_SECURITY_SDP)
                reason = ECONNREFUSED;
        else
                reason = ETIMEDOUT;
@@ -455,7 +459,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
        set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
 }
 
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
               __le16_to_cpu(chan->psm), chan->dcid);
@@ -504,7 +508,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        chan->local_msdu        = L2CAP_DEFAULT_MAX_SDU_SIZE;
        chan->local_sdu_itime   = L2CAP_DEFAULT_SDU_ITIME;
        chan->local_acc_lat     = L2CAP_DEFAULT_ACC_LAT;
-       chan->local_flush_to    = L2CAP_DEFAULT_FLUSH_TO;
+       chan->local_flush_to    = L2CAP_EFS_DEFAULT_FLUSH_TO;
 
        l2cap_chan_hold(chan);
 
@@ -527,6 +531,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
        BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
 
        if (conn) {
+               struct amp_mgr *mgr = conn->hcon->amp_mgr;
                /* Delete from channel list */
                list_del(&chan->list);
 
@@ -536,10 +541,12 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
                if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
                        hci_conn_put(conn->hcon);
+
+               if (mgr && mgr->bredr_chan == chan)
+                       mgr->bredr_chan = NULL;
        }
 
-       if (chan->ops->teardown)
-               chan->ops->teardown(chan, err);
+       chan->ops->teardown(chan, err);
 
        if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
                return;
@@ -573,19 +580,18 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
        struct l2cap_conn *conn = chan->conn;
        struct sock *sk = chan->sk;
 
-       BT_DBG("chan %p state %s sk %p", chan,
-                                       state_to_string(chan->state), sk);
+       BT_DBG("chan %p state %s sk %p", chan, state_to_string(chan->state),
+              sk);
 
        switch (chan->state) {
        case BT_LISTEN:
-               if (chan->ops->teardown)
-                       chan->ops->teardown(chan, 0);
+               chan->ops->teardown(chan, 0);
                break;
 
        case BT_CONNECTED:
        case BT_CONFIG:
                if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
-                                       conn->hcon->type == ACL_LINK) {
+                   conn->hcon->type == ACL_LINK) {
                        __set_chan_timer(chan, sk->sk_sndtimeo);
                        l2cap_send_disconn_req(conn, chan, reason);
                } else
@@ -594,7 +600,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 
        case BT_CONNECT2:
                if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
-                                       conn->hcon->type == ACL_LINK) {
+                   conn->hcon->type == ACL_LINK) {
                        struct l2cap_conn_rsp rsp;
                        __u16 result;
 
@@ -609,7 +615,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                        rsp.result = cpu_to_le16(result);
                        rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
-                                                       sizeof(rsp), &rsp);
+                                      sizeof(rsp), &rsp);
                }
 
                l2cap_chan_del(chan, reason);
@@ -621,8 +627,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                break;
 
        default:
-               if (chan->ops->teardown)
-                       chan->ops->teardown(chan, 0);
+               chan->ops->teardown(chan, 0);
                break;
        }
 }
@@ -691,7 +696,8 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn)
        return id;
 }
 
-static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
+static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
+                          void *data)
 {
        struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
        u8 flags;
@@ -718,10 +724,10 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
        u16 flags;
 
        BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
-                                                       skb->priority);
+              skb->priority);
 
        if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
-                                       lmp_no_flush_capable(hcon->hdev))
+           lmp_no_flush_capable(hcon->hdev))
                flags = ACL_START_NO_FLUSH;
        else
                flags = ACL_START;
@@ -946,7 +952,19 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
        return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 }
 
-static void l2cap_send_conn_req(struct l2cap_chan *chan)
+static bool __amp_capable(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
+
+       if (enable_hs &&
+           chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED &&
+           conn->fixed_chan_mask & L2CAP_FC_A2MP)
+               return true;
+       else
+               return false;
+}
+
+void l2cap_send_conn_req(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
        struct l2cap_conn_req req;
@@ -972,6 +990,16 @@ static void l2cap_chan_ready(struct l2cap_chan *chan)
        chan->ops->ready(chan);
 }
 
+static void l2cap_start_connection(struct l2cap_chan *chan)
+{
+       if (__amp_capable(chan)) {
+               BT_DBG("chan %p AMP capable: discover AMPs", chan);
+               a2mp_discover_amp(chan);
+       } else {
+               l2cap_send_conn_req(chan);
+       }
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
@@ -986,8 +1014,9 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                        return;
 
                if (l2cap_chan_check_security(chan) &&
-                               __l2cap_no_conn_pending(chan))
-                       l2cap_send_conn_req(chan);
+                   __l2cap_no_conn_pending(chan)) {
+                       l2cap_start_connection(chan);
+               }
        } else {
                struct l2cap_info_req req;
                req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -997,8 +1026,8 @@ static void l2cap_do_start(struct l2cap_chan *chan)
 
                schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
-               l2cap_send_cmd(conn, conn->info_ident,
-                                       L2CAP_INFO_REQ, sizeof(req), &req);
+               l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
+                              sizeof(req), &req);
        }
 }
 
@@ -1018,7 +1047,8 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
        }
 }
 
-static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
+static void l2cap_send_disconn_req(struct l2cap_conn *conn,
+                                  struct l2cap_chan *chan, int err)
 {
        struct sock *sk = chan->sk;
        struct l2cap_disconn_req req;
@@ -1033,14 +1063,14 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
        }
 
        if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
-               __l2cap_state_change(chan, BT_DISCONN);
+               l2cap_state_change(chan, BT_DISCONN);
                return;
        }
 
        req.dcid = cpu_to_le16(chan->dcid);
        req.scid = cpu_to_le16(chan->scid);
-       l2cap_send_cmd(conn, l2cap_get_ident(conn),
-                       L2CAP_DISCONN_REQ, sizeof(req), &req);
+       l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ,
+                      sizeof(req), &req);
 
        lock_sock(sk);
        __l2cap_state_change(chan, BT_DISCONN);
@@ -1069,20 +1099,20 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 
                if (chan->state == BT_CONNECT) {
                        if (!l2cap_chan_check_security(chan) ||
-                                       !__l2cap_no_conn_pending(chan)) {
+                           !__l2cap_no_conn_pending(chan)) {
                                l2cap_chan_unlock(chan);
                                continue;
                        }
 
                        if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
-                                       && test_bit(CONF_STATE2_DEVICE,
+                           && test_bit(CONF_STATE2_DEVICE,
                                        &chan->conf_state)) {
                                l2cap_chan_close(chan, ECONNRESET);
                                l2cap_chan_unlock(chan);
                                continue;
                        }
 
-                       l2cap_send_conn_req(chan);
+                       l2cap_start_connection(chan);
 
                } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
@@ -1094,11 +1124,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                lock_sock(sk);
                                if (test_bit(BT_SK_DEFER_SETUP,
                                             &bt_sk(sk)->flags)) {
-                                       struct sock *parent = bt_sk(sk)->parent;
                                        rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
                                        rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
-                                       if (parent)
-                                               parent->sk_data_ready(parent, 0);
+                                       chan->ops->defer(chan);
 
                                } else {
                                        __l2cap_state_change(chan, BT_CONFIG);
@@ -1112,17 +1140,17 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        }
 
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
-                                                       sizeof(rsp), &rsp);
+                                      sizeof(rsp), &rsp);
 
                        if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
-                                       rsp.result != L2CAP_CR_SUCCESS) {
+                           rsp.result != L2CAP_CR_SUCCESS) {
                                l2cap_chan_unlock(chan);
                                continue;
                        }
 
                        set_bit(CONF_REQ_SENT, &chan->conf_state);
                        l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                               l2cap_build_conf_req(chan, buf), buf);
+                                      l2cap_build_conf_req(chan, buf), buf);
                        chan->num_conf_req++;
                }
 
@@ -1204,8 +1232,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
 
-       bt_accept_enqueue(parent, sk);
-
        l2cap_chan_add(conn, chan);
 
        l2cap_chan_ready(chan);
@@ -1270,7 +1296,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 
        list_for_each_entry(chan, &conn->chan_l, list) {
                if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
-                       __l2cap_chan_set_err(chan, err);
+                       l2cap_chan_set_err(chan, err);
        }
 
        mutex_unlock(&conn->chan_lock);
@@ -1279,7 +1305,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 static void l2cap_info_timeout(struct work_struct *work)
 {
        struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
-                                                       info_timer.work);
+                                              info_timer.work);
 
        conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
        conn->info_ident = 0;
@@ -1333,7 +1359,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 static void security_timeout(struct work_struct *work)
 {
        struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
-                                               security_timer.work);
+                                              security_timer.work);
 
        BT_DBG("conn %p", conn);
 
@@ -1355,7 +1381,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        if (!hchan)
                return NULL;
 
-       conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
+       conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL);
        if (!conn) {
                hci_chan_del(hchan);
                return NULL;
@@ -1367,10 +1393,22 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 
        BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
 
-       if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
-               conn->mtu = hcon->hdev->le_mtu;
-       else
+       switch (hcon->type) {
+       case AMP_LINK:
+               conn->mtu = hcon->hdev->block_mtu;
+               break;
+
+       case LE_LINK:
+               if (hcon->hdev->le_mtu) {
+                       conn->mtu = hcon->hdev->le_mtu;
+                       break;
+               }
+               /* fall through */
+
+       default:
                conn->mtu = hcon->hdev->acl_mtu;
+               break;
+       }
 
        conn->src = &hcon->hdev->bdaddr;
        conn->dst = &hcon->dst;
@@ -1448,7 +1486,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
        __u8 auth_type;
        int err;
 
-       BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst),
+       BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", src, dst,
               dst_type, __le16_to_cpu(psm));
 
        hdev = hci_get_route(dst, src);
@@ -1461,7 +1499,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
        /* PSM must be odd and lsb of upper byte must be 0 */
        if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+           chan->chan_type != L2CAP_CHAN_RAW) {
                err = -EINVAL;
                goto done;
        }
@@ -1770,7 +1808,7 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
                skb = l2cap_ertm_seq_in_queue(&chan->tx_q, seq);
                if (!skb) {
                        BT_DBG("Error: Can't retransmit seq %d, frame missing",
-                               seq);
+                              seq);
                        continue;
                }
 
@@ -1795,9 +1833,9 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
                        /* Cloned sk_buffs are read-only, so we need a
                         * writeable copy
                         */
-                       tx_skb = skb_copy(skb, GFP_ATOMIC);
+                       tx_skb = skb_copy(skb, GFP_KERNEL);
                } else {
-                       tx_skb = skb_clone(skb, GFP_ATOMIC);
+                       tx_skb = skb_clone(skb, GFP_KERNEL);
                }
 
                if (!tx_skb) {
@@ -1855,7 +1893,7 @@ static void l2cap_retransmit_all(struct l2cap_chan *chan,
        if (chan->unacked_frames) {
                skb_queue_walk(&chan->tx_q, skb) {
                        if (bt_cb(skb)->control.txseq == control->reqseq ||
-                               skb == chan->tx_send_head)
+                           skb == chan->tx_send_head)
                                break;
                }
 
@@ -2156,7 +2194,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
 }
 
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
-                                                               u32 priority)
+                   u32 priority)
 {
        struct sk_buff *skb;
        int err;
@@ -2543,7 +2581,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
                /* Don't send frame to the socket it came from */
                if (skb->sk == sk)
                        continue;
-               nskb = skb_clone(skb, GFP_ATOMIC);
+               nskb = skb_clone(skb, GFP_KERNEL);
                if (!nskb)
                        continue;
 
@@ -2569,7 +2607,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code,
        len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
        count = min_t(unsigned int, conn->mtu, len);
 
-       skb = bt_skb_alloc(count, GFP_ATOMIC);
+       skb = bt_skb_alloc(count, GFP_KERNEL);
        if (!skb)
                return NULL;
 
@@ -2599,7 +2637,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code,
        while (len) {
                count = min_t(unsigned int, conn->mtu, len);
 
-               *frag = bt_skb_alloc(count, GFP_ATOMIC);
+               *frag = bt_skb_alloc(count, GFP_KERNEL);
                if (!*frag)
                        goto fail;
 
@@ -2618,7 +2656,8 @@ fail:
        return NULL;
 }
 
-static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
+static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
+                                    unsigned long *val)
 {
        struct l2cap_conf_opt *opt = *ptr;
        int len;
@@ -2692,7 +2731,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
                efs.msdu        = cpu_to_le16(chan->local_msdu);
                efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
                efs.acc_lat     = __constant_cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
-               efs.flush_to    = __constant_cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
+               efs.flush_to    = __constant_cpu_to_le32(L2CAP_EFS_DEFAULT_FLUSH_TO);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -2709,7 +2748,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
        }
 
        l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
-                                                       (unsigned long) &efs);
+                          (unsigned long) &efs);
 }
 
 static void l2cap_ack_timeout(struct work_struct *work)
@@ -2798,13 +2837,13 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
 static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
 {
        if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
-                                               __l2cap_ews_supported(chan)) {
+           __l2cap_ews_supported(chan)) {
                /* use extended control field */
                set_bit(FLAG_EXT_CTRL, &chan->flags);
                chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
        } else {
                chan->tx_win = min_t(u16, chan->tx_win,
-                                               L2CAP_DEFAULT_TX_WINDOW);
+                                    L2CAP_DEFAULT_TX_WINDOW);
                chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
        }
        chan->ack_win = chan->tx_win;
@@ -2844,7 +2883,7 @@ done:
        switch (chan->mode) {
        case L2CAP_MODE_BASIC:
                if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
-                               !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
+                   !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
                        break;
 
                rfc.mode            = L2CAP_MODE_BASIC;
@@ -2855,7 +2894,7 @@ done:
                rfc.max_pdu_size    = 0;
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-                                                       (unsigned long) &rfc);
+                                  (unsigned long) &rfc);
                break;
 
        case L2CAP_MODE_ERTM:
@@ -2865,18 +2904,17 @@ done:
                rfc.monitor_timeout = 0;
 
                size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                            L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
+                            L2CAP_FCS_SIZE);
                rfc.max_pdu_size = cpu_to_le16(size);
 
                l2cap_txwin_setup(chan);
 
                rfc.txwin_size = min_t(u16, chan->tx_win,
-                                               L2CAP_DEFAULT_TX_WINDOW);
+                                      L2CAP_DEFAULT_TX_WINDOW);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-                                                       (unsigned long) &rfc);
+                                  (unsigned long) &rfc);
 
                if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
                        l2cap_add_opt_efs(&ptr, chan);
@@ -2885,14 +2923,14 @@ done:
                        break;
 
                if (chan->fcs == L2CAP_FCS_NONE ||
-                               test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
+                   test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
 
                if (test_bit(FLAG_EXT_CTRL, &chan->flags))
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
-                                                               chan->tx_win);
+                                          chan->tx_win);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -2904,13 +2942,12 @@ done:
                rfc.monitor_timeout = 0;
 
                size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                            L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
+                            L2CAP_FCS_SIZE);
                rfc.max_pdu_size = cpu_to_le16(size);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-                                                       (unsigned long) &rfc);
+                                  (unsigned long) &rfc);
 
                if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
                        l2cap_add_opt_efs(&ptr, chan);
@@ -2919,7 +2956,7 @@ done:
                        break;
 
                if (chan->fcs == L2CAP_FCS_NONE ||
-                               test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
+                   test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
@@ -3011,7 +3048,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
        case L2CAP_MODE_ERTM:
                if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
                        chan->mode = l2cap_select_mode(rfc.mode,
-                                       chan->conn->feat_mask);
+                                                      chan->conn->feat_mask);
                        break;
                }
 
@@ -3036,8 +3073,8 @@ done:
                if (chan->num_conf_rsp == 1)
                        return -ECONNREFUSED;
 
-               l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+               l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+                                  (unsigned long) &rfc);
        }
 
        if (result == L2CAP_CONF_SUCCESS) {
@@ -3054,8 +3091,8 @@ done:
 
                if (remote_efs) {
                        if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != chan->local_stype) {
+                           efs.stype != L2CAP_SERV_NOTRAFIC &&
+                           efs.stype != chan->local_stype) {
 
                                result = L2CAP_CONF_UNACCEPT;
 
@@ -3063,8 +3100,8 @@ done:
                                        return -ECONNREFUSED;
 
                                l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
-                                                       sizeof(efs),
-                                                       (unsigned long) &efs);
+                                                  sizeof(efs),
+                                                  (unsigned long) &efs);
                        } else {
                                /* Send PENDING Conf Rsp */
                                result = L2CAP_CONF_PENDING;
@@ -3087,10 +3124,8 @@ done:
                        chan->remote_max_tx = rfc.max_transmit;
 
                        size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
-                                               chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                                    chan->conn->mtu - L2CAP_EXT_HDR_SIZE -
+                                    L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE);
                        rfc.max_pdu_size = cpu_to_le16(size);
                        chan->remote_mps = size;
 
@@ -3102,36 +3137,35 @@ done:
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+                                          sizeof(rfc), (unsigned long) &rfc);
 
                        if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
                                chan->remote_id = efs.id;
                                chan->remote_stype = efs.stype;
                                chan->remote_msdu = le16_to_cpu(efs.msdu);
                                chan->remote_flush_to =
-                                               le32_to_cpu(efs.flush_to);
+                                       le32_to_cpu(efs.flush_to);
                                chan->remote_acc_lat =
-                                               le32_to_cpu(efs.acc_lat);
+                                       le32_to_cpu(efs.acc_lat);
                                chan->remote_sdu_itime =
                                        le32_to_cpu(efs.sdu_itime);
                                l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
-                                       sizeof(efs), (unsigned long) &efs);
+                                                  sizeof(efs),
+                                                  (unsigned long) &efs);
                        }
                        break;
 
                case L2CAP_MODE_STREAMING:
                        size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
-                                               chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                                    chan->conn->mtu - L2CAP_EXT_HDR_SIZE -
+                                    L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE);
                        rfc.max_pdu_size = cpu_to_le16(size);
                        chan->remote_mps = size;
 
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
-                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+                                          (unsigned long) &rfc);
 
                        break;
 
@@ -3152,7 +3186,8 @@ done:
        return ptr - data;
 }
 
-static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result)
+static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
+                               void *data, u16 *result)
 {
        struct l2cap_conf_req *req = data;
        void *ptr = req->data;
@@ -3179,7 +3214,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                case L2CAP_CONF_FLUSH_TO:
                        chan->flush_to = val;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
-                                                       2, chan->flush_to);
+                                          2, chan->flush_to);
                        break;
 
                case L2CAP_CONF_RFC:
@@ -3187,13 +3222,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                                memcpy(&rfc, (void *)val, olen);
 
                        if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
-                                                       rfc.mode != chan->mode)
+                           rfc.mode != chan->mode)
                                return -ECONNREFUSED;
 
                        chan->fcs = 0;
 
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+                                          sizeof(rfc), (unsigned long) &rfc);
                        break;
 
                case L2CAP_CONF_EWS:
@@ -3207,12 +3242,12 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                                memcpy(&efs, (void *)val, olen);
 
                        if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != chan->local_stype)
+                           efs.stype != L2CAP_SERV_NOTRAFIC &&
+                           efs.stype != chan->local_stype)
                                return -ECONNREFUSED;
 
-                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
-                                       sizeof(efs), (unsigned long) &efs);
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
+                                          (unsigned long) &efs);
                        break;
                }
        }
@@ -3235,10 +3270,10 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                        if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
                                chan->local_msdu = le16_to_cpu(efs.msdu);
                                chan->local_sdu_itime =
-                                               le32_to_cpu(efs.sdu_itime);
+                                       le32_to_cpu(efs.sdu_itime);
                                chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
                                chan->local_flush_to =
-                                               le32_to_cpu(efs.flush_to);
+                                       le32_to_cpu(efs.flush_to);
                        }
                        break;
 
@@ -3253,7 +3288,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        return ptr - data;
 }
 
-static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
+static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data,
+                               u16 result, u16 flags)
 {
        struct l2cap_conf_rsp *rsp = data;
        void *ptr = rsp->data;
@@ -3277,14 +3313,13 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
        rsp.dcid   = cpu_to_le16(chan->scid);
        rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
        rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
-       l2cap_send_cmd(conn, chan->ident,
-                               L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
        if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
                return;
 
        l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                       l2cap_build_conf_req(chan, buf), buf);
+                      l2cap_build_conf_req(chan, buf), buf);
        chan->num_conf_req++;
 }
 
@@ -3339,7 +3374,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
        }
 }
 
-static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_command_rej(struct l2cap_conn *conn,
+                                   struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
 
@@ -3347,7 +3383,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
                return 0;
 
        if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
-                                       cmd->ident == conn->info_ident) {
+           cmd->ident == conn->info_ident) {
                cancel_delayed_work(&conn->info_timer);
 
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
@@ -3359,7 +3395,8 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
        return 0;
 }
 
-static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
+                         u8 *data, u8 rsp_code, u8 amp_id)
 {
        struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
        struct l2cap_conn_rsp rsp;
@@ -3386,7 +3423,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) &&
-                               !hci_conn_check_link_mode(conn->hcon)) {
+           !hci_conn_check_link_mode(conn->hcon)) {
                conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
@@ -3411,8 +3448,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        chan->psm  = psm;
        chan->dcid = scid;
 
-       bt_accept_enqueue(parent, sk);
-
        __l2cap_chan_add(conn, chan);
 
        dcid = chan->scid;
@@ -3427,7 +3462,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
                                __l2cap_state_change(chan, BT_CONNECT2);
                                result = L2CAP_CR_PEND;
                                status = L2CAP_CS_AUTHOR_PEND;
-                               parent->sk_data_ready(parent, 0);
+                               chan->ops->defer(chan);
                        } else {
                                __l2cap_state_change(chan, BT_CONFIG);
                                result = L2CAP_CR_SUCCESS;
@@ -3453,7 +3488,7 @@ sendresp:
        rsp.dcid   = cpu_to_le16(dcid);
        rsp.result = cpu_to_le16(result);
        rsp.status = cpu_to_le16(status);
-       l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+       l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp);
 
        if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
                struct l2cap_info_req info;
@@ -3464,23 +3499,29 @@ sendresp:
 
                schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
-               l2cap_send_cmd(conn, conn->info_ident,
-                                       L2CAP_INFO_REQ, sizeof(info), &info);
+               l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
+                              sizeof(info), &info);
        }
 
        if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
-                               result == L2CAP_CR_SUCCESS) {
+           result == L2CAP_CR_SUCCESS) {
                u8 buf[128];
                set_bit(CONF_REQ_SENT, &chan->conf_state);
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                       l2cap_build_conf_req(chan, buf), buf);
+                              l2cap_build_conf_req(chan, buf), buf);
                chan->num_conf_req++;
        }
+}
 
+static int l2cap_connect_req(struct l2cap_conn *conn,
+                            struct l2cap_cmd_hdr *cmd, u8 *data)
+{
+       l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
        return 0;
 }
 
-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_connect_rsp(struct l2cap_conn *conn,
+                                   struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
        u16 scid, dcid, result, status;
@@ -3494,7 +3535,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
        status = __le16_to_cpu(rsp->status);
 
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
-                                               dcid, scid, result, status);
+              dcid, scid, result, status);
 
        mutex_lock(&conn->chan_lock);
 
@@ -3527,7 +3568,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                        break;
 
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                       l2cap_build_conf_req(chan, req), req);
+                              l2cap_build_conf_req(chan, req), req);
                chan->num_conf_req++;
                break;
 
@@ -3559,7 +3600,25 @@ static inline void set_default_fcs(struct l2cap_chan *chan)
                chan->fcs = L2CAP_FCS_CRC16;
 }
 
-static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
+static void l2cap_send_efs_conf_rsp(struct l2cap_chan *chan, void *data,
+                                   u8 ident, u16 flags)
+{
+       struct l2cap_conn *conn = chan->conn;
+
+       BT_DBG("conn %p chan %p ident %d flags 0x%4.4x", conn, chan, ident,
+              flags);
+
+       clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+       l2cap_send_cmd(conn, ident, L2CAP_CONF_RSP,
+                      l2cap_build_conf_rsp(chan, data,
+                                           L2CAP_CONF_SUCCESS, flags), data);
+}
+
+static inline int l2cap_config_req(struct l2cap_conn *conn,
+                                  struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                  u8 *data)
 {
        struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
        u16 dcid, flags;
@@ -3584,7 +3643,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                rej.dcid = cpu_to_le16(chan->dcid);
 
                l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
-                               sizeof(rej), &rej);
+                              sizeof(rej), &rej);
                goto unlock;
        }
 
@@ -3592,8 +3651,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        len = cmd_len - sizeof(*req);
        if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                               l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_REJECT, flags), rsp);
+                              l2cap_build_conf_rsp(chan, rsp,
+                              L2CAP_CONF_REJECT, flags), rsp);
                goto unlock;
        }
 
@@ -3604,8 +3663,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (flags & L2CAP_CONF_FLAG_CONTINUATION) {
                /* Incomplete config. Send empty response. */
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                               l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_SUCCESS, flags), rsp);
+                              l2cap_build_conf_rsp(chan, rsp,
+                              L2CAP_CONF_SUCCESS, flags), rsp);
                goto unlock;
        }
 
@@ -3643,23 +3702,22 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
                u8 buf[64];
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                       l2cap_build_conf_req(chan, buf), buf);
+                              l2cap_build_conf_req(chan, buf), buf);
                chan->num_conf_req++;
        }
 
        /* Got Conf Rsp PENDING from remote side and asume we sent
           Conf Rsp PENDING in the code above */
        if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
-                       test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
+           test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
 
                /* check compatibility */
 
-               clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
-               set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
-
-               l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                                       l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_SUCCESS, flags), rsp);
+               /* Send rsp for BR/EDR channel */
+               if (!chan->ctrl_id)
+                       l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags);
+               else
+                       chan->ident = cmd->ident;
        }
 
 unlock:
@@ -3667,7 +3725,8 @@ unlock:
        return err;
 }
 
-static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_config_rsp(struct l2cap_conn *conn,
+                                  struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
        u16 scid, flags, result;
@@ -3699,7 +3758,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                        char buf[64];
 
                        len = l2cap_parse_conf_rsp(chan, rsp->data, len,
-                                                               buf, &result);
+                                                  buf, &result);
                        if (len < 0) {
                                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                                goto done;
@@ -3707,12 +3766,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
                        /* check compatibility */
 
-                       clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
-                       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
-
-                       l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                                               l2cap_build_conf_rsp(chan, buf,
-                                               L2CAP_CONF_SUCCESS, 0x0000), buf);
+                       if (!chan->ctrl_id)
+                               l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,
+                                                       0);
+                       else
+                               chan->ident = cmd->ident;
                }
                goto done;
 
@@ -3728,14 +3786,14 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                        /* throw out any old stored conf requests */
                        result = L2CAP_CONF_SUCCESS;
                        len = l2cap_parse_conf_rsp(chan, rsp->data, len,
-                                                               req, &result);
+                                                  req, &result);
                        if (len < 0) {
                                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                                goto done;
                        }
 
                        l2cap_send_cmd(conn, l2cap_get_ident(conn),
-                                               L2CAP_CONF_REQ, len, req);
+                                      L2CAP_CONF_REQ, len, req);
                        chan->num_conf_req++;
                        if (result != L2CAP_CONF_SUCCESS)
                                goto done;
@@ -3773,7 +3831,8 @@ done:
        return err;
 }
 
-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
+                                      struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
        struct l2cap_disconn_rsp rsp;
@@ -3819,7 +3878,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
        return 0;
 }
 
-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
+                                      struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
        u16 dcid, scid;
@@ -3853,7 +3913,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
        return 0;
 }
 
-static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_information_req(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_info_req *req = (struct l2cap_info_req *) data;
        u16 type;
@@ -3870,14 +3931,14 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
-                                                        | L2CAP_FEAT_FCS;
+                               | L2CAP_FEAT_FCS;
                if (enable_hs)
                        feat_mask |= L2CAP_FEAT_EXT_FLOW
-                                               | L2CAP_FEAT_EXT_WINDOW;
+                               | L2CAP_FEAT_EXT_WINDOW;
 
                put_unaligned_le32(feat_mask, rsp->data);
-               l2cap_send_cmd(conn, cmd->ident,
-                                       L2CAP_INFO_RSP, sizeof(buf), buf);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
+                              buf);
        } else if (type == L2CAP_IT_FIXED_CHAN) {
                u8 buf[12];
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
@@ -3890,20 +3951,21 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
                rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
-               l2cap_send_cmd(conn, cmd->ident,
-                                       L2CAP_INFO_RSP, sizeof(buf), buf);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
+                              buf);
        } else {
                struct l2cap_info_rsp rsp;
                rsp.type   = cpu_to_le16(type);
                rsp.result = __constant_cpu_to_le16(L2CAP_IR_NOTSUPP);
-               l2cap_send_cmd(conn, cmd->ident,
-                                       L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp),
+                              &rsp);
        }
 
        return 0;
 }
 
-static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_information_rsp(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
        u16 type, result;
@@ -3915,7 +3977,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
        /* L2CAP Info req/rsp are unbound to channels, add extra checks */
        if (cmd->ident != conn->info_ident ||
-                       conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
+           conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
                return 0;
 
        cancel_delayed_work(&conn->info_timer);
@@ -3940,7 +4002,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
                        conn->info_ident = l2cap_get_ident(conn);
 
                        l2cap_send_cmd(conn, conn->info_ident,
-                                       L2CAP_INFO_REQ, sizeof(req), &req);
+                                      L2CAP_INFO_REQ, sizeof(req), &req);
                } else {
                        conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                        conn->info_ident = 0;
@@ -3962,8 +4024,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 }
 
 static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
-                                       void *data)
+                                          struct l2cap_cmd_hdr *cmd,
+                                          u16 cmd_len, void *data)
 {
        struct l2cap_create_chan_req *req = data;
        struct l2cap_create_chan_rsp rsp;
@@ -3993,7 +4055,8 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, void *data)
+                                          struct l2cap_cmd_hdr *cmd,
+                                          void *data)
 {
        BT_DBG("conn %p", conn);
 
@@ -4126,7 +4189,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
-                                                       u16 to_multiplier)
+                                        u16 to_multiplier)
 {
        u16 max_latency;
 
@@ -4147,7 +4210,8 @@ static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
 }
 
 static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u8 *data)
+                                             struct l2cap_cmd_hdr *cmd,
+                                             u8 *data)
 {
        struct hci_conn *hcon = conn->hcon;
        struct l2cap_conn_param_update_req *req;
@@ -4169,7 +4233,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
        to_multiplier   = __le16_to_cpu(req->to_multiplier);
 
        BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
-                                               min, max, latency, to_multiplier);
+              min, max, latency, to_multiplier);
 
        memset(&rsp, 0, sizeof(rsp));
 
@@ -4180,7 +4244,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
                rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
 
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
-                                                       sizeof(rsp), &rsp);
+                      sizeof(rsp), &rsp);
 
        if (!err)
                hci_le_conn_update(hcon, min, max, latency, to_multiplier);
@@ -4189,7 +4253,8 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
-                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
+                                     struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                     u8 *data)
 {
        int err = 0;
 
@@ -4203,6 +4268,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_CONN_RSP:
+       case L2CAP_CREATE_CHAN_RSP:
                err = l2cap_connect_rsp(conn, cmd, data);
                break;
 
@@ -4241,10 +4307,6 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
                break;
 
-       case L2CAP_CREATE_CHAN_RSP:
-               err = l2cap_create_channel_rsp(conn, cmd, data);
-               break;
-
        case L2CAP_MOVE_CHAN_REQ:
                err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
                break;
@@ -4271,7 +4333,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u8 *data)
+                                  struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        switch (cmd->code) {
        case L2CAP_COMMAND_REJ:
@@ -4290,7 +4352,7 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
 }
 
 static inline void l2cap_sig_channel(struct l2cap_conn *conn,
-                                                       struct sk_buff *skb)
+                                    struct sk_buff *skb)
 {
        u8 *data = skb->data;
        int len = skb->len;
@@ -4307,7 +4369,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 
                cmd_len = le16_to_cpu(cmd.len);
 
-               BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident);
+               BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len,
+                      cmd.ident);
 
                if (cmd_len > len || !cmd.ident) {
                        BT_DBG("corrupted command");
@@ -4326,7 +4389,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 
                        /* FIXME: Map err to a valid reason */
                        rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
-                       l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
+                       l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ,
+                                      sizeof(rej), &rej);
                }
 
                data += cmd_len;
@@ -4391,8 +4455,8 @@ static void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
        }
 }
 
-static void append_skb_frag(struct sk_buff *skb,
-                       struct sk_buff *new_frag, struct sk_buff **last_frag)
+static void append_skb_frag(struct sk_buff *skb, struct sk_buff *new_frag,
+                           struct sk_buff **last_frag)
 {
        /* skb->len reflects data in skb as well as all fragments
         * skb->data_len reflects only data in fragments
@@ -4641,7 +4705,7 @@ static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
 
        if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
                if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
-                                                               chan->tx_win) {
+                   chan->tx_win) {
                        /* See notes below regarding "double poll" and
                         * invalid packets.
                         */
@@ -4682,8 +4746,7 @@ static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
        }
 
        if (__seq_offset(chan, txseq, chan->last_acked_seq) <
-               __seq_offset(chan, chan->expected_tx_seq,
-                            chan->last_acked_seq)){
+           __seq_offset(chan, chan->expected_tx_seq, chan->last_acked_seq)) {
                BT_DBG("Duplicate - expected_tx_seq later than txseq");
                return L2CAP_TXSEQ_DUPLICATE;
        }
@@ -5323,7 +5386,7 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        int exact = 0, lm1 = 0, lm2 = 0;
        struct l2cap_chan *c;
 
-       BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+       BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
 
        /* Find listening sockets and check their link_mode */
        read_lock(&chan_list_lock);
@@ -5353,7 +5416,7 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn;
 
-       BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
+       BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
 
        if (!status) {
                conn = l2cap_conn_add(hcon, status);
@@ -5443,7 +5506,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                }
 
                if (!status && (chan->state == BT_CONNECTED ||
-                                               chan->state == BT_CONFIG)) {
+                               chan->state == BT_CONFIG)) {
                        struct sock *sk = chan->sk;
 
                        clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
@@ -5456,7 +5519,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
                if (chan->state == BT_CONNECT) {
                        if (!status) {
-                               l2cap_send_conn_req(chan);
+                               l2cap_start_connection(chan);
                        } else {
                                __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        }
@@ -5470,11 +5533,9 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        if (!status) {
                                if (test_bit(BT_SK_DEFER_SETUP,
                                             &bt_sk(sk)->flags)) {
-                                       struct sock *parent = bt_sk(sk)->parent;
                                        res = L2CAP_CR_PEND;
                                        stat = L2CAP_CS_AUTHOR_PEND;
-                                       if (parent)
-                                               parent->sk_data_ready(parent, 0);
+                                       chan->ops->defer(chan);
                                } else {
                                        __l2cap_state_change(chan, BT_CONFIG);
                                        res = L2CAP_CR_SUCCESS;
@@ -5494,7 +5555,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        rsp.result = cpu_to_le16(res);
                        rsp.status = cpu_to_le16(stat);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
-                                                       sizeof(rsp), &rsp);
+                                      sizeof(rsp), &rsp);
 
                        if (!test_bit(CONF_REQ_SENT, &chan->conf_state) &&
                            res == L2CAP_CR_SUCCESS) {
@@ -5519,6 +5580,12 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
+       struct l2cap_hdr *hdr;
+       int len;
+
+       /* For AMP controller do not create l2cap conn */
+       if (!conn && hcon->hdev->dev_type != HCI_BREDR)
+               goto drop;
 
        if (!conn)
                conn = l2cap_conn_add(hcon, 0);
@@ -5528,10 +5595,10 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
        BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
 
-       if (!(flags & ACL_CONT)) {
-               struct l2cap_hdr *hdr;
-               int len;
-
+       switch (flags) {
+       case ACL_START:
+       case ACL_START_NO_FLUSH:
+       case ACL_COMPLETE:
                if (conn->rx_len) {
                        BT_ERR("Unexpected start frame (len %d)", skb->len);
                        kfree_skb(conn->rx_skb);
@@ -5560,20 +5627,22 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
                if (skb->len > len) {
                        BT_ERR("Frame is too long (len %d, expected len %d)",
-                               skb->len, len);
+                              skb->len, len);
                        l2cap_conn_unreliable(conn, ECOMM);
                        goto drop;
                }
 
                /* Allocate skb for the complete frame (with header) */
-               conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
+               conn->rx_skb = bt_skb_alloc(len, GFP_KERNEL);
                if (!conn->rx_skb)
                        goto drop;
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                                                               skb->len);
+                                         skb->len);
                conn->rx_len = len - skb->len;
-       } else {
+               break;
+
+       case ACL_CONT:
                BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
 
                if (!conn->rx_len) {
@@ -5584,7 +5653,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
                if (skb->len > conn->rx_len) {
                        BT_ERR("Fragment is too long (len %d, expected %d)",
-                                       skb->len, conn->rx_len);
+                              skb->len, conn->rx_len);
                        kfree_skb(conn->rx_skb);
                        conn->rx_skb = NULL;
                        conn->rx_len = 0;
@@ -5593,7 +5662,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                }
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                                                               skb->len);
+                                         skb->len);
                conn->rx_len -= skb->len;
 
                if (!conn->rx_len) {
@@ -5601,6 +5670,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                        l2cap_recv_frame(conn, conn->rx_skb);
                        conn->rx_skb = NULL;
                }
+               break;
        }
 
 drop:
@@ -5617,12 +5687,11 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
 
-               seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
-                                       batostr(&bt_sk(sk)->src),
-                                       batostr(&bt_sk(sk)->dst),
-                                       c->state, __le16_to_cpu(c->psm),
-                                       c->scid, c->dcid, c->imtu, c->omtu,
-                                       c->sec_level, c->mode);
+               seq_printf(f, "%pMR %pMR %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
+                          &bt_sk(sk)->src, &bt_sk(sk)->dst,
+                          c->state, __le16_to_cpu(c->psm),
+                          c->scid, c->dcid, c->imtu, c->omtu,
+                          c->sec_level, c->mode);
        }
 
        read_unlock(&chan_list_lock);
@@ -5653,8 +5722,8 @@ int __init l2cap_init(void)
                return err;
 
        if (bt_debugfs) {
-               l2cap_debugfs = debugfs_create_file("l2cap", 0444,
-                                       bt_debugfs, NULL, &l2cap_debugfs_fops);
+               l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
+                                                   NULL, &l2cap_debugfs_fops);
                if (!l2cap_debugfs)
                        BT_ERR("Failed to create L2CAP debug file");
        }
index 083f2bf..89f1472 100644 (file)
@@ -40,7 +40,8 @@ static struct bt_sock_list l2cap_sk_list = {
 
 static const struct proto_ops l2cap_sock_ops;
 static void l2cap_sock_init(struct sock *sk, struct sock *parent);
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
+                                    int proto, gfp_t prio);
 
 static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
@@ -106,7 +107,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
+                             int alen, int flags)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -134,7 +136,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
        lock_sock(sk);
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
-                       sock_sndtimeo(sk, flags & O_NONBLOCK));
+                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
        release_sock(sk);
 
@@ -185,7 +187,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int l2cap_sock_accept(struct socket *sock, struct socket *newsock,
+                            int flags)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct sock *sk = sock->sk, *nsk;
@@ -241,7 +244,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
+                             int *len, int peer)
 {
        struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
        struct sock *sk = sock->sk;
@@ -266,7 +270,8 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
        return 0;
 }
 
-static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
+static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
+                                    char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -309,7 +314,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                        break;
                case BT_SECURITY_HIGH:
                        opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
-                                                       L2CAP_LM_SECURE;
+                             L2CAP_LM_SECURE;
                        break;
                default:
                        opt = 0;
@@ -353,7 +358,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
        return err;
 }
 
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
+                                char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -377,19 +383,20 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
 
                memset(&sec, 0, sizeof(sec));
-               if (chan->conn)
+               if (chan->conn) {
                        sec.level = chan->conn->hcon->sec_level;
-               else
-                       sec.level = chan->sec_level;
 
-               if (sk->sk_state == BT_CONNECTED)
-                       sec.key_size = chan->conn->hcon->enc_key_size;
+                       if (sk->sk_state == BT_CONNECTED)
+                               sec.key_size = chan->conn->hcon->enc_key_size;
+               } else {
+                       sec.level = chan->sec_level;
+               }
 
                len = min_t(unsigned int, len, sizeof(sec));
                if (copy_to_user(optval, (char *) &sec, len))
@@ -411,14 +418,14 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
        case BT_FLUSHABLE:
                if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
-                                               (u32 __user *) optval))
+                            (u32 __user *) optval))
                        err = -EFAULT;
 
                break;
 
        case BT_POWER:
                if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
-                               && sk->sk_type != SOCK_RAW) {
+                   && sk->sk_type != SOCK_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -466,7 +473,8 @@ static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
        return true;
 }
 
-static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
+static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
+                                    char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -529,6 +537,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                chan->fcs  = opts.fcs;
                chan->max_tx = opts.max_tx;
                chan->tx_win = opts.txwin_size;
+               chan->flush_to = opts.flush_to;
                break;
 
        case L2CAP_LM:
@@ -564,7 +573,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
        return err;
 }
 
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
+                                char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -587,7 +597,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -601,7 +611,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                }
 
                if (sec.level < BT_SECURITY_LOW ||
-                                       sec.level > BT_SECURITY_HIGH) {
+                   sec.level > BT_SECURITY_HIGH) {
                        err = -EINVAL;
                        break;
                }
@@ -627,7 +637,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
                /* or for ACL link */
                } else if ((sk->sk_state == BT_CONNECT2 &&
-                          test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
+                           test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
                           sk->sk_state == BT_CONNECTED) {
                        if (!l2cap_chan_check_security(chan))
                                set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
@@ -684,7 +694,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
        case BT_POWER:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -720,7 +730,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                }
 
                if (chan->mode != L2CAP_MODE_ERTM &&
-                               chan->mode != L2CAP_MODE_STREAMING) {
+                   chan->mode != L2CAP_MODE_STREAMING) {
                        err = -EOPNOTSUPP;
                        break;
                }
@@ -737,7 +747,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
-static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
+static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+                             struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -762,7 +773,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        return err;
 }
 
-static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
+static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+                             struct msghdr *msg, size_t len, int flags)
 {
        struct sock *sk = sock->sk;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -866,7 +878,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
-                                                       sk->sk_lingertime);
+                                                sk->sk_lingertime);
        }
 
        if (!err && sk->sk_err)
@@ -930,7 +942,7 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
        }
 
        sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
-                                                               GFP_ATOMIC);
+                             GFP_ATOMIC);
        if (!sk)
                return NULL;
 
@@ -938,6 +950,8 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
 
        l2cap_sock_init(sk, parent);
 
+       bt_accept_enqueue(parent, sk);
+
        return l2cap_pi(sk)->chan;
 }
 
@@ -1068,6 +1082,15 @@ static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
        release_sock(sk);
 }
 
+static void l2cap_sock_defer_cb(struct l2cap_chan *chan)
+{
+       struct sock *sk = chan->data;
+       struct sock *parent = bt_sk(sk)->parent;
+
+       if (parent)
+               parent->sk_data_ready(parent, 0);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
        .name           = "L2CAP Socket Interface",
        .new_connection = l2cap_sock_new_connection_cb,
@@ -1076,6 +1099,7 @@ static struct l2cap_ops l2cap_chan_ops = {
        .teardown       = l2cap_sock_teardown_cb,
        .state_change   = l2cap_sock_state_change_cb,
        .ready          = l2cap_sock_ready_cb,
+       .defer          = l2cap_sock_defer_cb,
        .alloc_skb      = l2cap_sock_alloc_skb_cb,
 };
 
@@ -1083,7 +1107,8 @@ static void l2cap_sock_destruct(struct sock *sk)
 {
        BT_DBG("sk %p", sk);
 
-       l2cap_chan_put(l2cap_pi(sk)->chan);
+       if (l2cap_pi(sk)->chan)
+               l2cap_chan_put(l2cap_pi(sk)->chan);
        if (l2cap_pi(sk)->rx_busy_skb) {
                kfree_skb(l2cap_pi(sk)->rx_busy_skb);
                l2cap_pi(sk)->rx_busy_skb = NULL;
@@ -1159,7 +1184,8 @@ static struct proto l2cap_proto = {
        .obj_size       = sizeof(struct l2cap_pinfo)
 };
 
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
+                                    int proto, gfp_t prio)
 {
        struct sock *sk;
        struct l2cap_chan *chan;
@@ -1204,7 +1230,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
        sock->state = SS_UNCONNECTED;
 
        if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
-                       sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
+           sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
                return -ESOCKTNOSUPPORT;
 
        if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
@@ -1261,7 +1287,8 @@ int __init l2cap_init_sockets(void)
                goto error;
        }
 
-       err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list, NULL);
+       err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list,
+                            NULL);
        if (err < 0) {
                BT_ERR("Failed to create L2CAP proc file");
                bt_sock_unregister(BTPROTO_L2CAP);
index e1c9752..b3fbc73 100644 (file)
@@ -41,20 +41,6 @@ void baswap(bdaddr_t *dst, bdaddr_t *src)
 }
 EXPORT_SYMBOL(baswap);
 
-char *batostr(bdaddr_t *ba)
-{
-       static char str[2][18];
-       static int i = 1;
-
-       i ^= 1;
-       sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-               ba->b[5], ba->b[4], ba->b[3],
-               ba->b[2], ba->b[1], ba->b[0]);
-
-       return str[i];
-}
-EXPORT_SYMBOL(batostr);
-
 /* Bluetooth error codes to Unix errno mapping */
 int bt_to_errno(__u16 code)
 {
index aa2ea0a..399e502 100644 (file)
@@ -3125,6 +3125,9 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
        struct pending_cmd *cmd;
        int err;
 
+       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
+                            hdev);
+
        cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
        if (!cmd)
                return -ENOENT;
@@ -3137,8 +3140,6 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
        mgmt_pending_remove(cmd);
 
-       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
-                            hdev);
        return err;
 }
 
index c75107e..201fdf7 100644 (file)
@@ -377,8 +377,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
        int err = 0;
        u8 dlci;
 
-       BT_DBG("dlc %p state %ld %s %s channel %d",
-                       d, d->state, batostr(src), batostr(dst), channel);
+       BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d",
+              d, d->state, src, dst, channel);
 
        if (channel < 1 || channel > 30)
                return -EINVAL;
@@ -676,7 +676,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
        struct socket *sock;
        struct sock *sk;
 
-       BT_DBG("%s %s", batostr(src), batostr(dst));
+       BT_DBG("%pMR -> %pMR", src, dst);
 
        *err = rfcomm_l2sock_create(&sock);
        if (*err < 0)
@@ -709,7 +709,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
 
        bacpy(&addr.l2_bdaddr, dst);
        addr.l2_family = AF_BLUETOOTH;
-       addr.l2_psm    = cpu_to_le16(RFCOMM_PSM);
+       addr.l2_psm    = __constant_cpu_to_le16(RFCOMM_PSM);
        addr.l2_cid    = 0;
        *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
        if (*err == 0 || *err == -EINPROGRESS)
@@ -1987,7 +1987,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
        /* Bind socket */
        bacpy(&addr.l2_bdaddr, ba);
        addr.l2_family = AF_BLUETOOTH;
-       addr.l2_psm    = cpu_to_le16(RFCOMM_PSM);
+       addr.l2_psm    = __constant_cpu_to_le16(RFCOMM_PSM);
        addr.l2_cid    = 0;
        err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0) {
@@ -2125,11 +2125,10 @@ static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
                list_for_each_entry(d, &s->dlcs, list) {
                        struct sock *sk = s->sock->sk;
 
-                       seq_printf(f, "%s %s %ld %d %d %d %d\n",
-                                               batostr(&bt_sk(sk)->src),
-                                               batostr(&bt_sk(sk)->dst),
-                                               d->state, d->dlci, d->mtu,
-                                               d->rx_credits, d->tx_credits);
+                       seq_printf(f, "%pMR %pMR %ld %d %d %d %d\n",
+                                  &bt_sk(sk)->src, &bt_sk(sk)->dst,
+                                  d->state, d->dlci, d->mtu,
+                                  d->rx_credits, d->tx_credits);
                }
        }
 
index b3226f3..4ddef57 100644 (file)
@@ -334,7 +334,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
        struct sock *sk = sock->sk;
        int err = 0;
 
-       BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
+       BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
@@ -975,10 +975,9 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
        read_lock(&rfcomm_sk_list.lock);
 
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
-               seq_printf(f, "%s %s %d %d\n",
-                               batostr(&bt_sk(sk)->src),
-                               batostr(&bt_sk(sk)->dst),
-                               sk->sk_state, rfcomm_pi(sk)->channel);
+               seq_printf(f, "%pMR %pMR %d %d\n",
+                          &bt_sk(sk)->src, &bt_sk(sk)->dst,
+                          sk->sk_state, rfcomm_pi(sk)->channel);
        }
 
        read_unlock(&rfcomm_sk_list.lock);
index ccc2487..bd6fd0f 100644 (file)
@@ -166,7 +166,7 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
 static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
 {
        struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
-       return sprintf(buf, "%s\n", batostr(&dev->dst));
+       return sprintf(buf, "%pMR\n", &dev->dst);
 }
 
 static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
@@ -663,8 +663,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
        if (!dev)
                return -ENODEV;
 
-       BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
-                               dev->channel, dev->port.count);
+       BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst,
+              dev->channel, dev->port.count);
 
        spin_lock_irqsave(&dev->port.lock, flags);
        if (++dev->port.count > 1) {
index dc42b91..450cdcd 100644 (file)
@@ -172,7 +172,7 @@ static int sco_connect(struct sock *sk)
        struct hci_dev  *hdev;
        int err, type;
 
-       BT_DBG("%s -> %s", batostr(src), batostr(dst));
+       BT_DBG("%pMR -> %pMR", src, dst);
 
        hdev = hci_get_route(dst, src);
        if (!hdev)
@@ -460,7 +460,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
        struct sock *sk = sock->sk;
        int err = 0;
 
-       BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
+       BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
@@ -893,7 +893,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        struct hlist_node *node;
        int lm = 0;
 
-       BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+       BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
 
        /* Find listening sockets */
        read_lock(&sco_sk_list.lock);
@@ -914,7 +914,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
 void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
 {
-       BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
+       BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
        if (!status) {
                struct sco_conn *conn;
 
@@ -959,8 +959,8 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
        read_lock(&sco_sk_list.lock);
 
        sk_for_each(sk, node, &sco_sk_list.head) {
-               seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
-                          batostr(&bt_sk(sk)->dst), sk->sk_state);
+               seq_printf(f, "%pMR %pMR %d\n", &bt_sk(sk)->src,
+                          &bt_sk(sk)->dst, sk->sk_state);
        }
 
        read_unlock(&sco_sk_list.lock);
index 2ac8d50..9176bc1 100644 (file)
@@ -167,7 +167,7 @@ static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
 
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(sizeof(code) + dlen);
-       lh->cid = cpu_to_le16(L2CAP_CID_SMP);
+       lh->cid = __constant_cpu_to_le16(L2CAP_CID_SMP);
 
        memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
 
index 14b065c..65429b9 100644 (file)
 #include "br_private.h"
 #include "br_private_stp.h"
 
+static inline size_t br_port_info_size(void)
+{
+       return nla_total_size(1)        /* IFLA_BRPORT_STATE  */
+               + nla_total_size(2)     /* IFLA_BRPORT_PRIORITY */
+               + nla_total_size(4)     /* IFLA_BRPORT_COST */
+               + nla_total_size(1)     /* IFLA_BRPORT_MODE */
+               + nla_total_size(1)     /* IFLA_BRPORT_GUARD */
+               + nla_total_size(1)     /* IFLA_BRPORT_PROTECT */
+               + 0;
+}
+
 static inline size_t br_nlmsg_size(void)
 {
        return NLMSG_ALIGN(sizeof(struct ifinfomsg))
-              + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
-              + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
-              + nla_total_size(4) /* IFLA_MASTER */
-              + nla_total_size(4) /* IFLA_MTU */
-              + nla_total_size(4) /* IFLA_LINK */
-              + nla_total_size(1) /* IFLA_OPERSTATE */
-              + nla_total_size(1); /* IFLA_PROTINFO */
+               + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+               + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+               + nla_total_size(4) /* IFLA_MASTER */
+               + nla_total_size(4) /* IFLA_MTU */
+               + nla_total_size(4) /* IFLA_LINK */
+               + nla_total_size(1) /* IFLA_OPERSTATE */
+               + nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */
+}
+
+static int br_port_fill_attrs(struct sk_buff *skb,
+                             const struct net_bridge_port *p)
+{
+       u8 mode = !!(p->flags & BR_HAIRPIN_MODE);
+
+       if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
+           nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
+           nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
+           nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
+           nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
+           nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)))
+               return -EMSGSIZE;
+
+       return 0;
 }
 
 /*
@@ -67,10 +94,18 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
            (dev->addr_len &&
             nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
            (dev->ifindex != dev->iflink &&
-            nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
-           (event == RTM_NEWLINK &&
-            nla_put_u8(skb, IFLA_PROTINFO, port->state)))
+            nla_put_u32(skb, IFLA_LINK, dev->iflink)))
                goto nla_put_failure;
+
+       if (event == RTM_NEWLINK) {
+               struct nlattr *nest
+                       = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
+
+               if (nest == NULL || br_port_fill_attrs(skb, port) < 0)
+                       goto nla_put_failure;
+               nla_nest_end(skb, nest);
+       }
+
        return nlmsg_end(skb, nlh);
 
 nla_put_failure:
@@ -126,47 +161,118 @@ out:
        return err;
 }
 
-/*
- * Change state of port (ie from forwarding to blocking etc)
- * Used by spanning tree in user space.
- */
+static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
+       [IFLA_BRPORT_STATE]     = { .type = NLA_U8 },
+       [IFLA_BRPORT_COST]      = { .type = NLA_U32 },
+       [IFLA_BRPORT_PRIORITY]  = { .type = NLA_U16 },
+       [IFLA_BRPORT_MODE]      = { .type = NLA_U8 },
+       [IFLA_BRPORT_GUARD]     = { .type = NLA_U8 },
+       [IFLA_BRPORT_PROTECT]   = { .type = NLA_U8 },
+};
+
+/* Change the state of the port and notify spanning tree */
+static int br_set_port_state(struct net_bridge_port *p, u8 state)
+{
+       if (state > BR_STATE_BLOCKING)
+               return -EINVAL;
+
+       /* if kernel STP is running, don't allow changes */
+       if (p->br->stp_enabled == BR_KERNEL_STP)
+               return -EBUSY;
+
+       if (!netif_running(p->dev) ||
+           (!netif_carrier_ok(p->dev) && state != BR_STATE_DISABLED))
+               return -ENETDOWN;
+
+       p->state = state;
+       br_log_state(p);
+       br_port_state_selection(p->br);
+       return 0;
+}
+
+/* Set/clear or port flags based on attribute */
+static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[],
+                          int attrtype, unsigned long mask)
+{
+       if (tb[attrtype]) {
+               u8 flag = nla_get_u8(tb[attrtype]);
+               if (flag)
+                       p->flags |= mask;
+               else
+                       p->flags &= ~mask;
+       }
+}
+
+/* Process bridge protocol info on port */
+static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
+{
+       int err;
+
+       br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
+       br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
+
+       if (tb[IFLA_BRPORT_COST]) {
+               err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
+               if (err)
+                       return err;
+       }
+
+       if (tb[IFLA_BRPORT_PRIORITY]) {
+               err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY]));
+               if (err)
+                       return err;
+       }
+
+       if (tb[IFLA_BRPORT_STATE]) {
+               err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE]));
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+/* Change state and parameters on port. */
 int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
 {
        struct ifinfomsg *ifm;
        struct nlattr *protinfo;
        struct net_bridge_port *p;
-       u8 new_state;
+       struct nlattr *tb[IFLA_BRPORT_MAX];
+       int err;
 
        ifm = nlmsg_data(nlh);
 
        protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
-       if (!protinfo || nla_len(protinfo) < sizeof(u8))
-               return -EINVAL;
-
-       new_state = nla_get_u8(protinfo);
-       if (new_state > BR_STATE_BLOCKING)
-               return -EINVAL;
+       if (!protinfo)
+               return 0;
 
        p = br_port_get_rtnl(dev);
        if (!p)
                return -EINVAL;
 
-       /* if kernel STP is running, don't allow changes */
-       if (p->br->stp_enabled == BR_KERNEL_STP)
-               return -EBUSY;
+       if (protinfo->nla_type & NLA_F_NESTED) {
+               err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
+                                      protinfo, ifla_brport_policy);
+               if (err)
+                       return err;
 
-       if (!netif_running(dev) ||
-           (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
-               return -ENETDOWN;
+               spin_lock_bh(&p->br->lock);
+               err = br_setport(p, tb);
+               spin_unlock_bh(&p->br->lock);
+       } else {
+               /* Binary compatability with old RSTP */
+               if (nla_len(protinfo) < sizeof(u8))
+                       return -EINVAL;
 
-       p->state = new_state;
-       br_log_state(p);
+               spin_lock_bh(&p->br->lock);
+               err = br_set_port_state(p, nla_get_u8(protinfo));
+               spin_unlock_bh(&p->br->lock);
+       }
 
-       spin_lock_bh(&p->br->lock);
-       br_port_state_selection(p->br);
-       spin_unlock_bh(&p->br->lock);
+       if (err == 0)
+               br_ifinfo_notify(RTM_NEWLINK, p);
 
-       return 0;
+       return err;
 }
 
 static int br_validate(struct nlattr *tb[], struct nlattr *data[])
index 22111ff..eb9cd42 100644 (file)
@@ -135,6 +135,8 @@ struct net_bridge_port
 
        unsigned long                   flags;
 #define BR_HAIRPIN_MODE                0x00000001
+#define BR_BPDU_GUARD           0x00000002
+#define BR_ROOT_BLOCK          0x00000004
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
        u32                             multicast_startup_queries_sent;
index af9a120..b01849a 100644 (file)
@@ -100,6 +100,21 @@ static int br_should_become_root_port(const struct net_bridge_port *p,
        return 0;
 }
 
+static void br_root_port_block(const struct net_bridge *br,
+                              struct net_bridge_port *p)
+{
+
+       br_notice(br, "port %u(%s) tried to become root port (blocked)",
+                 (unsigned int) p->port_no, p->dev->name);
+
+       p->state = BR_STATE_LISTENING;
+       br_log_state(p);
+       br_ifinfo_notify(RTM_NEWLINK, p);
+
+       if (br->forward_delay > 0)
+               mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay);
+}
+
 /* called under bridge lock */
 static void br_root_selection(struct net_bridge *br)
 {
@@ -107,7 +122,12 @@ static void br_root_selection(struct net_bridge *br)
        u16 root_port = 0;
 
        list_for_each_entry(p, &br->port_list, list) {
-               if (br_should_become_root_port(p, root_port))
+               if (!br_should_become_root_port(p, root_port))
+                       continue;
+
+               if (p->flags & BR_ROOT_BLOCK)
+                       br_root_port_block(br, p);
+               else
                        root_port = p->port_no;
        }
 
index fd30a60..7f884e3 100644 (file)
@@ -170,6 +170,13 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
        if (!ether_addr_equal(dest, br->group_addr))
                goto out;
 
+       if (p->flags & BR_BPDU_GUARD) {
+               br_notice(br, "BPDU received on blocked port %u(%s)\n",
+                         (unsigned int) p->port_no, p->dev->name);
+               br_stp_disable_port(p);
+               goto out;
+       }
+
        buf = skb_pull(skb, 3);
 
        if (buf[0] == BPDU_TYPE_CONFIG) {
index 13b36bd..80a4fc5 100644 (file)
@@ -34,6 +34,28 @@ const struct brport_attribute brport_attr_##_name = {                \
        .store  = _store,                                       \
 };
 
+#define BRPORT_ATTR_FLAG(_name, _mask)                         \
+static ssize_t show_##_name(struct net_bridge_port *p, char *buf) \
+{                                                              \
+       return sprintf(buf, "%d\n", !!(p->flags & _mask));      \
+}                                                              \
+static int store_##_name(struct net_bridge_port *p, unsigned long v) \
+{                                                              \
+       unsigned long flags = p->flags;                         \
+       if (v)                                                  \
+               flags |= _mask;                                 \
+       else                                                    \
+               flags &= ~_mask;                                \
+       if (flags != p->flags) {                                \
+               p->flags = flags;                               \
+               br_ifinfo_notify(RTM_NEWLINK, p);               \
+       }                                                       \
+       return 0;                                               \
+}                                                              \
+static BRPORT_ATTR(_name, S_IRUGO | S_IWUSR,                   \
+                  show_##_name, store_##_name)
+
+
 static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
 {
        return sprintf(buf, "%d\n", p->path_cost);
@@ -133,21 +155,9 @@ static int store_flush(struct net_bridge_port *p, unsigned long v)
 }
 static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush);
 
-static ssize_t show_hairpin_mode(struct net_bridge_port *p, char *buf)
-{
-       int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0;
-       return sprintf(buf, "%d\n", hairpin_mode);
-}
-static int store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
-{
-       if (v)
-               p->flags |= BR_HAIRPIN_MODE;
-       else
-               p->flags &= ~BR_HAIRPIN_MODE;
-       return 0;
-}
-static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
-                  show_hairpin_mode, store_hairpin_mode);
+BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE);
+BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
+BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
@@ -181,6 +191,8 @@ static const struct brport_attribute *brport_attrs[] = {
        &brport_attr_hold_timer,
        &brport_attr_flush,
        &brport_attr_hairpin_mode,
+       &brport_attr_bpdu_guard,
+       &brport_attr_root_block,
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
        &brport_attr_multicast_router,
 #endif
index 7240f8e..127f2a1 100644 (file)
@@ -164,21 +164,6 @@ struct ipgre_net {
 #define tunnels_r      tunnels[2]
 #define tunnels_l      tunnels[1]
 #define tunnels_wc     tunnels[0]
-/*
- * Locking : hash tables are protected by RCU and RTNL
- */
-
-#define for_each_ip_tunnel_rcu(start) \
-       for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
-
-/* often modified stats are per cpu, other are shared (netdev->stats) */
-struct pcpu_tstats {
-       u64     rx_packets;
-       u64     rx_bytes;
-       u64     tx_packets;
-       u64     tx_bytes;
-       struct u64_stats_sync   syncp;
-};
 
 static struct rtnl_link_stats64 *ipgre_get_stats64(struct net_device *dev,
                                                   struct rtnl_link_stats64 *tot)
@@ -250,7 +235,7 @@ static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev,
                       ARPHRD_ETHER : ARPHRD_IPGRE;
        int score, cand_score = 4;
 
-       for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_r_l[h0 ^ h1]) {
                if (local != t->parms.iph.saddr ||
                    remote != t->parms.iph.daddr ||
                    !(t->dev->flags & IFF_UP))
@@ -277,7 +262,7 @@ static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev,
                }
        }
 
-       for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_r[h0 ^ h1]) {
                if (remote != t->parms.iph.daddr ||
                    !(t->dev->flags & IFF_UP))
                        continue;
@@ -303,7 +288,7 @@ static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev,
                }
        }
 
-       for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_l[h1]) {
                if ((local != t->parms.iph.saddr &&
                     (local != t->parms.iph.daddr ||
                      !ipv4_is_multicast(local))) ||
@@ -331,7 +316,7 @@ static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev,
                }
        }
 
-       for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_wc[h1]) {
                if (t->parms.i_key != key ||
                    !(t->dev->flags & IFF_UP))
                        continue;
@@ -753,7 +738,6 @@ drop:
 static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct pcpu_tstats *tstats;
        const struct iphdr  *old_iph = ip_hdr(skb);
        const struct iphdr  *tiph;
        struct flowi4 fl4;
@@ -977,9 +961,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                }
        }
 
-       nf_reset(skb);
-       tstats = this_cpu_ptr(dev->tstats);
-       __IPTUNNEL_XMIT(tstats, &dev->stats);
+       iptunnel_xmit(skb, dev);
        return NETDEV_TX_OK;
 
 #if IS_ENABLED(CONFIG_IPV6)
index 1831092..516188b 100644 (file)
@@ -66,20 +66,6 @@ static void vti_tunnel_setup(struct net_device *dev);
 static void vti_dev_free(struct net_device *dev);
 static int vti_tunnel_bind_dev(struct net_device *dev);
 
-/* Locking : hash tables are protected by RCU and RTNL */
-
-#define for_each_ip_tunnel_rcu(start) \
-       for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
-
-/* often modified stats are per cpu, other are shared (netdev->stats) */
-struct pcpu_tstats {
-       u64     rx_packets;
-       u64     rx_bytes;
-       u64     tx_packets;
-       u64     tx_bytes;
-       struct  u64_stats_sync  syncp;
-};
-
 #define VTI_XMIT(stats1, stats2) do {                          \
        int err;                                                \
        int pkt_len = skb->len;                                 \
@@ -142,19 +128,19 @@ static struct ip_tunnel *vti_tunnel_lookup(struct net *net,
        struct ip_tunnel *t;
        struct vti_net *ipn = net_generic(net, vti_net_id);
 
-       for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1])
+       for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1])
                if (local == t->parms.iph.saddr &&
                    remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
                        return t;
-       for_each_ip_tunnel_rcu(ipn->tunnels_r[h0])
+       for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0])
                if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
                        return t;
 
-       for_each_ip_tunnel_rcu(ipn->tunnels_l[h1])
+       for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1])
                if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
                        return t;
 
-       for_each_ip_tunnel_rcu(ipn->tunnels_wc[0])
+       for_each_ip_tunnel_rcu(t, ipn->tunnels_wc[0])
                if (t && (t->dev->flags&IFF_UP))
                        return t;
        return NULL;
index 720855e..64686e1 100644 (file)
@@ -140,22 +140,6 @@ static void ipip_tunnel_setup(struct net_device *dev);
 static void ipip_dev_free(struct net_device *dev);
 static struct rtnl_link_ops ipip_link_ops __read_mostly;
 
-/*
- * Locking : hash tables are protected by RCU and RTNL
- */
-
-#define for_each_ip_tunnel_rcu(start) \
-       for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
-
-/* often modified stats are per cpu, other are shared (netdev->stats) */
-struct pcpu_tstats {
-       u64     rx_packets;
-       u64     rx_bytes;
-       u64     tx_packets;
-       u64     tx_bytes;
-       struct u64_stats_sync   syncp;
-};
-
 static struct rtnl_link_stats64 *ipip_get_stats64(struct net_device *dev,
                                                  struct rtnl_link_stats64 *tot)
 {
@@ -198,16 +182,16 @@ static struct ip_tunnel *ipip_tunnel_lookup(struct net *net,
        struct ip_tunnel *t;
        struct ipip_net *ipn = net_generic(net, ipip_net_id);
 
-       for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1])
+       for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1])
                if (local == t->parms.iph.saddr &&
                    remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
                        return t;
 
-       for_each_ip_tunnel_rcu(ipn->tunnels_r[h0])
+       for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0])
                if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
                        return t;
 
-       for_each_ip_tunnel_rcu(ipn->tunnels_l[h1])
+       for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1])
                if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
                        return t;
 
@@ -265,6 +249,32 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
        rcu_assign_pointer(*tp, t);
 }
 
+static int ipip_tunnel_create(struct net_device *dev)
+{
+       struct ip_tunnel *t = netdev_priv(dev);
+       struct net *net = dev_net(dev);
+       struct ipip_net *ipn = net_generic(net, ipip_net_id);
+       int err;
+
+       err = ipip_tunnel_init(dev);
+       if (err < 0)
+               goto out;
+
+       err = register_netdevice(dev);
+       if (err < 0)
+               goto out;
+
+       strcpy(t->parms.name, dev->name);
+       dev->rtnl_link_ops = &ipip_link_ops;
+
+       dev_hold(dev);
+       ipip_tunnel_link(ipn, t);
+       return 0;
+
+out:
+       return err;
+}
+
 static struct ip_tunnel *ipip_tunnel_locate(struct net *net,
                struct ip_tunnel_parm *parms, int create)
 {
@@ -299,17 +309,9 @@ static struct ip_tunnel *ipip_tunnel_locate(struct net *net,
        nt = netdev_priv(dev);
        nt->parms = *parms;
 
-       if (ipip_tunnel_init(dev) < 0)
-               goto failed_free;
-
-       if (register_netdevice(dev) < 0)
+       if (ipip_tunnel_create(dev) < 0)
                goto failed_free;
 
-       strcpy(nt->parms.name, dev->name);
-       dev->rtnl_link_ops = &ipip_link_ops;
-
-       dev_hold(dev);
-       ipip_tunnel_link(ipn, nt);
        return nt;
 
 failed_free:
@@ -465,7 +467,6 @@ drop:
 static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct pcpu_tstats *tstats;
        const struct iphdr  *tiph = &tunnel->parms.iph;
        u8     tos = tunnel->parms.iph.tos;
        __be16 df = tiph->frag_off;
@@ -592,9 +593,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if ((iph->ttl = tiph->ttl) == 0)
                iph->ttl        =       old_iph->ttl;
 
-       nf_reset(skb);
-       tstats = this_cpu_ptr(dev->tstats);
-       __IPTUNNEL_XMIT(tstats, &dev->stats);
+       iptunnel_xmit(skb, dev);
        return NETDEV_TX_OK;
 
 tx_error_icmp:
@@ -641,6 +640,28 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
        dev->iflink = tunnel->parms.link;
 }
 
+static void ipip_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
+{
+       struct net *net = dev_net(t->dev);
+       struct ipip_net *ipn = net_generic(net, ipip_net_id);
+
+       ipip_tunnel_unlink(ipn, t);
+       synchronize_net();
+       t->parms.iph.saddr = p->iph.saddr;
+       t->parms.iph.daddr = p->iph.daddr;
+       memcpy(t->dev->dev_addr, &p->iph.saddr, 4);
+       memcpy(t->dev->broadcast, &p->iph.daddr, 4);
+       ipip_tunnel_link(ipn, t);
+       t->parms.iph.ttl = p->iph.ttl;
+       t->parms.iph.tos = p->iph.tos;
+       t->parms.iph.frag_off = p->iph.frag_off;
+       if (t->parms.link != p->link) {
+               t->parms.link = p->link;
+               ipip_tunnel_bind_dev(t->dev);
+       }
+       netdev_state_change(t->dev);
+}
+
 static int
 ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -699,29 +720,13 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
                                        break;
                                }
                                t = netdev_priv(dev);
-                               ipip_tunnel_unlink(ipn, t);
-                               synchronize_net();
-                               t->parms.iph.saddr = p.iph.saddr;
-                               t->parms.iph.daddr = p.iph.daddr;
-                               memcpy(dev->dev_addr, &p.iph.saddr, 4);
-                               memcpy(dev->broadcast, &p.iph.daddr, 4);
-                               ipip_tunnel_link(ipn, t);
-                               netdev_state_change(dev);
                        }
+
+                       ipip_tunnel_update(t, &p);
                }
 
                if (t) {
                        err = 0;
-                       if (cmd == SIOCCHGTUNNEL) {
-                               t->parms.iph.ttl = p.iph.ttl;
-                               t->parms.iph.tos = p.iph.tos;
-                               t->parms.iph.frag_off = p.iph.frag_off;
-                               if (t->parms.link != p.link) {
-                                       t->parms.link = p.link;
-                                       ipip_tunnel_bind_dev(dev);
-                                       netdev_state_change(dev);
-                               }
-                       }
                        if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
                                err = -EFAULT;
                } else
@@ -843,6 +848,84 @@ static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
        return 0;
 }
 
+static void ipip_netlink_parms(struct nlattr *data[],
+                              struct ip_tunnel_parm *parms)
+{
+       memset(parms, 0, sizeof(*parms));
+
+       parms->iph.version = 4;
+       parms->iph.protocol = IPPROTO_IPIP;
+       parms->iph.ihl = 5;
+
+       if (!data)
+               return;
+
+       if (data[IFLA_IPTUN_LINK])
+               parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
+
+       if (data[IFLA_IPTUN_LOCAL])
+               parms->iph.saddr = nla_get_u32(data[IFLA_IPTUN_LOCAL]);
+
+       if (data[IFLA_IPTUN_REMOTE])
+               parms->iph.daddr = nla_get_u32(data[IFLA_IPTUN_REMOTE]);
+
+       if (data[IFLA_IPTUN_TTL]) {
+               parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]);
+               if (parms->iph.ttl)
+                       parms->iph.frag_off = htons(IP_DF);
+       }
+
+       if (data[IFLA_IPTUN_TOS])
+               parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
+
+       if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
+               parms->iph.frag_off = htons(IP_DF);
+}
+
+static int ipip_newlink(struct net *src_net, struct net_device *dev,
+                       struct nlattr *tb[], struct nlattr *data[])
+{
+       struct net *net = dev_net(dev);
+       struct ip_tunnel *nt;
+
+       nt = netdev_priv(dev);
+       ipip_netlink_parms(data, &nt->parms);
+
+       if (ipip_tunnel_locate(net, &nt->parms, 0))
+               return -EEXIST;
+
+       return ipip_tunnel_create(dev);
+}
+
+static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
+                          struct nlattr *data[])
+{
+       struct ip_tunnel *t;
+       struct ip_tunnel_parm p;
+       struct net *net = dev_net(dev);
+       struct ipip_net *ipn = net_generic(net, ipip_net_id);
+
+       if (dev == ipn->fb_tunnel_dev)
+               return -EINVAL;
+
+       ipip_netlink_parms(data, &p);
+
+       if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
+           (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
+               return -EINVAL;
+
+       t = ipip_tunnel_locate(net, &p, 0);
+
+       if (t) {
+               if (t->dev != dev)
+                       return -EEXIST;
+       } else
+               t = netdev_priv(dev);
+
+       ipip_tunnel_update(t, &p);
+       return 0;
+}
+
 static size_t ipip_get_size(const struct net_device *dev)
 {
        return
@@ -856,6 +939,8 @@ static size_t ipip_get_size(const struct net_device *dev)
                nla_total_size(1) +
                /* IFLA_IPTUN_TOS */
                nla_total_size(1) +
+               /* IFLA_IPTUN_PMTUDISC */
+               nla_total_size(1) +
                0;
 }
 
@@ -868,7 +953,9 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
            nla_put_be32(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
            nla_put_be32(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
            nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
-           nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos))
+           nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
+           nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
+                      !!(parm->iph.frag_off & htons(IP_DF))))
                goto nla_put_failure;
        return 0;
 
@@ -876,10 +963,23 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
+       [IFLA_IPTUN_LINK]               = { .type = NLA_U32 },
+       [IFLA_IPTUN_LOCAL]              = { .type = NLA_U32 },
+       [IFLA_IPTUN_REMOTE]             = { .type = NLA_U32 },
+       [IFLA_IPTUN_TTL]                = { .type = NLA_U8 },
+       [IFLA_IPTUN_TOS]                = { .type = NLA_U8 },
+       [IFLA_IPTUN_PMTUDISC]           = { .type = NLA_U8 },
+};
+
 static struct rtnl_link_ops ipip_link_ops __read_mostly = {
        .kind           = "ipip",
        .maxtype        = IFLA_IPTUN_MAX,
+       .policy         = ipip_policy,
        .priv_size      = sizeof(struct ip_tunnel),
+       .setup          = ipip_tunnel_setup,
+       .newlink        = ipip_newlink,
+       .changelink     = ipip_changelink,
        .get_size       = ipip_get_size,
        .fill_info      = ipip_fill_info,
 };
index 12aa473..823fd64 100644 (file)
@@ -109,21 +109,6 @@ static u32 HASH_ADDR(const struct in6_addr *addr)
 #define tunnels_r      tunnels[2]
 #define tunnels_l      tunnels[1]
 #define tunnels_wc     tunnels[0]
-/*
- * Locking : hash tables are protected by RCU and RTNL
- */
-
-#define for_each_ip_tunnel_rcu(start) \
-       for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
-
-/* often modified stats are per cpu, other are shared (netdev->stats) */
-struct pcpu_tstats {
-       u64     rx_packets;
-       u64     rx_bytes;
-       u64     tx_packets;
-       u64     tx_bytes;
-       struct u64_stats_sync   syncp;
-};
 
 static struct rtnl_link_stats64 *ip6gre_get_stats64(struct net_device *dev,
                struct rtnl_link_stats64 *tot)
@@ -181,7 +166,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
                       ARPHRD_ETHER : ARPHRD_IP6GRE;
        int score, cand_score = 4;
 
-       for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_r_l[h0 ^ h1]) {
                if (!ipv6_addr_equal(local, &t->parms.laddr) ||
                    !ipv6_addr_equal(remote, &t->parms.raddr) ||
                    key != t->parms.i_key ||
@@ -206,7 +191,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
                }
        }
 
-       for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_r[h0 ^ h1]) {
                if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
                    key != t->parms.i_key ||
                    !(t->dev->flags & IFF_UP))
@@ -230,7 +215,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
                }
        }
 
-       for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_l[h1]) {
                if ((!ipv6_addr_equal(local, &t->parms.laddr) &&
                          (!ipv6_addr_equal(local, &t->parms.raddr) ||
                                 !ipv6_addr_is_multicast(local))) ||
@@ -256,7 +241,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
                }
        }
 
-       for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
+       for_each_ip_tunnel_rcu(t, ign->tunnels_wc[h1]) {
                if (t->parms.i_key != key ||
                    !(t->dev->flags & IFF_UP))
                        continue;
index 424ed45..ab4d056 100644 (file)
@@ -95,14 +95,6 @@ struct ip6_tnl_net {
        struct ip6_tnl __rcu **tnls[2];
 };
 
-/* often modified stats are per cpu, other are shared (netdev->stats) */
-struct pcpu_tstats {
-       unsigned long   rx_packets;
-       unsigned long   rx_bytes;
-       unsigned long   tx_packets;
-       unsigned long   tx_bytes;
-} __attribute__((aligned(4*sizeof(unsigned long))));
-
 static struct net_device_stats *ip6_get_stats(struct net_device *dev)
 {
        struct pcpu_tstats sum = { 0 };
@@ -259,6 +251,33 @@ static void ip6_dev_free(struct net_device *dev)
        free_netdev(dev);
 }
 
+static int ip6_tnl_create2(struct net_device *dev)
+{
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct net *net = dev_net(dev);
+       struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+       int err;
+
+       t = netdev_priv(dev);
+       err = ip6_tnl_dev_init(dev);
+       if (err < 0)
+               goto out;
+
+       err = register_netdevice(dev);
+       if (err < 0)
+               goto out;
+
+       strcpy(t->parms.name, dev->name);
+       dev->rtnl_link_ops = &ip6_link_ops;
+
+       dev_hold(dev);
+       ip6_tnl_link(ip6n, t);
+       return 0;
+
+out:
+       return err;
+}
+
 /**
  * ip6_tnl_create - create a new tunnel
  *   @p: tunnel parameters
@@ -277,7 +296,6 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
        struct ip6_tnl *t;
        char name[IFNAMSIZ];
        int err;
-       struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
 
        if (p->name[0])
                strlcpy(name, p->name, IFNAMSIZ);
@@ -292,18 +310,10 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
 
        t = netdev_priv(dev);
        t->parms = *p;
-       err = ip6_tnl_dev_init(dev);
+       err = ip6_tnl_create2(dev);
        if (err < 0)
                goto failed_free;
 
-       if ((err = register_netdevice(dev)) < 0)
-               goto failed_free;
-
-       strcpy(t->parms.name, dev->name);
-       dev->rtnl_link_ops = &ip6_link_ops;
-
-       dev_hold(dev);
-       ip6_tnl_link(ip6n, t);
        return t;
 
 failed_free:
@@ -1238,6 +1248,20 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
        return 0;
 }
 
+static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+{
+       struct net *net = dev_net(t->dev);
+       struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+       int err;
+
+       ip6_tnl_unlink(ip6n, t);
+       synchronize_net();
+       err = ip6_tnl_change(t, p);
+       ip6_tnl_link(ip6n, t);
+       netdev_state_change(t->dev);
+       return err;
+}
+
 static void
 ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
 {
@@ -1346,11 +1370,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        } else
                                t = netdev_priv(dev);
 
-                       ip6_tnl_unlink(ip6n, t);
-                       synchronize_net();
-                       err = ip6_tnl_change(t, &p1);
-                       ip6_tnl_link(ip6n, t);
-                       netdev_state_change(dev);
+                       err = ip6_tnl_update(t, &p1);
                }
                if (t) {
                        err = 0;
@@ -1506,7 +1526,97 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
        return 0;
 }
 
-static size_t ip6_get_size(const struct net_device *dev)
+static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+       u8 proto;
+
+       if (!data)
+               return 0;
+
+       proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
+       if (proto != IPPROTO_IPV6 &&
+           proto != IPPROTO_IPIP &&
+           proto != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void ip6_tnl_netlink_parms(struct nlattr *data[],
+                                 struct __ip6_tnl_parm *parms)
+{
+       memset(parms, 0, sizeof(*parms));
+
+       if (!data)
+               return;
+
+       if (data[IFLA_IPTUN_LINK])
+               parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
+
+       if (data[IFLA_IPTUN_LOCAL])
+               nla_memcpy(&parms->laddr, data[IFLA_IPTUN_LOCAL],
+                          sizeof(struct in6_addr));
+
+       if (data[IFLA_IPTUN_REMOTE])
+               nla_memcpy(&parms->raddr, data[IFLA_IPTUN_REMOTE],
+                          sizeof(struct in6_addr));
+
+       if (data[IFLA_IPTUN_TTL])
+               parms->hop_limit = nla_get_u8(data[IFLA_IPTUN_TTL]);
+
+       if (data[IFLA_IPTUN_ENCAP_LIMIT])
+               parms->encap_limit = nla_get_u8(data[IFLA_IPTUN_ENCAP_LIMIT]);
+
+       if (data[IFLA_IPTUN_FLOWINFO])
+               parms->flowinfo = nla_get_u32(data[IFLA_IPTUN_FLOWINFO]);
+
+       if (data[IFLA_IPTUN_FLAGS])
+               parms->flags = nla_get_u32(data[IFLA_IPTUN_FLAGS]);
+
+       if (data[IFLA_IPTUN_PROTO])
+               parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
+}
+
+static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
+                          struct nlattr *tb[], struct nlattr *data[])
+{
+       struct net *net = dev_net(dev);
+       struct ip6_tnl *nt;
+
+       nt = netdev_priv(dev);
+       ip6_tnl_netlink_parms(data, &nt->parms);
+
+       if (ip6_tnl_locate(net, &nt->parms, 0))
+               return -EEXIST;
+
+       return ip6_tnl_create2(dev);
+}
+
+static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
+                             struct nlattr *data[])
+{
+       struct ip6_tnl *t;
+       struct __ip6_tnl_parm p;
+       struct net *net = dev_net(dev);
+       struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+
+       if (dev == ip6n->fb_tnl_dev)
+               return -EINVAL;
+
+       ip6_tnl_netlink_parms(data, &p);
+
+       t = ip6_tnl_locate(net, &p, 0);
+
+       if (t) {
+               if (t->dev != dev)
+                       return -EEXIST;
+       } else
+               t = netdev_priv(dev);
+
+       return ip6_tnl_update(t, &p);
+}
+
+static size_t ip6_tnl_get_size(const struct net_device *dev)
 {
        return
                /* IFLA_IPTUN_LINK */
@@ -1523,10 +1633,12 @@ static size_t ip6_get_size(const struct net_device *dev)
                nla_total_size(4) +
                /* IFLA_IPTUN_FLAGS */
                nla_total_size(4) +
+               /* IFLA_IPTUN_PROTO */
+               nla_total_size(1) +
                0;
 }
 
-static int ip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
+static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
        struct ip6_tnl *tunnel = netdev_priv(dev);
        struct __ip6_tnl_parm *parm = &tunnel->parms;
@@ -1539,7 +1651,8 @@ static int ip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
            nla_put_u8(skb, IFLA_IPTUN_TTL, parm->hop_limit) ||
            nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
            nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
-           nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags))
+           nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
+           nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto))
                goto nla_put_failure;
        return 0;
 
@@ -1547,12 +1660,28 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = {
+       [IFLA_IPTUN_LINK]               = { .type = NLA_U32 },
+       [IFLA_IPTUN_LOCAL]              = { .len = sizeof(struct in6_addr) },
+       [IFLA_IPTUN_REMOTE]             = { .len = sizeof(struct in6_addr) },
+       [IFLA_IPTUN_TTL]                = { .type = NLA_U8 },
+       [IFLA_IPTUN_ENCAP_LIMIT]        = { .type = NLA_U8 },
+       [IFLA_IPTUN_FLOWINFO]           = { .type = NLA_U32 },
+       [IFLA_IPTUN_FLAGS]              = { .type = NLA_U32 },
+       [IFLA_IPTUN_PROTO]              = { .type = NLA_U8 },
+};
+
 static struct rtnl_link_ops ip6_link_ops __read_mostly = {
        .kind           = "ip6tnl",
        .maxtype        = IFLA_IPTUN_MAX,
+       .policy         = ip6_tnl_policy,
        .priv_size      = sizeof(struct ip6_tnl),
-       .get_size       = ip6_get_size,
-       .fill_info      = ip6_fill_info,
+       .setup          = ip6_tnl_dev_setup,
+       .validate       = ip6_tnl_validate,
+       .newlink        = ip6_tnl_newlink,
+       .changelink     = ip6_tnl_changelink,
+       .get_size       = ip6_tnl_get_size,
+       .fill_info      = ip6_tnl_fill_info,
 };
 
 static struct xfrm6_tunnel ip4ip6_handler __read_mostly = {
index 3045872..11249d2 100644 (file)
@@ -1371,12 +1371,6 @@ out:
        return entries > rt_max_size;
 }
 
-/* Clean host part of a prefix. Not necessary in radix tree,
-   but results in cleaner routing tables.
-
-   Remove it only when all the things will work!
- */
-
 int ip6_dst_hoplimit(struct dst_entry *dst)
 {
        int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
index b543c56..7bd2a06 100644 (file)
@@ -81,22 +81,6 @@ struct sit_net {
        struct net_device *fb_tunnel_dev;
 };
 
-/*
- * Locking : hash tables are protected by RCU and RTNL
- */
-
-#define for_each_ip_tunnel_rcu(start) \
-       for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
-
-/* often modified stats are per cpu, other are shared (netdev->stats) */
-struct pcpu_tstats {
-       u64     rx_packets;
-       u64     rx_bytes;
-       u64     tx_packets;
-       u64     tx_bytes;
-       struct u64_stats_sync   syncp;
-};
-
 static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev,
                                                   struct rtnl_link_stats64 *tot)
 {
@@ -142,20 +126,20 @@ static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net,
        struct ip_tunnel *t;
        struct sit_net *sitn = net_generic(net, sit_net_id);
 
-       for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) {
+       for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) {
                if (local == t->parms.iph.saddr &&
                    remote == t->parms.iph.daddr &&
                    (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
                    (t->dev->flags & IFF_UP))
                        return t;
        }
-       for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) {
+       for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) {
                if (remote == t->parms.iph.daddr &&
                    (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
                    (t->dev->flags & IFF_UP))
                        return t;
        }
-       for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) {
+       for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) {
                if (local == t->parms.iph.saddr &&
                    (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
                    (t->dev->flags & IFF_UP))
@@ -232,6 +216,37 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
 #endif
 }
 
+static int ipip6_tunnel_create(struct net_device *dev)
+{
+       struct ip_tunnel *t = netdev_priv(dev);
+       struct net *net = dev_net(dev);
+       struct sit_net *sitn = net_generic(net, sit_net_id);
+       int err;
+
+       err = ipip6_tunnel_init(dev);
+       if (err < 0)
+               goto out;
+       ipip6_tunnel_clone_6rd(dev, sitn);
+
+       if (t->parms.i_flags & SIT_ISATAP)
+               dev->priv_flags |= IFF_ISATAP;
+
+       err = register_netdevice(dev);
+       if (err < 0)
+               goto out;
+
+       strcpy(t->parms.name, dev->name);
+       dev->rtnl_link_ops = &sit_link_ops;
+
+       dev_hold(dev);
+
+       ipip6_tunnel_link(sitn, t);
+       return 0;
+
+out:
+       return err;
+}
+
 static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
                struct ip_tunnel_parm *parms, int create)
 {
@@ -272,22 +287,9 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
        nt = netdev_priv(dev);
 
        nt->parms = *parms;
-       if (ipip6_tunnel_init(dev) < 0)
-               goto failed_free;
-       ipip6_tunnel_clone_6rd(dev, sitn);
-
-       if (parms->i_flags & SIT_ISATAP)
-               dev->priv_flags |= IFF_ISATAP;
-
-       if (register_netdevice(dev) < 0)
+       if (ipip6_tunnel_create(dev) < 0)
                goto failed_free;
 
-       strcpy(nt->parms.name, dev->name);
-       dev->rtnl_link_ops = &sit_link_ops;
-
-       dev_hold(dev);
-
-       ipip6_tunnel_link(sitn, nt);
        return nt;
 
 failed_free:
@@ -685,7 +687,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                                     struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct pcpu_tstats *tstats;
        const struct iphdr  *tiph = &tunnel->parms.iph;
        const struct ipv6hdr *iph6 = ipv6_hdr(skb);
        u8     tos = tunnel->parms.iph.tos;
@@ -866,9 +867,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
        if ((iph->ttl = tiph->ttl) == 0)
                iph->ttl        =       iph6->hop_limit;
 
-       nf_reset(skb);
-       tstats = this_cpu_ptr(dev->tstats);
-       __IPTUNNEL_XMIT(tstats, &dev->stats);
+       iptunnel_xmit(skb, dev);
        return NETDEV_TX_OK;
 
 tx_error_icmp:
@@ -916,6 +915,27 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
        dev->iflink = tunnel->parms.link;
 }
 
+static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
+{
+       struct net *net = dev_net(t->dev);
+       struct sit_net *sitn = net_generic(net, sit_net_id);
+
+       ipip6_tunnel_unlink(sitn, t);
+       synchronize_net();
+       t->parms.iph.saddr = p->iph.saddr;
+       t->parms.iph.daddr = p->iph.daddr;
+       memcpy(t->dev->dev_addr, &p->iph.saddr, 4);
+       memcpy(t->dev->broadcast, &p->iph.daddr, 4);
+       ipip6_tunnel_link(sitn, t);
+       t->parms.iph.ttl = p->iph.ttl;
+       t->parms.iph.tos = p->iph.tos;
+       if (t->parms.link != p->link) {
+               t->parms.link = p->link;
+               ipip6_tunnel_bind_dev(t->dev);
+       }
+       netdev_state_change(t->dev);
+}
+
 static int
 ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -997,28 +1017,13 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
                                        break;
                                }
                                t = netdev_priv(dev);
-                               ipip6_tunnel_unlink(sitn, t);
-                               synchronize_net();
-                               t->parms.iph.saddr = p.iph.saddr;
-                               t->parms.iph.daddr = p.iph.daddr;
-                               memcpy(dev->dev_addr, &p.iph.saddr, 4);
-                               memcpy(dev->broadcast, &p.iph.daddr, 4);
-                               ipip6_tunnel_link(sitn, t);
-                               netdev_state_change(dev);
                        }
+
+                       ipip6_tunnel_update(t, &p);
                }
 
                if (t) {
                        err = 0;
-                       if (cmd == SIOCCHGTUNNEL) {
-                               t->parms.iph.ttl = p.iph.ttl;
-                               t->parms.iph.tos = p.iph.tos;
-                               if (t->parms.link != p.link) {
-                                       t->parms.link = p.link;
-                                       ipip6_tunnel_bind_dev(dev);
-                                       netdev_state_change(dev);
-                               }
-                       }
                        if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
                                err = -EFAULT;
                } else
@@ -1218,7 +1223,89 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
        return 0;
 }
 
-static size_t sit_get_size(const struct net_device *dev)
+static void ipip6_netlink_parms(struct nlattr *data[],
+                               struct ip_tunnel_parm *parms)
+{
+       memset(parms, 0, sizeof(*parms));
+
+       parms->iph.version = 4;
+       parms->iph.protocol = IPPROTO_IPV6;
+       parms->iph.ihl = 5;
+       parms->iph.ttl = 64;
+
+       if (!data)
+               return;
+
+       if (data[IFLA_IPTUN_LINK])
+               parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
+
+       if (data[IFLA_IPTUN_LOCAL])
+               parms->iph.saddr = nla_get_u32(data[IFLA_IPTUN_LOCAL]);
+
+       if (data[IFLA_IPTUN_REMOTE])
+               parms->iph.daddr = nla_get_u32(data[IFLA_IPTUN_REMOTE]);
+
+       if (data[IFLA_IPTUN_TTL]) {
+               parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]);
+               if (parms->iph.ttl)
+                       parms->iph.frag_off = htons(IP_DF);
+       }
+
+       if (data[IFLA_IPTUN_TOS])
+               parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
+
+       if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
+               parms->iph.frag_off = htons(IP_DF);
+
+       if (data[IFLA_IPTUN_FLAGS])
+               parms->i_flags = nla_get_u16(data[IFLA_IPTUN_FLAGS]);
+}
+
+static int ipip6_newlink(struct net *src_net, struct net_device *dev,
+                        struct nlattr *tb[], struct nlattr *data[])
+{
+       struct net *net = dev_net(dev);
+       struct ip_tunnel *nt;
+
+       nt = netdev_priv(dev);
+       ipip6_netlink_parms(data, &nt->parms);
+
+       if (ipip6_tunnel_locate(net, &nt->parms, 0))
+               return -EEXIST;
+
+       return ipip6_tunnel_create(dev);
+}
+
+static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
+                         struct nlattr *data[])
+{
+       struct ip_tunnel *t;
+       struct ip_tunnel_parm p;
+       struct net *net = dev_net(dev);
+       struct sit_net *sitn = net_generic(net, sit_net_id);
+
+       if (dev == sitn->fb_tunnel_dev)
+               return -EINVAL;
+
+       ipip6_netlink_parms(data, &p);
+
+       if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
+           (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
+               return -EINVAL;
+
+       t = ipip6_tunnel_locate(net, &p, 0);
+
+       if (t) {
+               if (t->dev != dev)
+                       return -EEXIST;
+       } else
+               t = netdev_priv(dev);
+
+       ipip6_tunnel_update(t, &p);
+       return 0;
+}
+
+static size_t ipip6_get_size(const struct net_device *dev)
 {
        return
                /* IFLA_IPTUN_LINK */
@@ -1231,10 +1318,14 @@ static size_t sit_get_size(const struct net_device *dev)
                nla_total_size(1) +
                /* IFLA_IPTUN_TOS */
                nla_total_size(1) +
+               /* IFLA_IPTUN_PMTUDISC */
+               nla_total_size(1) +
+               /* IFLA_IPTUN_FLAGS */
+               nla_total_size(2) +
                0;
 }
 
-static int sit_fill_info(struct sk_buff *skb, const struct net_device *dev)
+static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        struct ip_tunnel_parm *parm = &tunnel->parms;
@@ -1243,7 +1334,10 @@ static int sit_fill_info(struct sk_buff *skb, const struct net_device *dev)
            nla_put_be32(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
            nla_put_be32(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
            nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
-           nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos))
+           nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
+           nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
+                      !!(parm->iph.frag_off & htons(IP_DF))) ||
+           nla_put_u16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
                goto nla_put_failure;
        return 0;
 
@@ -1251,12 +1345,26 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
+       [IFLA_IPTUN_LINK]               = { .type = NLA_U32 },
+       [IFLA_IPTUN_LOCAL]              = { .type = NLA_U32 },
+       [IFLA_IPTUN_REMOTE]             = { .type = NLA_U32 },
+       [IFLA_IPTUN_TTL]                = { .type = NLA_U8 },
+       [IFLA_IPTUN_TOS]                = { .type = NLA_U8 },
+       [IFLA_IPTUN_PMTUDISC]           = { .type = NLA_U8 },
+       [IFLA_IPTUN_FLAGS]              = { .type = NLA_U16 },
+};
+
 static struct rtnl_link_ops sit_link_ops __read_mostly = {
        .kind           = "sit",
        .maxtype        = IFLA_IPTUN_MAX,
+       .policy         = ipip6_policy,
        .priv_size      = sizeof(struct ip_tunnel),
-       .get_size       = sit_get_size,
-       .fill_info      = sit_fill_info,
+       .setup          = ipip6_tunnel_setup,
+       .newlink        = ipip6_newlink,
+       .changelink     = ipip6_changelink,
+       .get_size       = ipip6_get_size,
+       .fill_info      = ipip6_fill_info,
 };
 
 static struct xfrm_tunnel sit_handler __read_mostly = {
index 63af254..b4ecf26 100644 (file)
@@ -248,7 +248,7 @@ config MAC80211_MHWMP_DEBUG
          Do not select this option.
 
 config MAC80211_MESH_SYNC_DEBUG
-       bool "Verbose mesh mesh synchronization debugging"
+       bool "Verbose mesh synchronization debugging"
        depends on MAC80211_DEBUG_MENU
        depends on MAC80211_MESH
        ---help---
index a7dd110..4911202 100644 (file)
@@ -8,6 +8,7 @@ mac80211-y := \
        wpa.o \
        scan.o offchannel.o \
        ht.o agg-tx.o agg-rx.o \
+       vht.o \
        ibss.o \
        iface.o \
        rate.o \
index a04752e..4933535 100644 (file)
@@ -126,3 +126,20 @@ void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm)
 {
        crypto_free_cipher(tfm);
 }
+
+void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf,
+                                       u8 *k1, u8 *k2)
+{
+       u8 l[AES_BLOCK_SIZE] = {};
+       struct ieee80211_key *key =
+               container_of(keyconf, struct ieee80211_key, conf);
+
+       crypto_cipher_encrypt_one(key->u.aes_cmac.tfm, l, l);
+
+       memcpy(k1, l, AES_BLOCK_SIZE);
+       gf_mulx(k1);
+
+       memcpy(k2, k1, AES_BLOCK_SIZE);
+       gf_mulx(k2);
+}
+EXPORT_SYMBOL(ieee80211_aes_cmac_calculate_k1_k2);
index 05f3a31..5eab132 100644 (file)
@@ -372,10 +372,11 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
 
 static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
 {
+       enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);
+
        if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
                struct ieee80211_supported_band *sband;
-               sband = sta->local->hw.wiphy->bands[
-                               sta->local->oper_channel->band];
+               sband = sta->local->hw.wiphy->bands[band];
                rate->legacy = sband->bitrates[idx].bitrate;
        } else
                rate->mcs = idx;
@@ -532,6 +533,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                                   u64 *data)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *channel;
        struct sta_info *sta;
        struct ieee80211_local *local = sdata->local;
        struct station_info sinfo;
@@ -607,19 +610,26 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
 do_survey:
        i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
        /* Get survey stats for current channel */
-       q = 0;
-       while (true) {
-               survey.filled = 0;
-               if (drv_get_survey(local, q, &survey) != 0) {
-                       survey.filled = 0;
-                       break;
-               }
+       survey.filled = 0;
 
-               if (survey.channel &&
-                   (local->oper_channel->center_freq ==
-                    survey.channel->center_freq))
-                       break;
-               q++;
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (chanctx_conf)
+               channel = chanctx_conf->channel;
+       else
+               channel = NULL;
+       rcu_read_unlock();
+
+       if (channel) {
+               q = 0;
+               do {
+                       survey.filled = 0;
+                       if (drv_get_survey(local, q, &survey) != 0) {
+                               survey.filled = 0;
+                               break;
+                       }
+                       q++;
+               } while (channel != survey.channel);
        }
 
        if (survey.filled)
@@ -724,47 +734,42 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
-static int ieee80211_set_channel(struct wiphy *wiphy,
-                                struct net_device *netdev,
-                                struct ieee80211_channel *chan,
-                                enum nl80211_channel_type channel_type)
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+                                        struct ieee80211_channel *chan,
+                                        enum nl80211_channel_type channel_type)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct ieee80211_sub_if_data *sdata = NULL;
-
-       if (netdev)
-               sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
-
-       switch (ieee80211_get_channel_mode(local, NULL)) {
-       case CHAN_MODE_HOPPING:
-               return -EBUSY;
-       case CHAN_MODE_FIXED:
-               if (local->oper_channel != chan ||
-                   (!sdata && local->_oper_channel_type != channel_type))
-                       return -EBUSY;
-               if (!sdata && local->_oper_channel_type == channel_type)
-                       return 0;
-               break;
-       case CHAN_MODE_UNDEFINED:
-               break;
-       }
-
-       if (!ieee80211_set_channel_type(local, sdata, channel_type))
-               return -EBUSY;
+       struct ieee80211_sub_if_data *sdata;
+       int ret = 0;
 
-       local->oper_channel = chan;
+       if (local->monitor_channel == chan &&
+           local->monitor_channel_type == channel_type)
+               return 0;
 
-       /* auto-detects changes */
-       ieee80211_hw_config(local, 0);
+       mutex_lock(&local->iflist_mtx);
+       if (local->use_chanctx) {
+               sdata = rcu_dereference_protected(
+                               local->monitor_sdata,
+                               lockdep_is_held(&local->iflist_mtx));
+               if (sdata) {
+                       ieee80211_vif_release_channel(sdata);
+                       ret = ieee80211_vif_use_channel(
+                                       sdata, chan, channel_type,
+                                       IEEE80211_CHANCTX_EXCLUSIVE);
+               }
+       } else if (local->open_count == local->monitors) {
+               local->_oper_channel = chan;
+               local->_oper_channel_type = channel_type;
+               ieee80211_hw_config(local, 0);
+       }
 
-       return 0;
-}
+       if (ret == 0) {
+               local->monitor_channel = chan;
+               local->monitor_channel_type = channel_type;
+       }
+       mutex_unlock(&local->iflist_mtx);
 
-static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
-                                        struct ieee80211_channel *chan,
-                                        enum nl80211_channel_type channel_type)
-{
-       return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+       return ret;
 }
 
 static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
@@ -879,8 +884,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        if (old)
                return -EALREADY;
 
-       err = ieee80211_set_channel(wiphy, dev, params->channel,
-                                   params->channel_type);
+       /* TODO: make hostapd tell us what it wants */
+       sdata->smps_mode = IEEE80211_SMPS_OFF;
+       sdata->needed_rx_chains = sdata->local->rx_chains;
+
+       err = ieee80211_vif_use_channel(sdata, params->channel,
+                                       params->channel_type,
+                                       IEEE80211_CHANCTX_SHARED);
        if (err)
                return err;
 
@@ -963,6 +973,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        sta_info_flush(sdata->local, sdata);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
+       ieee80211_vif_release_channel(sdata);
+
        return 0;
 }
 
@@ -1019,9 +1031,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
        int i, j;
        struct ieee80211_supported_band *sband;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        u32 mask, set;
 
-       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       sband = local->hw.wiphy->bands[band];
 
        mask = params->sta_flags_mask;
        set = params->sta_flags_set;
@@ -1136,7 +1149,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                        rates |= BIT(j);
                        }
                }
-               sta->sta.supp_rates[local->oper_channel->band] = rates;
+               sta->sta.supp_rates[band] = rates;
        }
 
        if (params->ht_capa)
@@ -1144,6 +1157,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                                  params->ht_capa,
                                                  &sta->sta.ht_cap);
 
+       if (params->vht_capa)
+               ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+                                                   params->vht_capa,
+                                                   &sta->sta.vht_cap);
+
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
                if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
@@ -1664,8 +1682,13 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
        if (err)
                return err;
 
-       err = ieee80211_set_channel(wiphy, dev, setup->channel,
-                                   setup->channel_type);
+       /* can mesh use other SMPS modes? */
+       sdata->smps_mode = IEEE80211_SMPS_OFF;
+       sdata->needed_rx_chains = sdata->local->rx_chains;
+
+       err = ieee80211_vif_use_channel(sdata, setup->channel,
+                                       setup->channel_type,
+                                       IEEE80211_CHANCTX_SHARED);
        if (err)
                return err;
 
@@ -1679,6 +1702,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        ieee80211_stop_mesh(sdata);
+       ieee80211_vif_release_channel(sdata);
 
        return 0;
 }
@@ -1688,10 +1712,14 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct bss_parameters *params)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       enum ieee80211_band band;
        u32 changed = 0;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (!rtnl_dereference(sdata->u.ap.beacon))
+               return -ENOENT;
+
+       band = ieee80211_get_sdata_band(sdata);
 
        if (params->use_cts_prot >= 0) {
                sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
@@ -1704,7 +1732,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
        }
 
        if (!sdata->vif.bss_conf.use_short_slot &&
-           sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) {
+           band == IEEE80211_BAND_5GHZ) {
                sdata->vif.bss_conf.use_short_slot = true;
                changed |= BSS_CHANGED_ERP_SLOT;
        }
@@ -1718,9 +1746,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
        if (params->basic_rates) {
                int i, j;
                u32 rates = 0;
-               struct ieee80211_local *local = wiphy_priv(wiphy);
-               struct ieee80211_supported_band *sband =
-                       wiphy->bands[local->oper_channel->band];
+               struct ieee80211_supported_band *sband = wiphy->bands[band];
 
                for (i = 0; i < params->basic_rates_len; i++) {
                        int rate = (params->basic_rates[i] & 0x7f) * 5;
@@ -1829,7 +1855,16 @@ static int ieee80211_scan(struct wiphy *wiphy,
                 * beaconing hasn't been configured yet
                 */
        case NL80211_IFTYPE_AP:
-               if (sdata->u.ap.beacon)
+               /*
+                * If the scan has been forced (and the driver supports
+                * forcing), don't care about being beaconing already.
+                * This will create problems to the attached stations (e.g. all
+                * the  frames sent while scanning on other channel will be
+                * lost)
+                */
+               if (sdata->u.ap.beacon &&
+                   (!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
+                    !(req->flags & NL80211_SCAN_FLAG_AP)))
                        return -EOPNOTSUPP;
                break;
        default:
@@ -1872,20 +1907,6 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
                           struct cfg80211_assoc_request *req)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       switch (ieee80211_get_channel_mode(local, sdata)) {
-       case CHAN_MODE_HOPPING:
-               return -EBUSY;
-       case CHAN_MODE_FIXED:
-               if (local->oper_channel == req->bss->channel)
-                       break;
-               return -EBUSY;
-       case CHAN_MODE_UNDEFINED:
-               break;
-       }
-
        return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
@@ -1904,30 +1925,12 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
                               struct cfg80211_ibss_params *params)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       switch (ieee80211_get_channel_mode(local, sdata)) {
-       case CHAN_MODE_HOPPING:
-               return -EBUSY;
-       case CHAN_MODE_FIXED:
-               if (!params->channel_fixed)
-                       return -EBUSY;
-               if (local->oper_channel == params->channel)
-                       break;
-               return -EBUSY;
-       case CHAN_MODE_UNDEFINED:
-               break;
-       }
-
-       return ieee80211_ibss_join(sdata, params);
+       return ieee80211_ibss_join(IEEE80211_DEV_TO_SUB_IF(dev), params);
 }
 
 static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       return ieee80211_ibss_leave(sdata);
+       return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
 }
 
 static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
@@ -1971,9 +1974,13 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
                                  enum nl80211_tx_power_setting type, int mbm)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct ieee80211_channel *chan = local->oper_channel;
+       struct ieee80211_channel *chan = local->_oper_channel;
        u32 changes = 0;
 
+       /* FIXME */
+       if (local->use_chanctx)
+               return -EOPNOTSUPP;
+
        switch (type) {
        case NL80211_TX_POWER_AUTOMATIC:
                local->user_power_level = -1;
@@ -2067,13 +2074,12 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
 
        /*
         * If not associated, or current association is not an HT
-        * association, there's no need to send an action frame.
+        * association, there's no need to do anything, just store
+        * the new value until we associate.
         */
        if (!sdata->u.mgd.associated ||
-           sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
-               ieee80211_recalc_smps(sdata->local);
+           sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
                return 0;
-       }
 
        ap = sdata->u.mgd.associated->bssid;
 
@@ -2189,6 +2195,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
        lockdep_assert_held(&local->mtx);
 
+       if (local->use_chanctx && !local->ops->remain_on_channel)
+               return -EOPNOTSUPP;
+
        roc = kzalloc(sizeof(*roc), GFP_KERNEL);
        if (!roc)
                return -ENOMEM;
@@ -2515,10 +2524,20 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 
        /* Check if the operating channel is the requested channel */
        if (!need_offchan) {
-               need_offchan = chan != local->oper_channel;
-               if (channel_type_valid &&
-                   channel_type != local->_oper_channel_type)
+               struct ieee80211_chanctx_conf *chanctx_conf;
+
+               rcu_read_lock();
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+
+               if (chanctx_conf) {
+                       need_offchan = chan != chanctx_conf->channel;
+                       if (channel_type_valid &&
+                           channel_type != chanctx_conf->channel_type)
+                               need_offchan = true;
+               } else {
                        need_offchan = true;
+               }
+               rcu_read_unlock();
        }
 
        if (need_offchan && !offchan) {
@@ -2667,7 +2686,7 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
        u16 capab;
 
        capab = 0;
-       if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
+       if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
                return capab;
 
        if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
@@ -2699,7 +2718,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
                               u16 status_code, struct sk_buff *skb)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        struct ieee80211_tdls_data *tf;
 
        tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
@@ -2719,10 +2738,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
                tf->u.setup_req.capability =
                        cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
 
-               ieee80211_add_srates_ie(sdata, skb, false,
-                                       local->oper_channel->band);
-               ieee80211_add_ext_srates_ie(sdata, skb, false,
-                                           local->oper_channel->band);
+               ieee80211_add_srates_ie(sdata, skb, false, band);
+               ieee80211_add_ext_srates_ie(sdata, skb, false, band);
                ieee80211_tdls_add_ext_capab(skb);
                break;
        case WLAN_TDLS_SETUP_RESPONSE:
@@ -2735,10 +2752,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
                tf->u.setup_resp.capability =
                        cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
 
-               ieee80211_add_srates_ie(sdata, skb, false,
-                                       local->oper_channel->band);
-               ieee80211_add_ext_srates_ie(sdata, skb, false,
-                                           local->oper_channel->band);
+               ieee80211_add_srates_ie(sdata, skb, false, band);
+               ieee80211_add_ext_srates_ie(sdata, skb, false, band);
                ieee80211_tdls_add_ext_capab(skb);
                break;
        case WLAN_TDLS_SETUP_CONFIRM:
@@ -2776,7 +2791,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
                           u16 status_code, struct sk_buff *skb)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        struct ieee80211_mgmt *mgmt;
 
        mgmt = (void *)skb_put(skb, 24);
@@ -2799,10 +2814,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
                mgmt->u.action.u.tdls_discover_resp.capability =
                        cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
 
-               ieee80211_add_srates_ie(sdata, skb, false,
-                                       local->oper_channel->band);
-               ieee80211_add_ext_srates_ie(sdata, skb, false,
-                                           local->oper_channel->band);
+               ieee80211_add_srates_ie(sdata, skb, false, band);
+               ieee80211_add_ext_srates_ie(sdata, skb, false, band);
                ieee80211_tdls_add_ext_capab(skb);
                break;
        default:
@@ -2819,7 +2832,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_tx_info *info;
        struct sk_buff *skb = NULL;
        bool send_direct;
        int ret;
@@ -2845,7 +2857,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
        if (!skb)
                return -ENOMEM;
 
-       info = IEEE80211_SKB_CB(skb);
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
        switch (action_code) {
@@ -2982,12 +2993,19 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
        bool qos;
        struct ieee80211_tx_info *info;
        struct sta_info *sta;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       enum ieee80211_band band;
 
        rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+       band = chanctx_conf->channel->band;
        sta = sta_info_get(sdata, peer);
        if (sta) {
                qos = test_sta_flag(sta, WLAN_STA_WME);
-               rcu_read_unlock();
        } else {
                rcu_read_unlock();
                return -ENOLINK;
@@ -3005,8 +3023,10 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
        }
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
-       if (!skb)
+       if (!skb) {
+               rcu_read_unlock();
                return -ENOMEM;
+       }
 
        skb->dev = dev;
 
@@ -3031,8 +3051,9 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
                nullfunc->qos_ctrl = cpu_to_le16(7);
 
        local_bh_disable();
-       ieee80211_xmit(sdata, skb);
+       ieee80211_xmit(sdata, skb, band);
        local_bh_enable();
+       rcu_read_unlock();
 
        *cookie = (unsigned long) skb;
        return 0;
@@ -3042,10 +3063,19 @@ static struct ieee80211_channel *
 ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
                          enum nl80211_channel_type *type)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *chan = NULL;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (chanctx_conf) {
+               *type = chanctx_conf->channel_type;
+               chan = chanctx_conf->channel;
+       }
+       rcu_read_unlock();
 
-       *type = local->_oper_channel_type;
-       return local->oper_channel;
+       return chan;
 }
 
 #ifdef CONFIG_PM
index 0bfc914..f84b860 100644 (file)
  */
 
 #include <linux/nl80211.h>
+#include <linux/export.h>
 #include <net/cfg80211.h>
 #include "ieee80211_i.h"
-
-static enum ieee80211_chan_mode
-__ieee80211_get_channel_mode(struct ieee80211_local *local,
-                            struct ieee80211_sub_if_data *ignore)
-{
-       struct ieee80211_sub_if_data *sdata;
-
-       lockdep_assert_held(&local->iflist_mtx);
-
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (sdata == ignore)
-                       continue;
-
-               if (!ieee80211_sdata_running(sdata))
-                       continue;
-
-               switch (sdata->vif.type) {
-               case NL80211_IFTYPE_MONITOR:
-                       continue;
-               case NL80211_IFTYPE_STATION:
-                       if (!sdata->u.mgd.associated)
-                               continue;
-                       break;
-               case NL80211_IFTYPE_ADHOC:
-                       if (!sdata->u.ibss.ssid_len)
-                               continue;
-                       if (!sdata->u.ibss.fixed_channel)
-                               return CHAN_MODE_HOPPING;
-                       break;
-               case NL80211_IFTYPE_AP_VLAN:
-                       /* will also have _AP interface */
-                       continue;
-               case NL80211_IFTYPE_AP:
-                       if (!sdata->u.ap.beacon)
-                               continue;
-                       break;
-               case NL80211_IFTYPE_MESH_POINT:
-                       if (!sdata->wdev.mesh_id_len)
-                               continue;
-                       break;
-               default:
-                       break;
-               }
-
-               return CHAN_MODE_FIXED;
-       }
-
-       return CHAN_MODE_UNDEFINED;
-}
-
-enum ieee80211_chan_mode
-ieee80211_get_channel_mode(struct ieee80211_local *local,
-                          struct ieee80211_sub_if_data *ignore)
-{
-       enum ieee80211_chan_mode mode;
-
-       mutex_lock(&local->iflist_mtx);
-       mode = __ieee80211_get_channel_mode(local, ignore);
-       mutex_unlock(&local->iflist_mtx);
-
-       return mode;
-}
-
-static enum nl80211_channel_type
-ieee80211_get_superchan(struct ieee80211_local *local,
-                       struct ieee80211_sub_if_data *sdata)
-{
-       enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
-       struct ieee80211_sub_if_data *tmp;
-
-       mutex_lock(&local->iflist_mtx);
-       list_for_each_entry(tmp, &local->interfaces, list) {
-               if (tmp == sdata)
-                       continue;
-
-               if (!ieee80211_sdata_running(tmp))
-                       continue;
-
-               switch (tmp->vif.bss_conf.channel_type) {
-               case NL80211_CHAN_NO_HT:
-               case NL80211_CHAN_HT20:
-                       if (superchan > tmp->vif.bss_conf.channel_type)
-                               break;
-
-                       superchan = tmp->vif.bss_conf.channel_type;
-                       break;
-               case NL80211_CHAN_HT40PLUS:
-                       WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
-                       superchan = NL80211_CHAN_HT40PLUS;
-                       break;
-               case NL80211_CHAN_HT40MINUS:
-                       WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
-                       superchan = NL80211_CHAN_HT40MINUS;
-                       break;
-               }
-       }
-       mutex_unlock(&local->iflist_mtx);
-
-       return superchan;
-}
+#include "driver-ops.h"
 
 static bool
 ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
@@ -148,23 +50,350 @@ ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
        return true;
 }
 
-bool ieee80211_set_channel_type(struct ieee80211_local *local,
-                               struct ieee80211_sub_if_data *sdata,
-                               enum nl80211_channel_type chantype)
+static void ieee80211_change_chantype(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx *ctx,
+                                     enum nl80211_channel_type chantype)
 {
-       enum nl80211_channel_type superchan;
-       enum nl80211_channel_type compatchan;
+       if (chantype == ctx->conf.channel_type)
+               return;
 
-       superchan = ieee80211_get_superchan(local, sdata);
-       if (!ieee80211_channel_types_are_compatible(superchan, chantype,
-                                                   &compatchan))
-               return false;
+       ctx->conf.channel_type = chantype;
+       drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE);
 
-       local->_oper_channel_type = compatchan;
+       if (!local->use_chanctx) {
+               local->_oper_channel_type = chantype;
+               ieee80211_hw_config(local, 0);
+       }
+}
 
-       if (sdata)
-               sdata->vif.bss_conf.channel_type = chantype;
+static struct ieee80211_chanctx *
+ieee80211_find_chanctx(struct ieee80211_local *local,
+                      struct ieee80211_channel *channel,
+                      enum nl80211_channel_type channel_type,
+                      enum ieee80211_chanctx_mode mode)
+{
+       struct ieee80211_chanctx *ctx;
+       enum nl80211_channel_type compat_type;
 
-       return true;
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
+               return NULL;
+       if (WARN_ON(!channel))
+               return NULL;
+
+       list_for_each_entry(ctx, &local->chanctx_list, list) {
+               compat_type = ctx->conf.channel_type;
+
+               if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
+                       continue;
+               if (ctx->conf.channel != channel)
+                       continue;
+               if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type,
+                                                           channel_type,
+                                                           &compat_type))
+                       continue;
+
+               ieee80211_change_chantype(local, ctx, compat_type);
+
+               return ctx;
+       }
+
+       return NULL;
+}
+
+static struct ieee80211_chanctx *
+ieee80211_new_chanctx(struct ieee80211_local *local,
+                     struct ieee80211_channel *channel,
+                     enum nl80211_channel_type channel_type,
+                     enum ieee80211_chanctx_mode mode)
+{
+       struct ieee80211_chanctx *ctx;
+       int err;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
+       if (!ctx)
+               return ERR_PTR(-ENOMEM);
+
+       ctx->conf.channel = channel;
+       ctx->conf.channel_type = channel_type;
+       ctx->conf.rx_chains_static = 1;
+       ctx->conf.rx_chains_dynamic = 1;
+       ctx->mode = mode;
+
+       if (!local->use_chanctx) {
+               local->_oper_channel_type = channel_type;
+               local->_oper_channel = channel;
+               ieee80211_hw_config(local, 0);
+       } else {
+               err = drv_add_chanctx(local, ctx);
+               if (err) {
+                       kfree(ctx);
+                       return ERR_PTR(err);
+               }
+       }
+
+       list_add_rcu(&ctx->list, &local->chanctx_list);
+
+       return ctx;
+}
+
+static void ieee80211_free_chanctx(struct ieee80211_local *local,
+                                  struct ieee80211_chanctx *ctx)
+{
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       WARN_ON_ONCE(ctx->refcount != 0);
+
+       if (!local->use_chanctx) {
+               local->_oper_channel_type = NL80211_CHAN_NO_HT;
+               ieee80211_hw_config(local, 0);
+       } else {
+               drv_remove_chanctx(local, ctx);
+       }
+
+       list_del_rcu(&ctx->list);
+       kfree_rcu(ctx, rcu_head);
+}
+
+static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
+                                       struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       ret = drv_assign_vif_chanctx(local, sdata, ctx);
+       if (ret)
+               return ret;
+
+       rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
+       ctx->refcount++;
+
+       return 0;
+}
+
+static enum nl80211_channel_type
+ieee80211_calc_chantype(struct ieee80211_local *local,
+                       struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_chanctx_conf *conf = &ctx->conf;
+       struct ieee80211_sub_if_data *sdata;
+       enum nl80211_channel_type result = NL80211_CHAN_NO_HT;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+               if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
+                       continue;
+
+               WARN_ON_ONCE(!ieee80211_channel_types_are_compatible(
+                                       sdata->vif.bss_conf.channel_type,
+                                       result, &result));
+       }
+       rcu_read_unlock();
+
+       return result;
+}
+
+static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
+                                             struct ieee80211_chanctx *ctx)
+{
+       enum nl80211_channel_type chantype;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       chantype = ieee80211_calc_chantype(local, ctx);
+       ieee80211_change_chantype(local, ctx, chantype);
+}
+
+static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
+                                          struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_local *local = sdata->local;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       ctx->refcount--;
+       rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
+
+       drv_unassign_vif_chanctx(local, sdata, ctx);
+
+       if (ctx->refcount > 0) {
+               ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
+               ieee80211_recalc_smps_chanctx(local, ctx);
+       }
+}
+
+static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *conf;
+       struct ieee80211_chanctx *ctx;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
+       if (!conf)
+               return;
+
+       ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+       ieee80211_unassign_vif_chanctx(sdata, ctx);
+       if (ctx->refcount == 0)
+               ieee80211_free_chanctx(local, ctx);
+}
+
+void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
+                                  struct ieee80211_chanctx *chanctx)
+{
+       struct ieee80211_sub_if_data *sdata;
+       u8 rx_chains_static, rx_chains_dynamic;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       rx_chains_static = 1;
+       rx_chains_dynamic = 1;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               u8 needed_static, needed_dynamic;
+
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
+                                               &chanctx->conf)
+                       continue;
+
+               switch (sdata->vif.type) {
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       continue;
+               case NL80211_IFTYPE_STATION:
+                       if (!sdata->u.mgd.associated)
+                               continue;
+                       break;
+               case NL80211_IFTYPE_AP_VLAN:
+                       continue;
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_WDS:
+               case NL80211_IFTYPE_MESH_POINT:
+                       break;
+               default:
+                       WARN_ON_ONCE(1);
+               }
+
+               switch (sdata->smps_mode) {
+               default:
+                       WARN_ONCE(1, "Invalid SMPS mode %d\n",
+                                 sdata->smps_mode);
+                       /* fall through */
+               case IEEE80211_SMPS_OFF:
+                       needed_static = sdata->needed_rx_chains;
+                       needed_dynamic = sdata->needed_rx_chains;
+                       break;
+               case IEEE80211_SMPS_DYNAMIC:
+                       needed_static = 1;
+                       needed_dynamic = sdata->needed_rx_chains;
+                       break;
+               case IEEE80211_SMPS_STATIC:
+                       needed_static = 1;
+                       needed_dynamic = 1;
+                       break;
+               }
+
+               rx_chains_static = max(rx_chains_static, needed_static);
+               rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
+       }
+       rcu_read_unlock();
+
+       if (!local->use_chanctx) {
+               if (rx_chains_static > 1)
+                       local->smps_mode = IEEE80211_SMPS_OFF;
+               else if (rx_chains_dynamic > 1)
+                       local->smps_mode = IEEE80211_SMPS_DYNAMIC;
+               else
+                       local->smps_mode = IEEE80211_SMPS_STATIC;
+               ieee80211_hw_config(local, 0);
+       }
+
+       if (rx_chains_static == chanctx->conf.rx_chains_static &&
+           rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
+               return;
+
+       chanctx->conf.rx_chains_static = rx_chains_static;
+       chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
+       drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
+}
+
+int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+                             struct ieee80211_channel *channel,
+                             enum nl80211_channel_type channel_type,
+                             enum ieee80211_chanctx_mode mode)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx *ctx;
+       int ret;
+
+       WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
+
+       mutex_lock(&local->chanctx_mtx);
+       __ieee80211_vif_release_channel(sdata);
+
+       ctx = ieee80211_find_chanctx(local, channel, channel_type, mode);
+       if (!ctx)
+               ctx = ieee80211_new_chanctx(local, channel, channel_type, mode);
+       if (IS_ERR(ctx)) {
+               ret = PTR_ERR(ctx);
+               goto out;
+       }
+
+       sdata->vif.bss_conf.channel_type = channel_type;
+
+       ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+       if (ret) {
+               /* if assign fails refcount stays the same */
+               if (ctx->refcount == 0)
+                       ieee80211_free_chanctx(local, ctx);
+               goto out;
+       }
+
+       ieee80211_recalc_smps_chanctx(local, ctx);
+ out:
+       mutex_unlock(&local->chanctx_mtx);
+       return ret;
+}
+
+void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+{
+       WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
+
+       mutex_lock(&sdata->local->chanctx_mtx);
+       __ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&sdata->local->chanctx_mtx);
+}
+
+void ieee80211_iter_chan_contexts_atomic(
+       struct ieee80211_hw *hw,
+       void (*iter)(struct ieee80211_hw *hw,
+                    struct ieee80211_chanctx_conf *chanctx_conf,
+                    void *data),
+       void *iter_data)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_chanctx *ctx;
 
+       rcu_read_lock();
+       list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
+               iter(hw, &ctx->conf, iter_data);
+       rcu_read_unlock();
 }
+EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);
index 9be4e6d..214ed4e 100644 (file)
@@ -2,9 +2,9 @@
 #define __MAC80211_DEBUGFS_H
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-extern void debugfs_hw_add(struct ieee80211_local *local);
-extern int mac80211_format_buffer(char __user *userbuf, size_t count,
-                                 loff_t *ppos, char *fmt, ...);
+void debugfs_hw_add(struct ieee80211_local *local);
+int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count,
+                                         loff_t *ppos, char *fmt, ...);
 #else
 static inline void debugfs_hw_add(struct ieee80211_local *local)
 {
index 6d5aec9..3393ad5 100644 (file)
@@ -217,7 +217,7 @@ static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
 
        return snprintf(buf, buflen, "request: %s\nused: %s\n",
                        smps_modes[sdata->u.mgd.req_smps],
-                       smps_modes[sdata->u.mgd.ap_smps]);
+                       smps_modes[sdata->smps_mode]);
 }
 
 static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
@@ -395,14 +395,14 @@ __IEEE80211_IF_FILE_W(uapsd_max_sp_len);
 
 /* AP attributes */
 IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
-IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
-IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
+IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
+IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
 
 static ssize_t ieee80211_if_fmt_num_buffered_multicast(
        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 {
        return scnprintf(buf, buflen, "%u\n",
-                        skb_queue_len(&sdata->u.ap.ps_bc_buf));
+                        skb_queue_len(&sdata->u.ap.ps.bc_buf));
 }
 __IEEE80211_IF_FILE(num_buffered_multicast, NULL);
 
@@ -471,7 +471,7 @@ IEEE80211_IF_FILE(dropped_frames_congestion,
                  u.mesh.mshstats.dropped_frames_congestion, DEC);
 IEEE80211_IF_FILE(dropped_frames_no_route,
                  u.mesh.mshstats.dropped_frames_no_route, DEC);
-IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
+IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
 
 /* Mesh parameters */
 IEEE80211_IF_FILE(dot11MeshMaxRetries,
index da9003b..77407b3 100644 (file)
@@ -871,4 +871,69 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
                local->ops->mgd_prepare_tx(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
 }
+
+static inline int drv_add_chanctx(struct ieee80211_local *local,
+                                 struct ieee80211_chanctx *ctx)
+{
+       int ret = -EOPNOTSUPP;
+
+       trace_drv_add_chanctx(local, ctx);
+       if (local->ops->add_chanctx)
+               ret = local->ops->add_chanctx(&local->hw, &ctx->conf);
+       trace_drv_return_int(local, ret);
+
+       return ret;
+}
+
+static inline void drv_remove_chanctx(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx *ctx)
+{
+       trace_drv_remove_chanctx(local, ctx);
+       if (local->ops->remove_chanctx)
+               local->ops->remove_chanctx(&local->hw, &ctx->conf);
+       trace_drv_return_void(local);
+}
+
+static inline void drv_change_chanctx(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx *ctx,
+                                     u32 changed)
+{
+       trace_drv_change_chanctx(local, ctx, changed);
+       if (local->ops->change_chanctx)
+               local->ops->change_chanctx(&local->hw, &ctx->conf, changed);
+       trace_drv_return_void(local);
+}
+
+static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
+                                        struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_chanctx *ctx)
+{
+       int ret = 0;
+
+       check_sdata_in_driver(sdata);
+
+       trace_drv_assign_vif_chanctx(local, sdata, ctx);
+       if (local->ops->assign_vif_chanctx)
+               ret = local->ops->assign_vif_chanctx(&local->hw,
+                                                    &sdata->vif,
+                                                    &ctx->conf);
+       trace_drv_return_int(local, ret);
+
+       return ret;
+}
+
+static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
+                                           struct ieee80211_sub_if_data *sdata,
+                                           struct ieee80211_chanctx *ctx)
+{
+       check_sdata_in_driver(sdata);
+
+       trace_drv_unassign_vif_chanctx(local, sdata, ctx);
+       if (local->ops->unassign_vif_chanctx)
+               local->ops->unassign_vif_chanctx(&local->hw,
+                                                &sdata->vif,
+                                                &ctx->conf);
+       trace_drv_return_void(local);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
index bf87c70..c7386b2 100644 (file)
@@ -26,7 +26,6 @@
 #include "rate.h"
 
 #define IEEE80211_SCAN_INTERVAL (2 * HZ)
-#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
 #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
 
 #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
@@ -39,7 +38,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                      const u8 *bssid, const int beacon_int,
                                      struct ieee80211_channel *chan,
                                      const u32 basic_rates,
-                                     const u16 capability, u64 tsf)
+                                     const u16 capability, u64 tsf,
+                                     bool creator)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
@@ -72,25 +72,27 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        /* if merging, indicate to driver that we leave the old IBSS */
        if (sdata->vif.bss_conf.ibss_joined) {
                sdata->vif.bss_conf.ibss_joined = false;
+               sdata->vif.bss_conf.ibss_creator = false;
                netif_carrier_off(sdata->dev);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
        }
 
-       memcpy(ifibss->bssid, bssid, ETH_ALEN);
-
        sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-       local->oper_channel = chan;
        channel_type = ifibss->channel_type;
        if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
                channel_type = NL80211_CHAN_HT20;
-       if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
-               /* can only fail due to HT40+/- mismatch */
-               channel_type = NL80211_CHAN_HT20;
-               WARN_ON(!ieee80211_set_channel_type(local, sdata,
-                                                   NL80211_CHAN_HT20));
+
+       ieee80211_vif_release_channel(sdata);
+       if (ieee80211_vif_use_channel(sdata, chan, channel_type,
+                                     ifibss->fixed_channel ?
+                                       IEEE80211_CHANCTX_SHARED :
+                                       IEEE80211_CHANCTX_EXCLUSIVE)) {
+               sdata_info(sdata, "Failed to join IBSS, no channel context\n");
+               return;
        }
-       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
+       memcpy(ifibss->bssid, bssid, ETH_ALEN);
 
        sband = local->hw.wiphy->bands[chan->band];
 
@@ -197,6 +199,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        bss_change |= BSS_CHANGED_HT;
        bss_change |= BSS_CHANGED_IBSS;
        sdata->vif.bss_conf.ibss_joined = true;
+       sdata->vif.bss_conf.ibss_creator = creator;
        ieee80211_bss_info_change_notify(sdata, bss_change);
 
        ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
@@ -249,7 +252,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                  cbss->channel,
                                  basic_rates,
                                  cbss->capability,
-                                 cbss->tsf);
+                                 cbss->tsf,
+                                 false);
 }
 
 static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
@@ -279,7 +283,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
                ibss_dbg(sdata,
                         "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
                         sdata->vif.addr, addr, sdata->u.ibss.bssid);
-               ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,
+               ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0,
                                    addr, sdata->u.ibss.bssid, NULL, 0, 0);
        }
        return sta;
@@ -294,7 +298,8 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
-       int band = local->oper_channel->band;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       int band;
 
        /*
         * XXX: Consider removing the least recently used entry and
@@ -317,6 +322,13 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
                return NULL;
        }
 
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON_ONCE(!chanctx_conf))
+               return NULL;
+       band = chanctx_conf->channel->band;
+       rcu_read_unlock();
+
        sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
        if (!sta) {
                rcu_read_lock();
@@ -389,7 +401,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
         * However, try to reply to authentication attempts if someone
         * has actually implemented this.
         */
-       ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
+       ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0,
                            mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0);
 }
 
@@ -517,7 +529,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                goto put_bss;
 
        /* different channel */
-       if (cbss->channel != local->oper_channel)
+       if (sdata->u.ibss.fixed_channel &&
+           sdata->u.ibss.channel != cbss->channel)
                goto put_bss;
 
        /* different SSID */
@@ -592,7 +605,8 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
-       int band = local->oper_channel->band;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       int band;
 
        /*
         * XXX: Consider removing the least recently used entry and
@@ -610,6 +624,15 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
        if (!ether_addr_equal(bssid, sdata->u.ibss.bssid))
                return;
 
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON_ONCE(!chanctx_conf)) {
+               rcu_read_unlock();
+               return;
+       }
+       band = chanctx_conf->channel->band;
+       rcu_read_unlock();
+
        sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
        if (!sta)
                return;
@@ -715,7 +738,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
 
        __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
                                  ifibss->channel, ifibss->basic_rates,
-                                 capability, 0);
+                                 capability, 0, true);
 }
 
 /*
@@ -784,18 +807,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                int interval = IEEE80211_SCAN_INTERVAL;
 
                if (time_after(jiffies, ifibss->ibss_join_req +
-                              IEEE80211_IBSS_JOIN_TIMEOUT)) {
-                       if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) {
-                               ieee80211_sta_create_ibss(sdata);
-                               return;
-                       }
-                       sdata_info(sdata, "IBSS not allowed on %d MHz\n",
-                                  local->oper_channel->center_freq);
-
-                       /* No IBSS found - decrease scan interval and continue
-                        * scanning. */
-                       interval = IEEE80211_SCAN_INTERVAL_SLOW;
-               }
+                              IEEE80211_IBSS_JOIN_TIMEOUT))
+                       ieee80211_sta_create_ibss(sdata);
 
                mod_timer(&ifibss->timer,
                          round_jiffies(jiffies + interval));
@@ -1086,17 +1099,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        sdata->u.ibss.channel_type = params->channel_type;
        sdata->u.ibss.fixed_channel = params->channel_fixed;
 
-       /* fix ourselves to that channel now already */
-       if (params->channel_fixed) {
-               sdata->local->oper_channel = params->channel;
-               if (!ieee80211_set_channel_type(sdata->local, sdata,
-                                              params->channel_type)) {
-                       mutex_unlock(&sdata->u.ibss.mtx);
-                       kfree_skb(skb);
-                       return -EINVAL;
-               }
-       }
-
        if (params->ie) {
                sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len,
                                           GFP_KERNEL);
@@ -1134,6 +1136,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        changed |= BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
 
+       sdata->smps_mode = IEEE80211_SMPS_OFF;
+       sdata->needed_rx_chains = sdata->local->rx_chains;
+
        ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 
        return 0;
@@ -1197,6 +1202,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
                                        lockdep_is_held(&sdata->u.ibss.mtx));
        RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
        sdata->vif.bss_conf.ibss_joined = false;
+       sdata->vif.bss_conf.ibss_creator = false;
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
                                                BSS_CHANGED_IBSS);
        synchronize_rcu();
index 8c80455..3026519 100644 (file)
@@ -280,23 +280,27 @@ struct probe_resp {
        u8 data[0];
 };
 
-struct ieee80211_if_ap {
-       struct beacon_data __rcu *beacon;
-       struct probe_resp __rcu *probe_resp;
-
-       struct list_head vlans;
-
+struct ps_data {
        /* yes, this looks ugly, but guarantees that we can later use
         * bitmap_empty :)
         * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
        u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
-       struct sk_buff_head ps_bc_buf;
+       struct sk_buff_head bc_buf;
        atomic_t num_sta_ps; /* number of stations in PS mode */
-       atomic_t num_mcast_sta; /* number of stations receiving multicast */
        int dtim_count;
        bool dtim_bc_mc;
 };
 
+struct ieee80211_if_ap {
+       struct beacon_data __rcu *beacon;
+       struct probe_resp __rcu *probe_resp;
+
+       struct list_head vlans;
+
+       struct ps_data ps;
+       atomic_t num_mcast_sta; /* number of stations receiving multicast */
+};
+
 struct ieee80211_if_wds {
        struct sta_info *sta;
        u8 remote_addr[ETH_ALEN];
@@ -316,7 +320,6 @@ struct mesh_stats {
        __u32 dropped_frames_ttl;       /* Not transmitted since mesh_ttl == 0*/
        __u32 dropped_frames_no_route;  /* Not transmitted, no route found */
        __u32 dropped_frames_congestion;/* Not forwarded due to congestion */
-       atomic_t estab_plinks;
 };
 
 #define PREQ_Q_F_START         0x1
@@ -378,8 +381,9 @@ struct ieee80211_mgd_auth_data {
        u8 key_len, key_idx;
        bool done;
 
-       size_t ie_len;
-       u8 ie[];
+       u16 sae_trans, sae_status;
+       size_t data_len;
+       u8 data[];
 };
 
 struct ieee80211_mgd_assoc_data {
@@ -433,7 +437,6 @@ struct ieee80211_if_managed {
        bool powersave; /* powersave requested for this iface */
        bool broken_ap; /* AP is broken -- turn off powersave */
        enum ieee80211_smps_mode req_smps, /* requested smps mode */
-                                ap_smps, /* smps mode AP thinks we're in */
                                 driver_smps_mode; /* smps mode request */
 
        struct work_struct request_smps_work;
@@ -599,6 +602,7 @@ struct ieee80211_if_mesh {
        int preq_queue_len;
        struct mesh_stats mshstats;
        struct mesh_config mshcfg;
+       atomic_t estab_plinks;
        u32 mesh_seqnum;
        bool accepting_plinks;
        int num_gates;
@@ -610,7 +614,7 @@ struct ieee80211_if_mesh {
                IEEE80211_MESH_SEC_SECURED = 0x2,
        } security;
        /* Extensible Synchronization Framework */
-       struct ieee80211_mesh_sync_ops *sync_ops;
+       const struct ieee80211_mesh_sync_ops *sync_ops;
        s64 sync_offset_clockdrift_max;
        spinlock_t sync_offset_lock;
        bool adjusting_tbtt;
@@ -658,6 +662,30 @@ enum ieee80211_sdata_state_bits {
        SDATA_STATE_OFFCHANNEL,
 };
 
+/**
+ * enum ieee80211_chanctx_mode - channel context configuration mode
+ *
+ * @IEEE80211_CHANCTX_SHARED: channel context may be used by
+ *     multiple interfaces
+ * @IEEE80211_CHANCTX_EXCLUSIVE: channel context can be used
+ *     only by a single interface. This can be used for example for
+ *     non-fixed channel IBSS.
+ */
+enum ieee80211_chanctx_mode {
+       IEEE80211_CHANCTX_SHARED,
+       IEEE80211_CHANCTX_EXCLUSIVE
+};
+
+struct ieee80211_chanctx {
+       struct list_head list;
+       struct rcu_head rcu_head;
+
+       enum ieee80211_chanctx_mode mode;
+       int refcount;
+
+       struct ieee80211_chanctx_conf conf;
+};
+
 struct ieee80211_sub_if_data {
        struct list_head list;
 
@@ -704,11 +732,17 @@ struct ieee80211_sub_if_data {
 
        struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
 
+       /* used to reconfigure hardware SM PS */
+       struct work_struct recalc_smps;
+
        struct work_struct work;
        struct sk_buff_head skb_queue;
 
        bool arp_filter_state;
 
+       u8 needed_rx_chains;
+       enum ieee80211_smps_mode smps_mode;
+
        /*
         * AP this belongs to: self in AP mode and
         * corresponding AP in VLAN mode, NULL for
@@ -749,6 +783,21 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
        return container_of(p, struct ieee80211_sub_if_data, vif);
 }
 
+static inline enum ieee80211_band
+ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata)
+{
+       enum ieee80211_band band = IEEE80211_BAND_2GHZ;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!WARN_ON(!chanctx_conf))
+               band = chanctx_conf->channel->band;
+       rcu_read_unlock();
+
+       return band;
+}
+
 enum sdata_queue_type {
        IEEE80211_SDATA_QUEUE_TYPE_FRAME        = 0,
        IEEE80211_SDATA_QUEUE_AGG_START         = 1,
@@ -821,6 +870,7 @@ enum {
  * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to
  *     send out data
  * @SCAN_RESUME: Resume the scan and scan the next channel
+ * @SCAN_ABORT: Abort the scan and go back to operating channel
  */
 enum mac80211_scan_state {
        SCAN_DECISION,
@@ -828,6 +878,7 @@ enum mac80211_scan_state {
        SCAN_SEND_PROBE,
        SCAN_SUSPEND,
        SCAN_RESUME,
+       SCAN_ABORT,
 };
 
 struct ieee80211_local {
@@ -858,15 +909,14 @@ struct ieee80211_local {
 
        bool wiphy_ciphers_allocated;
 
+       bool use_chanctx;
+
        /* protects the aggregated multicast list and filter calls */
        spinlock_t filter_lock;
 
        /* used for uploading changed mc list */
        struct work_struct reconfig_filter;
 
-       /* used to reconfigure hardware SM PS */
-       struct work_struct recalc_smps;
-
        /* aggregated multicast list */
        struct netdev_hw_addr_list mc_list;
 
@@ -903,6 +953,9 @@ struct ieee80211_local {
        /* wowlan is enabled -- don't reconfig on resume */
        bool wowlan;
 
+       /* number of RX chains the hardware has */
+       u8 rx_chains;
+
        int tx_headroom; /* required headroom for hardware/radiotap */
 
        /* Tasklet and skb queue to process calls from IRQ mode. All frames
@@ -980,13 +1033,19 @@ struct ieee80211_local {
        enum mac80211_scan_state next_scan_state;
        struct delayed_work scan_work;
        struct ieee80211_sub_if_data __rcu *scan_sdata;
+       struct ieee80211_channel *csa_channel;
+       /* For backward compatibility only -- do not use */
+       struct ieee80211_channel *_oper_channel;
        enum nl80211_channel_type _oper_channel_type;
-       struct ieee80211_channel *oper_channel, *csa_channel;
 
        /* Temporary remain-on-channel for off-channel operations */
        struct ieee80211_channel *tmp_channel;
        enum nl80211_channel_type tmp_channel_type;
 
+       /* channel contexts */
+       struct list_head chanctx_list;
+       struct mutex chanctx_mtx;
+
        /* SNMP counters */
        /* dot11CountersTable */
        u32 dot11TransmittedFragmentCount;
@@ -1091,6 +1150,8 @@ struct ieee80211_local {
 
        /* virtual monitor interface */
        struct ieee80211_sub_if_data __rcu *monitor_sdata;
+       struct ieee80211_channel *monitor_channel;
+       enum nl80211_channel_type monitor_channel_type;
 };
 
 static inline struct ieee80211_sub_if_data *
@@ -1133,6 +1194,8 @@ struct ieee802_11_elems {
        u8 *wmm_param;
        struct ieee80211_ht_cap *ht_cap_elem;
        struct ieee80211_ht_operation *ht_operation;
+       struct ieee80211_vht_cap *vht_cap_elem;
+       struct ieee80211_vht_operation *vht_operation;
        struct ieee80211_meshconf_ie *mesh_config;
        u8 *mesh_id;
        u8 *peering;
@@ -1359,6 +1422,13 @@ void ieee80211_ba_session_work(struct work_struct *work);
 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
 void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
 
+u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs);
+
+/* VHT */
+void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_supported_band *sband,
+                                        struct ieee80211_vht_cap *vht_cap_ie,
+                                        struct ieee80211_sta_vht_cap *vht_cap);
 /* Spectrum management */
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
                                       struct ieee80211_mgmt *mgmt,
@@ -1393,11 +1463,42 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
                                     gfp_t gfp);
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
                               bool bss_notify);
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+                   enum ieee80211_band band);
+
+void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
+                                struct sk_buff *skb, int tid,
+                                enum ieee80211_band band);
 
-void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
-                         struct sk_buff *skb, int tid);
-static void inline ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
+static inline void
+ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
+                         struct sk_buff *skb, int tid,
+                         enum ieee80211_band band)
+{
+       rcu_read_lock();
+       __ieee80211_tx_skb_tid_band(sdata, skb, tid, band);
+       rcu_read_unlock();
+}
+
+static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
+                                       struct sk_buff *skb, int tid)
+{
+       struct ieee80211_chanctx_conf *chanctx_conf;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               kfree_skb(skb);
+               return;
+       }
+
+       __ieee80211_tx_skb_tid_band(sdata, skb, tid,
+                                   chanctx_conf->channel->band);
+       rcu_read_unlock();
+}
+
+static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
                                    struct sk_buff *skb)
 {
        /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
@@ -1444,7 +1545,7 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
 }
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
-                        u16 transaction, u16 auth_alg,
+                        u16 transaction, u16 auth_alg, u16 status,
                         u8 *extra, size_t extra_len, const u8 *bssid,
                         const u8 *da, const u8 *key, u8 key_len, u8 key_idx);
 void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
@@ -1464,7 +1565,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              const u8 *ssid, size_t ssid_len,
                              const u8 *ie, size_t ie_len,
                              u32 ratemask, bool directed, bool no_cck,
-                             struct ieee80211_channel *channel);
+                             struct ieee80211_channel *channel, bool scan);
 
 void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
                                  const size_t supp_rates_len,
@@ -1474,7 +1575,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
                            enum ieee80211_band band, u32 *basic_rates);
 int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
                             enum ieee80211_smps_mode smps_mode);
-void ieee80211_recalc_smps(struct ieee80211_local *local);
+void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
 
 size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
                          const u8 *ids, int n_ids, size_t offset);
@@ -1495,21 +1596,19 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
                                enum ieee80211_band band);
 
 /* channel management */
-enum ieee80211_chan_mode {
-       CHAN_MODE_UNDEFINED,
-       CHAN_MODE_HOPPING,
-       CHAN_MODE_FIXED,
-};
-
-enum ieee80211_chan_mode
-ieee80211_get_channel_mode(struct ieee80211_local *local,
-                          struct ieee80211_sub_if_data *ignore);
-bool ieee80211_set_channel_type(struct ieee80211_local *local,
-                               struct ieee80211_sub_if_data *sdata,
-                               enum nl80211_channel_type chantype);
 enum nl80211_channel_type
 ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);
 
+int __must_check
+ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+                         struct ieee80211_channel *channel,
+                         enum nl80211_channel_type channel_type,
+                         enum ieee80211_chanctx_mode mode);
+void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
+
+void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
+                                  struct ieee80211_chanctx *chanctx);
+
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
 #else
index 7de7717..bc3e3e1 100644 (file)
@@ -380,6 +380,15 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
                goto out_unlock;
        }
 
+       ret = ieee80211_vif_use_channel(sdata, local->monitor_channel,
+                                       local->monitor_channel_type,
+                                       IEEE80211_CHANCTX_EXCLUSIVE);
+       if (ret) {
+               drv_remove_interface(local, sdata);
+               kfree(sdata);
+               goto out_unlock;
+       }
+
        rcu_assign_pointer(local->monitor_sdata, sdata);
  out_unlock:
        mutex_unlock(&local->iflist_mtx);
@@ -403,6 +412,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
        rcu_assign_pointer(local->monitor_sdata, NULL);
        synchronize_net();
 
+       ieee80211_vif_release_channel(sdata);
+
        drv_remove_interface(local, sdata);
 
        kfree(sdata);
@@ -665,7 +676,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        struct sk_buff *skb, *tmp;
        u32 hw_reconf_flags = 0;
        int i;
-       enum nl80211_channel_type orig_ct;
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
@@ -729,6 +739,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        del_timer_sync(&local->dynamic_ps_timer);
        cancel_work_sync(&local->dynamic_ps_enable_work);
 
+       cancel_work_sync(&sdata->recalc_smps);
+
        /* APs need special treatment */
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
@@ -755,8 +767,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                WARN_ON(!list_empty(&sdata->u.ap.vlans));
 
                /* free all potentially still buffered bcast frames */
-               local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf);
-               skb_queue_purge(&sdata->u.ap.ps_bc_buf);
+               local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
+               skb_queue_purge(&sdata->u.ap.ps.bc_buf);
        } else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                ieee80211_mgd_stop(sdata);
        }
@@ -837,14 +849,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                hw_reconf_flags = 0;
        }
 
-       /* Re-calculate channel-type, in case there are multiple vifs
-        * on different channel types.
-        */
-       orig_ct = local->_oper_channel_type;
-       ieee80211_set_channel_type(local, NULL, NL80211_CHAN_NO_HT);
-
        /* do after stop to avoid reconfiguring when we stop anyway */
-       if (hw_reconf_flags || (orig_ct != local->_oper_channel_type))
+       if (hw_reconf_flags)
                ieee80211_hw_config(local, hw_reconf_flags);
 
        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
@@ -1121,6 +1127,13 @@ static void ieee80211_iface_work(struct work_struct *work)
        }
 }
 
+static void ieee80211_recalc_smps_work(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata =
+               container_of(work, struct ieee80211_sub_if_data, recalc_smps);
+
+       ieee80211_recalc_smps(sdata);
+}
 
 /*
  * Helper function to initialise an interface to a specific type.
@@ -1149,6 +1162,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 
        skb_queue_head_init(&sdata->skb_queue);
        INIT_WORK(&sdata->work, ieee80211_iface_work);
+       INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 
        switch (type) {
        case NL80211_IFTYPE_P2P_GO:
@@ -1157,7 +1171,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                sdata->vif.p2p = true;
                /* fall through */
        case NL80211_IFTYPE_AP:
-               skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
+               skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
                INIT_LIST_HEAD(&sdata->u.ap.vlans);
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
@@ -1282,11 +1296,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
        if (type == ieee80211_vif_type_p2p(&sdata->vif))
                return 0;
 
-       /* Setting ad-hoc mode on non-IBSS channel is not supported. */
-       if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS &&
-           type == NL80211_IFTYPE_ADHOC)
-               return -EOPNOTSUPP;
-
        if (ieee80211_sdata_running(sdata)) {
                ret = ieee80211_runtime_change_iftype(sdata, type);
                if (ret)
@@ -1298,9 +1307,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
        }
 
        /* reset some values that shouldn't be kept across type changes */
-       sdata->vif.bss_conf.basic_rates =
-               ieee80211_mandatory_rates(sdata->local,
-                       sdata->local->oper_channel->band);
        sdata->drop_unencrypted = 0;
        if (type == NL80211_IFTYPE_STATION)
                sdata->u.mgd.use_4addr = false;
index c80c449..fd8345c 100644 (file)
@@ -93,23 +93,21 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
        ieee80211_configure_filter(local);
 }
 
-int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
+static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
 {
        struct ieee80211_channel *chan;
-       int ret = 0;
+       u32 changed = 0;
        int power;
        enum nl80211_channel_type channel_type;
        u32 offchannel_flag;
 
-       might_sleep();
-
        offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
        if (local->scan_channel) {
                chan = local->scan_channel;
                /* If scanning on oper channel, use whatever channel-type
                 * is currently in use.
                 */
-               if (chan == local->oper_channel)
+               if (chan == local->_oper_channel)
                        channel_type = local->_oper_channel_type;
                else
                        channel_type = NL80211_CHAN_NO_HT;
@@ -117,11 +115,11 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
-               chan = local->oper_channel;
+               chan = local->_oper_channel;
                channel_type = local->_oper_channel_type;
        }
 
-       if (chan != local->oper_channel ||
+       if (chan != local->_oper_channel ||
            channel_type != local->_oper_channel_type)
                local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
        else
@@ -164,6 +162,21 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                local->hw.conf.power_level = power;
        }
 
+       return changed;
+}
+
+int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
+{
+       int ret = 0;
+
+       might_sleep();
+
+       if (!local->use_chanctx)
+               changed |= ieee80211_hw_conf_chan(local);
+       else
+               changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL |
+                            IEEE80211_CONF_CHANGE_POWER);
+
        if (changed && local->open_count) {
                ret = drv_config(local, changed);
                /*
@@ -359,14 +372,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_restart_hw);
 
-static void ieee80211_recalc_smps_work(struct work_struct *work)
-{
-       struct ieee80211_local *local =
-               container_of(work, struct ieee80211_local, recalc_smps);
-
-       ieee80211_recalc_smps(local);
-}
-
 #ifdef CONFIG_INET
 static int ieee80211_ifa_changed(struct notifier_block *nb,
                                 unsigned long data, void *arg)
@@ -540,6 +545,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        struct ieee80211_local *local;
        int priv_size, i;
        struct wiphy *wiphy;
+       bool use_chanctx;
 
        if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
                    !ops->add_interface || !ops->remove_interface ||
@@ -549,6 +555,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
                return NULL;
 
+       /* check all or no channel context operations exist */
+       i = !!ops->add_chanctx + !!ops->remove_chanctx +
+           !!ops->change_chanctx + !!ops->assign_vif_chanctx +
+           !!ops->unassign_vif_chanctx;
+       if (WARN_ON(i != 0 && i != 5))
+               return NULL;
+       use_chanctx = i == 5;
+
        /* Ensure 32-byte alignment of our private data and hw private data.
         * We use the wiphy priv data for both our ieee80211_local and for
         * the driver's private data
@@ -584,8 +598,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        if (ops->remain_on_channel)
                wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
-       wiphy->features = NL80211_FEATURE_SK_TX_STATUS |
-                         NL80211_FEATURE_HT_IBSS;
+       wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
+                          NL80211_FEATURE_SAE |
+                          NL80211_FEATURE_HT_IBSS;
+
+       if (!ops->hw_scan)
+               wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
+                                  NL80211_FEATURE_AP_SCAN;
+
 
        if (!ops->set_key)
                wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -599,6 +619,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
 
        local->ops = ops;
+       local->use_chanctx = use_chanctx;
 
        /* set up some defaults */
        local->hw.queues = 1;
@@ -626,6 +647,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        spin_lock_init(&local->filter_lock);
        spin_lock_init(&local->queue_stop_reason_lock);
 
+       INIT_LIST_HEAD(&local->chanctx_list);
+       mutex_init(&local->chanctx_mtx);
+
        /*
         * The rx_skb_queue is only accessed from tasklets,
         * but other SKB queues are used from within IRQ
@@ -641,7 +665,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
        INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
-       INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work);
        local->smps_mode = IEEE80211_SMPS_OFF;
 
        INIT_WORK(&local->dynamic_ps_enable_work,
@@ -719,6 +742,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
                return -EINVAL;
 
+       if (!local->use_chanctx) {
+               for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
+                       const struct ieee80211_iface_combination *comb;
+
+                       comb = &local->hw.wiphy->iface_combinations[i];
+
+                       if (comb->num_different_channels > 1)
+                               return -EINVAL;
+               }
+       } else {
+               /*
+                * WDS is currently prohibited when channel contexts are used
+                * because there's no clear definition of which channel WDS
+                * type interfaces use
+                */
+               if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
+                       return -EINVAL;
+       }
+
        /* Only HW csum features are currently compatible with mac80211 */
        feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                            NETIF_F_HW_CSUM;
@@ -728,6 +770,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (hw->max_report_rates == 0)
                hw->max_report_rates = hw->max_rates;
 
+       local->rx_chains = 1;
+
        /*
         * generic code guarantees at least one band,
         * set this very early because much code assumes
@@ -743,18 +787,29 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                sband = local->hw.wiphy->bands[band];
                if (!sband)
                        continue;
-               if (!local->oper_channel) {
+               if (!local->use_chanctx && !local->_oper_channel) {
                        /* init channel we're on */
                        local->hw.conf.channel =
-                       local->oper_channel = &sband->channels[0];
+                       local->_oper_channel = &sband->channels[0];
                        local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
                }
+               if (!local->monitor_channel) {
+                       local->monitor_channel = &sband->channels[0];
+                       local->monitor_channel_type = NL80211_CHAN_NO_HT;
+               }
                channels += sband->n_channels;
 
                if (max_bitrates < sband->n_bitrates)
                        max_bitrates = sband->n_bitrates;
                supp_ht = supp_ht || sband->ht_cap.ht_supported;
                supp_vht = supp_vht || sband->vht_cap.vht_supported;
+
+               if (sband->ht_cap.ht_supported)
+                       local->rx_chains =
+                               max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
+                                   local->rx_chains);
+
+               /* TODO: consider VHT for RX chains, hopefully it's the same */
        }
 
        local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
@@ -778,19 +833,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
        hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
 
-       /*
-        * mac80211 doesn't support more than 1 channel, and also not more
-        * than one IBSS interface
-        */
+       /* mac80211 doesn't support more than one IBSS interface right now */
        for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
                const struct ieee80211_iface_combination *c;
                int j;
 
                c = &hw->wiphy->iface_combinations[i];
 
-               if (c->num_different_channels > 1)
-                       return -EINVAL;
-
                for (j = 0; j < c->n_limits; j++)
                        if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
                            c->limits[j].max > 1)
@@ -832,7 +881,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        if (supp_vht)
                local->scan_ies_len +=
-                       2 + sizeof(struct ieee80211_vht_capabilities);
+                       2 + sizeof(struct ieee80211_vht_cap);
 
        if (!local->ops->hw_scan) {
                /* For hw_scan, driver needs to set these up. */
index ff0296c..a350cab 100644 (file)
@@ -97,7 +97,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
             (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
                goto mismatch;
 
-       ieee80211_sta_get_rates(local, ie, local->oper_channel->band,
+       ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata),
                                &basic_rates);
 
        if (sdata->vif.bss_conf.basic_rates != basic_rates)
@@ -264,7 +264,7 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
        /* Authentication Protocol identifier */
        *pos++ = ifmsh->mesh_auth_id;
        /* Mesh Formation Info - number of neighbors */
-       neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
+       neighbors = atomic_read(&ifmsh->estab_plinks);
        /* Number of neighbor mesh STAs or 15 whichever is smaller */
        neighbors = (neighbors > 15) ? 15 : neighbors;
        *pos++ = neighbors << 1;
@@ -355,12 +355,22 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *chan = local->oper_channel;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *chan;
        u8 *pos;
 
        if (skb_tailroom(skb) < 3)
                return -ENOMEM;
 
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+       chan = chanctx_conf->channel;
+       rcu_read_unlock();
+
        sband = local->hw.wiphy->bands[chan->band];
        if (sband->band == IEEE80211_BAND_2GHZ) {
                pos = skb_put(skb, 2 + 1);
@@ -376,10 +386,11 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
                       struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        struct ieee80211_supported_band *sband;
        u8 *pos;
 
-       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       sband = local->hw.wiphy->bands[band];
        if (!sband->ht_cap.ht_supported ||
            sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
                return 0;
@@ -397,14 +408,26 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
                        struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_channel *channel = local->oper_channel;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *channel;
        enum nl80211_channel_type channel_type =
-                               sdata->vif.bss_conf.channel_type;
-       struct ieee80211_supported_band *sband =
-                               local->hw.wiphy->bands[channel->band];
-       struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
+               sdata->vif.bss_conf.channel_type;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_sta_ht_cap *ht_cap;
        u8 *pos;
 
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+       channel = chanctx_conf->channel;
+       rcu_read_unlock();
+
+       sband = local->hw.wiphy->bands[channel->band];
+       ht_cap = &sband->ht_cap;
+
        if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
                return 0;
 
@@ -610,7 +633,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
        sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
        sdata->vif.bss_conf.basic_rates =
                ieee80211_mandatory_rates(sdata->local,
-                                         sdata->local->oper_channel->band);
+                                         ieee80211_get_sdata_band(sdata));
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
                                                BSS_CHANGED_BEACON_ENABLED |
                                                BSS_CHANGED_HT |
@@ -680,8 +703,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
        ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
                               &elems);
 
-       /* ignore beacons from secure mesh peers if our security is off */
-       if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE)
+       /* ignore non-mesh or secure / unsecure mismatch */
+       if ((!elems.mesh_id || !elems.mesh_config) ||
+           (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
+           (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
                return;
 
        if (elems.ds_params && elems.ds_params_len == 1)
@@ -694,8 +719,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
        if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
                return;
 
-       if (elems.mesh_id && elems.mesh_config &&
-           mesh_matches_local(sdata, &elems))
+       if (mesh_matches_local(sdata, &elems))
                mesh_neighbour_update(sdata, mgmt->sa, &elems);
 
        if (ifmsh->sync_ops)
index 25d0f17..9285f3f 100644 (file)
@@ -256,7 +256,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
-struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
+const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
 
 /* Mesh paths */
 int mesh_nexthop_lookup(struct sk_buff *skb,
@@ -324,7 +324,7 @@ extern int mesh_allocated;
 static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
 {
        return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks -
-              atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
+              atomic_read(&sdata->u.mesh.estab_plinks);
 }
 
 static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)
index 3ab34d8..234fe75 100644 (file)
@@ -50,14 +50,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 static inline
 u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
 {
-       atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
+       atomic_inc(&sdata->u.mesh.estab_plinks);
        return mesh_accept_plinks_update(sdata);
 }
 
 static inline
 u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
 {
-       atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
+       atomic_dec(&sdata->u.mesh.estab_plinks);
        return mesh_accept_plinks_update(sdata);
 }
 
@@ -252,6 +252,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.self_prot.action_code = action;
 
        if (action != WLAN_SP_MESH_PEERING_CLOSE) {
+               enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
+
                /* capability info */
                pos = skb_put(skb, 2);
                memset(pos, 0, 2);
@@ -260,10 +262,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                        pos = skb_put(skb, 2);
                        memcpy(pos + 2, &plid, 2);
                }
-               if (ieee80211_add_srates_ie(sdata, skb, true,
-                                           local->oper_channel->band) ||
-                   ieee80211_add_ext_srates_ie(sdata, skb, true,
-                                               local->oper_channel->band) ||
+               if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
+                   ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
                    mesh_add_rsn_ie(skb, sdata) ||
                    mesh_add_meshid_ie(skb, sdata) ||
                    mesh_add_meshconf_ie(skb, sdata))
@@ -343,7 +343,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
                                       struct ieee802_11_elems *elems)
 {
        struct ieee80211_local *local = sdata->local;
-       enum ieee80211_band band = local->oper_channel->band;
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        struct ieee80211_supported_band *sband;
        u32 rates, basic_rates = 0;
        struct sta_info *sta;
index a16b7b4..407c870 100644 (file)
@@ -234,49 +234,7 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
        spin_unlock_bh(&ifmsh->sync_offset_lock);
 }
 
-static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       u8 offset;
-
-       if (!ifmsh->ie || !ifmsh->ie_len)
-               return NULL;
-
-       offset = ieee80211_ie_split_vendor(ifmsh->ie,
-                                       ifmsh->ie_len, 0);
-
-       if (!offset)
-               return NULL;
-
-       return ifmsh->ie + offset + 2;
-}
-
-static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
-                                  u16 stype,
-                                  struct ieee80211_mgmt *mgmt,
-                                  struct ieee802_11_elems *elems,
-                                  struct ieee80211_rx_status *rx_status)
-{
-       const u8 *oui;
-
-       WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
-       msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n");
-       oui = mesh_get_vendor_oui(sdata);
-       /*  here you would implement the vendor offset tracking for this oui */
-}
-
-static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
-{
-       const u8 *oui;
-
-       WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
-       msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n");
-       oui = mesh_get_vendor_oui(sdata);
-       /*  here you would implement the vendor tsf adjustment for this oui */
-}
-
-/* global variable */
-static struct sync_method sync_methods[] = {
+static const struct sync_method sync_methods[] = {
        {
                .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
                .ops = {
@@ -284,18 +242,11 @@ static struct sync_method sync_methods[] = {
                        .adjust_tbtt = &mesh_sync_offset_adjust_tbtt,
                }
        },
-       {
-               .method = IEEE80211_SYNC_METHOD_VENDOR,
-               .ops = {
-                       .rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp,
-                       .adjust_tbtt = &mesh_sync_vendor_adjust_tbtt,
-               }
-       },
 };
 
-struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
+const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
 {
-       struct ieee80211_mesh_sync_ops *ops = NULL;
+       const struct ieee80211_mesh_sync_ops *ops = NULL;
        u8 i;
 
        for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) {
index 1b7eed2..1d1fdf0 100644 (file)
@@ -178,20 +178,30 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *chan;
        struct sta_info *sta;
        u32 changed = 0;
        u16 ht_opmode;
        bool disable_40 = false;
 
-       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               return 0;
+       }
+       chan = chanctx_conf->channel;
+       rcu_read_unlock();
+       sband = local->hw.wiphy->bands[chan->band];
 
        switch (sdata->vif.bss_conf.channel_type) {
        case NL80211_CHAN_HT40PLUS:
-               if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
+               if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
                        disable_40 = true;
                break;
        case NL80211_CHAN_HT40MINUS:
-               if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
+               if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
                        disable_40 = true;
                break;
        default:
@@ -343,7 +353,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
        cap = vht_cap.cap;
 
        /* reserve and fill IE */
-       pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2);
+       pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
        ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
 }
 
@@ -359,11 +369,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        int i, count, rates_len, supp_rates_len;
        u16 capab;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *chan;
        u32 rates = 0;
 
        lockdep_assert_held(&ifmgd->mtx);
 
-       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               return;
+       }
+       chan = chanctx_conf->channel;
+       rcu_read_unlock();
+       sband = local->hw.wiphy->bands[chan->band];
 
        if (assoc_data->supp_rates_len) {
                /*
@@ -392,7 +412,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                        4 + /* power capability */
                        2 + 2 * sband->n_channels + /* supported channels */
                        2 + sizeof(struct ieee80211_ht_cap) + /* HT */
-                       2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */
+                       2 + sizeof(struct ieee80211_vht_cap) + /* VHT */
                        assoc_data->ie_len + /* extra IEs */
                        9, /* WMM */
                        GFP_KERNEL);
@@ -485,7 +505,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                *pos++ = WLAN_EID_PWR_CAPABILITY;
                *pos++ = 2;
                *pos++ = 0; /* min tx power */
-               *pos++ = local->oper_channel->max_power; /* max tx power */
+               *pos++ = chan->max_power; /* max tx power */
 
                /* 2. supported channels */
                /* TODO: get this in reg domain format */
@@ -523,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
                ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
-                                   sband, local->oper_channel, ifmgd->ap_smps);
+                                   sband, chan, sdata->smps_mode);
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                ieee80211_add_vht_ie(sdata, skb, sband);
@@ -657,18 +677,18 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        if (!ifmgd->associated)
                goto out;
 
-       sdata->local->oper_channel = sdata->local->csa_channel;
+       sdata->local->_oper_channel = sdata->local->csa_channel;
        if (!sdata->local->ops->channel_switch) {
                /* call "hw_config" only if doing sw channel switch */
                ieee80211_hw_config(sdata->local,
                        IEEE80211_CONF_CHANGE_CHANNEL);
        } else {
                /* update the device channel directly */
-               sdata->local->hw.conf.channel = sdata->local->oper_channel;
+               sdata->local->hw.conf.channel = sdata->local->_oper_channel;
        }
 
        /* XXX: shouldn't really modify cfg80211-owned data! */
-       ifmgd->associated->channel = sdata->local->oper_channel;
+       ifmgd->associated->channel = sdata->local->_oper_channel;
 
        /* XXX: wait for a beacon first? */
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
@@ -680,11 +700,8 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 
 void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
 {
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_managed *ifmgd;
-
-       sdata = vif_to_sdata(vif);
-       ifmgd = &sdata->u.mgd;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        trace_api_chswitch_done(sdata, success);
        if (!success) {
@@ -723,6 +740,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num,
                                                      cbss->channel->band);
+       struct ieee80211_chanctx *chanctx;
 
        ASSERT_MGD_MTX(ifmgd);
 
@@ -748,10 +766,34 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
-       sdata->local->csa_channel = new_ch;
-
        ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
 
+       if (sdata->local->use_chanctx) {
+               sdata_info(sdata,
+                          "not handling channel switch with channel contexts\n");
+               ieee80211_queue_work(&sdata->local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+       }
+
+       mutex_lock(&sdata->local->chanctx_mtx);
+       if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
+               mutex_unlock(&sdata->local->chanctx_mtx);
+               return;
+       }
+       chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
+                              struct ieee80211_chanctx, conf);
+       if (chanctx->refcount > 1) {
+               sdata_info(sdata,
+                          "channel switch with multiple interfaces on the same channel, disconnecting\n");
+               ieee80211_queue_work(&sdata->local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               mutex_unlock(&sdata->local->chanctx_mtx);
+               return;
+       }
+       mutex_unlock(&sdata->local->chanctx_mtx);
+
+       sdata->local->csa_channel = new_ch;
+
        if (sw_elem->mode)
                ieee80211_stop_queues_by_reason(&sdata->local->hw,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1280,7 +1322,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
        }
 
        use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
-       if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ)
+       if (ieee80211_get_sdata_band(sdata) == IEEE80211_BAND_5GHZ)
                use_short_slot = true;
 
        if (use_protection != bss_conf->use_cts_prot) {
@@ -1350,7 +1392,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_ps(local, -1);
        mutex_unlock(&local->iflist_mtx);
 
-       ieee80211_recalc_smps(local);
+       ieee80211_recalc_smps(sdata);
        ieee80211_recalc_ps_vif(sdata);
 
        netif_tx_start_all_queues(sdata->dev);
@@ -1465,9 +1507,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
 
-       /* channel(_type) changes are handled by ieee80211_hw_config */
-       WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
-       ieee80211_hw_config(local, 0);
+       ieee80211_vif_release_channel(sdata);
 
        /* disassociated - set to defaults now */
        ieee80211_set_wmm_default(sdata, false);
@@ -1589,7 +1629,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
 
                ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
                                         0, (u32) -1, true, false,
-                                        ifmgd->associated->channel);
+                                        ifmgd->associated->channel, false);
        }
 
        ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
@@ -1692,8 +1732,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
                ssid_len = ssid[1];
 
        skb = ieee80211_build_probe_req(sdata, cbss->bssid,
-                                       (u32) -1,
-                                       sdata->local->oper_channel,
+                                       (u32) -1, cbss->channel,
                                        ssid + 2, ssid_len,
                                        NULL, 0, true);
 
@@ -1804,6 +1843,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
 
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
+               ieee80211_vif_release_channel(sdata);
        }
 
        cfg80211_put_bss(auth_data->bss);
@@ -1824,7 +1864,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
                return;
        auth_data->expected_transaction = 4;
        drv_mgd_prepare_tx(sdata->local, sdata);
-       ieee80211_send_auth(sdata, 3, auth_data->algorithm,
+       ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
                            elems.challenge - 2, elems.challenge_len + 2,
                            auth_data->bss->bssid, auth_data->bss->bssid,
                            auth_data->key, auth_data->key_len,
@@ -1858,8 +1898,13 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
        if (auth_alg != ifmgd->auth_data->algorithm ||
-           auth_transaction != ifmgd->auth_data->expected_transaction)
+           auth_transaction != ifmgd->auth_data->expected_transaction) {
+               sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n",
+                          mgmt->sa, auth_alg, ifmgd->auth_data->algorithm,
+                          auth_transaction,
+                          ifmgd->auth_data->expected_transaction);
                return RX_MGMT_NONE;
+       }
 
        if (status_code != WLAN_STATUS_SUCCESS) {
                sdata_info(sdata, "%pM denied authentication (status %d)\n",
@@ -1872,6 +1917,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        case WLAN_AUTH_OPEN:
        case WLAN_AUTH_LEAP:
        case WLAN_AUTH_FT:
+       case WLAN_AUTH_SAE:
                break;
        case WLAN_AUTH_SHARED_KEY:
                if (ifmgd->auth_data->expected_transaction != 4) {
@@ -1891,6 +1937,15 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
        run_again(ifmgd, ifmgd->auth_data->timeout);
 
+       if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
+           ifmgd->auth_data->expected_transaction != 2) {
+               /*
+                * Report auth frame to user space for processing since another
+                * round of Authentication frames is still needed.
+                */
+               return RX_MGMT_CFG80211_RX_AUTH;
+       }
+
        /* move station state to auth */
        mutex_lock(&sdata->local->sta_mtx);
        sta = sta_info_get(sdata, bssid);
@@ -2030,6 +2085,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
 
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
+               ieee80211_vif_release_channel(sdata);
        }
 
        kfree(assoc_data);
@@ -2091,7 +2147,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                return false;
        }
 
-       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
 
        if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
@@ -2100,6 +2156,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        sta->supports_40mhz =
                sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 
+       if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+               ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+                                                   elems.vht_cap_elem,
+                                                   &sta->sta.vht_cap);
+
        rate_control_rate_init(sta);
 
        if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
@@ -2369,8 +2430,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        size_t baselen;
        struct ieee802_11_elems elems;
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *chan;
        u32 changed = 0;
-       bool erp_valid, directed_tim = false;
+       bool erp_valid;
        u8 erp_value = 0;
        u32 ncrc;
        u8 *bssid;
@@ -2382,8 +2445,19 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (baselen > len)
                return;
 
-       if (rx_status->freq != local->oper_channel->center_freq)
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!chanctx_conf) {
+               rcu_read_unlock();
+               return;
+       }
+
+       if (rx_status->freq != chanctx_conf->channel->center_freq) {
+               rcu_read_unlock();
                return;
+       }
+       chan = chanctx_conf->channel;
+       rcu_read_unlock();
 
        if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
            ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
@@ -2490,11 +2564,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                          len - baselen, &elems,
                                          care_about_ies, ncrc);
 
-       if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
-               directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
-                                                  ifmgd->aid);
-
        if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
+               bool directed_tim = ieee80211_check_tim(elems.tim,
+                                                       elems.tim_len,
+                                                       ifmgd->aid);
                if (directed_tim) {
                        if (local->hw.conf.dynamic_ps_timeout > 0) {
                                if (local->hw.conf.flags & IEEE80211_CONF_PS) {
@@ -2543,19 +2616,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
 
        if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
-           !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
-               struct ieee80211_supported_band *sband;
-
-               sband = local->hw.wiphy->bands[local->oper_channel->band];
-
+           !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
                changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
                                                  bssid, true);
-       }
 
        if (elems.country_elem && elems.pwr_constr_elem &&
            mgmt->u.probe_resp.capab_info &
                                cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
-               ieee80211_handle_pwr_constr(sdata, local->oper_channel,
+               ieee80211_handle_pwr_constr(sdata, chan,
                                            elems.country_elem,
                                            elems.country_elem_len,
                                            elems.pwr_constr_elem);
@@ -2703,13 +2771,23 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
        drv_mgd_prepare_tx(local, sdata);
 
        if (auth_data->bss->proberesp_ies) {
+               u16 trans = 1;
+               u16 status = 0;
+
                sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
                           auth_data->bss->bssid, auth_data->tries,
                           IEEE80211_AUTH_MAX_TRIES);
 
                auth_data->expected_transaction = 2;
-               ieee80211_send_auth(sdata, 1, auth_data->algorithm,
-                                   auth_data->ie, auth_data->ie_len,
+
+               if (auth_data->algorithm == WLAN_AUTH_SAE) {
+                       trans = auth_data->sae_trans;
+                       status = auth_data->sae_status;
+                       auth_data->expected_transaction = trans;
+               }
+
+               ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
+                                   auth_data->data, auth_data->data_len,
                                    auth_data->bss->bssid,
                                    auth_data->bss->bssid, NULL, 0, 0);
        } else {
@@ -2728,7 +2806,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
                 */
                ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
                                         NULL, 0, (u32) -1, true, false,
-                                        auth_data->bss->channel);
+                                        auth_data->bss->channel, false);
        }
 
        auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -3111,6 +3189,11 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                 * HT type, so do that here as well. If HT40 isn't allowed
                 * on this channel, disable 40 MHz operation.
                 */
+               const u8 *ht_cap_ie;
+               const struct ieee80211_ht_cap *ht_cap;
+               u8 chains = 1;
+
+               channel_type = NL80211_CHAN_HT20;
 
                switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
                case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
@@ -3126,22 +3209,25 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                                channel_type = NL80211_CHAN_HT40MINUS;
                        break;
                }
-       }
 
-       if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
-               /* can only fail due to HT40+/- mismatch */
-               channel_type = NL80211_CHAN_HT20;
-               sdata_info(sdata,
-                          "disabling 40 MHz due to multi-vif mismatch\n");
-               ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
-               WARN_ON(!ieee80211_set_channel_type(local, sdata,
-                                                   channel_type));
+               ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY,
+                                            cbss->information_elements,
+                                            cbss->len_information_elements);
+               if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) {
+                       ht_cap = (void *)(ht_cap_ie + 2);
+                       chains = ieee80211_mcs_to_chains(&ht_cap->mcs);
+               }
+               sdata->needed_rx_chains = min(chains, local->rx_chains);
+       } else {
+               sdata->needed_rx_chains = 1;
        }
 
-       local->oper_channel = cbss->channel;
-       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       /* will change later if needed */
+       sdata->smps_mode = IEEE80211_SMPS_OFF;
 
-       return 0;
+       ieee80211_vif_release_channel(sdata);
+       return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type,
+                                        IEEE80211_CHANCTX_SHARED);
 }
 
 static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
@@ -3211,7 +3297,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.basic_rates = basic_rates;
 
                /* cf. IEEE 802.11 9.2.12 */
-               if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
+               if (cbss->channel->band == IEEE80211_BAND_2GHZ &&
                    have_higher_than_11mbit)
                        sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
                else
@@ -3273,19 +3359,33 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        case NL80211_AUTHTYPE_NETWORK_EAP:
                auth_alg = WLAN_AUTH_LEAP;
                break;
+       case NL80211_AUTHTYPE_SAE:
+               auth_alg = WLAN_AUTH_SAE;
+               break;
        default:
                return -EOPNOTSUPP;
        }
 
-       auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL);
+       auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len +
+                           req->ie_len, GFP_KERNEL);
        if (!auth_data)
                return -ENOMEM;
 
        auth_data->bss = req->bss;
 
+       if (req->sae_data_len >= 4) {
+               __le16 *pos = (__le16 *) req->sae_data;
+               auth_data->sae_trans = le16_to_cpu(pos[0]);
+               auth_data->sae_status = le16_to_cpu(pos[1]);
+               memcpy(auth_data->data, req->sae_data + 4,
+                      req->sae_data_len - 4);
+               auth_data->data_len += req->sae_data_len - 4;
+       }
+
        if (req->ie && req->ie_len) {
-               memcpy(auth_data->ie, req->ie, req->ie_len);
-               auth_data->ie_len = req->ie_len;
+               memcpy(&auth_data->data[auth_data->data_len],
+                      req->ie, req->ie_len);
+               auth_data->data_len += req->ie_len;
        }
 
        if (req->key && req->key_len) {
@@ -3452,11 +3552,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
                if (ifmgd->powersave)
-                       ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
+                       sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
                else
-                       ifmgd->ap_smps = IEEE80211_SMPS_OFF;
+                       sdata->smps_mode = IEEE80211_SMPS_OFF;
        } else
-               ifmgd->ap_smps = ifmgd->req_smps;
+               sdata->smps_mode = ifmgd->req_smps;
 
        assoc_data->capability = req->bss->capability;
        assoc_data->wmm = bss->wmm_used &&
index 83608ac..c349f3a 100644 (file)
@@ -107,6 +107,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
 {
        struct ieee80211_sub_if_data *sdata;
 
+       if (WARN_ON(local->use_chanctx))
+               return;
+
        /*
         * notify the AP about us leaving the channel and stop all
         * STA interfaces.
@@ -145,6 +148,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
 {
        struct ieee80211_sub_if_data *sdata;
 
+       if (WARN_ON(local->use_chanctx))
+               return;
+
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
@@ -193,7 +199,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
 
        if (roc->mgmt_tx_cookie) {
                if (!WARN_ON(!roc->frame)) {
-                       ieee80211_tx_skb(roc->sdata, roc->frame);
+                       ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7,
+                                                 roc->chan->band);
                        roc->frame = NULL;
                }
        } else {
index 5c572e7..9f404ac 100644 (file)
@@ -135,6 +135,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                ieee80211_bss_info_change_notify(sdata,
                        BSS_CHANGED_BEACON_ENABLED);
 
+               /* the interface is leaving the channel and is removed */
+               ieee80211_vif_release_channel(sdata);
                drv_remove_interface(local, sdata);
        }
 
index 10de668..ec198ef 100644 (file)
@@ -52,11 +52,21 @@ static inline void rate_control_rate_init(struct sta_info *sta)
        struct ieee80211_sta *ista = &sta->sta;
        void *priv_sta = sta->rate_ctrl_priv;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_chanctx_conf *chanctx_conf;
 
        if (!ref)
                return;
 
-       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       rcu_read_lock();
+
+       chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               return;
+       }
+
+       sband = local->hw.wiphy->bands[chanctx_conf->channel->band];
+       rcu_read_unlock();
 
        ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
        set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
index 00ade7f..8c1f152 100644 (file)
@@ -1148,12 +1148,19 @@ ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-static void ap_sta_ps_start(struct sta_info *sta)
+static void sta_ps_start(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
+       struct ps_data *ps;
 
-       atomic_inc(&sdata->bss->num_sta_ps);
+       if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
+           sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               ps = &sdata->bss->ps;
+       else
+               return;
+
+       atomic_inc(&ps->num_sta_ps);
        set_sta_flag(sta, WLAN_STA_PS_STA);
        if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
                drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
@@ -1161,7 +1168,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
               sta->sta.addr, sta->sta.aid);
 }
 
-static void ap_sta_ps_end(struct sta_info *sta)
+static void sta_ps_end(struct sta_info *sta)
 {
        ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
               sta->sta.addr, sta->sta.aid);
@@ -1188,9 +1195,9 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
                return -EINVAL;
 
        if (start)
-               ap_sta_ps_start(sta_inf);
+               sta_ps_start(sta_inf);
        else
-               ap_sta_ps_end(sta_inf);
+               sta_ps_end(sta_inf);
 
        return 0;
 }
@@ -1342,10 +1349,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                         */
                        if (ieee80211_is_data(hdr->frame_control) &&
                            !ieee80211_has_pm(hdr->frame_control))
-                               ap_sta_ps_end(sta);
+                               sta_ps_end(sta);
                } else {
                        if (ieee80211_has_pm(hdr->frame_control))
-                               ap_sta_ps_start(sta);
+                               sta_ps_start(sta);
                }
        }
 
@@ -1391,9 +1398,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
                         struct sk_buff **skb)
 {
        struct ieee80211_fragment_entry *entry;
-       int idx;
 
-       idx = sdata->fragment_next;
        entry = &sdata->fragments[sdata->fragment_next++];
        if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
                sdata->fragment_next = 0;
@@ -3048,8 +3053,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        WARN_ON_ONCE(softirq_count() == 0);
 
-       if (WARN_ON(status->band < 0 ||
-                   status->band >= IEEE80211_NUM_BANDS))
+       if (WARN_ON(status->band >= IEEE80211_NUM_BANDS))
                goto drop;
 
        sband = local->hw.wiphy->bands[status->band];
@@ -3094,8 +3098,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                         * hardware error. The driver should catch hardware
                         * errors.
                         */
-                       if (WARN((status->rate_idx < 0 ||
-                                status->rate_idx > 76),
+                       if (WARN(status->rate_idx > 76,
                                 "Rate marked as an HT rate but passed "
                                 "status->rate_idx is not "
                                 "an MCS index [0-76]: %d (0x%02x)\n",
@@ -3103,8 +3106,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                                 status->rate_idx))
                                goto drop;
                } else {
-                       if (WARN_ON(status->rate_idx < 0 ||
-                                   status->rate_idx >= sband->n_bitrates))
+                       if (WARN_ON(status->rate_idx >= sband->n_bitrates))
                                goto drop;
                        rate = &sband->bitrates[status->rate_idx];
                }
index c4cdbde..13d2329 100644 (file)
@@ -336,6 +336,10 @@ EXPORT_SYMBOL(ieee80211_scan_completed);
 
 static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 {
+       /* Software scan is not supported in multi-channel cases */
+       if (local->use_chanctx)
+               return -EOPNOTSUPP;
+
        /*
         * Hardware/driver doesn't support hw_scan, so use software
         * scanning instead. First send a nullfunc frame with power save
@@ -417,7 +421,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
                        local->scan_req->ie, local->scan_req->ie_len,
                        local->scan_req->rates[band], false,
                        local->scan_req->no_cck,
-                       local->hw.conf.channel);
+                       local->hw.conf.channel, true);
 
        /*
         * After sending probe requests, wait for probe responses
@@ -462,6 +466,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                        sizeof(*local->hw_scan_req) +
                        req->n_channels * sizeof(req->channels[0]);
                local->hw_scan_req->ie = ies;
+               local->hw_scan_req->flags = req->flags;
 
                local->hw_scan_band = 0;
 
@@ -480,7 +485,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        if (local->ops->hw_scan) {
                __set_bit(SCAN_HW_SCANNING, &local->scanning);
        } else if ((req->n_channels == 1) &&
-                  (req->channels[0] == local->oper_channel)) {
+                  (req->channels[0] == local->_oper_channel)) {
                /*
                 * If we are scanning only on the operating channel
                 * then we do not need to stop normal activities
@@ -562,6 +567,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
        unsigned long min_beacon_int = 0;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_channel *next_chan;
+       enum mac80211_scan_state next_scan_state;
 
        /*
         * check if at least one STA interface is associated,
@@ -620,10 +626,18 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
                        usecs_to_jiffies(min_beacon_int * 1024) *
                        local->hw.conf.listen_interval);
 
-       if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
-               local->next_scan_state = SCAN_SUSPEND;
-       else
-               local->next_scan_state = SCAN_SET_CHANNEL;
+       if (associated && !tx_empty) {
+               if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
+                       next_scan_state = SCAN_ABORT;
+               else
+                       next_scan_state = SCAN_SUSPEND;
+       } else if (associated && (bad_latency || listen_int_exceeded)) {
+               next_scan_state = SCAN_SUSPEND;
+       } else {
+               next_scan_state = SCAN_SET_CHANNEL;
+       }
+
+       local->next_scan_state = next_scan_state;
 
        *next_delay = 0;
 }
@@ -794,6 +808,9 @@ void ieee80211_scan_work(struct work_struct *work)
                case SCAN_RESUME:
                        ieee80211_scan_state_resume(local, &next_delay);
                        break;
+               case SCAN_ABORT:
+                       aborted = true;
+                       goto out_complete;
                }
        } while (next_delay == 0);
 
index 0a4e4c0..f7bb54f 100644 (file)
@@ -98,6 +98,7 @@ static void free_sta_work(struct work_struct *wk)
        struct tid_ampdu_tx *tid_tx;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
+       struct ps_data *ps;
 
        /*
         * At this point, when being called as call_rcu callback,
@@ -107,11 +108,15 @@ static void free_sta_work(struct work_struct *wk)
         */
 
        if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
-               BUG_ON(!sdata->bss);
+               if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
+                   sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                       ps = &sdata->bss->ps;
+               else
+                       return;
 
                clear_sta_flag(sta, WLAN_STA_PS_STA);
 
-               atomic_dec(&sdata->bss->num_sta_ps);
+               atomic_dec(&ps->num_sta_ps);
                sta_info_recalc_tim(sta);
        }
 
@@ -502,22 +507,22 @@ int sta_info_insert(struct sta_info *sta)
        return err;
 }
 
-static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
+static inline void __bss_tim_set(u8 *tim, u16 id)
 {
        /*
         * This format has been mandated by the IEEE specifications,
         * so this line may not be changed to use the __set_bit() format.
         */
-       bss->tim[aid / 8] |= (1 << (aid % 8));
+       tim[id / 8] |= (1 << (id % 8));
 }
 
-static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
+static inline void __bss_tim_clear(u8 *tim, u16 id)
 {
        /*
         * This format has been mandated by the IEEE specifications,
         * so this line may not be changed to use the __clear_bit() format.
         */
-       bss->tim[aid / 8] &= ~(1 << (aid % 8));
+       tim[id / 8] &= ~(1 << (id % 8));
 }
 
 static unsigned long ieee80211_tids_for_ac(int ac)
@@ -541,14 +546,23 @@ static unsigned long ieee80211_tids_for_ac(int ac)
 void sta_info_recalc_tim(struct sta_info *sta)
 {
        struct ieee80211_local *local = sta->local;
-       struct ieee80211_if_ap *bss = sta->sdata->bss;
+       struct ps_data *ps;
        unsigned long flags;
        bool indicate_tim = false;
        u8 ignore_for_tim = sta->sta.uapsd_queues;
        int ac;
+       u16 id;
+
+       if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
+           sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+               if (WARN_ON_ONCE(!sta->sdata->bss))
+                       return;
 
-       if (WARN_ON_ONCE(!sta->sdata->bss))
+               ps = &sta->sdata->bss->ps;
+               id = sta->sta.aid;
+       } else {
                return;
+       }
 
        /* No need to do anything if the driver does all */
        if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
@@ -587,9 +601,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
        spin_lock_irqsave(&local->tim_lock, flags);
 
        if (indicate_tim)
-               __bss_tim_set(bss, sta->sta.aid);
+               __bss_tim_set(ps->tim, id);
        else
-               __bss_tim_clear(bss, sta->sta.aid);
+               __bss_tim_clear(ps->tim, id);
 
        if (local->ops->set_tim) {
                local->tim_in_locked_section = true;
@@ -893,8 +907,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                        continue;
 
                if (time_after(jiffies, sta->last_rx + exp_time)) {
-                       ibss_dbg(sdata, "expiring inactive STA %pM\n",
-                                sta->sta.addr);
+                       sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
+                               sta->sta.addr);
                        WARN_ON(__sta_info_destroy(sta));
                }
        }
@@ -948,10 +962,17 @@ static void clear_sta_ps_flags(void *_sta)
 {
        struct sta_info *sta = _sta;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ps_data *ps;
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP ||
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               ps = &sdata->bss->ps;
+       else
+               return;
 
        clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
        if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
-               atomic_dec(&sdata->bss->num_sta_ps);
+               atomic_dec(&ps->num_sta_ps);
 }
 
 /* powersave support code */
@@ -1008,6 +1029,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
        __le16 fc;
        bool qos = test_sta_flag(sta, WLAN_STA_WME);
        struct ieee80211_tx_info *info;
+       struct ieee80211_chanctx_conf *chanctx_conf;
 
        if (qos) {
                fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
@@ -1057,7 +1079,16 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
 
        drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
 
-       ieee80211_xmit(sdata, skb);
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               kfree_skb(skb);
+               return;
+       }
+
+       ieee80211_xmit(sdata, skb, chanctx_conf->channel->band);
+       rcu_read_unlock();
 }
 
 static void
index 3af0cc4..21fa5c7 100644 (file)
@@ -189,30 +189,31 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
        }
 
        if (ieee80211_is_action(mgmt->frame_control) &&
-           sdata->vif.type == NL80211_IFTYPE_STATION &&
            mgmt->u.action.category == WLAN_CATEGORY_HT &&
-           mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) {
+           mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS &&
+           sdata->vif.type == NL80211_IFTYPE_STATION &&
+           ieee80211_sdata_running(sdata)) {
                /*
                 * This update looks racy, but isn't -- if we come
                 * here we've definitely got a station that we're
                 * talking to, and on a managed interface that can
                 * only be the AP. And the only other place updating
-                * this variable is before we're associated.
+                * this variable in managed mode is before association.
                 */
                switch (mgmt->u.action.u.ht_smps.smps_control) {
                case WLAN_HT_SMPS_CONTROL_DYNAMIC:
-                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC;
+                       sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
                        break;
                case WLAN_HT_SMPS_CONTROL_STATIC:
-                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC;
+                       sdata->smps_mode = IEEE80211_SMPS_STATIC;
                        break;
                case WLAN_HT_SMPS_CONTROL_DISABLED:
                default: /* shouldn't happen since we don't send that */
-                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF;
+                       sdata->smps_mode = IEEE80211_SMPS_OFF;
                        break;
                }
 
-               ieee80211_queue_work(&local->hw, &local->recalc_smps);
+               ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
        }
 }
 
index 18d9c8a..0638541 100644 (file)
 #define VIF_PR_FMT     " vif:%s(%d%s)"
 #define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
 
+#define CHANCTX_ENTRY  __field(int, freq)                                      \
+                       __field(int, chantype)                                  \
+                       __field(u8, rx_chains_static)                           \
+                       __field(u8, rx_chains_dynamic)
+#define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq;         \
+                       __entry->chantype = ctx->conf.channel_type;             \
+                       __entry->rx_chains_static = ctx->conf.rx_chains_static; \
+                       __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
+#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d chains:%d/%d"
+#define CHANCTX_PR_ARG __entry->freq, __entry->chantype,                       \
+                       __entry->rx_chains_static, __entry->rx_chains_dynamic
+
+
+
 /*
  * Tracing for driver callbacks.
  */
@@ -301,20 +315,33 @@ TRACE_EVENT(drv_bss_info_changed,
        TP_STRUCT__entry(
                LOCAL_ENTRY
                VIF_ENTRY
+               __field(u32, changed)
                __field(bool, assoc)
+               __field(bool, ibss_joined)
+               __field(bool, ibss_creator)
                __field(u16, aid)
                __field(bool, cts)
                __field(bool, shortpre)
                __field(bool, shortslot)
+               __field(bool, enable_beacon)
                __field(u8, dtimper)
                __field(u16, bcnint)
                __field(u16, assoc_cap)
                __field(u64, sync_tsf)
                __field(u32, sync_device_ts)
                __field(u32, basic_rates)
-               __field(u32, changed)
-               __field(bool, enable_beacon)
+               __array(int, mcast_rate, IEEE80211_NUM_BANDS)
                __field(u16, ht_operation_mode)
+               __field(s32, cqm_rssi_thold);
+               __field(s32, cqm_rssi_hyst);
+               __field(u32, channel_type);
+               __dynamic_array(u32, arp_addr_list, info->arp_addr_cnt);
+               __field(bool, arp_filter_enabled);
+               __field(bool, qos);
+               __field(bool, idle);
+               __field(bool, ps);
+               __dynamic_array(u8, ssid, info->ssid_len);
+               __field(bool, hidden_ssid);
        ),
 
        TP_fast_assign(
@@ -323,17 +350,32 @@ TRACE_EVENT(drv_bss_info_changed,
                __entry->changed = changed;
                __entry->aid = info->aid;
                __entry->assoc = info->assoc;
+               __entry->ibss_joined = info->ibss_joined;
+               __entry->ibss_creator = info->ibss_creator;
                __entry->shortpre = info->use_short_preamble;
                __entry->cts = info->use_cts_prot;
                __entry->shortslot = info->use_short_slot;
+               __entry->enable_beacon = info->enable_beacon;
                __entry->dtimper = info->dtim_period;
                __entry->bcnint = info->beacon_int;
                __entry->assoc_cap = info->assoc_capability;
                __entry->sync_tsf = info->sync_tsf;
                __entry->sync_device_ts = info->sync_device_ts;
                __entry->basic_rates = info->basic_rates;
-               __entry->enable_beacon = info->enable_beacon;
+               memcpy(__entry->mcast_rate, info->mcast_rate,
+                      sizeof(__entry->mcast_rate));
                __entry->ht_operation_mode = info->ht_operation_mode;
+               __entry->cqm_rssi_thold = info->cqm_rssi_thold;
+               __entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
+               __entry->channel_type = info->channel_type;
+               memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
+                      sizeof(u32) * info->arp_addr_cnt);
+               __entry->arp_filter_enabled = info->arp_filter_enabled;
+               __entry->qos = info->qos;
+               __entry->idle = info->idle;
+               __entry->ps = info->ps;
+               memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
+               __entry->hidden_ssid = info->hidden_ssid;
        ),
 
        TP_printk(
@@ -1256,6 +1298,104 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx,
        TP_ARGS(local, sdata)
 );
 
+DECLARE_EVENT_CLASS(local_chanctx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_chanctx *ctx),
+
+       TP_ARGS(local, ctx),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               CHANCTX_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               CHANCTX_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT CHANCTX_PR_FMT,
+               LOCAL_PR_ARG, CHANCTX_PR_ARG
+       )
+);
+
+DEFINE_EVENT(local_chanctx, drv_add_chanctx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_chanctx *ctx),
+       TP_ARGS(local, ctx)
+);
+
+DEFINE_EVENT(local_chanctx, drv_remove_chanctx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_chanctx *ctx),
+       TP_ARGS(local, ctx)
+);
+
+TRACE_EVENT(drv_change_chanctx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_chanctx *ctx,
+                u32 changed),
+
+       TP_ARGS(local, ctx, changed),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               CHANCTX_ENTRY
+               __field(u32, changed)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               CHANCTX_ASSIGN;
+               __entry->changed = changed;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT CHANCTX_PR_FMT " changed:%#x",
+               LOCAL_PR_ARG, CHANCTX_PR_ARG, __entry->changed
+       )
+);
+
+DECLARE_EVENT_CLASS(local_sdata_chanctx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_chanctx *ctx),
+
+       TP_ARGS(local, sdata, ctx),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               CHANCTX_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               CHANCTX_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT CHANCTX_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG, CHANCTX_PR_ARG
+       )
+);
+
+DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_chanctx *ctx),
+       TP_ARGS(local, sdata, ctx)
+);
+
+DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_chanctx *ctx),
+       TP_ARGS(local, sdata, ctx)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
index c9bf83f..065f81c 100644 (file)
@@ -324,22 +324,20 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
 
-       /*
-        * virtual interfaces are protected by RCU
-        */
-       rcu_read_lock();
-
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               struct ieee80211_if_ap *ap;
-               if (sdata->vif.type != NL80211_IFTYPE_AP)
+               struct ps_data *ps;
+
+               if (sdata->vif.type == NL80211_IFTYPE_AP)
+                       ps = &sdata->u.ap.ps;
+               else
                        continue;
-               ap = &sdata->u.ap;
-               skb = skb_dequeue(&ap->ps_bc_buf);
+
+               skb = skb_dequeue(&ps->bc_buf);
                if (skb) {
                        purged++;
                        dev_kfree_skb(skb);
                }
-               total += skb_queue_len(&ap->ps_bc_buf);
+               total += skb_queue_len(&ps->bc_buf);
        }
 
        /*
@@ -360,8 +358,6 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
                }
        }
 
-       rcu_read_unlock();
-
        local->total_ps_buffered = total;
        ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);
 }
@@ -371,6 +367,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+       struct ps_data *ps;
 
        /*
         * broadcast/multicast frame
@@ -380,16 +377,24 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
         * This is done either by the hardware or us.
         */
 
-       /* powersaving STAs only in AP/VLAN mode */
-       if (!tx->sdata->bss)
+       /* powersaving STAs currently only in AP/VLAN mode */
+       if (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
+           tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+               if (!tx->sdata->bss)
+                       return TX_CONTINUE;
+
+               ps = &tx->sdata->bss->ps;
+       } else {
                return TX_CONTINUE;
+       }
+
 
        /* no buffering for ordered frames */
        if (ieee80211_has_order(hdr->frame_control))
                return TX_CONTINUE;
 
        /* no stations in PS mode */
-       if (!atomic_read(&tx->sdata->bss->num_sta_ps))
+       if (!atomic_read(&ps->num_sta_ps))
                return TX_CONTINUE;
 
        info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
@@ -404,14 +409,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
        if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
                purge_old_ps_buffers(tx->local);
 
-       if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) {
+       if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) {
                ps_dbg(tx->sdata,
                       "BC TX buffer full - dropping the oldest frame\n");
-               dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
+               dev_kfree_skb(skb_dequeue(&ps->bc_buf));
        } else
                tx->local->total_ps_buffered++;
 
-       skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
+       skb_queue_tail(&ps->bc_buf, tx->skb);
 
        return TX_QUEUED;
 }
@@ -951,7 +956,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
        fragnum = 0;
 
        skb_queue_walk(&tx->skbs, skb) {
-               int next_len;
                const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
 
                hdr = (void *)skb->data;
@@ -970,7 +974,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
                        info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
                } else {
                        hdr->frame_control &= ~morefrags;
-                       next_len = 0;
                }
                hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
                fragnum++;
@@ -1372,7 +1375,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
  * Returns false if the frame couldn't be transmitted but was queued instead.
  */
 static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
-                        struct sk_buff *skb, bool txpending)
+                        struct sk_buff *skb, bool txpending,
+                        enum ieee80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_data tx;
@@ -1386,20 +1390,18 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
                return true;
        }
 
-       rcu_read_lock();
-
        /* initialises tx */
        led_len = skb->len;
        res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
 
        if (unlikely(res_prepare == TX_DROP)) {
                ieee80211_free_txskb(&local->hw, skb);
-               goto out;
+               return true;
        } else if (unlikely(res_prepare == TX_QUEUED)) {
-               goto out;
+               return true;
        }
 
-       info->band = local->hw.conf.channel->band;
+       info->band = band;
 
        /* set up hw_queue value early */
        if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
@@ -1410,8 +1412,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
        if (!invoke_tx_handlers(&tx))
                result = __ieee80211_tx(local, &tx.skbs, led_len,
                                        tx.sta, txpending);
- out:
-       rcu_read_unlock();
+
        return result;
 }
 
@@ -1446,7 +1447,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+                   enum ieee80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1454,8 +1456,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        int headroom;
        bool may_encrypt;
 
-       rcu_read_lock();
-
        may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
 
        headroom = local->tx_headroom;
@@ -1466,7 +1466,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 
        if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
                ieee80211_free_txskb(&local->hw, skb);
-               rcu_read_unlock();
                return;
        }
 
@@ -1478,13 +1477,11 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
            !is_multicast_ether_addr(hdr->addr1) &&
            mesh_nexthop_resolve(skb, sdata)) {
                /* skb queued: don't free */
-               rcu_read_unlock();
                return;
        }
 
        ieee80211_set_qos_hdr(sdata, skb);
-       ieee80211_tx(sdata, skb, false);
-       rcu_read_unlock();
+       ieee80211_tx(sdata, skb, false, band);
 }
 
 static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
@@ -1574,7 +1571,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
                                         struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_channel *chan = local->hw.conf.channel;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *chan;
        struct ieee80211_radiotap_header *prthdr =
                (struct ieee80211_radiotap_header *)skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1583,26 +1581,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
        u16 len_rthdr;
        int hdrlen;
 
-       /*
-        * Frame injection is not allowed if beaconing is not allowed
-        * or if we need radar detection. Beaconing is usually not allowed when
-        * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
-        * Passive scan is also used in world regulatory domains where
-        * your country is not known and as such it should be treated as
-        * NO TX unless the channel is explicitly allowed in which case
-        * your current regulatory domain would not have the passive scan
-        * flag.
-        *
-        * Since AP mode uses monitor interfaces to inject/TX management
-        * frames we can make AP mode the exception to this rule once it
-        * supports radar detection as its implementation can deal with
-        * radar detection by itself. We can do that later by adding a
-        * monitor flag interfaces used for AP support.
-        */
-       if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
-            IEEE80211_CHAN_PASSIVE_SCAN)))
-               goto fail;
-
        /* check for not even having the fixed radiotap header part */
        if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
                goto fail; /* too short to be possibly valid */
@@ -1688,11 +1666,45 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
                }
        }
 
-       ieee80211_xmit(sdata, skb);
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!chanctx_conf) {
+               tmp_sdata = rcu_dereference(local->monitor_sdata);
+               if (tmp_sdata)
+                       chanctx_conf =
+                               rcu_dereference(tmp_sdata->vif.chanctx_conf);
+       }
+       if (!chanctx_conf)
+               goto fail_rcu;
+
+       chan = chanctx_conf->channel;
+
+       /*
+        * Frame injection is not allowed if beaconing is not allowed
+        * or if we need radar detection. Beaconing is usually not allowed when
+        * the mode or operation (Adhoc, AP, Mesh) does not support DFS.
+        * Passive scan is also used in world regulatory domains where
+        * your country is not known and as such it should be treated as
+        * NO TX unless the channel is explicitly allowed in which case
+        * your current regulatory domain would not have the passive scan
+        * flag.
+        *
+        * Since AP mode uses monitor interfaces to inject/TX management
+        * frames we can make AP mode the exception to this rule once it
+        * supports radar detection as its implementation can deal with
+        * radar detection by itself. We can do that later by adding a
+        * monitor flag interfaces used for AP support.
+        */
+       if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
+                           IEEE80211_CHAN_PASSIVE_SCAN)))
+               goto fail_rcu;
+
+       ieee80211_xmit(sdata, skb, chan->band);
        rcu_read_unlock();
 
        return NETDEV_TX_OK;
 
+fail_rcu:
+       rcu_read_unlock();
 fail:
        dev_kfree_skb(skb);
        return NETDEV_TX_OK; /* meaning, we dealt with the skb */
@@ -1734,6 +1746,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        bool multicast;
        u32 info_flags = 0;
        u16 info_id = 0;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_sub_if_data *ap_sdata;
+       enum ieee80211_band band;
 
        if (unlikely(skb->len < ETH_HLEN))
                goto fail;
@@ -1743,9 +1758,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        ethertype = (skb->data[12] << 8) | skb->data[13];
        fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 
+       rcu_read_lock();
+
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
-               rcu_read_lock();
                sta = rcu_dereference(sdata->u.vlan.sta);
                if (sta) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@@ -1758,7 +1774,12 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
                        wme_sta = test_sta_flag(sta, WLAN_STA_WME);
                }
-               rcu_read_unlock();
+               ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
+                                       u.ap);
+               chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf);
+               if (!chanctx_conf)
+                       goto fail_rcu;
+               band = chanctx_conf->channel->band;
                if (sta)
                        break;
                /* fall through */
@@ -1769,6 +1790,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 24;
+               if (sdata->vif.type == NL80211_IFTYPE_AP)
+                       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (!chanctx_conf)
+                       goto fail_rcu;
+               band = chanctx_conf->channel->band;
                break;
        case NL80211_IFTYPE_WDS:
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@@ -1778,15 +1804,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 30;
+               /*
+                * This is the exception! WDS style interfaces are prohibited
+                * when channel contexts are in used so this must be valid
+                */
+               band = local->hw.conf.channel->band;
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
                if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
                        /* Do not send frames with mesh_ttl == 0 */
                        sdata->u.mesh.mshstats.dropped_frames_ttl++;
-                       goto fail;
+                       goto fail_rcu;
                }
-               rcu_read_lock();
+
                if (!is_multicast_ether_addr(skb->data)) {
                        mpath = mesh_path_lookup(skb->data, sdata);
                        if (!mpath)
@@ -1803,7 +1834,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                    !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
                                        skb->data, skb->data + ETH_ALEN);
-                       rcu_read_unlock();
                        meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
                                        sdata, NULL, NULL);
                } else {
@@ -1819,7 +1849,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                                mesh_da = mppath->mpp;
                        else if (mpath)
                                mesh_da = mpath->dst;
-                       rcu_read_unlock();
 
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
                                        mesh_da, sdata->vif.addr);
@@ -1839,13 +1868,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                                                        skb->data + ETH_ALEN);
 
                }
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (!chanctx_conf)
+                       goto fail_rcu;
+               band = chanctx_conf->channel->band;
                break;
 #endif
        case NL80211_IFTYPE_STATION:
                if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
                        bool tdls_peer = false;
 
-                       rcu_read_lock();
                        sta = sta_info_get(sdata, skb->data);
                        if (sta) {
                                authorized = test_sta_flag(sta,
@@ -1856,7 +1888,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                                tdls_auth = test_sta_flag(sta,
                                                WLAN_STA_TDLS_PEER_AUTH);
                        }
-                       rcu_read_unlock();
 
                        /*
                         * If the TDLS link is enabled, send everything
@@ -1871,7 +1902,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                if (tdls_direct) {
                        /* link during setup - throw out frames to peer */
                        if (!tdls_auth)
-                               goto fail;
+                               goto fail_rcu;
 
                        /* DA SA BSSID */
                        memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -1896,6 +1927,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        hdrlen = 24;
                }
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (!chanctx_conf)
+                       goto fail_rcu;
+               band = chanctx_conf->channel->band;
                break;
        case NL80211_IFTYPE_ADHOC:
                /* DA SA BSSID */
@@ -1903,9 +1938,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
                memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
                hdrlen = 24;
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (!chanctx_conf)
+                       goto fail_rcu;
+               band = chanctx_conf->channel->band;
                break;
        default:
-               goto fail;
+               goto fail_rcu;
        }
 
        /*
@@ -1915,13 +1954,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         */
        multicast = is_multicast_ether_addr(hdr.addr1);
        if (!multicast) {
-               rcu_read_lock();
                sta = sta_info_get(sdata, hdr.addr1);
                if (sta) {
                        authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
                        wme_sta = test_sta_flag(sta, WLAN_STA_WME);
                }
-               rcu_read_unlock();
        }
 
        /* For mesh, the use of the QoS header is mandatory */
@@ -1949,7 +1986,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 
                I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
 
-               goto fail;
+               goto fail_rcu;
        }
 
        if (unlikely(!multicast && skb->sk &&
@@ -2004,7 +2041,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                kfree_skb(tmp_skb);
 
                if (!skb)
-                       goto fail;
+                       goto fail_rcu;
        }
 
        hdr.frame_control = fc;
@@ -2052,7 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                head_need = max_t(int, 0, head_need);
                if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
                        ieee80211_free_txskb(&local->hw, skb);
-                       return NETDEV_TX_OK;
+                       goto fail_rcu;
                }
        }
 
@@ -2104,10 +2141,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        info->flags = info_flags;
        info->ack_frame_id = info_id;
 
-       ieee80211_xmit(sdata, skb);
+       ieee80211_xmit(sdata, skb, band);
+       rcu_read_unlock();
 
        return NETDEV_TX_OK;
 
+ fail_rcu:
+       rcu_read_unlock();
  fail:
        dev_kfree_skb(skb);
        return NETDEV_TX_OK;
@@ -2139,11 +2179,18 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
        struct sta_info *sta;
        struct ieee80211_hdr *hdr;
        bool result;
+       struct ieee80211_chanctx_conf *chanctx_conf;
 
        sdata = vif_to_sdata(info->control.vif);
 
        if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
-               result = ieee80211_tx(sdata, skb, true);
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (unlikely(!chanctx_conf)) {
+                       dev_kfree_skb(skb);
+                       return true;
+               }
+               result = ieee80211_tx(sdata, skb, true,
+                                     chanctx_conf->channel->band);
        } else {
                struct sk_buff_head skbs;
 
@@ -2211,9 +2258,8 @@ void ieee80211_tx_pending(unsigned long data)
 /* functions for drivers to get certain frames */
 
 static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_ap *bss,
-                                    struct sk_buff *skb,
-                                    struct beacon_data *beacon)
+                                    struct ps_data *ps,
+                                    struct sk_buff *skb)
 {
        u8 *pos, *tim;
        int aid0 = 0;
@@ -2221,27 +2267,27 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
 
        /* Generate bitmap for TIM only if there are any STAs in power save
         * mode. */
-       if (atomic_read(&bss->num_sta_ps) > 0)
+       if (atomic_read(&ps->num_sta_ps) > 0)
                /* in the hope that this is faster than
                 * checking byte-for-byte */
-               have_bits = !bitmap_empty((unsigned long*)bss->tim,
+               have_bits = !bitmap_empty((unsigned long*)ps->tim,
                                          IEEE80211_MAX_AID+1);
 
-       if (bss->dtim_count == 0)
-               bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
+       if (ps->dtim_count == 0)
+               ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
        else
-               bss->dtim_count--;
+               ps->dtim_count--;
 
        tim = pos = (u8 *) skb_put(skb, 6);
        *pos++ = WLAN_EID_TIM;
        *pos++ = 4;
-       *pos++ = bss->dtim_count;
+       *pos++ = ps->dtim_count;
        *pos++ = sdata->vif.bss_conf.dtim_period;
 
-       if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
+       if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf))
                aid0 = 1;
 
-       bss->dtim_bc_mc = aid0 == 1;
+       ps->dtim_bc_mc = aid0 == 1;
 
        if (have_bits) {
                /* Find largest even number N1 so that bits numbered 1 through
@@ -2249,14 +2295,14 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
                 * (N2 + 1) x 8 through 2007 are 0. */
                n1 = 0;
                for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
-                       if (bss->tim[i]) {
+                       if (ps->tim[i]) {
                                n1 = i & 0xfe;
                                break;
                        }
                }
                n2 = n1;
                for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
-                       if (bss->tim[i]) {
+                       if (ps->tim[i]) {
                                n2 = i;
                                break;
                        }
@@ -2266,7 +2312,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
                *pos++ = n1 | aid0;
                /* Part Virt Bitmap */
                skb_put(skb, n2 - n1);
-               memcpy(pos, bss->tim + n1, n2 - n1 + 1);
+               memcpy(pos, ps->tim + n1, n2 - n1 + 1);
 
                tim[1] = n2 - n1 + 4;
        } else {
@@ -2283,16 +2329,16 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
        struct sk_buff *skb = NULL;
        struct ieee80211_tx_info *info;
        struct ieee80211_sub_if_data *sdata = NULL;
-       struct ieee80211_if_ap *ap = NULL;
-       struct beacon_data *beacon;
-       enum ieee80211_band band = local->oper_channel->band;
+       enum ieee80211_band band;
        struct ieee80211_tx_rate_control txrc;
+       struct ieee80211_chanctx_conf *chanctx_conf;
 
        rcu_read_lock();
 
        sdata = vif_to_sdata(vif);
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 
-       if (!ieee80211_sdata_running(sdata))
+       if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
                goto out;
 
        if (tim_offset)
@@ -2301,8 +2347,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                *tim_length = 0;
 
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
-               ap = &sdata->u.ap;
-               beacon = rcu_dereference(ap->beacon);
+               struct ieee80211_if_ap *ap = &sdata->u.ap;
+               struct beacon_data *beacon = rcu_dereference(ap->beacon);
+
                if (beacon) {
                        /*
                         * headroom, head length,
@@ -2326,14 +2373,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                         * of the tim bitmap in mac80211 and the driver.
                         */
                        if (local->tim_in_locked_section) {
-                               ieee80211_beacon_add_tim(sdata, ap, skb,
-                                                        beacon);
+                               ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
                        } else {
                                unsigned long flags;
 
                                spin_lock_irqsave(&local->tim_lock, flags);
-                               ieee80211_beacon_add_tim(sdata, ap, skb,
-                                                        beacon);
+                               ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
                                spin_unlock_irqrestore(&local->tim_lock, flags);
                        }
 
@@ -2409,6 +2454,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                *pos++ = WLAN_EID_SSID;
                *pos++ = 0x0;
 
+               band = chanctx_conf->channel->band;
+
                if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
                    mesh_add_ds_params_ie(skb, sdata) ||
                    ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@ -2426,6 +2473,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                goto out;
        }
 
+       band = chanctx_conf->channel->band;
+
        info = IEEE80211_SKB_CB(skb);
 
        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@ -2653,29 +2702,40 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        struct sk_buff *skb = NULL;
        struct ieee80211_tx_data tx;
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_ap *bss = NULL;
-       struct beacon_data *beacon;
+       struct ps_data *ps;
        struct ieee80211_tx_info *info;
+       struct ieee80211_chanctx_conf *chanctx_conf;
 
        sdata = vif_to_sdata(vif);
-       bss = &sdata->u.ap;
 
        rcu_read_lock();
-       beacon = rcu_dereference(bss->beacon);
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 
-       if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head)
+       if (!chanctx_conf)
                goto out;
 
-       if (bss->dtim_count != 0 || !bss->dtim_bc_mc)
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               struct beacon_data *beacon =
+                               rcu_dereference(sdata->u.ap.beacon);
+
+               if (!beacon || !beacon->head)
+                       goto out;
+
+               ps = &sdata->u.ap.ps;
+       } else {
+               goto out;
+       }
+
+       if (ps->dtim_count != 0 || !ps->dtim_bc_mc)
                goto out; /* send buffered bc/mc only after DTIM beacon */
 
        while (1) {
-               skb = skb_dequeue(&bss->ps_bc_buf);
+               skb = skb_dequeue(&ps->bc_buf);
                if (!skb)
                        goto out;
                local->total_ps_buffered--;
 
-               if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
+               if (!skb_queue_empty(&ps->bc_buf) && skb->len >= 2) {
                        struct ieee80211_hdr *hdr =
                                (struct ieee80211_hdr *) skb->data;
                        /* more buffered multicast/broadcast frames ==> set
@@ -2693,7 +2753,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        info = IEEE80211_SKB_CB(skb);
 
        tx.flags |= IEEE80211_TX_PS_BUFFERED;
-       info->band = local->oper_channel->band;
+       info->band = chanctx_conf->channel->band;
 
        if (invoke_tx_handlers(&tx))
                skb = NULL;
@@ -2704,8 +2764,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
 
-void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
-                         struct sk_buff *skb, int tid)
+void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
+                                struct sk_buff *skb, int tid,
+                                enum ieee80211_band band)
 {
        int ac = ieee802_1d_to_ac[tid & 7];
 
@@ -2722,6 +2783,6 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
         * requirements are that we do not come into tx with bhs on.
         */
        local_bh_disable();
-       ieee80211_xmit(sdata, skb);
+       ieee80211_xmit(sdata, skb, band);
        local_bh_enable();
 }
index 2393918..9556391 100644 (file)
@@ -769,6 +769,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                        else
                                elem_parse_failed = true;
                        break;
+               case WLAN_EID_VHT_CAPABILITY:
+                       if (elen >= sizeof(struct ieee80211_vht_cap))
+                               elems->vht_cap_elem = (void *)pos;
+                       else
+                               elem_parse_failed = true;
+                       break;
+               case WLAN_EID_VHT_OPERATION:
+                       if (elen >= sizeof(struct ieee80211_vht_operation))
+                               elems->vht_operation = (void *)pos;
+                       else
+                               elem_parse_failed = true;
+                       break;
                case WLAN_EID_MESH_ID:
                        elems->mesh_id = pos;
                        elems->mesh_id_len = elen;
@@ -837,7 +849,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                if (elem_parse_failed)
                        elems->parse_error = true;
                else
-                       set_bit(id, seen_elems);
+                       __set_bit(id, seen_elems);
 
                left -= elen;
                pos += elen;
@@ -860,6 +872,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_queue_params qparam;
+       struct ieee80211_chanctx_conf *chanctx_conf;
        int ac;
        bool use_11b, enable_qos;
        int aCWmin, aCWmax;
@@ -872,8 +885,12 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 
        memset(&qparam, 0, sizeof(qparam));
 
-       use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) &&
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       use_11b = (chanctx_conf &&
+                  chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) &&
                 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
+       rcu_read_unlock();
 
        /*
         * By default disable QoS in STA mode for old access points, which do
@@ -952,7 +969,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
                                  const size_t supp_rates_len,
                                  const u8 *supp_rates)
 {
-       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *chanctx_conf;
        int i, have_higher_than_11mbit = 0;
 
        /* cf. IEEE 802.11 9.2.12 */
@@ -960,11 +977,16 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
                if ((supp_rates[i] & 0x7f) * 5 > 110)
                        have_higher_than_11mbit = 1;
 
-       if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+
+       if (chanctx_conf &&
+           chanctx_conf->channel->band == IEEE80211_BAND_2GHZ &&
            have_higher_than_11mbit)
                sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+       rcu_read_unlock();
 
        ieee80211_set_wmm_default(sdata, true);
 }
@@ -996,7 +1018,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 }
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
-                        u16 transaction, u16 auth_alg,
+                        u16 transaction, u16 auth_alg, u16 status,
                         u8 *extra, size_t extra_len, const u8 *da,
                         const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx)
 {
@@ -1021,7 +1043,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->bssid, bssid, ETH_ALEN);
        mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
        mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
-       mgmt->u.auth.status_code = cpu_to_le16(0);
+       mgmt->u.auth.status_code = cpu_to_le16(status);
        if (extra)
                memcpy(skb_put(skb, extra_len), extra, extra_len);
 
@@ -1234,7 +1256,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              const u8 *ssid, size_t ssid_len,
                              const u8 *ie, size_t ie_len,
                              u32 ratemask, bool directed, bool no_cck,
-                             struct ieee80211_channel *channel)
+                             struct ieee80211_channel *channel, bool scan)
 {
        struct sk_buff *skb;
 
@@ -1245,7 +1267,10 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                if (no_cck)
                        IEEE80211_SKB_CB(skb)->flags |=
                                IEEE80211_TX_CTL_NO_CCK_RATE;
-               ieee80211_tx_skb(sdata, skb);
+               if (scan)
+                       ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);
+               else
+                       ieee80211_tx_skb(sdata, skb);
        }
 }
 
@@ -1308,6 +1333,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_chanctx *ctx;
        struct sta_info *sta;
        int res, i;
 
@@ -1380,6 +1406,12 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        res = drv_add_interface(local, sdata);
        }
 
+       /* add channel contexts */
+       mutex_lock(&local->chanctx_mtx);
+       list_for_each_entry(ctx, &local->chanctx_list, list)
+               WARN_ON(drv_add_chanctx(local, ctx));
+       mutex_unlock(&local->chanctx_mtx);
+
        /* add STAs back */
        mutex_lock(&local->sta_mtx);
        list_for_each_entry(sta, &local->sta_list, list) {
@@ -1420,11 +1452,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
        /* Finally also reconfigure all the BSS information */
        list_for_each_entry(sdata, &local->interfaces, list) {
+               struct ieee80211_chanctx_conf *ctx_conf;
                u32 changed;
 
                if (!ieee80211_sdata_running(sdata))
                        continue;
 
+               mutex_lock(&local->chanctx_mtx);
+               ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                               lockdep_is_held(&local->chanctx_mtx));
+               if (ctx_conf) {
+                       ctx = container_of(ctx_conf, struct ieee80211_chanctx,
+                                          conf);
+                       drv_assign_vif_chanctx(local, sdata, ctx);
+               }
+               mutex_unlock(&local->chanctx_mtx);
+
                /* common change flags for all interface types */
                changed = BSS_CHANGED_ERP_CTS_PROT |
                          BSS_CHANGED_ERP_PREAMBLE |
@@ -1615,68 +1658,24 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
 
-static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
-                         enum ieee80211_smps_mode *smps_mode)
-{
-       if (ifmgd->associated) {
-               *smps_mode = ifmgd->ap_smps;
-
-               if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
-                       if (ifmgd->powersave)
-                               *smps_mode = IEEE80211_SMPS_DYNAMIC;
-                       else
-                               *smps_mode = IEEE80211_SMPS_OFF;
-               }
-
-               return 1;
-       }
-
-       return 0;
-}
-
-void ieee80211_recalc_smps(struct ieee80211_local *local)
+void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_sub_if_data *sdata;
-       enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
-       int count = 0;
-
-       mutex_lock(&local->iflist_mtx);
-
-       /*
-        * This function could be improved to handle multiple
-        * interfaces better, but right now it makes any
-        * non-station interfaces force SM PS to be turned
-        * off. If there are multiple station interfaces it
-        * could also use the best possible mode, e.g. if
-        * one is in static and the other in dynamic then
-        * dynamic is ok.
-        */
-
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata))
-                       continue;
-               if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
-                       continue;
-               if (sdata->vif.type != NL80211_IFTYPE_STATION)
-                       goto set;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_chanctx *chanctx;
 
-               count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
+       mutex_lock(&local->chanctx_mtx);
 
-               if (count > 1) {
-                       smps_mode = IEEE80211_SMPS_OFF;
-                       break;
-               }
-       }
+       chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                       lockdep_is_held(&local->chanctx_mtx));
 
-       if (smps_mode == local->smps_mode)
+       if (WARN_ON_ONCE(!chanctx_conf))
                goto unlock;
 
- set:
-       local->smps_mode = smps_mode;
-       /* changed flag is auto-detected for this */
-       ieee80211_hw_config(local, 0);
+       chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+       ieee80211_recalc_smps_chanctx(local, chanctx);
  unlock:
-       mutex_unlock(&local->iflist_mtx);
+       mutex_unlock(&local->chanctx_mtx);
 }
 
 static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
@@ -1816,8 +1815,8 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
        __le32 tmp;
 
        *pos++ = WLAN_EID_VHT_CAPABILITY;
-       *pos++ = sizeof(struct ieee80211_vht_capabilities);
-       memset(pos, 0, sizeof(struct ieee80211_vht_capabilities));
+       *pos++ = sizeof(struct ieee80211_vht_cap);
+       memset(pos, 0, sizeof(struct ieee80211_vht_cap));
 
        /* capability flags */
        tmp = cpu_to_le32(cap);
@@ -1975,3 +1974,19 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif)
        return ifmgd->ave_beacon_signal;
 }
 EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
+
+u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs)
+{
+       if (!mcs)
+               return 1;
+
+       /* TODO: consider rx_highest */
+
+       if (mcs->rx_mask[3])
+               return 4;
+       if (mcs->rx_mask[2])
+               return 3;
+       if (mcs->rx_mask[1])
+               return 2;
+       return 1;
+}
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
new file mode 100644 (file)
index 0000000..f311388
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * VHT handling
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ieee80211.h>
+#include <linux/export.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+
+void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_supported_band *sband,
+                                        struct ieee80211_vht_cap *vht_cap_ie,
+                                        struct ieee80211_sta_vht_cap *vht_cap)
+{
+       if (WARN_ON_ONCE(!vht_cap))
+               return;
+
+       memset(vht_cap, 0, sizeof(*vht_cap));
+
+       if (!vht_cap_ie || !sband->vht_cap.vht_supported)
+               return;
+
+       vht_cap->vht_supported = true;
+
+       vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
+
+       /* Copy peer MCS info, the driver might need them. */
+       memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
+              sizeof(struct ieee80211_vht_mcs_info));
+}
index 8d8d9bc..60c3bbb 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 menuconfig NFC
-       depends on NET && EXPERIMENTAL
-       tristate "NFC subsystem support (EXPERIMENTAL)"
+       depends on NET
+       tristate "NFC subsystem support"
        default n
        help
          Say Y here if you want to build support for NFC (Near field
index 479bee3..aa64ea4 100644 (file)
@@ -40,6 +40,9 @@
 int nfc_devlist_generation;
 DEFINE_MUTEX(nfc_devlist_mutex);
 
+/* NFC device ID bitmap */
+static DEFINE_IDA(nfc_index_ida);
+
 /**
  * nfc_dev_up - turn on the NFC device
  *
@@ -181,6 +184,7 @@ int nfc_stop_poll(struct nfc_dev *dev)
 
        dev->ops->stop_poll(dev);
        dev->polling = false;
+       dev->rf_mode = NFC_RF_NONE;
 
 error:
        device_unlock(&dev->dev);
@@ -194,7 +198,7 @@ static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)
        if (dev->n_targets == 0)
                return NULL;
 
-       for (i = 0; i < dev->n_targets ; i++) {
+       for (i = 0; i < dev->n_targets; i++) {
                if (dev->targets[i].idx == target_idx)
                        return &dev->targets[i];
        }
@@ -274,12 +278,14 @@ int nfc_dep_link_down(struct nfc_dev *dev)
        if (!rc) {
                dev->dep_link_up = false;
                dev->active_target = NULL;
+               dev->rf_mode = NFC_RF_NONE;
                nfc_llcp_mac_is_down(dev);
                nfc_genl_dep_link_down_event(dev);
        }
 
 error:
        device_unlock(&dev->dev);
+
        return rc;
 }
 
@@ -503,6 +509,7 @@ EXPORT_SYMBOL(nfc_tm_activated);
 int nfc_tm_deactivated(struct nfc_dev *dev)
 {
        dev->dep_link_up = false;
+       dev->rf_mode = NFC_RF_NONE;
 
        return nfc_genl_tm_deactivated(dev);
 }
@@ -697,6 +704,8 @@ static void nfc_check_pres_work(struct work_struct *work)
 
        if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) {
                rc = dev->ops->check_presence(dev, dev->active_target);
+               if (rc == -EOPNOTSUPP)
+                       goto exit;
                if (!rc) {
                        mod_timer(&dev->check_pres_timer, jiffies +
                                  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
@@ -708,6 +717,7 @@ static void nfc_check_pres_work(struct work_struct *work)
                }
        }
 
+exit:
        device_unlock(&dev->dev);
 }
 
@@ -753,7 +763,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
                                    u32 supported_protocols,
                                    int tx_headroom, int tx_tailroom)
 {
-       static atomic_t dev_no = ATOMIC_INIT(0);
        struct nfc_dev *dev;
 
        if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
@@ -767,11 +776,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
        if (!dev)
                return NULL;
 
-       dev->dev.class = &nfc_class;
-       dev->idx = atomic_inc_return(&dev_no) - 1;
-       dev_set_name(&dev->dev, "nfc%d", dev->idx);
-       device_initialize(&dev->dev);
-
        dev->ops = ops;
        dev->supported_protocols = supported_protocols;
        dev->tx_headroom = tx_headroom;
@@ -779,6 +783,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 
        nfc_genl_data_init(&dev->genl_data);
 
+       dev->rf_mode = NFC_RF_NONE;
 
        /* first generation must not be 0 */
        dev->targets_generation = 1;
@@ -806,6 +811,14 @@ int nfc_register_device(struct nfc_dev *dev)
 
        pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
+       dev->idx = ida_simple_get(&nfc_index_ida, 0, 0, GFP_KERNEL);
+       if (dev->idx < 0)
+               return dev->idx;
+
+       dev->dev.class = &nfc_class;
+       dev_set_name(&dev->dev, "nfc%d", dev->idx);
+       device_initialize(&dev->dev);
+
        mutex_lock(&nfc_devlist_mutex);
        nfc_devlist_generation++;
        rc = device_add(&dev->dev);
@@ -834,10 +847,12 @@ EXPORT_SYMBOL(nfc_register_device);
  */
 void nfc_unregister_device(struct nfc_dev *dev)
 {
-       int rc;
+       int rc, id;
 
        pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
+       id = dev->idx;
+
        mutex_lock(&nfc_devlist_mutex);
        nfc_devlist_generation++;
 
@@ -856,6 +871,8 @@ void nfc_unregister_device(struct nfc_dev *dev)
                pr_debug("The userspace won't be notified that the device %s was removed\n",
                         dev_name(&dev->dev));
 
+       ida_simple_remove(&nfc_index_ida, id);
+
 }
 EXPORT_SYMBOL(nfc_unregister_device);
 
index 71c6a70..07659cf 100644 (file)
@@ -257,16 +257,16 @@ static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,
        *result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
                                      NFC_HCI_ADM_CREATE_PIPE,
                                      (u8 *) &params, sizeof(params), &skb);
-       if (*result == 0) {
-               resp = (struct hci_create_pipe_resp *)skb->data;
-               pipe = resp->pipe;
-               kfree_skb(skb);
+       if (*result < 0)
+               return NFC_HCI_INVALID_PIPE;
 
-               pr_debug("pipe created=%d\n", pipe);
+       resp = (struct hci_create_pipe_resp *)skb->data;
+       pipe = resp->pipe;
+       kfree_skb(skb);
 
-               return pipe;
-       } else
-               return NFC_HCI_INVALID_PIPE;
+       pr_debug("pipe created=%d\n", pipe);
+
+       return pipe;
 }
 
 static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
@@ -279,8 +279,6 @@ static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
 
 static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
 {
-       int r;
-
        u8 param[2];
 
        /* TODO: Find out what the identity reference data is
@@ -288,10 +286,8 @@ static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
 
        pr_debug("\n");
 
-       r = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
-                               NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
-
-       return 0;
+       return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
+                                  NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
 }
 
 int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
index 5fbb6e4..bc571b0 100644 (file)
@@ -65,8 +65,9 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
                                                          -ETIME);
                        kfree(hdev->cmd_pending_msg);
                        hdev->cmd_pending_msg = NULL;
-               } else
+               } else {
                        goto exit;
+               }
        }
 
 next_msg:
@@ -182,7 +183,7 @@ static u32 nfc_hci_sak_to_protocol(u8 sak)
        }
 }
 
-static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
+int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
 {
        struct nfc_target *targets;
        struct sk_buff *atqa_skb = NULL;
@@ -263,7 +264,9 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
                break;
        }
 
-       targets->hci_reader_gate = gate;
+       /* if driver set the new gate, we will skip the old one */
+       if (targets->hci_reader_gate == 0x00)
+               targets->hci_reader_gate = gate;
 
        r = nfc_targets_found(hdev->ndev, targets, 1);
 
@@ -275,6 +278,7 @@ exit:
 
        return r;
 }
+EXPORT_SYMBOL(nfc_hci_target_discovered);
 
 void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
                            struct sk_buff *skb)
@@ -307,8 +311,13 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
                                              nfc_hci_pipe2gate(hdev, pipe));
                break;
        default:
-               /* TODO: Unknown events are hardware specific
-                * pass them to the driver (needs a new hci_ops) */
+               if (hdev->ops->event_received) {
+                       hdev->ops->event_received(hdev,
+                                               nfc_hci_pipe2gate(hdev, pipe),
+                                               event, skb);
+                       return;
+               }
+
                break;
        }
 
@@ -527,7 +536,8 @@ static int hci_start_poll(struct nfc_dev *nfc_dev,
                return hdev->ops->start_poll(hdev, im_protocols, tm_protocols);
        else
                return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
-                                      NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
+                                         NFC_HCI_EVT_READER_REQUESTED,
+                                         NULL, 0);
 }
 
 static void hci_stop_poll(struct nfc_dev *nfc_dev)
@@ -538,6 +548,28 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev)
                           NFC_HCI_EVT_END_OPERATION, NULL, 0);
 }
 
+static int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
+                               __u8 comm_mode, __u8 *gb, size_t gb_len)
+{
+       struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+
+       if (hdev->ops->dep_link_up)
+               return hdev->ops->dep_link_up(hdev, target, comm_mode,
+                                               gb, gb_len);
+
+       return 0;
+}
+
+static int hci_dep_link_down(struct nfc_dev *nfc_dev)
+{
+       struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+
+       if (hdev->ops->dep_link_down)
+               return hdev->ops->dep_link_down(hdev);
+
+       return 0;
+}
+
 static int hci_activate_target(struct nfc_dev *nfc_dev,
                               struct nfc_target *target, u32 protocol)
 {
@@ -586,8 +618,8 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
        switch (target->hci_reader_gate) {
        case NFC_HCI_RF_READER_A_GATE:
        case NFC_HCI_RF_READER_B_GATE:
-               if (hdev->ops->data_exchange) {
-                       r = hdev->ops->data_exchange(hdev, target, skb, cb,
+               if (hdev->ops->im_transceive) {
+                       r = hdev->ops->im_transceive(hdev, target, skb, cb,
                                                     cb_context);
                        if (r <= 0)     /* handled */
                                break;
@@ -604,14 +636,14 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
                                           skb->len, hci_transceive_cb, hdev);
                break;
        default:
-               if (hdev->ops->data_exchange) {
-                       r = hdev->ops->data_exchange(hdev, target, skb, cb,
+               if (hdev->ops->im_transceive) {
+                       r = hdev->ops->im_transceive(hdev, target, skb, cb,
                                                     cb_context);
                        if (r == 1)
                                r = -ENOTSUPP;
-               }
-               else
+               } else {
                        r = -ENOTSUPP;
+               }
                break;
        }
 
@@ -620,6 +652,16 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
        return r;
 }
 
+static int hci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
+{
+       struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+
+       if (hdev->ops->tm_send)
+               return hdev->ops->tm_send(hdev, skb);
+       else
+               return -ENOTSUPP;
+}
+
 static int hci_check_presence(struct nfc_dev *nfc_dev,
                              struct nfc_target *target)
 {
@@ -723,9 +765,12 @@ static struct nfc_ops hci_nfc_ops = {
        .dev_down = hci_dev_down,
        .start_poll = hci_start_poll,
        .stop_poll = hci_stop_poll,
+       .dep_link_up = hci_dep_link_up,
+       .dep_link_down = hci_dep_link_down,
        .activate_target = hci_activate_target,
        .deactivate_target = hci_deactivate_target,
        .im_transceive = hci_transceive,
+       .tm_send = hci_tm_send,
        .check_presence = hci_check_presence,
 };
 
@@ -848,7 +893,7 @@ void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err)
 }
 EXPORT_SYMBOL(nfc_hci_driver_failure);
 
-void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb)
 {
        nfc_llc_rcv_from_drv(hdev->llc, skb);
 }
index ae1205d..fe5e966 100644 (file)
@@ -72,7 +72,7 @@ int nfc_llc_register(const char *name, struct nfc_llc_ops *ops)
        llc_engine->ops = ops;
 
        INIT_LIST_HEAD(&llc_engine->entry);
-       list_add_tail (&llc_engine->entry, &llc_engines);
+       list_add_tail(&llc_engine->entry, &llc_engines);
 
        return 0;
 }
index 01cbc72..27b313b 100644 (file)
@@ -634,9 +634,9 @@ static void llc_shdlc_sm_work(struct work_struct *work)
                        r = llc_shdlc_connect_initiate(shdlc);
                else
                        r = -ETIME;
-               if (r < 0)
+               if (r < 0) {
                        llc_shdlc_connect_complete(shdlc, r);
-               else {
+               else {
                        mod_timer(&shdlc->connect_timer, jiffies +
                                  msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS));
 
@@ -682,9 +682,8 @@ static void llc_shdlc_sm_work(struct work_struct *work)
                        llc_shdlc_handle_send_queue(shdlc);
                }
 
-               if (shdlc->hard_fault) {
+               if (shdlc->hard_fault)
                        shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault);
-               }
                break;
        default:
                break;
index fbf5e81..a1a41cd 100644 (file)
@@ -1,6 +1,6 @@
 config NFC_LLCP
-       depends on NFC && EXPERIMENTAL
-       bool "NFC LLCP support (EXPERIMENTAL)"
+       depends on NFC
+       bool "NFC LLCP support"
        default n
        help
         Say Y here if you want to build support for a kernel NFC LLCP
index c45ccd6..ed2d173 100644 (file)
@@ -261,7 +261,6 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)
        struct sk_buff *skb;
        struct nfc_dev *dev;
        struct nfc_llcp_local *local;
-       u16 size = 0;
 
        pr_debug("Sending DISC\n");
 
@@ -273,17 +272,10 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)
        if (dev == NULL)
                return -ENODEV;
 
-       size += LLCP_HEADER_SIZE;
-       size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
-
-       skb = alloc_skb(size, GFP_ATOMIC);
+       skb = llcp_allocate_pdu(sock, LLCP_PDU_DISC, 0);
        if (skb == NULL)
                return -ENOMEM;
 
-       skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
-
-       skb = llcp_add_header(skb, sock->dsap, sock->ssap, LLCP_PDU_DISC);
-
        skb_queue_tail(&local->tx_queue, skb);
 
        return 0;
@@ -324,8 +316,7 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
        struct sk_buff *skb;
        u8 *service_name_tlv = NULL, service_name_tlv_length;
        u8 *miux_tlv = NULL, miux_tlv_length;
-       u8 *rw_tlv = NULL, rw_tlv_length, rw;
-       __be16 miux;
+       u8 *rw_tlv = NULL, rw_tlv_length;
        int err;
        u16 size = 0;
 
@@ -343,13 +334,11 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
                size += service_name_tlv_length;
        }
 
-       miux = cpu_to_be16(LLCP_MAX_MIUX);
-       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
                                      &miux_tlv_length);
        size += miux_tlv_length;
 
-       rw = LLCP_MAX_RW;
-       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
+       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
        size += rw_tlv_length;
 
        pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len);
@@ -386,8 +375,7 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
        struct nfc_llcp_local *local;
        struct sk_buff *skb;
        u8 *miux_tlv = NULL, miux_tlv_length;
-       u8 *rw_tlv = NULL, rw_tlv_length, rw;
-       __be16 miux;
+       u8 *rw_tlv = NULL, rw_tlv_length;
        int err;
        u16 size = 0;
 
@@ -397,13 +385,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
        if (local == NULL)
                return -ENODEV;
 
-       miux = cpu_to_be16(LLCP_MAX_MIUX);
-       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
                                      &miux_tlv_length);
        size += miux_tlv_length;
 
-       rw = LLCP_MAX_RW;
-       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
+       rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
        size += rw_tlv_length;
 
        skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
@@ -428,6 +414,52 @@ error_tlv:
        return err;
 }
 
+int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap)
+{
+       struct sk_buff *skb;
+       struct nfc_dev *dev;
+       u8 *sdres_tlv = NULL, sdres_tlv_length, sdres[2];
+       u16 size = 0;
+
+       pr_debug("Sending SNL tid 0x%x sap 0x%x\n", tid, sap);
+
+       if (local == NULL)
+               return -ENODEV;
+
+       dev = local->dev;
+       if (dev == NULL)
+               return -ENODEV;
+
+       sdres[0] = tid;
+       sdres[1] = sap;
+       sdres_tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, sdres, 0,
+                                      &sdres_tlv_length);
+       if (sdres_tlv == NULL)
+               return -ENOMEM;
+
+       size += LLCP_HEADER_SIZE;
+       size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
+       size += sdres_tlv_length;
+
+       skb = alloc_skb(size, GFP_KERNEL);
+       if (skb == NULL) {
+               kfree(sdres_tlv);
+               return -ENOMEM;
+       }
+
+       skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
+
+       skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL);
+
+       memcpy(skb_put(skb, sdres_tlv_length), sdres_tlv, sdres_tlv_length);
+
+       skb_queue_tail(&local->tx_queue, skb);
+
+       kfree(sdres_tlv);
+
+       return 0;
+}
+
 int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
 {
        struct sk_buff *skb;
@@ -541,6 +573,52 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
        return len;
 }
 
+int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
+                          struct msghdr *msg, size_t len)
+{
+       struct sk_buff *pdu;
+       struct nfc_llcp_local *local;
+       size_t frag_len = 0, remaining_len;
+       u8 *msg_ptr;
+       int err;
+
+       pr_debug("Send UI frame len %zd\n", len);
+
+       local = sock->local;
+       if (local == NULL)
+               return -ENODEV;
+
+       remaining_len = len;
+       msg_ptr = (u8 *) msg->msg_iov;
+
+       while (remaining_len > 0) {
+
+               frag_len = min_t(size_t, sock->miu, remaining_len);
+
+               pr_debug("Fragment %zd bytes remaining %zd",
+                        frag_len, remaining_len);
+
+               pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT,
+                                        frag_len + LLCP_HEADER_SIZE, &err);
+               if (pdu == NULL) {
+                       pr_err("Could not allocate PDU\n");
+                       continue;
+               }
+
+               pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
+
+               memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
+
+               /* No need to check for the peer RW for UI frames */
+               skb_queue_tail(&local->tx_queue, pdu);
+
+               remaining_len -= frag_len;
+               msg_ptr += frag_len;
+       }
+
+       return len;
+}
+
 int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
 {
        struct sk_buff *skb;
index cc10d07..f680453 100644 (file)
@@ -45,12 +45,38 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
        write_unlock(&l->lock);
 }
 
+static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
+{
+       struct nfc_llcp_local *local = sock->local;
+       struct sk_buff *s, *tmp;
+
+       pr_debug("%p\n", &sock->sk);
+
+       skb_queue_purge(&sock->tx_queue);
+       skb_queue_purge(&sock->tx_pending_queue);
+       skb_queue_purge(&sock->tx_backlog_queue);
+
+       if (local == NULL)
+               return;
+
+       /* Search for local pending SKBs that are related to this socket */
+       skb_queue_walk_safe(&local->tx_queue, s, tmp) {
+               if (s->sk != &sock->sk)
+                       continue;
+
+               skb_unlink(s, &local->tx_queue);
+               kfree_skb(s);
+       }
+}
+
 static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
 {
        struct sock *sk;
        struct hlist_node *node, *tmp;
        struct nfc_llcp_sock *llcp_sock;
 
+       skb_queue_purge(&local->tx_queue);
+
        write_lock(&local->sockets.lock);
 
        sk_for_each_safe(sk, node, tmp, &local->sockets.head) {
@@ -58,6 +84,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
 
                bh_lock_sock(sk);
 
+               nfc_llcp_socket_purge(llcp_sock);
+
                if (sk->sk_state == LLCP_CONNECTED)
                        nfc_put_device(llcp_sock->dev);
 
@@ -65,7 +93,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
                        struct nfc_llcp_sock *lsk, *n;
                        struct sock *accept_sk;
 
-                       list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
+                       list_for_each_entry_safe(lsk, n,
+                                                &llcp_sock->accept_queue,
                                                 accept_queue) {
                                accept_sk = &lsk->sk;
                                bh_lock_sock(accept_sk);
@@ -85,6 +114,16 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen)
                        }
                }
 
+               /*
+                * If we have a connection less socket bound, we keep it alive
+                * if the device is still present.
+                */
+               if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM &&
+                   listen == true) {
+                       bh_unlock_sock(sk);
+                       continue;
+               }
+
                sk->sk_state = LLCP_CLOSED;
 
                bh_unlock_sock(sk);
@@ -134,7 +173,7 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
 {
        struct sock *sk;
        struct hlist_node *node;
-       struct nfc_llcp_sock *llcp_sock;
+       struct nfc_llcp_sock *llcp_sock, *tmp_sock;
 
        pr_debug("ssap dsap %d %d\n", ssap, dsap);
 
@@ -146,10 +185,12 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
        llcp_sock = NULL;
 
        sk_for_each(sk, node, &local->sockets.head) {
-               llcp_sock = nfc_llcp_sock(sk);
+               tmp_sock = nfc_llcp_sock(sk);
 
-               if (llcp_sock->ssap == ssap && llcp_sock->dsap == dsap)
+               if (tmp_sock->ssap == ssap && tmp_sock->dsap == dsap) {
+                       llcp_sock = tmp_sock;
                        break;
+               }
        }
 
        read_unlock(&local->sockets.lock);
@@ -249,7 +290,12 @@ struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local,
 
                pr_debug("llcp sock %p\n", tmp_sock);
 
-               if (tmp_sock->sk.sk_state != LLCP_LISTEN)
+               if (tmp_sock->sk.sk_type == SOCK_STREAM &&
+                   tmp_sock->sk.sk_state != LLCP_LISTEN)
+                       continue;
+
+               if (tmp_sock->sk.sk_type == SOCK_DGRAM &&
+                   tmp_sock->sk.sk_state != LLCP_BOUND)
                        continue;
 
                if (tmp_sock->service_name == NULL ||
@@ -421,10 +467,9 @@ static u8 nfc_llcp_reserve_sdp_ssap(struct nfc_llcp_local *local)
 static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
 {
        u8 *gb_cur, *version_tlv, version, version_length;
-       u8 *lto_tlv, lto, lto_length;
+       u8 *lto_tlv, lto_length;
        u8 *wks_tlv, wks_length;
        u8 *miux_tlv, miux_length;
-       __be16 miux;
        u8 gb_len = 0;
        int ret = 0;
 
@@ -433,9 +478,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
                                         1, &version_length);
        gb_len += version_length;
 
-       /* 1500 ms */
-       lto = 150;
-       lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &lto, 1, &lto_length);
+       lto_tlv = nfc_llcp_build_tlv(LLCP_TLV_LTO, &local->lto, 1, &lto_length);
        gb_len += lto_length;
 
        pr_debug("Local wks 0x%lx\n", local->local_wks);
@@ -443,8 +486,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
                                     &wks_length);
        gb_len += wks_length;
 
-       miux = cpu_to_be16(LLCP_MAX_MIUX);
-       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+       miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
                                      &miux_length);
        gb_len += miux_length;
 
@@ -610,7 +652,10 @@ static void nfc_llcp_tx_work(struct work_struct *work)
        if (skb != NULL) {
                sk = skb->sk;
                llcp_sock = nfc_llcp_sock(sk);
-               if (llcp_sock != NULL) {
+
+               if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
+                       nfc_llcp_send_symm(local->dev);
+               } else {
                        int ret;
 
                        pr_debug("Sending pending skb\n");
@@ -629,8 +674,6 @@ static void nfc_llcp_tx_work(struct work_struct *work)
                                skb_queue_tail(&llcp_sock->tx_pending_queue,
                                               skb);
                        }
-               } else {
-                       nfc_llcp_send_symm(local->dev);
                }
        } else {
                nfc_llcp_send_symm(local->dev);
@@ -704,6 +747,39 @@ static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len)
        return NULL;
 }
 
+static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
+                            struct sk_buff *skb)
+{
+       struct nfc_llcp_sock *llcp_sock;
+       struct nfc_llcp_ui_cb *ui_cb;
+       u8 dsap, ssap;
+
+       dsap = nfc_llcp_dsap(skb);
+       ssap = nfc_llcp_ssap(skb);
+
+       ui_cb = nfc_llcp_ui_skb_cb(skb);
+       ui_cb->dsap = dsap;
+       ui_cb->ssap = ssap;
+
+       printk("%s %d %d\n", __func__, dsap, ssap);
+
+       pr_debug("%d %d\n", dsap, ssap);
+
+       /* We're looking for a bound socket, not a client one */
+       llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
+       if (llcp_sock == NULL || llcp_sock->sk.sk_type != SOCK_DGRAM)
+               return;
+
+       /* There is no sequence with UI frames */
+       skb_pull(skb, LLCP_HEADER_SIZE);
+       if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
+               pr_err("receive queue is full\n");
+               skb_queue_head(&llcp_sock->tx_backlog_queue, skb);
+       }
+
+       nfc_llcp_sock_put(llcp_sock);
+}
+
 static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
                                  struct sk_buff *skb)
 {
@@ -823,9 +899,6 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
 fail:
        /* Send DM */
        nfc_llcp_send_dm(local, dsap, ssap, reason);
-
-       return;
-
 }
 
 int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
@@ -953,6 +1026,9 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
 
        sk = &llcp_sock->sk;
        lock_sock(sk);
+
+       nfc_llcp_socket_purge(llcp_sock);
+
        if (sk->sk_state == LLCP_CLOSED) {
                release_sock(sk);
                nfc_llcp_sock_put(llcp_sock);
@@ -1027,7 +1103,7 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb)
        }
 
        if (llcp_sock == NULL) {
-               pr_err("Invalid DM\n");
+               pr_debug("Already closed\n");
                return;
        }
 
@@ -1038,8 +1114,100 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb)
        sk->sk_state_change(sk);
 
        nfc_llcp_sock_put(llcp_sock);
+}
 
-       return;
+static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
+                             struct sk_buff *skb)
+{
+       struct nfc_llcp_sock *llcp_sock;
+       u8 dsap, ssap, *tlv, type, length, tid, sap;
+       u16 tlv_len, offset;
+       char *service_name;
+       size_t service_name_len;
+
+       dsap = nfc_llcp_dsap(skb);
+       ssap = nfc_llcp_ssap(skb);
+
+       pr_debug("%d %d\n", dsap, ssap);
+
+       if (dsap != LLCP_SAP_SDP || ssap != LLCP_SAP_SDP) {
+               pr_err("Wrong SNL SAP\n");
+               return;
+       }
+
+       tlv = &skb->data[LLCP_HEADER_SIZE];
+       tlv_len = skb->len - LLCP_HEADER_SIZE;
+       offset = 0;
+
+       while (offset < tlv_len) {
+               type = tlv[0];
+               length = tlv[1];
+
+               switch (type) {
+               case LLCP_TLV_SDREQ:
+                       tid = tlv[2];
+                       service_name = (char *) &tlv[3];
+                       service_name_len = length - 1;
+
+                       pr_debug("Looking for %.16s\n", service_name);
+
+                       if (service_name_len == strlen("urn:nfc:sn:sdp") &&
+                           !strncmp(service_name, "urn:nfc:sn:sdp",
+                                    service_name_len)) {
+                               sap = 1;
+                               goto send_snl;
+                       }
+
+                       llcp_sock = nfc_llcp_sock_from_sn(local, service_name,
+                                                         service_name_len);
+                       if (!llcp_sock) {
+                               sap = 0;
+                               goto send_snl;
+                       }
+
+                       /*
+                        * We found a socket but its ssap has not been reserved
+                        * yet. We need to assign it for good and send a reply.
+                        * The ssap will be freed when the socket is closed.
+                        */
+                       if (llcp_sock->ssap == LLCP_SDP_UNBOUND) {
+                               atomic_t *client_count;
+
+                               sap = nfc_llcp_reserve_sdp_ssap(local);
+
+                               pr_debug("Reserving %d\n", sap);
+
+                               if (sap == LLCP_SAP_MAX) {
+                                       sap = 0;
+                                       goto send_snl;
+                               }
+
+                               client_count =
+                                       &local->local_sdp_cnt[sap -
+                                                             LLCP_WKS_NUM_SAP];
+
+                               atomic_inc(client_count);
+
+                               llcp_sock->ssap = sap;
+                               llcp_sock->reserved_ssap = sap;
+                       } else {
+                               sap = llcp_sock->ssap;
+                       }
+
+                       pr_debug("%p %d\n", llcp_sock, sap);
+
+send_snl:
+                       nfc_llcp_send_snl(local, tid, sap);
+                       break;
+
+               default:
+                       pr_err("Invalid SNL tlv value 0x%x\n", type);
+                       break;
+               }
+
+               offset += length + 2;
+               tlv += length + 2;
+       }
 }
 
 static void nfc_llcp_rx_work(struct work_struct *work)
@@ -1072,6 +1240,11 @@ static void nfc_llcp_rx_work(struct work_struct *work)
                pr_debug("SYMM\n");
                break;
 
+       case LLCP_PDU_UI:
+               pr_debug("UI\n");
+               nfc_llcp_recv_ui(local, skb);
+               break;
+
        case LLCP_PDU_CONNECT:
                pr_debug("CONNECT\n");
                nfc_llcp_recv_connect(local, skb);
@@ -1092,6 +1265,11 @@ static void nfc_llcp_rx_work(struct work_struct *work)
                nfc_llcp_recv_dm(local, skb);
                break;
 
+       case LLCP_PDU_SNL:
+               pr_debug("SNL\n");
+               nfc_llcp_recv_snl(local, skb);
+               break;
+
        case LLCP_PDU_I:
        case LLCP_PDU_RR:
        case LLCP_PDU_RNR:
@@ -1104,8 +1282,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)
        schedule_work(&local->tx_work);
        kfree_skb(local->rx_pending);
        local->rx_pending = NULL;
-
-       return;
 }
 
 void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
@@ -1121,8 +1297,6 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
        local->rx_pending = skb_get(skb);
        del_timer(&local->link_timer);
        schedule_work(&local->rx_work);
-
-       return;
 }
 
 int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
@@ -1205,6 +1379,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
        rwlock_init(&local->connecting_sockets.lock);
        rwlock_init(&local->raw_sockets.lock);
 
+       local->lto = 150; /* 1500 ms */
+       local->rw = LLCP_MAX_RW;
+       local->miux = cpu_to_be16(LLCP_MAX_MIUX);
+
        nfc_llcp_build_gb(local);
 
        local->remote_miu = LLCP_DEFAULT_MIU;
index fdb2d24..0d62366 100644 (file)
@@ -64,6 +64,9 @@ struct nfc_llcp_local {
        u32 target_idx;
        u8 rf_mode;
        u8 comm_mode;
+       u8 lto;
+       u8 rw;
+       __be16 miux;
        unsigned long local_wks;      /* Well known services */
        unsigned long local_sdp;      /* Local services  */
        unsigned long local_sap; /* Local SAPs, not available for discovery */
@@ -124,6 +127,13 @@ struct nfc_llcp_sock {
        struct sock *parent;
 };
 
+struct nfc_llcp_ui_cb {
+       __u8 dsap;
+       __u8 ssap;
+};
+
+#define nfc_llcp_ui_skb_cb(__skb) ((struct nfc_llcp_ui_cb *)&((__skb)->cb[0]))
+
 #define nfc_llcp_sock(sk) ((struct nfc_llcp_sock *) (sk))
 #define nfc_llcp_dev(sk)  (nfc_llcp_sock((sk))->dev)
 
@@ -209,10 +219,13 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_symm(struct nfc_dev *dev);
 int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
+int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap);
 int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
 int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
 int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
                          struct msghdr *msg, size_t len);
+int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
+                          struct msghdr *msg, size_t len);
 int nfc_llcp_send_rr(struct nfc_llcp_sock *sock);
 
 /* Socket API */
index 63e4cdc..0fa1e92 100644 (file)
@@ -205,8 +205,8 @@ static int llcp_sock_listen(struct socket *sock, int backlog)
 
        lock_sock(sk);
 
-       if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
-           || sk->sk_state != LLCP_BOUND) {
+       if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) ||
+           sk->sk_state != LLCP_BOUND) {
                ret = -EBADFD;
                goto error;
        }
@@ -608,6 +608,25 @@ static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        lock_sock(sk);
 
+       if (sk->sk_type == SOCK_DGRAM) {
+               struct sockaddr_nfc_llcp *addr =
+                       (struct sockaddr_nfc_llcp *)msg->msg_name;
+
+               if (msg->msg_namelen < sizeof(*addr)) {
+                       release_sock(sk);
+
+                       pr_err("Invalid socket address length %d\n",
+                              msg->msg_namelen);
+
+                       return -EINVAL;
+               }
+
+               release_sock(sk);
+
+               return nfc_llcp_send_ui_frame(llcp_sock, addr->dsap, addr->ssap,
+                                             msg, len);
+       }
+
        if (sk->sk_state != LLCP_CONNECTED) {
                release_sock(sk);
                return -ENOTCONN;
@@ -663,11 +682,28 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                return -EFAULT;
        }
 
+       if (sk->sk_type == SOCK_DGRAM && msg->msg_name) {
+               struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb);
+               struct sockaddr_nfc_llcp sockaddr;
+
+               pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap);
+
+               sockaddr.sa_family = AF_NFC;
+               sockaddr.nfc_protocol = NFC_PROTO_NFC_DEP;
+               sockaddr.dsap = ui_cb->dsap;
+               sockaddr.ssap = ui_cb->ssap;
+
+               memcpy(msg->msg_name, &sockaddr, sizeof(sockaddr));
+               msg->msg_namelen = sizeof(sockaddr);
+       }
+
        /* Mark read part of skb as used */
        if (!(flags & MSG_PEEK)) {
 
                /* SOCK_STREAM: re-queue skb if it contains unreceived data */
-               if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) {
+               if (sk->sk_type == SOCK_STREAM ||
+                   sk->sk_type == SOCK_DGRAM ||
+                   sk->sk_type == SOCK_RAW) {
                        skb_pull(skb, copied);
                        if (skb->len) {
                                skb_queue_head(&sk->sk_receive_queue, skb);
index decdc49..6d69b5f 100644 (file)
@@ -1,6 +1,6 @@
 config NFC_NCI
-       depends on NFC && EXPERIMENTAL
-       tristate "NCI protocol support (EXPERIMENTAL)"
+       depends on NFC
+       tristate "NCI protocol support"
        default n
        help
          NCI (NFC Controller Interface) is a communication protocol between
index acf9abb..5f98dc1 100644 (file)
@@ -205,10 +205,10 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
        cmd.num_disc_configs = 0;
 
        if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
-           (protocols & NFC_PROTO_JEWEL_MASK
-            || protocols & NFC_PROTO_MIFARE_MASK
-            || protocols & NFC_PROTO_ISO14443_MASK
-            || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+           (protocols & NFC_PROTO_JEWEL_MASK ||
+            protocols & NFC_PROTO_MIFARE_MASK ||
+            protocols & NFC_PROTO_ISO14443_MASK ||
+            protocols & NFC_PROTO_NFC_DEP_MASK)) {
                cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
                        NCI_NFC_A_PASSIVE_POLL_MODE;
                cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
@@ -224,8 +224,8 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
        }
 
        if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
-           (protocols & NFC_PROTO_FELICA_MASK
-            || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+           (protocols & NFC_PROTO_FELICA_MASK ||
+            protocols & NFC_PROTO_NFC_DEP_MASK)) {
                cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
                        NCI_NFC_F_PASSIVE_POLL_MODE;
                cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
@@ -414,13 +414,13 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        struct nci_set_config_param param;
        __u8 local_gb[NFC_MAX_GT_LEN];
-       int i, rc = 0;
+       int i;
 
        param.val = nfc_get_local_general_bytes(nfc_dev, &param.len);
        if ((param.val == NULL) || (param.len == 0))
-               return rc;
+               return 0;
 
-       if (param.len > NCI_MAX_PARAM_LEN)
+       if (param.len > NFC_MAX_GT_LEN)
                return -EINVAL;
 
        for (i = 0; i < param.len; i++)
@@ -429,10 +429,8 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
        param.id = NCI_PN_ATR_REQ_GEN_BYTES;
        param.val = local_gb;
 
-       rc = nci_request(ndev, nci_set_config_req, (unsigned long)&param,
-                        msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
-
-       return rc;
+       return nci_request(ndev, nci_set_config_req, (unsigned long)&param,
+                          msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
 }
 
 static int nci_start_poll(struct nfc_dev *nfc_dev,
@@ -579,7 +577,6 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev,
        }
 }
 
-
 static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
                           __u8 comm_mode, __u8 *gb, size_t gb_len)
 {
@@ -806,8 +803,8 @@ int nci_recv_frame(struct sk_buff *skb)
 
        pr_debug("len %d\n", skb->len);
 
-       if (!ndev || (!test_bit(NCI_UP, &ndev->flags)
-                     && !test_bit(NCI_INIT, &ndev->flags))) {
+       if (!ndev || (!test_bit(NCI_UP, &ndev->flags) &&
+           !test_bit(NCI_INIT, &ndev->flags))) {
                kfree_skb(skb);
                return -ENXIO;
        }
index c1b5285..3568ae1 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "nfc.h"
 
+#include "llcp/llcp.h"
+
 static struct genl_multicast_group nfc_genl_event_mcgrp = {
        .name = NFC_GENL_MCAST_EVENT_NAME,
 };
@@ -364,7 +366,8 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
        if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
            nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
            nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
-           nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up))
+           nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
+           nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
                goto nla_put_failure;
 
        return genlmsg_end(msg, hdr);
@@ -590,7 +593,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
            ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
              !info->attrs[NFC_ATTR_PROTOCOLS]) &&
-            !info->attrs[NFC_ATTR_TM_PROTOCOLS]))
+             !info->attrs[NFC_ATTR_TM_PROTOCOLS]))
                return -EINVAL;
 
        idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
@@ -715,6 +718,146 @@ static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info)
        return rc;
 }
 
+static int nfc_genl_send_params(struct sk_buff *msg,
+                               struct nfc_llcp_local *local,
+                               u32 portid, u32 seq)
+{
+       void *hdr;
+
+       hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, 0,
+                         NFC_CMD_LLC_GET_PARAMS);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, local->dev->idx) ||
+           nla_put_u8(msg, NFC_ATTR_LLC_PARAM_LTO, local->lto) ||
+           nla_put_u8(msg, NFC_ATTR_LLC_PARAM_RW, local->rw) ||
+           nla_put_u16(msg, NFC_ATTR_LLC_PARAM_MIUX, be16_to_cpu(local->miux)))
+               goto nla_put_failure;
+
+       return genlmsg_end(msg, hdr);
+
+nla_put_failure:
+
+       genlmsg_cancel(msg, hdr);
+       return -EMSGSIZE;
+}
+
+static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nfc_dev *dev;
+       struct nfc_llcp_local *local;
+       int rc = 0;
+       struct sk_buff *msg = NULL;
+       u32 idx;
+
+       if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+               return -EINVAL;
+
+       idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+       dev = nfc_get_device(idx);
+       if (!dev)
+               return -ENODEV;
+
+       device_lock(&dev->dev);
+
+       local = nfc_llcp_find_local(dev);
+       if (!local) {
+               rc = -ENODEV;
+               goto exit;
+       }
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg) {
+               rc = -ENOMEM;
+               goto exit;
+       }
+
+       rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq);
+
+exit:
+       device_unlock(&dev->dev);
+
+       nfc_put_device(dev);
+
+       if (rc < 0) {
+               if (msg)
+                       nlmsg_free(msg);
+
+               return rc;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nfc_dev *dev;
+       struct nfc_llcp_local *local;
+       u8 rw = 0;
+       u16 miux = 0;
+       u32 idx;
+       int rc = 0;
+
+       if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+           (!info->attrs[NFC_ATTR_LLC_PARAM_LTO] &&
+            !info->attrs[NFC_ATTR_LLC_PARAM_RW] &&
+            !info->attrs[NFC_ATTR_LLC_PARAM_MIUX]))
+               return -EINVAL;
+
+       if (info->attrs[NFC_ATTR_LLC_PARAM_RW]) {
+               rw = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_RW]);
+
+               if (rw > LLCP_MAX_RW)
+                       return -EINVAL;
+       }
+
+       if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) {
+               miux = nla_get_u16(info->attrs[NFC_ATTR_LLC_PARAM_MIUX]);
+
+               if (miux > LLCP_MAX_MIUX)
+                       return -EINVAL;
+       }
+
+       idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+       dev = nfc_get_device(idx);
+       if (!dev)
+               return -ENODEV;
+
+       device_lock(&dev->dev);
+
+       local = nfc_llcp_find_local(dev);
+       if (!local) {
+               nfc_put_device(dev);
+               rc = -ENODEV;
+               goto exit;
+       }
+
+       if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) {
+               if (dev->dep_link_up) {
+                       rc = -EINPROGRESS;
+                       goto exit;
+               }
+
+               local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]);
+       }
+
+       if (info->attrs[NFC_ATTR_LLC_PARAM_RW])
+               local->rw = rw;
+
+       if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX])
+               local->miux = cpu_to_be16(miux);
+
+exit:
+       device_unlock(&dev->dev);
+
+       nfc_put_device(dev);
+
+       return rc;
+}
+
 static struct genl_ops nfc_genl_ops[] = {
        {
                .cmd = NFC_CMD_GET_DEVICE,
@@ -759,6 +902,16 @@ static struct genl_ops nfc_genl_ops[] = {
                .done = nfc_genl_dump_targets_done,
                .policy = nfc_genl_policy,
        },
+       {
+               .cmd = NFC_CMD_LLC_GET_PARAMS,
+               .doit = nfc_genl_llc_get_params,
+               .policy = nfc_genl_policy,
+       },
+       {
+               .cmd = NFC_CMD_LLC_SET_PARAMS,
+               .doit = nfc_genl_llc_set_params,
+               .policy = nfc_genl_policy,
+       },
 };
 
 
index c5e42b7..87d914d 100644 (file)
@@ -56,6 +56,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev);
 int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len);
 u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
 int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
+struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
 int __init nfc_llcp_init(void);
 void nfc_llcp_exit(void);
 
@@ -97,6 +98,11 @@ static inline int nfc_llcp_data_received(struct nfc_dev *dev,
        return 0;
 }
 
+static inline struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
+{
+       return NULL;
+}
+
 static inline int nfc_llcp_init(void)
 {
        return 0;
index 8b8a6a2..313bf1b 100644 (file)
@@ -256,7 +256,6 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
        return rc ? : copied;
 }
 
-
 static const struct proto_ops rawsock_ops = {
        .family         = PF_NFC,
        .owner          = THIS_MODULE,
index 0f7e0d6..a761670 100644 (file)
@@ -10,11 +10,13 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
 obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
 cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
 
+CFLAGS_trace.o := -I$(src)
+
 ccflags-y += -D__CHECK_ENDIAN__
 
 $(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk
index fcc60d8..e143505 100644 (file)
@@ -3,6 +3,7 @@
 #include <net/cfg80211.h>
 #include "nl80211.h"
 #include "core.h"
+#include "rdev-ops.h"
 
 
 static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
@@ -23,7 +24,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
        if (!wdev->beacon_interval)
                return -ENOENT;
 
-       err = rdev->ops->stop_ap(&rdev->wiphy, dev);
+       err = rdev_stop_ap(rdev, dev);
        if (!err) {
                wdev->beacon_interval = 0;
                wdev->channel = NULL;
index 2f876b9..48febd2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/export.h>
 #include <net/cfg80211.h>
 #include "core.h"
+#include "rdev-ops.h"
 
 struct ieee80211_channel *
 rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
@@ -52,6 +53,8 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
        struct ieee80211_channel *sec_chan;
        int diff;
 
+       trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type);
+
        switch (channel_type) {
        case NL80211_CHAN_HT40PLUS:
                diff = 20;
@@ -60,20 +63,25 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
                diff = -20;
                break;
        default:
+               trace_cfg80211_return_bool(true);
                return true;
        }
 
        sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
-       if (!sec_chan)
+       if (!sec_chan) {
+               trace_cfg80211_return_bool(false);
                return false;
+       }
 
        /* we'll need a DFS capability later */
        if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
                               IEEE80211_CHAN_PASSIVE_SCAN |
                               IEEE80211_CHAN_NO_IBSS |
-                              IEEE80211_CHAN_RADAR))
+                              IEEE80211_CHAN_RADAR)) {
+               trace_cfg80211_return_bool(false);
                return false;
-
+       }
+       trace_cfg80211_return_bool(true);
        return true;
 }
 EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
@@ -92,7 +100,7 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
        if (!chan)
                return -EINVAL;
 
-       return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
+       return rdev_set_monitor_channel(rdev, chan, chantype);
 }
 
 void
index 3f72530..26711f4 100644 (file)
@@ -26,6 +26,7 @@
 #include "debugfs.h"
 #include "wext-compat.h"
 #include "ethtool.h"
+#include "rdev-ops.h"
 
 /* name for sysfs, %d is appended */
 #define PHY_NAME "phy"
@@ -216,7 +217,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
 {
        struct cfg80211_registered_device *rdev = data;
 
-       rdev->ops->rfkill_poll(&rdev->wiphy);
+       rdev_rfkill_poll(rdev);
 }
 
 static int cfg80211_rfkill_set_block(void *data, bool blocked)
@@ -240,7 +241,7 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
                case NL80211_IFTYPE_P2P_DEVICE:
                        if (!wdev->p2p_started)
                                break;
-                       rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
+                       rdev_stop_p2p_device(rdev, wdev);
                        wdev->p2p_started = false;
                        rdev->opencount--;
                        break;
@@ -370,6 +371,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        rdev->wiphy.rts_threshold = (u32) -1;
        rdev->wiphy.coverage_class = 0;
 
+       rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
+
        return &rdev->wiphy;
 }
 EXPORT_SYMBOL(wiphy_new);
@@ -687,7 +690,7 @@ void wiphy_unregister(struct wiphy *wiphy)
        flush_work(&rdev->event_work);
 
        if (rdev->wowlan && rdev->ops->set_wakeup)
-               rdev->ops->set_wakeup(&rdev->wiphy, false);
+               rdev_set_wakeup(rdev, false);
        cfg80211_rdev_free_wowlan(rdev);
 }
 EXPORT_SYMBOL(wiphy_unregister);
@@ -770,7 +773,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
        case NL80211_IFTYPE_P2P_DEVICE:
                if (!wdev->p2p_started)
                        break;
-               rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
+               rdev_stop_p2p_device(rdev, wdev);
                wdev->p2p_started = false;
                rdev->opencount--;
                break;
@@ -961,9 +964,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                if ((wdev->iftype == NL80211_IFTYPE_STATION ||
                     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
                    rdev->ops->set_power_mgmt)
-                       if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
-                                                     wdev->ps,
-                                                     wdev->ps_timeout)) {
+                       if (rdev_set_power_mgmt(rdev, dev, wdev->ps,
+                                               wdev->ps_timeout)) {
                                /* assume this means it's off */
                                wdev->ps = false;
                        }
index a343be4..b8eb743 100644 (file)
@@ -320,13 +320,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx);
+                        const u8 *key, int key_len, int key_idx,
+                        const u8 *sae_data, int sae_data_len);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, struct ieee80211_channel *chan,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx);
+                      const u8 *key, int key_len, int key_idx,
+                      const u8 *sae_data, int sae_data_len);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
                          struct ieee80211_channel *chan,
index 7eecdf4..48c48ff 100644 (file)
@@ -2,6 +2,7 @@
 #include <net/cfg80211.h>
 #include "core.h"
 #include "ethtool.h"
+#include "rdev-ops.h"
 
 static void cfg80211_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *info)
@@ -47,9 +48,8 @@ static void cfg80211_get_ringparam(struct net_device *dev,
        memset(rp, 0, sizeof(*rp));
 
        if (rdev->ops->get_ringparam)
-               rdev->ops->get_ringparam(wdev->wiphy,
-                                        &rp->tx_pending, &rp->tx_max_pending,
-                                        &rp->rx_pending, &rp->rx_max_pending);
+               rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending,
+                                  &rp->rx_pending, &rp->rx_max_pending);
 }
 
 static int cfg80211_set_ringparam(struct net_device *dev,
@@ -62,8 +62,7 @@ static int cfg80211_set_ringparam(struct net_device *dev,
                return -EINVAL;
 
        if (rdev->ops->set_ringparam)
-               return rdev->ops->set_ringparam(wdev->wiphy,
-                                               rp->tx_pending, rp->rx_pending);
+               return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending);
 
        return -ENOTSUPP;
 }
@@ -73,7 +72,7 @@ static int cfg80211_get_sset_count(struct net_device *dev, int sset)
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        if (rdev->ops->get_et_sset_count)
-               return rdev->ops->get_et_sset_count(wdev->wiphy, dev, sset);
+               return rdev_get_et_sset_count(rdev, dev, sset);
        return -EOPNOTSUPP;
 }
 
@@ -83,7 +82,7 @@ static void cfg80211_get_stats(struct net_device *dev,
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        if (rdev->ops->get_et_stats)
-               rdev->ops->get_et_stats(wdev->wiphy, dev, stats, data);
+               rdev_get_et_stats(rdev, dev, stats, data);
 }
 
 static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
@@ -91,7 +90,7 @@ static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        if (rdev->ops->get_et_strings)
-               rdev->ops->get_et_strings(wdev->wiphy, dev, sset, data);
+               rdev_get_et_strings(rdev, dev, sset, data);
 }
 
 const struct ethtool_ops cfg80211_ethtool_ops = {
index ca5672f..27941d5 100644 (file)
@@ -11,6 +11,7 @@
 #include <net/cfg80211.h>
 #include "wext-compat.h"
 #include "nl80211.h"
+#include "rdev-ops.h"
 
 
 void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
@@ -61,6 +62,8 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
        struct cfg80211_event *ev;
        unsigned long flags;
 
+       trace_cfg80211_ibss_joined(dev, bssid);
+
        CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
 
        ev = kzalloc(sizeof(*ev), gfp);
@@ -128,7 +131,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                return err;
        }
 
-       err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
+       err = rdev_join_ibss(rdev, dev, params);
        if (err) {
                wdev->connect_keys = NULL;
                wdev->sme_state = CFG80211_SME_IDLE;
@@ -175,7 +178,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
         */
        if (rdev->ops->del_key)
                for (i = 0; i < 6; i++)
-                       rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
+                       rdev_del_key(rdev, dev, i, false, NULL);
 
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
@@ -211,7 +214,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
        if (!wdev->ssid_len)
                return -ENOLINK;
 
-       err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
+       err = rdev_leave_ibss(rdev, dev);
 
        if (err)
                return err;
index c384e77..966cfc4 100644 (file)
@@ -3,6 +3,7 @@
 #include <net/cfg80211.h>
 #include "nl80211.h"
 #include "core.h"
+#include "rdev-ops.h"
 
 /* Default values, timeouts in ms */
 #define MESH_TTL               31
@@ -160,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        if (err)
                return err;
 
-       err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
+       err = rdev_join_mesh(rdev, dev, conf, setup);
        if (!err) {
                memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
                wdev->mesh_id_len = setup->mesh_id_len;
@@ -220,9 +221,8 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
                if (err)
                        return err;
 
-               err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
-                                                          wdev->netdev,
-                                                          channel);
+               err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
+                                                    channel);
                if (!err)
                        wdev->channel = channel;
 
@@ -242,6 +242,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
 
+       trace_cfg80211_notify_new_peer_candidate(dev, macaddr);
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
                return;
 
@@ -267,7 +268,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
        if (!wdev->mesh_id_len)
                return -ENOTCONN;
 
-       err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
+       err = rdev_leave_mesh(rdev, dev);
        if (!err) {
                wdev->mesh_id_len = 0;
                wdev->channel = NULL;
index 904a7f3..4bfd14f 100644 (file)
@@ -15,6 +15,8 @@
 #include <net/iw_handler.h>
 #include "core.h"
 #include "nl80211.h"
+#include "rdev-ops.h"
+
 
 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
 {
@@ -22,6 +24,7 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_send_rx_auth(dev);
        wdev_lock(wdev);
 
        nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
@@ -42,6 +45,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
        u8 *ie = mgmt->u.assoc_resp.variable;
        int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
 
+       trace_cfg80211_send_rx_assoc(dev, bss);
        wdev_lock(wdev);
 
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -98,6 +102,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
        const u8 *bssid = mgmt->bssid;
        bool was_current = false;
 
+       trace___cfg80211_send_deauth(dev);
        ASSERT_WDEV_LOCK(wdev);
 
        if (wdev->current_bss &&
@@ -147,6 +152,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
        u16 reason_code;
        bool from_ap;
 
+       trace___cfg80211_send_disassoc(dev);
        ASSERT_WDEV_LOCK(wdev);
 
        nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
@@ -188,6 +194,7 @@ void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_send_unprot_deauth(dev);
        nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
@@ -199,6 +206,7 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_send_unprot_disassoc(dev);
        nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
@@ -209,6 +217,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_send_auth_timeout(dev, addr);
        wdev_lock(wdev);
 
        nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
@@ -227,6 +236,7 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_send_assoc_timeout(dev, addr);
        wdev_lock(wdev);
 
        nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
@@ -261,6 +271,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
        }
 #endif
 
+       trace_cfg80211_michael_mic_failure(dev, addr, key_type, key_id, tsc);
        nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
 }
 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
@@ -273,7 +284,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx)
+                        const u8 *key, int key_len, int key_idx,
+                        const u8 *sae_data, int sae_data_len)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_auth_request req;
@@ -293,6 +305,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 
        req.ie = ie;
        req.ie_len = ie_len;
+       req.sae_data = sae_data;
+       req.sae_data_len = sae_data_len;
        req.auth_type = auth_type;
        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
                                   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@@ -307,7 +321,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        if (err)
                goto out;
 
-       err = rdev->ops->auth(&rdev->wiphy, dev, &req);
+       err = rdev_auth(rdev, dev, &req);
 
 out:
        cfg80211_put_bss(req.bss);
@@ -319,7 +333,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx)
+                      const u8 *key, int key_len, int key_idx,
+                      const u8 *sae_data, int sae_data_len)
 {
        int err;
 
@@ -327,7 +342,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                   ssid, ssid_len, ie, ie_len,
-                                  key, key_len, key_idx);
+                                  key, key_len, key_idx,
+                                  sae_data, sae_data_len);
        wdev_unlock(dev->ieee80211_ptr);
        mutex_unlock(&rdev->devlist_mtx);
 
@@ -410,7 +426,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        if (err)
                goto out;
 
-       err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
+       err = rdev_assoc(rdev, dev, &req);
 
 out:
        if (err) {
@@ -466,7 +482,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
            !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
                return 0;
 
-       return rdev->ops->deauth(&rdev->wiphy, dev, &req);
+       return rdev_deauth(rdev, dev, &req);
 }
 
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
@@ -511,7 +527,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
        else
                return -ENOTCONN;
 
-       return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
+       return rdev_disassoc(rdev, dev, &req);
 }
 
 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
@@ -552,7 +568,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
 
        memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
        req.bssid = bssid;
-       rdev->ops->deauth(&rdev->wiphy, dev, &req);
+       rdev_deauth(rdev, dev, &req);
 
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
@@ -569,6 +585,8 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type,
+                                       duration);
        nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type,
                                       duration, gfp);
 }
@@ -582,6 +600,8 @@ void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan,
+                                               channel_type);
        nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan,
                                              channel_type, gfp);
 }
@@ -593,6 +613,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_new_sta(dev, mac_addr, sinfo);
        nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
 }
 EXPORT_SYMBOL(cfg80211_new_sta);
@@ -602,6 +623,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_del_sta(dev, mac_addr);
        nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp);
 }
 EXPORT_SYMBOL(cfg80211_del_sta);
@@ -682,7 +704,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
        list_add(&nreg->list, &wdev->mgmt_registrations);
 
        if (rdev->ops->mgmt_frame_register)
-               rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true);
+               rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
 
  out:
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
@@ -705,8 +727,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
                if (rdev->ops->mgmt_frame_register) {
                        u16 frame_type = le16_to_cpu(reg->frame_type);
 
-                       rdev->ops->mgmt_frame_register(wiphy, wdev,
-                                                      frame_type, false);
+                       rdev_mgmt_frame_register(rdev, wdev,
+                                                frame_type, false);
                }
 
                list_del(&reg->list);
@@ -832,10 +854,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        /* Transmit the Action frame as requested by user space */
-       return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
-                                 channel_type, channel_type_valid,
-                                 wait, buf, len, no_cck, dont_wait_for_ack,
-                                 cookie);
+       return rdev_mgmt_tx(rdev, wdev, chan, offchan,
+                           channel_type, channel_type_valid,
+                           wait, buf, len, no_cck, dont_wait_for_ack,
+                           cookie);
 }
 
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
@@ -854,10 +876,13 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
                cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
        u16 stype;
 
+       trace_cfg80211_rx_mgmt(wdev, freq, sig_mbm);
        stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
 
-       if (!(stypes->rx & BIT(stype)))
+       if (!(stypes->rx & BIT(stype))) {
+               trace_cfg80211_return_bool(false);
                return false;
+       }
 
        data = buf + ieee80211_hdrlen(mgmt->frame_control);
        data_len = len - ieee80211_hdrlen(mgmt->frame_control);
@@ -888,6 +913,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
 
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
 
+       trace_cfg80211_return_bool(result);
        return result;
 }
 EXPORT_SYMBOL(cfg80211_rx_mgmt);
@@ -898,6 +924,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
+
        /* Indicate TX status of the Action frame to user space */
        nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp);
 }
@@ -911,6 +939,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+
        /* Indicate roaming trigger event to user space */
        nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
 }
@@ -923,6 +953,8 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
+
        /* Indicate roaming trigger event to user space */
        nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
 }
@@ -948,6 +980,7 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_gtk_rekey_notify(dev, bssid);
        nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
 }
 EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
@@ -959,6 +992,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
        nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
@@ -971,6 +1005,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct ieee80211_channel *chan;
 
+       trace_cfg80211_ch_switch_notify(dev, freq, type);
+
        wdev_lock(wdev);
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
@@ -993,12 +1029,18 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev,
                                const u8 *addr, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       bool ret;
+
+       trace_cfg80211_rx_spurious_frame(dev, addr);
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
+               trace_cfg80211_return_bool(false);
                return false;
-
-       return nl80211_unexpected_frame(dev, addr, gfp);
+       }
+       ret = nl80211_unexpected_frame(dev, addr, gfp);
+       trace_cfg80211_return_bool(ret);
+       return ret;
 }
 EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
 
@@ -1006,12 +1048,18 @@ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
                                        const u8 *addr, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       bool ret;
+
+       trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
                    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
-                   wdev->iftype != NL80211_IFTYPE_AP_VLAN))
+                   wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
+               trace_cfg80211_return_bool(false);
                return false;
-
-       return nl80211_unexpected_4addr_frame(dev, addr, gfp);
+       }
+       ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
+       trace_cfg80211_return_bool(ret);
+       return ret;
 }
 EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
index 0418a6d..8c08578 100644 (file)
@@ -22,8 +22,8 @@
 #include "core.h"
 #include "nl80211.h"
 #include "reg.h"
+#include "rdev-ops.h"
 
-static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type);
 static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
                                   struct genl_info *info,
                                   struct cfg80211_crypto_settings *settings,
@@ -355,6 +355,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
        [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
        [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
+       [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
+       [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
+       [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
 };
 
 /* policy for the key attributes */
@@ -690,7 +693,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
 
 static struct cfg80211_cached_keys *
 nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
-                      struct nlattr *keys)
+                      struct nlattr *keys, bool *no_ht)
 {
        struct key_parse parse;
        struct nlattr *key;
@@ -733,6 +736,12 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
                result->params[parse.idx].key_len = parse.p.key_len;
                result->params[parse.idx].key = result->data[parse.idx];
                memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
+
+               if (parse.p.cipher == WLAN_CIPHER_SUITE_WEP40 ||
+                   parse.p.cipher == WLAN_CIPHER_SUITE_WEP104) {
+                       if (no_ht)
+                               *no_ht = true;
+               }
        }
 
        return result;
@@ -943,7 +952,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag
             dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
                u32 tx_ant = 0, rx_ant = 0;
                int res;
-               res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant);
+               res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
                if (!res) {
                        if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX,
                                        tx_ant) ||
@@ -1457,7 +1466,7 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
                return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
-       return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid);
+       return rdev_set_wds_peer(rdev, dev, bssid);
 }
 
 
@@ -1562,9 +1571,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        if (result)
                                goto bad_res;
 
-                       result = rdev->ops->set_txq_params(&rdev->wiphy,
-                                                          netdev,
-                                                          &txq_params);
+                       result = rdev_set_txq_params(rdev, netdev,
+                                                    &txq_params);
                        if (result)
                                goto bad_res;
                }
@@ -1599,7 +1607,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        mbm = nla_get_u32(info->attrs[idx]);
                }
 
-               result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
+               result = rdev_set_tx_power(rdev, type, mbm);
                if (result)
                        goto bad_res;
        }
@@ -1628,7 +1636,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
                rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
 
-               result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant);
+               result = rdev_set_antenna(rdev, tx_ant, rx_ant);
                if (result)
                        goto bad_res;
        }
@@ -1713,7 +1721,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                if (changed & WIPHY_PARAM_COVERAGE_CLASS)
                        rdev->wiphy.coverage_class = coverage_class;
 
-               result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed);
+               result = rdev_set_wiphy_params(rdev, changed);
                if (result) {
                        rdev->wiphy.retry_short = old_retry_short;
                        rdev->wiphy.retry_long = old_retry_long;
@@ -1765,8 +1773,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
                struct ieee80211_channel *chan;
                enum nl80211_channel_type channel_type;
 
-               chan = rdev->ops->get_channel(&rdev->wiphy, wdev,
-                                             &channel_type);
+               chan = rdev_get_channel(rdev, wdev, &channel_type);
                if (chan &&
                    (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
                                 chan->center_freq) ||
@@ -2014,9 +2021,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
-       wdev = rdev->ops->add_virtual_intf(&rdev->wiphy,
-               nla_data(info->attrs[NL80211_ATTR_IFNAME]),
-               type, err ? NULL : &flags, &params);
+       wdev = rdev_add_virtual_intf(rdev,
+                               nla_data(info->attrs[NL80211_ATTR_IFNAME]),
+                               type, err ? NULL : &flags, &params);
        if (IS_ERR(wdev)) {
                nlmsg_free(msg);
                return PTR_ERR(wdev);
@@ -2083,7 +2090,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
        if (!wdev->netdev)
                info->user_ptr[1] = NULL;
 
-       return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev);
+       return rdev_del_virtual_intf(rdev, wdev);
 }
 
 static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
@@ -2100,7 +2107,7 @@ static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
 
        noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
 
-       return rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map);
+       return rdev_set_noack_map(rdev, dev, noack_map);
 }
 
 struct get_key_cookie {
@@ -2210,8 +2217,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
            !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
                return -ENOENT;
 
-       err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise,
-                                mac_addr, &cookie, get_key_callback);
+       err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
+                          get_key_callback);
 
        if (err)
                goto free_msg;
@@ -2259,7 +2266,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
                if (err)
                        goto out;
 
-               err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx,
+               err = rdev_set_default_key(rdev, dev, key.idx,
                                                 key.def_uni, key.def_multi);
 
                if (err)
@@ -2283,8 +2290,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
                if (err)
                        goto out;
 
-               err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
-                                                     dev, key.idx);
+               err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
                if (err)
                        goto out;
 
@@ -2340,9 +2346,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
        if (!err)
-               err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
-                                        key.type == NL80211_KEYTYPE_PAIRWISE,
-                                        mac_addr, &key.p);
+               err = rdev_add_key(rdev, dev, key.idx,
+                                  key.type == NL80211_KEYTYPE_PAIRWISE,
+                                   mac_addr, &key.p);
        wdev_unlock(dev->ieee80211_ptr);
 
        return err;
@@ -2386,9 +2392,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
                err = -ENOENT;
 
        if (!err)
-               err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx,
-                                        key.type == NL80211_KEYTYPE_PAIRWISE,
-                                        mac_addr);
+               err = rdev_del_key(rdev, dev, key.idx,
+                                  key.type == NL80211_KEYTYPE_PAIRWISE,
+                                  mac_addr);
 
 #ifdef CONFIG_CFG80211_WEXT
        if (!err) {
@@ -2490,6 +2496,30 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
+                                   enum nl80211_auth_type auth_type,
+                                   enum nl80211_commands cmd)
+{
+       if (auth_type > NL80211_AUTHTYPE_MAX)
+               return false;
+
+       switch (cmd) {
+       case NL80211_CMD_AUTHENTICATE:
+               if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
+                   auth_type == NL80211_AUTHTYPE_SAE)
+                       return false;
+               return true;
+       case NL80211_CMD_CONNECT:
+       case NL80211_CMD_START_AP:
+               /* SAE not supported yet */
+               if (auth_type == NL80211_AUTHTYPE_SAE)
+                       return false;
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -2559,7 +2589,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
                params.auth_type = nla_get_u32(
                        info->attrs[NL80211_ATTR_AUTH_TYPE]);
-               if (!nl80211_valid_auth_type(params.auth_type))
+               if (!nl80211_valid_auth_type(rdev, params.auth_type,
+                                            NL80211_CMD_START_AP))
                        return -EINVAL;
        } else
                params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@@ -2607,7 +2638,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
-       err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
+       err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
                wdev->preset_chan = params.channel;
                wdev->preset_chantype = params.channel_type;
@@ -2639,7 +2670,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
-       return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
+       return rdev_change_beacon(rdev, dev, &params);
 }
 
 static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
@@ -2923,8 +2954,8 @@ static int nl80211_dump_station(struct sk_buff *skb,
 
        while (1) {
                memset(&sinfo, 0, sizeof(sinfo));
-               err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
-                                            mac_addr, &sinfo);
+               err = rdev_dump_station(dev, netdev, sta_idx,
+                                       mac_addr, &sinfo);
                if (err == -ENOENT)
                        break;
                if (err)
@@ -2969,7 +3000,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->get_station)
                return -EOPNOTSUPP;
 
-       err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
+       err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
        if (err)
                return err;
 
@@ -3146,7 +3177,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 
        /* be aware of params.vlan when changing code here */
 
-       err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, &params);
+       err = rdev_change_station(rdev, dev, mac_addr, &params);
 
        if (params.vlan)
                dev_put(params.vlan);
@@ -3198,6 +3229,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                params.ht_capa =
                        nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
 
+       if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
+               params.vht_capa =
+                       nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
+
        if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
                params.plink_action =
                    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
@@ -3275,7 +3310,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 
        /* be aware of params.vlan when changing code here */
 
-       err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
+       err = rdev_add_station(rdev, dev, mac_addr, &params);
 
        if (params.vlan)
                dev_put(params.vlan);
@@ -3300,7 +3335,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->del_station)
                return -EOPNOTSUPP;
 
-       return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
+       return rdev_del_station(rdev, dev, mac_addr);
 }
 
 static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
@@ -3382,8 +3417,8 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        }
 
        while (1) {
-               err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
-                                          dst, next_hop, &pinfo);
+               err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop,
+                                     &pinfo);
                if (err == -ENOENT)
                        break;
                if (err)
@@ -3430,7 +3465,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
                return -EOPNOTSUPP;
 
-       err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
+       err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
        if (err)
                return err;
 
@@ -3469,7 +3504,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
                return -EOPNOTSUPP;
 
-       return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
+       return rdev_change_mpath(rdev, dev, dst, next_hop);
 }
 
 static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
@@ -3494,7 +3529,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
                return -EOPNOTSUPP;
 
-       return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
+       return rdev_add_mpath(rdev, dev, dst, next_hop);
 }
 
 static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
@@ -3509,7 +3544,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->del_mpath)
                return -EOPNOTSUPP;
 
-       return rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
+       return rdev_del_mpath(rdev, dev, dst);
 }
 
 static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
@@ -3554,7 +3589,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
 
-       return rdev->ops->change_bss(&rdev->wiphy, dev, &params);
+       return rdev_change_bss(rdev, dev, &params);
 }
 
 static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@@ -3668,8 +3703,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
        if (!wdev->mesh_id_len)
                memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
        else
-               err = rdev->ops->get_mesh_config(&rdev->wiphy, dev,
-                                                &cur_params);
+               err = rdev_get_mesh_config(rdev, dev, &cur_params);
        wdev_unlock(wdev);
 
        if (err)
@@ -3971,8 +4005,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb,
                err = -ENOLINK;
 
        if (!err)
-               err = rdev->ops->update_mesh_config(&rdev->wiphy, dev,
-                                                   mask, &cfg);
+               err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
 
        wdev_unlock(wdev);
 
@@ -4337,14 +4370,27 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+       if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
+               request->flags = nla_get_u32(
+                       info->attrs[NL80211_ATTR_SCAN_FLAGS]);
+               if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+                    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
+                   ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
+                    !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
+                       err = -EOPNOTSUPP;
+                       goto out_free;
+               }
+       }
+
        request->no_cck =
                nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
        request->wdev = wdev;
        request->wiphy = &rdev->wiphy;
+       request->scan_start = jiffies;
 
        rdev->scan_req = request;
-       err = rdev->ops->scan(&rdev->wiphy, request);
+       err = rdev_scan(rdev, request);
 
        if (!err) {
                nl80211_send_scan_start(rdev, wdev);
@@ -4568,11 +4614,24 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                       request->ie_len);
        }
 
+       if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
+               request->flags = nla_get_u32(
+                       info->attrs[NL80211_ATTR_SCAN_FLAGS]);
+               if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+                    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
+                   ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
+                    !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
+                       err = -EOPNOTSUPP;
+                       goto out_free;
+               }
+       }
+
        request->dev = dev;
        request->wiphy = &rdev->wiphy;
        request->interval = interval;
+       request->scan_start = jiffies;
 
-       err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
+       err = rdev_sched_scan_start(rdev, dev, request);
        if (!err) {
                rdev->sched_scan_req = request;
                nl80211_send_sched_scan(rdev, dev,
@@ -4815,8 +4874,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        while (1) {
                struct ieee80211_channel *chan;
 
-               res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
-                                           &survey);
+               res = rdev_dump_survey(dev, netdev, survey_idx, &survey);
                if (res == -ENOENT)
                        break;
                if (res)
@@ -4852,11 +4910,6 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        return res;
 }
 
-static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
-{
-       return auth_type <= NL80211_AUTHTYPE_MAX;
-}
-
 static bool nl80211_valid_wpa_versions(u32 wpa_versions)
 {
        return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
@@ -4868,8 +4921,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
-       const u8 *bssid, *ssid, *ie = NULL;
-       int err, ssid_len, ie_len = 0;
+       const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
+       int err, ssid_len, ie_len = 0, sae_data_len = 0;
        enum nl80211_auth_type auth_type;
        struct key_parse key;
        bool local_state_change;
@@ -4945,9 +4998,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        }
 
        auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
-       if (!nl80211_valid_auth_type(auth_type))
+       if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
                return -EINVAL;
 
+       if (auth_type == NL80211_AUTHTYPE_SAE &&
+           !info->attrs[NL80211_ATTR_SAE_DATA])
+               return -EINVAL;
+
+       if (info->attrs[NL80211_ATTR_SAE_DATA]) {
+               if (auth_type != NL80211_AUTHTYPE_SAE)
+                       return -EINVAL;
+               sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
+               sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
+               /* need to include at least Auth Transaction and Status Code */
+               if (sae_data_len < 4)
+                       return -EINVAL;
+       }
+
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
        /*
@@ -4959,7 +5026,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 
        return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                  ssid, ssid_len, ie, ie_len,
-                                 key.p.key, key.p.key_len, key.idx);
+                                 key.p.key, key.p.key_len, key.idx,
+                                 sae_data, sae_data_len);
 }
 
 static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
@@ -5339,10 +5407,18 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+               bool no_ht = false;
+
                connkeys = nl80211_parse_connkeys(rdev,
-                                       info->attrs[NL80211_ATTR_KEYS]);
+                                         info->attrs[NL80211_ATTR_KEYS],
+                                         &no_ht);
                if (IS_ERR(connkeys))
                        return PTR_ERR(connkeys);
+
+               if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) {
+                       kfree(connkeys);
+                       return -EINVAL;
+               }
        }
 
        ibss.control_port =
@@ -5384,7 +5460,7 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
        err = -EOPNOTSUPP;
        if (rdev->ops->testmode_cmd) {
                rdev->testmode_info = info;
-               err = rdev->ops->testmode_cmd(&rdev->wiphy,
+               err = rdev_testmode_cmd(rdev,
                                nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
                                nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
                rdev->testmode_info = NULL;
@@ -5466,8 +5542,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
                        genlmsg_cancel(skb, hdr);
                        break;
                }
-               err = rdev->ops->testmode_dump(&rdev->wiphy, skb, cb,
-                                              data, data_len);
+               err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
                nla_nest_end(skb, tmdata);
 
                if (err == -ENOBUFS || err == -ENOENT) {
@@ -5596,7 +5671,8 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
                connect.auth_type =
                        nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
-               if (!nl80211_valid_auth_type(connect.auth_type))
+               if (!nl80211_valid_auth_type(rdev, connect.auth_type,
+                                            NL80211_CMD_CONNECT))
                        return -EINVAL;
        } else
                connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@@ -5642,7 +5718,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 
        if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
                connkeys = nl80211_parse_connkeys(rdev,
-                                       info->attrs[NL80211_ATTR_KEYS]);
+                                         info->attrs[NL80211_ATTR_KEYS], NULL);
                if (IS_ERR(connkeys))
                        return PTR_ERR(connkeys);
        }
@@ -5771,7 +5847,7 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->flush_pmksa)
                return -EOPNOTSUPP;
 
-       return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
+       return rdev_flush_pmksa(rdev, dev);
 }
 
 static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
@@ -5798,10 +5874,10 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
        status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
        dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
 
-       return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
-                                   dialog_token, status_code,
-                                   nla_data(info->attrs[NL80211_ATTR_IE]),
-                                   nla_len(info->attrs[NL80211_ATTR_IE]));
+       return rdev_tdls_mgmt(rdev, dev, peer, action_code,
+                             dialog_token, status_code,
+                             nla_data(info->attrs[NL80211_ATTR_IE]),
+                             nla_len(info->attrs[NL80211_ATTR_IE]));
 }
 
 static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
@@ -5822,7 +5898,7 @@ static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
        operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
        peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation);
+       return rdev_tdls_oper(rdev, dev, peer, operation);
 }
 
 static int nl80211_remain_on_channel(struct sk_buff *skb,
@@ -5877,8 +5953,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
                goto free_msg;
        }
 
-       err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
-                                          channel_type, duration, &cookie);
+       err = rdev_remain_on_channel(rdev, wdev, chan, channel_type, duration,
+                                    &cookie);
 
        if (err)
                goto free_msg;
@@ -5912,7 +5988,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
 
        cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
 
-       return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
+       return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
 }
 
 static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
@@ -6055,7 +6131,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
                }
        }
 
-       return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
+       return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
 }
 
 static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
@@ -6230,7 +6306,7 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in
 
        cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
 
-       return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
+       return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
 }
 
 static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
@@ -6260,8 +6336,7 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
        if (state == wdev->ps)
                return 0;
 
-       err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state,
-                                       wdev->ps_timeout);
+       err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
        if (!err)
                wdev->ps = state;
        return err;
@@ -6341,8 +6416,7 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
            wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
                return -EOPNOTSUPP;
 
-       return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev,
-                                            rate, pkts, intvl);
+       return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
 }
 
 static int nl80211_set_cqm_rssi(struct genl_info *info,
@@ -6364,8 +6438,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
            wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
                return -EOPNOTSUPP;
 
-       return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
-                                             threshold, hysteresis);
+       return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
 }
 
 static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@@ -6690,7 +6763,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
 
  set_wakeup:
        if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
-               rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
+               rdev_set_wakeup(rdev, rdev->wowlan);
 
        return 0;
  error:
@@ -6746,7 +6819,7 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data);
+       err = rdev_set_rekey_data(rdev, dev, &rekey_data);
  out:
        wdev_unlock(wdev);
        return err;
@@ -6805,7 +6878,7 @@ static int nl80211_probe_client(struct sk_buff *skb,
 
        addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
+       err = rdev_probe_client(rdev, dev, addr, &cookie);
        if (err)
                goto free_msg;
 
@@ -6859,7 +6932,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
-       err = rdev->ops->start_p2p_device(&rdev->wiphy, wdev);
+       err = rdev_start_p2p_device(rdev, wdev);
        if (err)
                return err;
 
@@ -6885,7 +6958,7 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
        if (!wdev->p2p_started)
                return 0;
 
-       rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
+       rdev_stop_p2p_device(rdev, wdev);
        wdev->p2p_started = false;
 
        mutex_lock(&rdev->devlist_mtx);
@@ -7622,6 +7695,9 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
            nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
                goto nla_put_failure;
 
+       if (req->flags)
+               nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags);
+
        return 0;
  nla_put_failure:
        return -ENOBUFS;
@@ -8800,7 +8876,10 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
        void *hdr;
        int err;
 
+       trace_cfg80211_probe_status(dev, addr, cookie, acked);
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+
        if (!msg)
                return;
 
@@ -8842,6 +8921,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
        void *hdr;
        u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid);
 
+       trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
+
        if (!nlportid)
                return;
 
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
new file mode 100644 (file)
index 0000000..eb5f897
--- /dev/null
@@ -0,0 +1,879 @@
+#ifndef __CFG80211_RDEV_OPS
+#define __CFG80211_RDEV_OPS
+
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+#include "core.h"
+#include "trace.h"
+
+static inline int rdev_suspend(struct cfg80211_registered_device *rdev)
+{
+       int ret;
+       trace_rdev_suspend(&rdev->wiphy, rdev->wowlan);
+       ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_resume(struct cfg80211_registered_device *rdev)
+{
+       int ret;
+       trace_rdev_resume(&rdev->wiphy);
+       ret = rdev->ops->resume(&rdev->wiphy);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev,
+                                  bool enabled)
+{
+       trace_rdev_set_wakeup(&rdev->wiphy, enabled);
+       rdev->ops->set_wakeup(&rdev->wiphy, enabled);
+       trace_rdev_return_void(&rdev->wiphy);
+}
+
+static inline struct wireless_dev
+*rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name,
+                      enum nl80211_iftype type, u32 *flags,
+                      struct vif_params *params)
+{
+       struct wireless_dev *ret;
+       trace_rdev_add_virtual_intf(&rdev->wiphy, name, type);
+       ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags,
+                                         params);
+       trace_rdev_return_wdev(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_del_virtual_intf(struct cfg80211_registered_device *rdev,
+                     struct wireless_dev *wdev)
+{
+       int ret;
+       trace_rdev_del_virtual_intf(&rdev->wiphy, wdev);
+       ret = rdev->ops->del_virtual_intf(&rdev->wiphy, wdev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_change_virtual_intf(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev, enum nl80211_iftype type,
+                        u32 *flags, struct vif_params *params)
+{
+       int ret;
+       trace_rdev_change_virtual_intf(&rdev->wiphy, dev, type);
+       ret = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, flags,
+                                            params);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev, u8 key_index,
+                              bool pairwise, const u8 *mac_addr,
+                              struct key_params *params)
+{
+       int ret;
+       trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
+       ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise,
+                                 mac_addr, params);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_get_key(struct cfg80211_registered_device *rdev, struct net_device *netdev,
+            u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie,
+            void (*callback)(void *cookie, struct key_params*))
+{
+       int ret;
+       trace_rdev_get_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
+       ret = rdev->ops->get_key(&rdev->wiphy, netdev, key_index, pairwise,
+                                 mac_addr, cookie, callback);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_del_key(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev, u8 key_index,
+                              bool pairwise, const u8 *mac_addr)
+{
+       int ret;
+       trace_rdev_del_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
+       ret = rdev->ops->del_key(&rdev->wiphy, netdev, key_index, pairwise,
+                                 mac_addr);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_set_default_key(struct cfg80211_registered_device *rdev,
+                    struct net_device *netdev, u8 key_index, bool unicast,
+                    bool multicast)
+{
+       int ret;
+       trace_rdev_set_default_key(&rdev->wiphy, netdev, key_index,
+                                  unicast, multicast);
+       ret = rdev->ops->set_default_key(&rdev->wiphy, netdev, key_index,
+                                         unicast, multicast);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_set_default_mgmt_key(struct cfg80211_registered_device *rdev,
+                         struct net_device *netdev, u8 key_index)
+{
+       int ret;
+       trace_rdev_set_default_mgmt_key(&rdev->wiphy, netdev, key_index);
+       ret = rdev->ops->set_default_mgmt_key(&rdev->wiphy, netdev,
+                                              key_index);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_start_ap(struct cfg80211_registered_device *rdev,
+                               struct net_device *dev,
+                               struct cfg80211_ap_settings *settings)
+{
+       int ret;
+       trace_rdev_start_ap(&rdev->wiphy, dev, settings);
+       ret = rdev->ops->start_ap(&rdev->wiphy, dev, settings);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_change_beacon(struct cfg80211_registered_device *rdev,
+                                    struct net_device *dev,
+                                    struct cfg80211_beacon_data *info)
+{
+       int ret;
+       trace_rdev_change_beacon(&rdev->wiphy, dev, info);
+       ret = rdev->ops->change_beacon(&rdev->wiphy, dev, info);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev,
+                              struct net_device *dev)
+{
+       int ret;
+       trace_rdev_stop_ap(&rdev->wiphy, dev);
+       ret = rdev->ops->stop_ap(&rdev->wiphy, dev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_add_station(struct cfg80211_registered_device *rdev,
+                                  struct net_device *dev, u8 *mac,
+                                  struct station_parameters *params)
+{
+       int ret;
+       trace_rdev_add_station(&rdev->wiphy, dev, mac, params);
+       ret = rdev->ops->add_station(&rdev->wiphy, dev, mac, params);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_del_station(struct cfg80211_registered_device *rdev,
+                                  struct net_device *dev, u8 *mac)
+{
+       int ret;
+       trace_rdev_del_station(&rdev->wiphy, dev, mac);
+       ret = rdev->ops->del_station(&rdev->wiphy, dev, mac);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_change_station(struct cfg80211_registered_device *rdev,
+                                     struct net_device *dev, u8 *mac,
+                                     struct station_parameters *params)
+{
+       int ret;
+       trace_rdev_change_station(&rdev->wiphy, dev, mac, params);
+       ret = rdev->ops->change_station(&rdev->wiphy, dev, mac, params);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_get_station(struct cfg80211_registered_device *rdev,
+                                  struct net_device *dev, u8 *mac,
+                                  struct station_info *sinfo)
+{
+       int ret;
+       trace_rdev_get_station(&rdev->wiphy, dev, mac);
+       ret = rdev->ops->get_station(&rdev->wiphy, dev, mac, sinfo);
+       trace_rdev_return_int_station_info(&rdev->wiphy, ret, sinfo);
+       return ret;
+}
+
+static inline int rdev_dump_station(struct cfg80211_registered_device *rdev,
+                                   struct net_device *dev, int idx, u8 *mac,
+                                   struct station_info *sinfo)
+{
+       int ret;
+       trace_rdev_dump_station(&rdev->wiphy, dev, idx, mac);
+       ret = rdev->ops->dump_station(&rdev->wiphy, dev, idx, mac, sinfo);
+       trace_rdev_return_int_station_info(&rdev->wiphy, ret, sinfo);
+       return ret;
+}
+
+static inline int rdev_add_mpath(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev, u8 *dst, u8 *next_hop)
+{
+       int ret;
+       trace_rdev_add_mpath(&rdev->wiphy, dev, dst, next_hop);
+       ret = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_del_mpath(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev, u8 *dst)
+{
+       int ret;
+       trace_rdev_del_mpath(&rdev->wiphy, dev, dst);
+       ret = rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_change_mpath(struct cfg80211_registered_device *rdev,
+                                   struct net_device *dev, u8 *dst,
+                                   u8 *next_hop)
+{
+       int ret;
+       trace_rdev_change_mpath(&rdev->wiphy, dev, dst, next_hop);
+       ret = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev, u8 *dst, u8 *next_hop,
+                                struct mpath_info *pinfo)
+{
+       int ret;
+       trace_rdev_get_mpath(&rdev->wiphy, dev, dst, next_hop);
+       ret = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, pinfo);
+       trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+       return ret;
+
+}
+
+static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
+                                 struct net_device *dev, int idx, u8 *dst,
+                                 u8 *next_hop, struct mpath_info *pinfo)
+
+{
+       int ret;
+       trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
+       ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
+                                    pinfo);
+       trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+       return ret;
+}
+
+static inline int
+rdev_get_mesh_config(struct cfg80211_registered_device *rdev,
+                    struct net_device *dev, struct mesh_config *conf)
+{
+       int ret;
+       trace_rdev_get_mesh_config(&rdev->wiphy, dev);
+       ret = rdev->ops->get_mesh_config(&rdev->wiphy, dev, conf);
+       trace_rdev_return_int_mesh_config(&rdev->wiphy, ret, conf);
+       return ret;
+}
+
+static inline int
+rdev_update_mesh_config(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev, u32 mask,
+                       const struct mesh_config *nconf)
+{
+       int ret;
+       trace_rdev_update_mesh_config(&rdev->wiphy, dev, mask, nconf);
+       ret = rdev->ops->update_mesh_config(&rdev->wiphy, dev, mask, nconf);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_join_mesh(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev,
+                                const struct mesh_config *conf,
+                                const struct mesh_setup *setup)
+{
+       int ret;
+       trace_rdev_join_mesh(&rdev->wiphy, dev, conf, setup);
+       ret = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+
+static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev,
+                                 struct net_device *dev)
+{
+       int ret;
+       trace_rdev_leave_mesh(&rdev->wiphy, dev);
+       ret = rdev->ops->leave_mesh(&rdev->wiphy, dev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_change_bss(struct cfg80211_registered_device *rdev,
+                                 struct net_device *dev,
+                                 struct bss_parameters *params)
+
+{
+       int ret;
+       trace_rdev_change_bss(&rdev->wiphy, dev, params);
+       ret = rdev->ops->change_bss(&rdev->wiphy, dev, params);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_set_txq_params(struct cfg80211_registered_device *rdev,
+                                     struct net_device *dev,
+                                     struct ieee80211_txq_params *params)
+
+{
+       int ret;
+       trace_rdev_set_txq_params(&rdev->wiphy, dev, params);
+       ret = rdev->ops->set_txq_params(&rdev->wiphy, dev, params);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev,
+                              struct net_device *dev,
+                              struct ieee80211_channel *chan)
+{
+       int ret;
+       trace_rdev_libertas_set_mesh_channel(&rdev->wiphy, dev, chan);
+       ret = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, dev, chan);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
+                        struct ieee80211_channel *chan,
+                        enum nl80211_channel_type channel_type)
+{
+       int ret;
+       trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type);
+       ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_scan(struct cfg80211_registered_device *rdev,
+                           struct cfg80211_scan_request *request)
+{
+       int ret;
+       trace_rdev_scan(&rdev->wiphy, request);
+       ret = rdev->ops->scan(&rdev->wiphy, request);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_auth(struct cfg80211_registered_device *rdev,
+                           struct net_device *dev,
+                           struct cfg80211_auth_request *req)
+{
+       int ret;
+       trace_rdev_auth(&rdev->wiphy, dev, req);
+       ret = rdev->ops->auth(&rdev->wiphy, dev, req);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_assoc(struct cfg80211_registered_device *rdev,
+                            struct net_device *dev,
+                            struct cfg80211_assoc_request *req)
+{
+       int ret;
+       trace_rdev_assoc(&rdev->wiphy, dev, req);
+       ret = rdev->ops->assoc(&rdev->wiphy, dev, req);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_deauth(struct cfg80211_registered_device *rdev,
+                             struct net_device *dev,
+                             struct cfg80211_deauth_request *req)
+{
+       int ret;
+       trace_rdev_deauth(&rdev->wiphy, dev, req);
+       ret = rdev->ops->deauth(&rdev->wiphy, dev, req);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_disassoc(struct cfg80211_registered_device *rdev,
+                               struct net_device *dev,
+                               struct cfg80211_disassoc_request *req)
+{
+       int ret;
+       trace_rdev_disassoc(&rdev->wiphy, dev, req);
+       ret = rdev->ops->disassoc(&rdev->wiphy, dev, req);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_connect(struct cfg80211_registered_device *rdev,
+                              struct net_device *dev,
+                              struct cfg80211_connect_params *sme)
+{
+       int ret;
+       trace_rdev_connect(&rdev->wiphy, dev, sme);
+       ret = rdev->ops->connect(&rdev->wiphy, dev, sme);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_disconnect(struct cfg80211_registered_device *rdev,
+                                 struct net_device *dev, u16 reason_code)
+{
+       int ret;
+       trace_rdev_disconnect(&rdev->wiphy, dev, reason_code);
+       ret = rdev->ops->disconnect(&rdev->wiphy, dev, reason_code);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_join_ibss(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev,
+                                struct cfg80211_ibss_params *params)
+{
+       int ret;
+       trace_rdev_join_ibss(&rdev->wiphy, dev, params);
+       ret = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_leave_ibss(struct cfg80211_registered_device *rdev,
+                                 struct net_device *dev)
+{
+       int ret;
+       trace_rdev_leave_ibss(&rdev->wiphy, dev);
+       ret = rdev->ops->leave_ibss(&rdev->wiphy, dev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed)
+{
+       int ret;
+       trace_rdev_set_wiphy_params(&rdev->wiphy, changed);
+       ret = rdev->ops->set_wiphy_params(&rdev->wiphy, changed);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev,
+                                   enum nl80211_tx_power_setting type, int mbm)
+{
+       int ret;
+       trace_rdev_set_tx_power(&rdev->wiphy, type, mbm);
+       ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev,
+                                   int *dbm)
+{
+       int ret;
+       trace_rdev_get_tx_power(&rdev->wiphy);
+       ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm);
+       trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);
+       return ret;
+}
+
+static inline int rdev_set_wds_peer(struct cfg80211_registered_device *rdev,
+                                   struct net_device *dev, const u8 *addr)
+{
+       int ret;
+       trace_rdev_set_wds_peer(&rdev->wiphy, dev, addr);
+       ret = rdev->ops->set_wds_peer(&rdev->wiphy, dev, addr);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
+{
+       trace_rdev_rfkill_poll(&rdev->wiphy);
+       rdev->ops->rfkill_poll(&rdev->wiphy);
+       trace_rdev_return_void(&rdev->wiphy);
+}
+
+
+#ifdef CONFIG_NL80211_TESTMODE
+static inline int rdev_testmode_cmd(struct cfg80211_registered_device *rdev,
+                                   void *data, int len)
+{
+       int ret;
+       trace_rdev_testmode_cmd(&rdev->wiphy);
+       ret = rdev->ops->testmode_cmd(&rdev->wiphy, data, len);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev,
+                                    struct sk_buff *skb,
+                                    struct netlink_callback *cb, void *data,
+                                    int len)
+{
+       int ret;
+       trace_rdev_testmode_dump(&rdev->wiphy);
+       ret = rdev->ops->testmode_dump(&rdev->wiphy, skb, cb, data, len);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+#endif
+
+static inline int
+rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev, const u8 *peer,
+                     const struct cfg80211_bitrate_mask *mask)
+{
+       int ret;
+       trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, peer, mask);
+       ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_dump_survey(struct cfg80211_registered_device *rdev,
+                                  struct net_device *netdev, int idx,
+                                  struct survey_info *info)
+{
+       int ret;
+       trace_rdev_dump_survey(&rdev->wiphy, netdev, idx);
+       ret = rdev->ops->dump_survey(&rdev->wiphy, netdev, idx, info);
+       if (ret < 0)
+               trace_rdev_return_int(&rdev->wiphy, ret);
+       else
+               trace_rdev_return_int_survey_info(&rdev->wiphy, ret, info);
+       return ret;
+}
+
+static inline int rdev_set_pmksa(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev,
+                                struct cfg80211_pmksa *pmksa)
+{
+       int ret;
+       trace_rdev_set_pmksa(&rdev->wiphy, netdev, pmksa);
+       ret = rdev->ops->set_pmksa(&rdev->wiphy, netdev, pmksa);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_del_pmksa(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev,
+                                struct cfg80211_pmksa *pmksa)
+{
+       int ret;
+       trace_rdev_del_pmksa(&rdev->wiphy, netdev, pmksa);
+       ret = rdev->ops->del_pmksa(&rdev->wiphy, netdev, pmksa);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_flush_pmksa(struct cfg80211_registered_device *rdev,
+                                  struct net_device *netdev)
+{
+       int ret;
+       trace_rdev_flush_pmksa(&rdev->wiphy, netdev);
+       ret = rdev->ops->flush_pmksa(&rdev->wiphy, netdev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_remain_on_channel(struct cfg80211_registered_device *rdev,
+                      struct wireless_dev *wdev,
+                      struct ieee80211_channel *chan,
+                      enum nl80211_channel_type channel_type,
+                      unsigned int duration, u64 *cookie)
+{
+       int ret;
+       trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, channel_type,
+                                    duration);
+       ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
+                                           channel_type, duration, cookie);
+       trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
+       return ret;
+}
+
+static inline int
+rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev,
+                             struct wireless_dev *wdev, u64 cookie)
+{
+       int ret;
+       trace_rdev_cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
+       ret = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
+                              struct wireless_dev *wdev,
+                              struct ieee80211_channel *chan, bool offchan,
+                              enum nl80211_channel_type channel_type,
+                              bool channel_type_valid, unsigned int wait,
+                              const u8 *buf, size_t len, bool no_cck,
+                              bool dont_wait_for_ack, u64 *cookie)
+{
+       int ret;
+       trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type,
+                          channel_type_valid, wait, no_cck, dont_wait_for_ack);
+       ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
+                                 channel_type, channel_type_valid, wait, buf,
+                                 len, no_cck, dont_wait_for_ack, cookie);
+       trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
+       return ret;
+}
+
+static inline int
+rdev_mgmt_tx_cancel_wait(struct cfg80211_registered_device *rdev,
+                        struct wireless_dev *wdev, u64 cookie)
+{
+       int ret;
+       trace_rdev_mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
+       ret = rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_set_power_mgmt(struct cfg80211_registered_device *rdev,
+                                     struct net_device *dev, bool enabled,
+                                     int timeout)
+{
+       int ret;
+       trace_rdev_set_power_mgmt(&rdev->wiphy, dev, enabled, timeout);
+       ret = rdev->ops->set_power_mgmt(&rdev->wiphy, dev, enabled, timeout);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev, s32 rssi_thold, u32 rssi_hyst)
+{
+       int ret;
+       trace_rdev_set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold,
+                                      rssi_hyst);
+       ret = rdev->ops->set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold,
+                                      rssi_hyst);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev, u32 rate, u32 pkts, u32 intvl)
+{
+       int ret;
+       trace_rdev_set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts, intvl);
+       ret = rdev->ops->set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts,
+                                            intvl);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline void
+rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev,
+                        struct wireless_dev *wdev, u16 frame_type, bool reg)
+{
+       trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
+       rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
+       trace_rdev_return_void(&rdev->wiphy);
+}
+
+static inline int rdev_set_antenna(struct cfg80211_registered_device *rdev,
+                                  u32 tx_ant, u32 rx_ant)
+{
+       int ret;
+       trace_rdev_set_antenna(&rdev->wiphy, tx_ant, rx_ant);
+       ret = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_get_antenna(struct cfg80211_registered_device *rdev,
+                                  u32 *tx_ant, u32 *rx_ant)
+{
+       int ret;
+       trace_rdev_get_antenna(&rdev->wiphy);
+       ret = rdev->ops->get_antenna(&rdev->wiphy, tx_ant, rx_ant);
+       if (ret)
+               trace_rdev_return_int(&rdev->wiphy, ret);
+       else
+               trace_rdev_return_int_tx_rx(&rdev->wiphy, ret, *tx_ant,
+                                           *rx_ant);
+       return ret;
+}
+
+static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev,
+                                    u32 tx, u32 rx)
+{
+       int ret;
+       trace_rdev_set_ringparam(&rdev->wiphy, tx, rx);
+       ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev,
+                                     u32 *tx, u32 *tx_max, u32 *rx,
+                                     u32 *rx_max)
+{
+       trace_rdev_get_ringparam(&rdev->wiphy);
+       rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max);
+       trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max);
+}
+
+static inline int
+rdev_sched_scan_start(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev,
+                     struct cfg80211_sched_scan_request *request)
+{
+       int ret;
+       trace_rdev_sched_scan_start(&rdev->wiphy, dev, request);
+       ret = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_sched_scan_stop(struct cfg80211_registered_device *rdev,
+                                      struct net_device *dev)
+{
+       int ret;
+       trace_rdev_sched_scan_stop(&rdev->wiphy, dev);
+       ret = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev,
+                                     struct net_device *dev,
+                                     struct cfg80211_gtk_rekey_data *data)
+{
+       int ret;
+       trace_rdev_set_rekey_data(&rdev->wiphy, dev);
+       ret = rdev->ops->set_rekey_data(&rdev->wiphy, dev, data);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev, u8 *peer,
+                                u8 action_code, u8 dialog_token,
+                                u16 status_code, const u8 *buf, size_t len)
+{
+       int ret;
+       trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
+                            dialog_token, status_code, buf, len);
+       ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
+                                  dialog_token, status_code, buf, len);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_tdls_oper(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev, u8 *peer,
+                                enum nl80211_tdls_operation oper)
+{
+       int ret;
+       trace_rdev_tdls_oper(&rdev->wiphy, dev, peer, oper);
+       ret = rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, oper);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_probe_client(struct cfg80211_registered_device *rdev,
+                                   struct net_device *dev, const u8 *peer,
+                                   u64 *cookie)
+{
+       int ret;
+       trace_rdev_probe_client(&rdev->wiphy, dev, peer);
+       ret = rdev->ops->probe_client(&rdev->wiphy, dev, peer, cookie);
+       trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
+       return ret;
+}
+
+static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev,
+                                    struct net_device *dev, u16 noack_map)
+{
+       int ret;
+       trace_rdev_set_noack_map(&rdev->wiphy, dev, noack_map);
+       ret = rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int
+rdev_get_et_sset_count(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev, int sset)
+{
+       int ret;
+       trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset);
+       ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev,
+                                    struct net_device *dev,
+                                    struct ethtool_stats *stats, u64 *data)
+{
+       trace_rdev_get_et_stats(&rdev->wiphy, dev);
+       rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data);
+       trace_rdev_return_void(&rdev->wiphy);
+}
+
+static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev,
+                                      struct net_device *dev, u32 sset,
+                                      u8 *data)
+{
+       trace_rdev_get_et_strings(&rdev->wiphy, dev, sset);
+       rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data);
+       trace_rdev_return_void(&rdev->wiphy);
+}
+
+static inline struct ieee80211_channel
+*rdev_get_channel(struct cfg80211_registered_device *rdev,
+                 struct wireless_dev *wdev, enum nl80211_channel_type *type)
+{
+       struct ieee80211_channel *ret;
+       trace_rdev_get_channel(&rdev->wiphy, wdev);
+       ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type);
+       trace_rdev_return_channel(&rdev->wiphy, ret, *type);
+       return ret;
+}
+
+static inline int rdev_start_p2p_device(struct cfg80211_registered_device *rdev,
+                                       struct wireless_dev *wdev)
+{
+       int ret;
+
+       trace_rdev_start_p2p_device(&rdev->wiphy, wdev);
+       ret = rdev->ops->start_p2p_device(&rdev->wiphy, wdev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev,
+                                       struct wireless_dev *wdev)
+{
+       trace_rdev_stop_p2p_device(&rdev->wiphy, wdev);
+       rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
+       trace_rdev_return_void(&rdev->wiphy);
+}                                      
+#endif /* __CFG80211_RDEV_OPS */
index 9730c98..7f97a08 100644 (file)
 #include "core.h"
 #include "nl80211.h"
 #include "wext-compat.h"
+#include "rdev-ops.h"
 
 #define IEEE80211_SCAN_RESULT_EXPIRE   (30 * HZ)
 
+static void bss_release(struct kref *ref)
+{
+       struct cfg80211_internal_bss *bss;
+
+       bss = container_of(ref, struct cfg80211_internal_bss, ref);
+       if (bss->pub.free_priv)
+               bss->pub.free_priv(&bss->pub);
+
+       if (bss->beacon_ies_allocated)
+               kfree(bss->pub.beacon_ies);
+       if (bss->proberesp_ies_allocated)
+               kfree(bss->pub.proberesp_ies);
+
+       BUG_ON(atomic_read(&bss->hold));
+
+       kfree(bss);
+}
+
+/* must hold dev->bss_lock! */
+static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
+                                 struct cfg80211_internal_bss *bss)
+{
+       list_del_init(&bss->list);
+       rb_erase(&bss->rbn, &dev->bss_tree);
+       kref_put(&bss->ref, bss_release);
+}
+
+/* must hold dev->bss_lock! */
+static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
+                                 unsigned long expire_time)
+{
+       struct cfg80211_internal_bss *bss, *tmp;
+       bool expired = false;
+
+       list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
+               if (atomic_read(&bss->hold))
+                       continue;
+               if (!time_after(expire_time, bss->ts))
+                       continue;
+
+               __cfg80211_unlink_bss(dev, bss);
+               expired = true;
+       }
+
+       if (expired)
+               dev->bss_generation++;
+}
+
 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
 {
        struct cfg80211_scan_request *request;
@@ -45,10 +94,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
        if (wdev->netdev)
                cfg80211_sme_scan_done(wdev->netdev);
 
-       if (request->aborted)
+       if (request->aborted) {
                nl80211_send_scan_aborted(rdev, wdev);
-       else
+       } else {
+               if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
+                       /* flush entries from previous scans */
+                       spin_lock_bh(&rdev->bss_lock);
+                       __cfg80211_bss_expire(rdev, request->scan_start);
+                       spin_unlock_bh(&rdev->bss_lock);
+               }
                nl80211_send_scan_done(rdev, wdev);
+       }
 
 #ifdef CONFIG_CFG80211_WEXT
        if (wdev->netdev && !request->aborted) {
@@ -89,6 +145,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
 
 void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
 {
+       trace_cfg80211_scan_done(request, aborted);
        WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
 
        request->aborted = aborted;
@@ -99,22 +156,34 @@ EXPORT_SYMBOL(cfg80211_scan_done);
 void __cfg80211_sched_scan_results(struct work_struct *wk)
 {
        struct cfg80211_registered_device *rdev;
+       struct cfg80211_sched_scan_request *request;
 
        rdev = container_of(wk, struct cfg80211_registered_device,
                            sched_scan_results_wk);
 
+       request = rdev->sched_scan_req;
+
        mutex_lock(&rdev->sched_scan_mtx);
 
        /* we don't have sched_scan_req anymore if the scan is stopping */
-       if (rdev->sched_scan_req)
-               nl80211_send_sched_scan_results(rdev,
-                                               rdev->sched_scan_req->dev);
+       if (request) {
+               if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
+                       /* flush entries from previous scans */
+                       spin_lock_bh(&rdev->bss_lock);
+                       __cfg80211_bss_expire(rdev, request->scan_start);
+                       spin_unlock_bh(&rdev->bss_lock);
+                       request->scan_start =
+                               jiffies + msecs_to_jiffies(request->interval);
+               }
+               nl80211_send_sched_scan_results(rdev, request->dev);
+       }
 
        mutex_unlock(&rdev->sched_scan_mtx);
 }
 
 void cfg80211_sched_scan_results(struct wiphy *wiphy)
 {
+       trace_cfg80211_sched_scan_results(wiphy);
        /* ignore if we're not scanning */
        if (wiphy_to_dev(wiphy)->sched_scan_req)
                queue_work(cfg80211_wq,
@@ -126,6 +195,8 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
+       trace_cfg80211_sched_scan_stopped(wiphy);
+
        mutex_lock(&rdev->sched_scan_mtx);
        __cfg80211_stop_sched_scan(rdev, true);
        mutex_unlock(&rdev->sched_scan_mtx);
@@ -145,7 +216,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
        dev = rdev->sched_scan_req->dev;
 
        if (!driver_initiated) {
-               int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
+               int err = rdev_sched_scan_stop(rdev, dev);
                if (err)
                        return err;
        }
@@ -158,24 +229,6 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
        return 0;
 }
 
-static void bss_release(struct kref *ref)
-{
-       struct cfg80211_internal_bss *bss;
-
-       bss = container_of(ref, struct cfg80211_internal_bss, ref);
-       if (bss->pub.free_priv)
-               bss->pub.free_priv(&bss->pub);
-
-       if (bss->beacon_ies_allocated)
-               kfree(bss->pub.beacon_ies);
-       if (bss->proberesp_ies_allocated)
-               kfree(bss->pub.proberesp_ies);
-
-       BUG_ON(atomic_read(&bss->hold));
-
-       kfree(bss);
-}
-
 /* must hold dev->bss_lock! */
 void cfg80211_bss_age(struct cfg80211_registered_device *dev,
                       unsigned long age_secs)
@@ -188,32 +241,9 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
        }
 }
 
-/* must hold dev->bss_lock! */
-static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
-                                 struct cfg80211_internal_bss *bss)
-{
-       list_del_init(&bss->list);
-       rb_erase(&bss->rbn, &dev->bss_tree);
-       kref_put(&bss->ref, bss_release);
-}
-
-/* must hold dev->bss_lock! */
 void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
 {
-       struct cfg80211_internal_bss *bss, *tmp;
-       bool expired = false;
-
-       list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
-               if (atomic_read(&bss->hold))
-                       continue;
-               if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
-                       continue;
-               __cfg80211_unlink_bss(dev, bss);
-               expired = true;
-       }
-
-       if (expired)
-               dev->bss_generation++;
+       __cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
 }
 
 const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
@@ -459,6 +489,9 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
        struct cfg80211_internal_bss *bss, *res = NULL;
        unsigned long now = jiffies;
 
+       trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
+                              capa_val);
+
        spin_lock_bh(&dev->bss_lock);
 
        list_for_each_entry(bss, &dev->bss_list, list) {
@@ -480,6 +513,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
        spin_unlock_bh(&dev->bss_lock);
        if (!res)
                return NULL;
+       trace_cfg80211_return_bss(&res->pub);
        return &res->pub;
 }
 EXPORT_SYMBOL(cfg80211_get_bss);
@@ -792,6 +826,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
        if (res->pub.capability & WLAN_CAPABILITY_ESS)
                regulatory_hint_found_beacon(wiphy, channel, gfp);
 
+       trace_cfg80211_return_bss(&res->pub);
        /* cfg80211_bss_update gives us a referenced result */
        return &res->pub;
 }
@@ -804,10 +839,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          s32 signal, gfp_t gfp)
 {
        struct cfg80211_internal_bss *res;
+
        size_t ielen = len - offsetof(struct ieee80211_mgmt,
                                      u.probe_resp.variable);
        size_t privsz;
 
+       trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal);
+
        if (WARN_ON(!mgmt))
                return NULL;
 
@@ -861,6 +899,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        if (res->pub.capability & WLAN_CAPABILITY_ESS)
                regulatory_hint_found_beacon(wiphy, channel, gfp);
 
+       trace_cfg80211_return_bss(&res->pub);
        /* cfg80211_bss_update gives us a referenced result */
        return &res->pub;
 }
@@ -962,6 +1001,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
        creq->ssids = (void *)&creq->channels[n_channels];
        creq->n_channels = n_channels;
        creq->n_ssids = 1;
+       creq->scan_start = jiffies;
 
        /* translate "Scan on frequencies" request */
        i = 0;
@@ -1026,7 +1066,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
                        creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
 
        rdev->scan_req = creq;
-       err = rdev->ops->scan(wiphy, creq);
+       err = rdev_scan(rdev, creq);
        if (err) {
                rdev->scan_req = NULL;
                /* creq will be freed below */
index 6f39cb8..c749002 100644 (file)
@@ -16,6 +16,7 @@
 #include <net/rtnetlink.h>
 #include "nl80211.h"
 #include "reg.h"
+#include "rdev-ops.h"
 
 struct cfg80211_conn {
        struct cfg80211_connect_params params;
@@ -138,10 +139,11 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
 
        request->wdev = wdev;
        request->wiphy = &rdev->wiphy;
+       request->scan_start = jiffies;
 
        rdev->scan_req = request;
 
-       err = rdev->ops->scan(wdev->wiphy, request);
+       err = rdev_scan(rdev, request);
        if (!err) {
                wdev->conn->state = CFG80211_CONN_SCANNING;
                nl80211_send_scan_start(rdev, wdev);
@@ -179,7 +181,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                            params->ssid, params->ssid_len,
                                            NULL, 0,
                                            params->key, params->key_len,
-                                           params->key_idx);
+                                           params->key_idx, NULL, 0);
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -716,7 +718,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
         */
        if (rdev->ops->del_key)
                for (i = 0; i < 6; i++)
-                       rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
+                       rdev_del_key(rdev, dev, i, false, NULL);
 
 #ifdef CONFIG_CFG80211_WEXT
        memset(&wrqu, 0, sizeof(wrqu));
@@ -892,7 +894,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
        } else {
                wdev->sme_state = CFG80211_SME_CONNECTING;
                wdev->connect_keys = connkeys;
-               err = rdev->ops->connect(&rdev->wiphy, dev, connect);
+               err = rdev_connect(rdev, dev, connect);
                if (err) {
                        wdev->connect_keys = NULL;
                        wdev->sme_state = CFG80211_SME_IDLE;
@@ -964,7 +966,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
                if (err)
                        return err;
        } else {
-               err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
+               err = rdev_disconnect(rdev, dev, reason);
                if (err)
                        return err;
        }
index ff57459..9bf6d5e 100644 (file)
@@ -16,6 +16,7 @@
 #include <net/cfg80211.h>
 #include "sysfs.h"
 #include "core.h"
+#include "rdev-ops.h"
 
 static inline struct cfg80211_registered_device *dev_to_rdev(
        struct device *dev)
@@ -94,7 +95,7 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
        if (rdev->ops->suspend) {
                rtnl_lock();
                if (rdev->wiphy.registered)
-                       ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
+                       ret = rdev_suspend(rdev);
                rtnl_unlock();
        }
 
@@ -114,7 +115,7 @@ static int wiphy_resume(struct device *dev)
        if (rdev->ops->resume) {
                rtnl_lock();
                if (rdev->wiphy.registered)
-                       ret = rdev->ops->resume(&rdev->wiphy);
+                       ret = rdev_resume(rdev);
                rtnl_unlock();
        }
 
diff --git a/net/wireless/trace.c b/net/wireless/trace.c
new file mode 100644 (file)
index 0000000..95f997f
--- /dev/null
@@ -0,0 +1,7 @@
+#include <linux/module.h>
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#endif
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
new file mode 100644 (file)
index 0000000..0ca71ca
--- /dev/null
@@ -0,0 +1,2296 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cfg80211
+
+#if !defined(__RDEV_OPS_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __RDEV_OPS_TRACE
+
+#include <linux/tracepoint.h>
+
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+#include "core.h"
+
+#define MAC_ENTRY(entry_mac) __array(u8, entry_mac, ETH_ALEN)
+#define MAC_ASSIGN(entry_mac, given_mac) do {                       \
+       if (given_mac)                                               \
+               memcpy(__entry->entry_mac, given_mac, ETH_ALEN);     \
+       else                                                         \
+               memset(__entry->entry_mac, 0, ETH_ALEN);             \
+       } while (0)
+#define MAC_PR_FMT "%pM"
+#define MAC_PR_ARG(entry_mac) (__entry->entry_mac)
+
+#define WIPHY_ENTRY MAC_ENTRY(wiphy_mac)
+#define WIPHY_ASSIGN MAC_ASSIGN(wiphy_mac, wiphy->perm_addr)
+#define WIPHY_PR_FMT "wiphy " MAC_PR_FMT
+#define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac)
+
+#define WDEV_ENTRY __field(u32, id)
+#define WDEV_ASSIGN (__entry->id) = (wdev->identifier)
+#define WDEV_PR_FMT ", wdev id: %u"
+#define WDEV_PR_ARG (__entry->id)
+
+#define NETDEV_ENTRY __array(char, name, IFNAMSIZ) \
+                    MAC_ENTRY(netdev_addr)        \
+                    __field(int, ifindex)
+#define NETDEV_ASSIGN                                         \
+       do {                                                   \
+               memcpy(__entry->name, netdev->name, IFNAMSIZ); \
+               MAC_ASSIGN(netdev_addr, netdev->dev_addr);     \
+               (__entry->ifindex) = (netdev->ifindex);        \
+       } while (0)
+#define NETDEV_PR_FMT ", netdev - name: %s, addr: " MAC_PR_FMT \
+                     ", intf index: %d"
+#define NETDEV_PR_ARG (__entry->name), MAC_PR_ARG(netdev_addr), \
+                     (__entry->ifindex)
+
+#define MESH_CFG_ENTRY __field(u16, dot11MeshRetryTimeout)                \
+                      __field(u16, dot11MeshConfirmTimeout)               \
+                      __field(u16, dot11MeshHoldingTimeout)               \
+                      __field(u16, dot11MeshMaxPeerLinks)                 \
+                      __field(u8, dot11MeshMaxRetries)                    \
+                      __field(u8, dot11MeshTTL)                           \
+                      __field(u8, element_ttl)                            \
+                      __field(bool, auto_open_plinks)                     \
+                      __field(u32, dot11MeshNbrOffsetMaxNeighbor)         \
+                      __field(u8, dot11MeshHWMPmaxPREQretries)            \
+                      __field(u32, path_refresh_time)                     \
+                      __field(u32, dot11MeshHWMPactivePathTimeout)        \
+                      __field(u16, min_discovery_timeout)                 \
+                      __field(u16, dot11MeshHWMPpreqMinInterval)          \
+                      __field(u16, dot11MeshHWMPperrMinInterval)          \
+                      __field(u16, dot11MeshHWMPnetDiameterTraversalTime) \
+                      __field(u8, dot11MeshHWMPRootMode)                  \
+                      __field(u16, dot11MeshHWMPRannInterval)             \
+                      __field(bool, dot11MeshGateAnnouncementProtocol)    \
+                      __field(bool, dot11MeshForwarding)                  \
+                      __field(s32, rssi_threshold)                        \
+                      __field(u16, ht_opmode)                             \
+                      __field(u32, dot11MeshHWMPactivePathToRootTimeout)  \
+                      __field(u16, dot11MeshHWMProotInterval)             \
+                      __field(u16, dot11MeshHWMPconfirmationInterval)
+#define MESH_CFG_ASSIGN                                                              \
+       do {                                                                  \
+               __entry->dot11MeshRetryTimeout = conf->dot11MeshRetryTimeout; \
+               __entry->dot11MeshConfirmTimeout =                            \
+                               conf->dot11MeshConfirmTimeout;                \
+               __entry->dot11MeshHoldingTimeout =                            \
+                               conf->dot11MeshHoldingTimeout;                \
+               __entry->dot11MeshMaxPeerLinks = conf->dot11MeshMaxPeerLinks; \
+               __entry->dot11MeshMaxRetries = conf->dot11MeshMaxRetries;     \
+               __entry->dot11MeshTTL = conf->dot11MeshTTL;                   \
+               __entry->element_ttl = conf->element_ttl;                     \
+               __entry->auto_open_plinks = conf->auto_open_plinks;           \
+               __entry->dot11MeshNbrOffsetMaxNeighbor =                      \
+                               conf->dot11MeshNbrOffsetMaxNeighbor;          \
+               __entry->dot11MeshHWMPmaxPREQretries =                        \
+                               conf->dot11MeshHWMPmaxPREQretries;            \
+               __entry->path_refresh_time = conf->path_refresh_time;         \
+               __entry->dot11MeshHWMPactivePathTimeout =                     \
+                               conf->dot11MeshHWMPactivePathTimeout;         \
+               __entry->min_discovery_timeout = conf->min_discovery_timeout; \
+               __entry->dot11MeshHWMPpreqMinInterval =                       \
+                               conf->dot11MeshHWMPpreqMinInterval;           \
+               __entry->dot11MeshHWMPperrMinInterval =                       \
+                               conf->dot11MeshHWMPperrMinInterval;           \
+               __entry->dot11MeshHWMPnetDiameterTraversalTime =              \
+                               conf->dot11MeshHWMPnetDiameterTraversalTime;  \
+               __entry->dot11MeshHWMPRootMode = conf->dot11MeshHWMPRootMode; \
+               __entry->dot11MeshHWMPRannInterval =                          \
+                               conf->dot11MeshHWMPRannInterval;              \
+               __entry->dot11MeshGateAnnouncementProtocol =                  \
+                               conf->dot11MeshGateAnnouncementProtocol;      \
+               __entry->dot11MeshForwarding = conf->dot11MeshForwarding;     \
+               __entry->rssi_threshold = conf->rssi_threshold;               \
+               __entry->ht_opmode = conf->ht_opmode;                         \
+               __entry->dot11MeshHWMPactivePathToRootTimeout =               \
+                               conf->dot11MeshHWMPactivePathToRootTimeout;   \
+               __entry->dot11MeshHWMProotInterval =                          \
+                               conf->dot11MeshHWMProotInterval;              \
+               __entry->dot11MeshHWMPconfirmationInterval =                  \
+                               conf->dot11MeshHWMPconfirmationInterval;      \
+       } while (0)
+
+#define CHAN_ENTRY __field(enum ieee80211_band, band) \
+                  __field(u16, center_freq)
+#define CHAN_ASSIGN(chan)                                        \
+       do {                                                      \
+               if (chan) {                                       \
+                       __entry->band = chan->band;               \
+                       __entry->center_freq = chan->center_freq; \
+               } else {                                          \
+                       __entry->band = 0;                        \
+                       __entry->center_freq = 0;                 \
+               }                                                 \
+       } while (0)
+#define CHAN_PR_FMT ", band: %d, freq: %u"
+#define CHAN_PR_ARG __entry->band, __entry->center_freq
+
+#define SINFO_ENTRY __field(int, generation)       \
+                   __field(u32, connected_time)    \
+                   __field(u32, inactive_time)     \
+                   __field(u32, rx_bytes)          \
+                   __field(u32, tx_bytes)          \
+                   __field(u32, rx_packets)        \
+                   __field(u32, tx_packets)        \
+                   __field(u32, tx_retries)        \
+                   __field(u32, tx_failed)         \
+                   __field(u32, rx_dropped_misc)   \
+                   __field(u32, beacon_loss_count) \
+                   __field(u16, llid)              \
+                   __field(u16, plid)              \
+                   __field(u8, plink_state)
+#define SINFO_ASSIGN                                                  \
+       do {                                                           \
+               __entry->generation = sinfo->generation;               \
+               __entry->connected_time = sinfo->connected_time;       \
+               __entry->inactive_time = sinfo->inactive_time;         \
+               __entry->rx_bytes = sinfo->rx_bytes;                   \
+               __entry->tx_bytes = sinfo->tx_bytes;                   \
+               __entry->rx_packets = sinfo->rx_packets;               \
+               __entry->tx_packets = sinfo->tx_packets;               \
+               __entry->tx_retries = sinfo->tx_retries;               \
+               __entry->tx_failed = sinfo->tx_failed;                 \
+               __entry->rx_dropped_misc = sinfo->rx_dropped_misc;     \
+               __entry->beacon_loss_count = sinfo->beacon_loss_count; \
+               __entry->llid = sinfo->llid;                           \
+               __entry->plid = sinfo->plid;                           \
+               __entry->plink_state = sinfo->plink_state;             \
+       } while (0)
+
+#define BOOL_TO_STR(bo) (bo) ? "true" : "false"
+
+/*************************************************************
+ *                     rdev->ops traces                     *
+ *************************************************************/
+
+TRACE_EVENT(rdev_suspend,
+       TP_PROTO(struct wiphy *wiphy, struct cfg80211_wowlan *wow),
+       TP_ARGS(wiphy, wow),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(bool, any)
+               __field(bool, disconnect)
+               __field(bool, magic_pkt)
+               __field(bool, gtk_rekey_failure)
+               __field(bool, eap_identity_req)
+               __field(bool, four_way_handshake)
+               __field(bool, rfkill_release)
+               __field(bool, valid_wow)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               if (wow) {
+                       __entry->any = wow->any;
+                       __entry->disconnect = wow->disconnect;
+                       __entry->magic_pkt = wow->magic_pkt;
+                       __entry->gtk_rekey_failure = wow->gtk_rekey_failure;
+                       __entry->eap_identity_req = wow->eap_identity_req;
+                       __entry->four_way_handshake = wow->four_way_handshake;
+                       __entry->rfkill_release = wow->rfkill_release;
+                       __entry->valid_wow = true;
+               } else {
+                       __entry->valid_wow = false;
+               }
+       ),
+       TP_printk(WIPHY_PR_FMT ", wow%s - any: %d, disconnect: %d, "
+                 "magic pkt: %d, gtk rekey failure: %d, eap identify req: %d, "
+                 "four way handshake: %d, rfkill release: %d.",
+                 WIPHY_PR_ARG, __entry->valid_wow ? "" : "(Not configured!)",
+                 __entry->any, __entry->disconnect, __entry->magic_pkt,
+                 __entry->gtk_rekey_failure, __entry->eap_identity_req,
+                 __entry->four_way_handshake, __entry->rfkill_release)
+);
+
+TRACE_EVENT(rdev_return_int,
+       TP_PROTO(struct wiphy *wiphy, int ret),
+       TP_ARGS(wiphy, ret),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->ret = ret;
+       ),
+       TP_printk(WIPHY_PR_FMT ", returned: %d", WIPHY_PR_ARG, __entry->ret)
+);
+
+TRACE_EVENT(rdev_scan,
+       TP_PROTO(struct wiphy *wiphy, struct cfg80211_scan_request *request),
+       TP_ARGS(wiphy, request),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG)
+);
+
+DECLARE_EVENT_CLASS(wiphy_only_evt,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG)
+);
+
+DEFINE_EVENT(wiphy_only_evt, rdev_resume,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+DEFINE_EVENT(wiphy_only_evt, rdev_return_void,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+DEFINE_EVENT(wiphy_only_evt, rdev_get_ringparam,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+DECLARE_EVENT_CLASS(wiphy_enabled_evt,
+       TP_PROTO(struct wiphy *wiphy, bool enabled),
+       TP_ARGS(wiphy, enabled),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(bool, enabled)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->enabled = enabled;
+       ),
+       TP_printk(WIPHY_PR_FMT ", %senabled ",
+                 WIPHY_PR_ARG, __entry->enabled ? "" : "not ")
+);
+
+DEFINE_EVENT(wiphy_enabled_evt, rdev_set_wakeup,
+       TP_PROTO(struct wiphy *wiphy, bool enabled),
+       TP_ARGS(wiphy, enabled)
+);
+
+TRACE_EVENT(rdev_add_virtual_intf,
+       TP_PROTO(struct wiphy *wiphy, char *name, enum nl80211_iftype type),
+       TP_ARGS(wiphy, name, type),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __string(vir_intf_name, name ? name : "<noname>")
+               __field(enum nl80211_iftype, type)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __assign_str(vir_intf_name, name ? name : "<noname>");
+               __entry->type = type;
+       ),
+       TP_printk(WIPHY_PR_FMT ", virtual intf name: %s, type: %d",
+                 WIPHY_PR_ARG, __get_str(vir_intf_name), __entry->type)
+);
+
+DECLARE_EVENT_CLASS(wiphy_wdev_evt,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               WDEV_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               WDEV_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
+);
+
+DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev)
+);
+
+DEFINE_EVENT(wiphy_wdev_evt, rdev_del_virtual_intf,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev)
+);
+
+TRACE_EVENT(rdev_change_virtual_intf,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                enum nl80211_iftype type),
+       TP_ARGS(wiphy, netdev, type),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(enum nl80211_iftype, type)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->type = type;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", type: %d",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->type)
+);
+
+DECLARE_EVENT_CLASS(key_handle,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+                bool pairwise, const u8 *mac_addr),
+       TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(mac_addr)
+               __field(u8, key_index)
+               __field(bool, pairwise)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(mac_addr, mac_addr);
+               __entry->key_index = key_index;
+               __entry->pairwise = pairwise;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
+                 BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr))
+);
+
+DEFINE_EVENT(key_handle, rdev_add_key,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+                bool pairwise, const u8 *mac_addr),
+       TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
+);
+
+DEFINE_EVENT(key_handle, rdev_get_key,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+                bool pairwise, const u8 *mac_addr),
+       TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
+);
+
+DEFINE_EVENT(key_handle, rdev_del_key,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+                bool pairwise, const u8 *mac_addr),
+       TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
+);
+
+TRACE_EVENT(rdev_set_default_key,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
+                bool unicast, bool multicast),
+       TP_ARGS(wiphy, netdev, key_index, unicast, multicast),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u8, key_index)
+               __field(bool, unicast)
+               __field(bool, multicast)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->key_index = key_index;
+               __entry->unicast = unicast;
+               __entry->multicast = multicast;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
+                 BOOL_TO_STR(__entry->unicast),
+                 BOOL_TO_STR(__entry->multicast))
+);
+
+TRACE_EVENT(rdev_set_default_mgmt_key,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index),
+       TP_ARGS(wiphy, netdev, key_index),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u8, key_index)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->key_index = key_index;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index)
+);
+
+TRACE_EVENT(rdev_start_ap,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_ap_settings *settings),
+       TP_ARGS(wiphy, netdev, settings),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               CHAN_ENTRY
+               __field(int, beacon_interval)
+               __field(int, dtim_period)
+               __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1)
+               __field(enum nl80211_hidden_ssid, hidden_ssid)
+               __field(u32, wpa_ver)
+               __field(bool, privacy)
+               __field(enum nl80211_auth_type, auth_type)
+               __field(int, inactivity_timeout)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               CHAN_ASSIGN(settings->channel);
+               __entry->beacon_interval = settings->beacon_interval;
+               __entry->dtim_period = settings->dtim_period;
+               __entry->hidden_ssid = settings->hidden_ssid;
+               __entry->wpa_ver = settings->crypto.wpa_versions;
+               __entry->privacy = settings->privacy;
+               __entry->auth_type = settings->auth_type;
+               __entry->inactivity_timeout = settings->inactivity_timeout;
+               memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
+               memcpy(__entry->ssid, settings->ssid, settings->ssid_len);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", AP settings - ssid: %s, "
+                 CHAN_PR_FMT ", beacon interval: %d, dtim period: %d, "
+                 "hidden ssid: %d, wpa versions: %u, privacy: %s, "
+                 "auth type: %d, inactivity timeout: %d",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_PR_ARG,
+                 __entry->beacon_interval, __entry->dtim_period,
+                 __entry->hidden_ssid, __entry->wpa_ver,
+                 BOOL_TO_STR(__entry->privacy), __entry->auth_type,
+                 __entry->inactivity_timeout)
+);
+
+TRACE_EVENT(rdev_change_beacon,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_beacon_data *info),
+       TP_ARGS(wiphy, netdev, info),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __dynamic_array(u8, head, info ? info->head_len : 0)
+               __dynamic_array(u8, tail, info ? info->tail_len : 0)
+               __dynamic_array(u8, beacon_ies, info ? info->beacon_ies_len : 0)
+               __dynamic_array(u8, proberesp_ies,
+                               info ? info->proberesp_ies_len : 0)
+               __dynamic_array(u8, assocresp_ies,
+                               info ? info->assocresp_ies_len : 0)
+               __dynamic_array(u8, probe_resp, info ? info->probe_resp_len : 0)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               if (info) {
+                       if (info->head)
+                               memcpy(__get_dynamic_array(head), info->head,
+                                      info->head_len);
+                       if (info->tail)
+                               memcpy(__get_dynamic_array(tail), info->tail,
+                                      info->tail_len);
+                       if (info->beacon_ies)
+                               memcpy(__get_dynamic_array(beacon_ies),
+                                      info->beacon_ies, info->beacon_ies_len);
+                       if (info->proberesp_ies)
+                               memcpy(__get_dynamic_array(proberesp_ies),
+                                      info->proberesp_ies,
+                                      info->proberesp_ies_len);
+                       if (info->assocresp_ies)
+                               memcpy(__get_dynamic_array(assocresp_ies),
+                                      info->assocresp_ies,
+                                      info->assocresp_ies_len);
+                       if (info->probe_resp)
+                               memcpy(__get_dynamic_array(probe_resp),
+                                      info->probe_resp, info->probe_resp_len);
+               }
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
+);
+
+DECLARE_EVENT_CLASS(wiphy_netdev_evt,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_get_et_stats,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_set_rekey_data,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_get_mesh_config,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_mesh,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ibss,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
+DECLARE_EVENT_CLASS(station_add_change,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac,
+                struct station_parameters *params),
+       TP_ARGS(wiphy, netdev, mac, params),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(sta_mac)
+               __field(u32, sta_flags_mask)
+               __field(u32, sta_flags_set)
+               __field(u32, sta_modify_mask)
+               __field(int, listen_interval)
+               __field(u16, aid)
+               __field(u8, plink_action)
+               __field(u8, plink_state)
+               __field(u8, uapsd_queues)
+               __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap))
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(sta_mac, mac);
+               __entry->sta_flags_mask = params->sta_flags_mask;
+               __entry->sta_flags_set = params->sta_flags_set;
+               __entry->sta_modify_mask = params->sta_modify_mask;
+               __entry->listen_interval = params->listen_interval;
+               __entry->aid = params->aid;
+               __entry->plink_action = params->plink_action;
+               __entry->plink_state = params->plink_state;
+               __entry->uapsd_queues = params->uapsd_queues;
+               memset(__entry->ht_capa, 0, sizeof(struct ieee80211_ht_cap));
+               if (params->ht_capa)
+                       memcpy(__entry->ht_capa, params->ht_capa,
+                              sizeof(struct ieee80211_ht_cap));
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+                 ", station flags mask: %u, station flags set: %u, "
+                 "station modify mask: %u, listen interval: %d, aid: %u, "
+                 "plink action: %u, plink state: %u, uapsd queues: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
+                 __entry->sta_flags_mask, __entry->sta_flags_set,
+                 __entry->sta_modify_mask, __entry->listen_interval,
+                 __entry->aid, __entry->plink_action, __entry->plink_state,
+                 __entry->uapsd_queues)
+);
+
+DEFINE_EVENT(station_add_change, rdev_add_station,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac,
+                struct station_parameters *params),
+       TP_ARGS(wiphy, netdev, mac, params)
+);
+
+DEFINE_EVENT(station_add_change, rdev_change_station,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac,
+                struct station_parameters *params),
+       TP_ARGS(wiphy, netdev, mac, params)
+);
+
+DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
+       TP_ARGS(wiphy, netdev, mac),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(sta_mac)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(sta_mac, mac);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mac: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac))
+);
+
+DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
+       TP_ARGS(wiphy, netdev, mac)
+);
+
+DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
+       TP_ARGS(wiphy, netdev, mac)
+);
+
+DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_mpath,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
+       TP_ARGS(wiphy, netdev, mac)
+);
+
+DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_set_wds_peer,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
+       TP_ARGS(wiphy, netdev, mac)
+);
+
+TRACE_EVENT(rdev_dump_station,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
+                u8 *mac),
+       TP_ARGS(wiphy, netdev, idx, mac),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(sta_mac)
+               __field(int, idx)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(sta_mac, mac);
+               __entry->idx = idx;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
+                 __entry->idx)
+);
+
+TRACE_EVENT(rdev_return_int_station_info,
+       TP_PROTO(struct wiphy *wiphy, int ret, struct station_info *sinfo),
+       TP_ARGS(wiphy, ret, sinfo),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(int, ret)
+               SINFO_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->ret = ret;
+               SINFO_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT ", returned %d" ,
+                 WIPHY_PR_ARG, __entry->ret)
+);
+
+DECLARE_EVENT_CLASS(mpath_evt,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst,
+                u8 *next_hop),
+       TP_ARGS(wiphy, netdev, dst, next_hop),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(dst)
+               MAC_ENTRY(next_hop)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(dst, dst);
+               MAC_ASSIGN(next_hop, next_hop);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dst),
+                 MAC_PR_ARG(next_hop))
+);
+
+DEFINE_EVENT(mpath_evt, rdev_add_mpath,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst,
+                u8 *next_hop),
+       TP_ARGS(wiphy, netdev, dst, next_hop)
+);
+
+DEFINE_EVENT(mpath_evt, rdev_change_mpath,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst,
+                u8 *next_hop),
+       TP_ARGS(wiphy, netdev, dst, next_hop)
+);
+
+DEFINE_EVENT(mpath_evt, rdev_get_mpath,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *dst,
+                u8 *next_hop),
+       TP_ARGS(wiphy, netdev, dst, next_hop)
+);
+
+TRACE_EVENT(rdev_dump_mpath,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
+                u8 *dst, u8 *next_hop),
+       TP_ARGS(wiphy, netdev, idx, dst, next_hop),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(dst)
+               MAC_ENTRY(next_hop)
+               __field(int, idx)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(dst, dst);
+               MAC_ASSIGN(next_hop, next_hop);
+               __entry->idx = idx;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d, destination: "
+                 MAC_PR_FMT ", next hop: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
+                 MAC_PR_ARG(next_hop))
+);
+
+TRACE_EVENT(rdev_return_int_mpath_info,
+       TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo),
+       TP_ARGS(wiphy, ret, pinfo),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(int, ret)
+               __field(int, generation)
+               __field(u32, filled)
+               __field(u32, frame_qlen)
+               __field(u32, sn)
+               __field(u32, metric)
+               __field(u32, exptime)
+               __field(u32, discovery_timeout)
+               __field(u8, discovery_retries)
+               __field(u8, flags)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->ret = ret;
+               __entry->generation = pinfo->generation;
+               __entry->filled = pinfo->filled;
+               __entry->frame_qlen = pinfo->frame_qlen;
+               __entry->sn = pinfo->sn;
+               __entry->metric = pinfo->metric;
+               __entry->exptime = pinfo->exptime;
+               __entry->discovery_timeout = pinfo->discovery_timeout;
+               __entry->discovery_retries = pinfo->discovery_retries;
+               __entry->flags = pinfo->flags;
+       ),
+       TP_printk(WIPHY_PR_FMT ", returned %d. mpath info - generation: %d, "
+                 "filled: %u, frame qlen: %u, sn: %u, metric: %u, exptime: %u,"
+                 " discovery timeout: %u, discovery retries: %u, flags: %u",
+                 WIPHY_PR_ARG, __entry->ret, __entry->generation,
+                 __entry->filled, __entry->frame_qlen, __entry->sn,
+                 __entry->metric, __entry->exptime, __entry->discovery_timeout,
+                 __entry->discovery_retries, __entry->flags)
+);
+
+TRACE_EVENT(rdev_return_int_mesh_config,
+       TP_PROTO(struct wiphy *wiphy, int ret, struct mesh_config *conf),
+       TP_ARGS(wiphy, ret, conf),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               MESH_CFG_ENTRY
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               MESH_CFG_ASSIGN;
+               __entry->ret = ret;
+       ),
+       TP_printk(WIPHY_PR_FMT ", returned: %d",
+                 WIPHY_PR_ARG, __entry->ret)
+);
+
+TRACE_EVENT(rdev_update_mesh_config,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 mask,
+                const struct mesh_config *conf),
+       TP_ARGS(wiphy, netdev, mask, conf),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MESH_CFG_ENTRY
+               __field(u32, mask)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MESH_CFG_ASSIGN;
+               __entry->mask = mask;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mask: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->mask)
+);
+
+TRACE_EVENT(rdev_join_mesh,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                const struct mesh_config *conf,
+                const struct mesh_setup *setup),
+       TP_ARGS(wiphy, netdev, conf, setup),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MESH_CFG_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MESH_CFG_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG)
+);
+
+TRACE_EVENT(rdev_change_bss,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct bss_parameters *params),
+       TP_ARGS(wiphy, netdev, params),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(int, use_cts_prot)
+               __field(int, use_short_preamble)
+               __field(int, use_short_slot_time)
+               __field(int, ap_isolate)
+               __field(int, ht_opmode)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->use_cts_prot = params->use_cts_prot;
+               __entry->use_short_preamble = params->use_short_preamble;
+               __entry->use_short_slot_time = params->use_short_slot_time;
+               __entry->ap_isolate = params->ap_isolate;
+               __entry->ht_opmode = params->ht_opmode;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", use cts prot: %d, "
+                 "use short preamble: %d, use short slot time: %d, "
+                 "ap isolate: %d, ht opmode: %d",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->use_cts_prot,
+                 __entry->use_short_preamble, __entry->use_short_slot_time,
+                 __entry->ap_isolate, __entry->ht_opmode)
+);
+
+TRACE_EVENT(rdev_set_txq_params,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct ieee80211_txq_params *params),
+       TP_ARGS(wiphy, netdev, params),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(enum nl80211_ac, ac)
+               __field(u16, txop)
+               __field(u16, cwmin)
+               __field(u16, cwmax)
+               __field(u8, aifs)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->ac = params->ac;
+               __entry->txop = params->txop;
+               __entry->cwmin = params->cwmin;
+               __entry->cwmax = params->cwmax;
+               __entry->aifs = params->aifs;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ac, __entry->txop,
+                 __entry->cwmin, __entry->cwmax, __entry->aifs)
+);
+
+TRACE_EVENT(rdev_libertas_set_mesh_channel,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct ieee80211_channel *chan),
+       TP_ARGS(wiphy, netdev, chan),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               CHAN_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               CHAN_ASSIGN(chan);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT CHAN_PR_FMT, WIPHY_PR_ARG,
+                 NETDEV_PR_ARG, CHAN_PR_ARG)
+);
+
+TRACE_EVENT(rdev_set_monitor_channel,
+       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan,
+                enum nl80211_channel_type chan_type),
+       TP_ARGS(wiphy, chan, chan_type),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               CHAN_ENTRY
+               __field(enum nl80211_channel_type, chan_type)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               CHAN_ASSIGN(chan);
+               __entry->chan_type = chan_type;
+       ),
+       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type : %d",
+                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->chan_type)
+);
+
+TRACE_EVENT(rdev_auth,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_auth_request *req),
+       TP_ARGS(wiphy, netdev, req),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               __field(enum nl80211_auth_type, auth_type)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               if (req->bss)
+                       MAC_ASSIGN(bssid, req->bss->bssid);
+               else
+                       memset(__entry->bssid, 0, ETH_ALEN);
+               __entry->auth_type = req->auth_type;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->auth_type,
+                 MAC_PR_ARG(bssid))
+);
+
+TRACE_EVENT(rdev_assoc,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_assoc_request *req),
+       TP_ARGS(wiphy, netdev, req),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               MAC_ENTRY(prev_bssid)
+               __field(bool, use_mfp)
+               __field(u32, flags)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               if (req->bss)
+                       MAC_ASSIGN(bssid, req->bss->bssid);
+               else
+                       memset(__entry->bssid, 0, ETH_ALEN);
+               MAC_ASSIGN(prev_bssid, req->prev_bssid);
+               __entry->use_mfp = req->use_mfp;
+               __entry->flags = req->flags;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+                 ", previous bssid: " MAC_PR_FMT ", use mfp: %s, flags: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid),
+                 MAC_PR_ARG(prev_bssid), BOOL_TO_STR(__entry->use_mfp),
+                 __entry->flags)
+);
+
+TRACE_EVENT(rdev_deauth,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_deauth_request *req),
+       TP_ARGS(wiphy, netdev, req),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               __field(u16, reason_code)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(bssid, req->bssid);
+               __entry->reason_code = req->reason_code;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid),
+                 __entry->reason_code)
+);
+
+TRACE_EVENT(rdev_disassoc,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_disassoc_request *req),
+       TP_ARGS(wiphy, netdev, req),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               __field(u16, reason_code)
+               __field(bool, local_state_change)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               if (req->bss)
+                       MAC_ASSIGN(bssid, req->bss->bssid);
+               else
+                       memset(__entry->bssid, 0, ETH_ALEN);
+               __entry->reason_code = req->reason_code;
+               __entry->local_state_change = req->local_state_change;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+                 ", reason: %u, local state change: %s",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid),
+                 __entry->reason_code,
+                 BOOL_TO_STR(__entry->local_state_change))
+);
+
+TRACE_EVENT(rdev_mgmt_tx_cancel_wait,
+       TP_PROTO(struct wiphy *wiphy,
+                struct wireless_dev *wdev, u64 cookie),
+       TP_ARGS(wiphy, wdev, cookie),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               WDEV_ENTRY
+               __field(u64, cookie)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               WDEV_ASSIGN;
+               __entry->cookie = cookie;
+       ),
+       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu ",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie)
+);
+
+TRACE_EVENT(rdev_set_power_mgmt,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                bool enabled, int timeout),
+       TP_ARGS(wiphy, netdev, enabled, timeout),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(bool, enabled)
+               __field(int, timeout)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->enabled = enabled;
+               __entry->timeout = timeout;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", %senabled, timeout: %d ",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG,
+                 __entry->enabled ? "" : "not ", __entry->timeout)
+);
+
+TRACE_EVENT(rdev_connect,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_connect_params *sme),
+       TP_ARGS(wiphy, netdev, sme),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1)
+               __field(enum nl80211_auth_type, auth_type)
+               __field(bool, privacy)
+               __field(u32, wpa_versions)
+               __field(u32, flags)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(bssid, sme->bssid);
+               memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
+               memcpy(__entry->ssid, sme->ssid, sme->ssid_len);
+               __entry->auth_type = sme->auth_type;
+               __entry->privacy = sme->privacy;
+               __entry->wpa_versions = sme->crypto.wpa_versions;
+               __entry->flags = sme->flags;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+                 ", ssid: %s, auth type: %d, privacy: %s, wpa versions: %u, "
+                 "flags: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid,
+                 __entry->auth_type, BOOL_TO_STR(__entry->privacy),
+                 __entry->wpa_versions, __entry->flags)
+);
+
+TRACE_EVENT(rdev_set_cqm_rssi_config,
+       TP_PROTO(struct wiphy *wiphy,
+                struct net_device *netdev, s32 rssi_thold,
+                u32 rssi_hyst),
+       TP_ARGS(wiphy, netdev, rssi_thold, rssi_hyst),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(s32, rssi_thold)
+               __field(u32, rssi_hyst)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->rssi_thold = rssi_thold;
+               __entry->rssi_hyst = rssi_hyst;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT
+                 ", rssi_thold: %d, rssi_hyst: %u ",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG,
+                __entry->rssi_thold, __entry->rssi_hyst)
+);
+
+TRACE_EVENT(rdev_set_cqm_txe_config,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate,
+                u32 pkts, u32 intvl),
+       TP_ARGS(wiphy, netdev, rate, pkts, intvl),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u32, rate)
+               __field(u32, pkts)
+               __field(u32, intvl)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->rate = rate;
+               __entry->pkts = pkts;
+               __entry->intvl = intvl;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->rate, __entry->pkts,
+                 __entry->intvl)
+);
+
+TRACE_EVENT(rdev_disconnect,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                u16 reason_code),
+       TP_ARGS(wiphy, netdev, reason_code),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u16, reason_code)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->reason_code = reason_code;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG,
+                 NETDEV_PR_ARG, __entry->reason_code)
+);
+
+TRACE_EVENT(rdev_join_ibss,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_ibss_params *params),
+       TP_ARGS(wiphy, netdev, params),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(bssid, params->bssid);
+               memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
+               memcpy(__entry->ssid, params->ssid, params->ssid_len);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid)
+);
+
+TRACE_EVENT(rdev_set_wiphy_params,
+       TP_PROTO(struct wiphy *wiphy, u32 changed),
+       TP_ARGS(wiphy, changed),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(u32, changed)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->changed = changed;
+       ),
+       TP_printk(WIPHY_PR_FMT ", changed: %u",
+                 WIPHY_PR_ARG, __entry->changed)
+);
+
+TRACE_EVENT(rdev_set_tx_power,
+       TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type,
+                int mbm),
+       TP_ARGS(wiphy, type, mbm),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(enum nl80211_tx_power_setting, type)
+               __field(int, mbm)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->type = type;
+               __entry->mbm = mbm;
+       ),
+       TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d",
+                 WIPHY_PR_ARG, __entry->type, __entry->mbm)
+);
+
+TRACE_EVENT(rdev_return_int_int,
+       TP_PROTO(struct wiphy *wiphy, int func_ret, int func_fill),
+       TP_ARGS(wiphy, func_ret, func_fill),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(int, func_ret)
+               __field(int, func_fill)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->func_ret = func_ret;
+               __entry->func_fill = func_fill;
+       ),
+       TP_printk(WIPHY_PR_FMT ", function returns: %d, function filled: %d",
+                 WIPHY_PR_ARG, __entry->func_ret, __entry->func_fill)
+);
+
+#ifdef CONFIG_NL80211_TESTMODE
+TRACE_EVENT(rdev_testmode_cmd,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG)
+);
+
+TRACE_EVENT(rdev_testmode_dump,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT, WIPHY_PR_ARG)
+);
+#endif /* CONFIG_NL80211_TESTMODE */
+
+TRACE_EVENT(rdev_set_bitrate_mask,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                const u8 *peer, const struct cfg80211_bitrate_mask *mask),
+       TP_ARGS(wiphy, netdev, peer, mask),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(peer)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(peer, peer);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", peer: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
+);
+
+TRACE_EVENT(rdev_mgmt_frame_register,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+                u16 frame_type, bool reg),
+       TP_ARGS(wiphy, wdev, frame_type, reg),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               WDEV_ENTRY
+               __field(u16, frame_type)
+               __field(bool, reg)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               WDEV_ASSIGN;
+               __entry->frame_type = frame_type;
+               __entry->reg = reg;
+       ),
+       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", frame_type: %u, reg: %s ",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type,
+                 __entry->reg ? "true" : "false")
+);
+
+TRACE_EVENT(rdev_return_int_tx_rx,
+       TP_PROTO(struct wiphy *wiphy, int ret, u32 tx, u32 rx),
+       TP_ARGS(wiphy, ret, tx, rx),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(int, ret)
+               __field(u32, tx)
+               __field(u32, rx)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->ret = ret;
+               __entry->tx = tx;
+               __entry->rx = rx;
+       ),
+       TP_printk(WIPHY_PR_FMT ", returned %d, tx: %u, rx: %u",
+                 WIPHY_PR_ARG, __entry->ret, __entry->tx, __entry->rx)
+);
+
+TRACE_EVENT(rdev_return_void_tx_rx,
+       TP_PROTO(struct wiphy *wiphy, u32 tx, u32 tx_max,
+                u32 rx, u32 rx_max),
+       TP_ARGS(wiphy, tx, tx_max, rx, rx_max),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(u32, tx)
+               __field(u32, tx_max)
+               __field(u32, rx)
+               __field(u32, rx_max)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->tx = tx;
+               __entry->tx_max = tx_max;
+               __entry->rx = rx;
+               __entry->rx_max = rx_max;
+       ),
+       TP_printk(WIPHY_PR_FMT ", tx: %u, tx_max: %u, rx: %u, rx_max: %u ",
+                 WIPHY_PR_ARG, __entry->tx, __entry->tx_max, __entry->rx,
+                 __entry->rx_max)
+);
+
+DECLARE_EVENT_CLASS(tx_rx_evt,
+       TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx),
+       TP_ARGS(wiphy, rx, tx),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(u32, tx)
+               __field(u32, rx)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->tx = tx;
+               __entry->rx = rx;
+       ),
+       TP_printk(WIPHY_PR_FMT ", tx: %u, rx: %u ",
+                 WIPHY_PR_ARG, __entry->tx, __entry->rx)
+);
+
+DEFINE_EVENT(tx_rx_evt, rdev_set_ringparam,
+       TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx),
+       TP_ARGS(wiphy, rx, tx)
+);
+
+DEFINE_EVENT(tx_rx_evt, rdev_set_antenna,
+       TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx),
+       TP_ARGS(wiphy, rx, tx)
+);
+
+TRACE_EVENT(rdev_sched_scan_start,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_sched_scan_request *request),
+       TP_ARGS(wiphy, netdev, request),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG)
+);
+
+TRACE_EVENT(rdev_tdls_mgmt,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                u8 *peer, u8 action_code, u8 dialog_token,
+                u16 status_code, const u8 *buf, size_t len),
+       TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code,
+               buf, len),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(peer)
+               __field(u8, action_code)
+               __field(u8, dialog_token)
+               __field(u16, status_code)
+               __dynamic_array(u8, buf, len)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(peer, peer);
+               __entry->action_code = action_code;
+               __entry->dialog_token = dialog_token;
+               __entry->status_code = status_code;
+               memcpy(__get_dynamic_array(buf), buf, len);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", action_code: %u, "
+                 "dialog_token: %u, status_code: %u, buf: %#.2x ",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
+                 __entry->action_code, __entry->dialog_token,
+                 __entry->status_code, ((u8 *)__get_dynamic_array(buf))[0])
+);
+
+TRACE_EVENT(rdev_dump_survey,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx),
+       TP_ARGS(wiphy, netdev, idx),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(int, idx)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->idx = idx;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx)
+);
+
+TRACE_EVENT(rdev_return_int_survey_info,
+       TP_PROTO(struct wiphy *wiphy, int ret, struct survey_info *info),
+       TP_ARGS(wiphy, ret, info),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               CHAN_ENTRY
+               __field(int, ret)
+               __field(u64, channel_time)
+               __field(u64, channel_time_busy)
+               __field(u64, channel_time_ext_busy)
+               __field(u64, channel_time_rx)
+               __field(u64, channel_time_tx)
+               __field(u32, filled)
+               __field(s8, noise)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               CHAN_ASSIGN(info->channel);
+               __entry->ret = ret;
+               __entry->channel_time = info->channel_time;
+               __entry->channel_time_busy = info->channel_time_busy;
+               __entry->channel_time_ext_busy = info->channel_time_ext_busy;
+               __entry->channel_time_rx = info->channel_time_rx;
+               __entry->channel_time_tx = info->channel_time_tx;
+               __entry->filled = info->filled;
+               __entry->noise = info->noise;
+       ),
+       TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT
+                 ", channel time: %llu, channel time busy: %llu, "
+                 "channel time extension busy: %llu, channel time rx: %llu, "
+                 "channel time tx: %llu, filled: %u, noise: %d",
+                 WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG,
+                 __entry->channel_time, __entry->channel_time_busy,
+                 __entry->channel_time_ext_busy, __entry->channel_time_rx,
+                 __entry->channel_time_tx, __entry->filled, __entry->noise)
+);
+
+TRACE_EVENT(rdev_tdls_oper,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                u8 *peer, enum nl80211_tdls_operation oper),
+       TP_ARGS(wiphy, netdev, peer, oper),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(peer)
+               __field(enum nl80211_tdls_operation, oper)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(peer, peer);
+               __entry->oper = oper;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", oper: %d",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper)
+);
+
+DECLARE_EVENT_CLASS(rdev_pmksa,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_pmksa *pmksa),
+       TP_ARGS(wiphy, netdev, pmksa),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(bssid, pmksa->bssid);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid))
+);
+
+TRACE_EVENT(rdev_probe_client,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                const u8 *peer),
+       TP_ARGS(wiphy, netdev, peer),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(peer)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(peer, peer);
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
+);
+
+DEFINE_EVENT(rdev_pmksa, rdev_set_pmksa,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_pmksa *pmksa),
+       TP_ARGS(wiphy, netdev, pmksa)
+);
+
+DEFINE_EVENT(rdev_pmksa, rdev_del_pmksa,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_pmksa *pmksa),
+       TP_ARGS(wiphy, netdev, pmksa)
+);
+
+TRACE_EVENT(rdev_remain_on_channel,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+                struct ieee80211_channel *chan,
+                enum nl80211_channel_type channel_type, unsigned int duration),
+       TP_ARGS(wiphy, wdev, chan, channel_type, duration),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               WDEV_ENTRY
+               CHAN_ENTRY
+               __field(enum nl80211_channel_type, channel_type)
+               __field(unsigned int, duration)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               WDEV_ASSIGN;
+               CHAN_ASSIGN(chan);
+               __entry->channel_type = channel_type;
+               __entry->duration = duration;
+       ),
+       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", channel type: %d, duration: %u",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->channel_type,
+                 __entry->duration)
+);
+
+TRACE_EVENT(rdev_return_int_cookie,
+       TP_PROTO(struct wiphy *wiphy, int ret, u64 cookie),
+       TP_ARGS(wiphy, ret, cookie),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(int, ret)
+               __field(u64, cookie)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->ret = ret;
+               __entry->cookie = cookie;
+       ),
+       TP_printk(WIPHY_PR_FMT ", returned %d, cookie: %llu",
+                 WIPHY_PR_ARG, __entry->ret, __entry->cookie)
+);
+
+TRACE_EVENT(rdev_cancel_remain_on_channel,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie),
+       TP_ARGS(wiphy, wdev, cookie),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               WDEV_ENTRY
+               __field(u64, cookie)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               WDEV_ASSIGN;
+               __entry->cookie = cookie;
+       ),
+       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie)
+);
+
+TRACE_EVENT(rdev_mgmt_tx,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+                struct ieee80211_channel *chan, bool offchan,
+                enum nl80211_channel_type channel_type,
+                bool channel_type_valid, unsigned int wait, bool no_cck,
+                bool dont_wait_for_ack),
+       TP_ARGS(wiphy, wdev, chan, offchan, channel_type, channel_type_valid,
+               wait, no_cck, dont_wait_for_ack),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               WDEV_ENTRY
+               CHAN_ENTRY
+               __field(bool, offchan)
+               __field(enum nl80211_channel_type, channel_type)
+               __field(bool, channel_type_valid)
+               __field(unsigned int, wait)
+               __field(bool, no_cck)
+               __field(bool, dont_wait_for_ack)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               WDEV_ASSIGN;
+               CHAN_ASSIGN(chan);
+               __entry->offchan = offchan;
+               __entry->channel_type = channel_type;
+               __entry->channel_type_valid = channel_type_valid;
+               __entry->wait = wait;
+               __entry->no_cck = no_cck;
+               __entry->dont_wait_for_ack = dont_wait_for_ack;
+       ),
+       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", offchan: %s, "
+                 "channel type: %d, channel type valid: %s, wait: %u, "
+                 "no cck: %s, dont wait for ack: %s",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG,
+                 BOOL_TO_STR(__entry->offchan), __entry->channel_type,
+                 BOOL_TO_STR(__entry->channel_type_valid), __entry->wait,
+                 BOOL_TO_STR(__entry->no_cck),
+                 BOOL_TO_STR(__entry->dont_wait_for_ack))
+);
+
+TRACE_EVENT(rdev_set_noack_map,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                u16 noack_map),
+       TP_ARGS(wiphy, netdev, noack_map),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u16, noack_map)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->noack_map = noack_map;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", noack_map: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map)
+);
+
+TRACE_EVENT(rdev_get_et_sset_count,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int sset),
+       TP_ARGS(wiphy, netdev, sset),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(int, sset)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->sset = sset;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %d",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset)
+);
+
+TRACE_EVENT(rdev_get_et_strings,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 sset),
+       TP_ARGS(wiphy, netdev, sset),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               __field(u32, sset)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               __entry->sset = sset;
+       ),
+       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset)
+);
+
+DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev)
+);
+
+TRACE_EVENT(rdev_return_channel,
+       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan,
+                enum nl80211_channel_type type),
+       TP_ARGS(wiphy, chan, type),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               CHAN_ENTRY
+               __field(enum nl80211_channel_type, type)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               CHAN_ASSIGN(chan);
+               __entry->type = type;
+       ),
+       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type: %d",
+                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type)
+);
+
+DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev)
+);
+
+DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev)
+);
+
+/*************************************************************
+ *          cfg80211 exported functions traces              *
+ *************************************************************/
+
+TRACE_EVENT(cfg80211_return_bool,
+       TP_PROTO(bool ret),
+       TP_ARGS(ret),
+       TP_STRUCT__entry(
+               __field(bool, ret)
+       ),
+       TP_fast_assign(
+               __entry->ret = ret;
+       ),
+       TP_printk("returned %s", BOOL_TO_STR(__entry->ret))
+);
+
+DECLARE_EVENT_CLASS(cfg80211_netdev_mac_evt,
+       TP_PROTO(struct net_device *netdev, const u8 *macaddr),
+       TP_ARGS(netdev, macaddr),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(macaddr)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(macaddr, macaddr);
+       ),
+       TP_printk(NETDEV_PR_FMT ", mac: " MAC_PR_FMT,
+                 NETDEV_PR_ARG, MAC_PR_ARG(macaddr))
+);
+
+DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_notify_new_peer_candidate,
+       TP_PROTO(struct net_device *netdev, const u8 *macaddr),
+       TP_ARGS(netdev, macaddr)
+);
+
+DECLARE_EVENT_CLASS(netdev_evt_only,
+       TP_PROTO(struct net_device *netdev),
+       TP_ARGS(netdev),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+       ),
+       TP_printk(NETDEV_PR_FMT , NETDEV_PR_ARG)
+);
+
+DEFINE_EVENT(netdev_evt_only, cfg80211_send_rx_auth,
+       TP_PROTO(struct net_device *netdev),
+       TP_ARGS(netdev)
+);
+
+TRACE_EVENT(cfg80211_send_rx_assoc,
+       TP_PROTO(struct net_device *netdev, struct cfg80211_bss *bss),
+       TP_ARGS(netdev, bss),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               CHAN_ENTRY
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(bssid, bss->bssid);
+               CHAN_ASSIGN(bss->channel);
+       ),
+       TP_printk(NETDEV_PR_FMT MAC_PR_FMT CHAN_PR_FMT,
+                 NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
+);
+
+DEFINE_EVENT(netdev_evt_only, __cfg80211_send_deauth,
+       TP_PROTO(struct net_device *netdev),
+       TP_ARGS(netdev)
+);
+
+DEFINE_EVENT(netdev_evt_only, __cfg80211_send_disassoc,
+       TP_PROTO(struct net_device *netdev),
+       TP_ARGS(netdev)
+);
+
+DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_deauth,
+       TP_PROTO(struct net_device *netdev),
+       TP_ARGS(netdev)
+);
+
+DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_disassoc,
+       TP_PROTO(struct net_device *netdev),
+       TP_ARGS(netdev)
+);
+
+DECLARE_EVENT_CLASS(netdev_mac_evt,
+       TP_PROTO(struct net_device *netdev, const u8 *mac),
+       TP_ARGS(netdev, mac),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(mac)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(mac, mac)
+       ),
+       TP_printk(NETDEV_PR_FMT ", mac: " MAC_PR_FMT,
+                 NETDEV_PR_ARG, MAC_PR_ARG(mac))
+);
+
+DEFINE_EVENT(netdev_mac_evt, cfg80211_send_auth_timeout,
+       TP_PROTO(struct net_device *netdev, const u8 *mac),
+       TP_ARGS(netdev, mac)
+);
+
+DEFINE_EVENT(netdev_mac_evt, cfg80211_send_assoc_timeout,
+       TP_PROTO(struct net_device *netdev, const u8 *mac),
+       TP_ARGS(netdev, mac)
+);
+
+TRACE_EVENT(cfg80211_michael_mic_failure,
+       TP_PROTO(struct net_device *netdev, const u8 *addr,
+                enum nl80211_key_type key_type, int key_id, const u8 *tsc),
+       TP_ARGS(netdev, addr, key_type, key_id, tsc),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(addr)
+               __field(enum nl80211_key_type, key_type)
+               __field(int, key_id)
+               __array(u8, tsc, 6)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(addr, addr);
+               __entry->key_type = key_type;
+               __entry->key_id = key_id;
+               memcpy(__entry->tsc, tsc, 6);
+       ),
+       TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm",
+                 NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type,
+                 __entry->key_id, __entry->tsc)
+);
+
+TRACE_EVENT(cfg80211_ready_on_channel,
+       TP_PROTO(struct wireless_dev *wdev, u64 cookie,
+                struct ieee80211_channel *chan,
+                enum nl80211_channel_type channel_type, unsigned int duration),
+       TP_ARGS(wdev, cookie, chan, channel_type, duration),
+       TP_STRUCT__entry(
+               WDEV_ENTRY
+               __field(u64, cookie)
+               CHAN_ENTRY
+               __field(enum nl80211_channel_type, channel_type)
+               __field(unsigned int, duration)
+       ),
+       TP_fast_assign(
+               WDEV_ASSIGN;
+               __entry->cookie = cookie;
+               CHAN_ASSIGN(chan);
+               __entry->channel_type = channel_type;
+               __entry->duration = duration;
+       ),
+       TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d, duration: %u",
+                 WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG,
+                 __entry->channel_type, __entry->duration)
+);
+
+TRACE_EVENT(cfg80211_ready_on_channel_expired,
+       TP_PROTO(struct wireless_dev *wdev, u64 cookie,
+                struct ieee80211_channel *chan,
+                enum nl80211_channel_type channel_type),
+       TP_ARGS(wdev, cookie, chan, channel_type),
+       TP_STRUCT__entry(
+               WDEV_ENTRY
+               __field(u64, cookie)
+               CHAN_ENTRY
+               __field(enum nl80211_channel_type, channel_type)
+       ),
+       TP_fast_assign(
+               WDEV_ASSIGN;
+               __entry->cookie = cookie;
+               CHAN_ASSIGN(chan);
+               __entry->channel_type = channel_type;
+       ),
+       TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d",
+                 WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG,
+                 __entry->channel_type)
+);
+
+TRACE_EVENT(cfg80211_new_sta,
+       TP_PROTO(struct net_device *netdev, const u8 *mac_addr,
+                struct station_info *sinfo),
+       TP_ARGS(netdev, mac_addr, sinfo),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(mac_addr)
+               SINFO_ENTRY
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(mac_addr, mac_addr);
+               SINFO_ASSIGN;
+       ),
+       TP_printk(NETDEV_PR_FMT MAC_PR_FMT,
+                 NETDEV_PR_ARG, MAC_PR_ARG(mac_addr))
+);
+
+DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_del_sta,
+       TP_PROTO(struct net_device *netdev, const u8 *macaddr),
+       TP_ARGS(netdev, macaddr)
+);
+
+TRACE_EVENT(cfg80211_rx_mgmt,
+       TP_PROTO(struct wireless_dev *wdev, int freq, int sig_mbm),
+       TP_ARGS(wdev, freq, sig_mbm),
+       TP_STRUCT__entry(
+               WDEV_ENTRY
+               __field(int, freq)
+               __field(int, sig_mbm)
+       ),
+       TP_fast_assign(
+               WDEV_ASSIGN;
+               __entry->freq = freq;
+               __entry->sig_mbm = sig_mbm;
+       ),
+       TP_printk(WDEV_PR_FMT ", freq: %d, sig mbm: %d",
+                 WDEV_PR_ARG, __entry->freq, __entry->sig_mbm)
+);
+
+TRACE_EVENT(cfg80211_mgmt_tx_status,
+       TP_PROTO(struct wireless_dev *wdev, u64 cookie, bool ack),
+       TP_ARGS(wdev, cookie, ack),
+       TP_STRUCT__entry(
+               WDEV_ENTRY
+               __field(u64, cookie)
+               __field(bool, ack)
+       ),
+       TP_fast_assign(
+               WDEV_ASSIGN;
+               __entry->cookie = cookie;
+               __entry->ack = ack;
+       ),
+       TP_printk(WDEV_PR_FMT", cookie: %llu, ack: %s",
+                 WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack))
+);
+
+TRACE_EVENT(cfg80211_cqm_rssi_notify,
+       TP_PROTO(struct net_device *netdev,
+                enum nl80211_cqm_rssi_threshold_event rssi_event),
+       TP_ARGS(netdev, rssi_event),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               __field(enum nl80211_cqm_rssi_threshold_event, rssi_event)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               __entry->rssi_event = rssi_event;
+       ),
+       TP_printk(NETDEV_PR_FMT ", rssi event: %d",
+                 NETDEV_PR_ARG, __entry->rssi_event)
+);
+
+TRACE_EVENT(cfg80211_can_beacon_sec_chan,
+       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
+                enum nl80211_channel_type channel_type),
+       TP_ARGS(wiphy, channel, channel_type),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               CHAN_ENTRY
+               __field(enum nl80211_channel_type, channel_type)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               CHAN_ASSIGN(channel);
+               __entry->channel_type = channel_type;
+       ),
+       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel_type: %d",
+                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->channel_type)
+);
+
+TRACE_EVENT(cfg80211_ch_switch_notify,
+       TP_PROTO(struct net_device *netdev, int freq,
+                enum nl80211_channel_type type),
+       TP_ARGS(netdev, freq, type),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               __field(int, freq)
+               __field(enum nl80211_channel_type, type)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               __entry->freq = freq;
+               __entry->type = type;
+       ),
+       TP_printk(NETDEV_PR_FMT ", freq: %d, type: %d", NETDEV_PR_ARG,
+                 __entry->freq, __entry->type)
+);
+
+DECLARE_EVENT_CLASS(cfg80211_rx_evt,
+       TP_PROTO(struct net_device *netdev, const u8 *addr),
+       TP_ARGS(netdev, addr),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(addr)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(addr, addr);
+       ),
+       TP_printk(NETDEV_PR_FMT MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr))
+);
+
+DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined,
+       TP_PROTO(struct net_device *netdev, const u8 *addr),
+       TP_ARGS(netdev, addr)
+);
+
+DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame,
+       TP_PROTO(struct net_device *netdev, const u8 *addr),
+       TP_ARGS(netdev, addr)
+);
+
+DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame,
+       TP_PROTO(struct net_device *netdev, const u8 *addr),
+       TP_ARGS(netdev, addr)
+);
+
+TRACE_EVENT(cfg80211_probe_status,
+       TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie,
+                bool acked),
+       TP_ARGS(netdev, addr, cookie, acked),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(addr)
+               __field(u64, cookie)
+               __field(bool, acked)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(addr, addr);
+               __entry->cookie = cookie;
+               __entry->acked = acked;
+       ),
+       TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", cookie: %llu, acked: %s",
+                 NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->cookie,
+                 BOOL_TO_STR(__entry->acked))
+);
+
+TRACE_EVENT(cfg80211_cqm_pktloss_notify,
+       TP_PROTO(struct net_device *netdev, const u8 *peer, u32 num_packets),
+       TP_ARGS(netdev, peer, num_packets),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(peer)
+               __field(u32, num_packets)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(peer, peer);
+               __entry->num_packets = num_packets;
+       ),
+       TP_printk(NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", num of lost packets: %u",
+                 NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->num_packets)
+);
+
+DEFINE_EVENT(cfg80211_netdev_mac_evt, cfg80211_gtk_rekey_notify,
+       TP_PROTO(struct net_device *netdev, const u8 *macaddr),
+       TP_ARGS(netdev, macaddr)
+);
+
+TRACE_EVENT(cfg80211_pmksa_candidate_notify,
+       TP_PROTO(struct net_device *netdev, int index, const u8 *bssid,
+                bool preauth),
+       TP_ARGS(netdev, index, bssid, preauth),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               __field(int, index)
+               MAC_ENTRY(bssid)
+               __field(bool, preauth)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               __entry->index = index;
+               MAC_ASSIGN(bssid, bssid);
+               __entry->preauth = preauth;
+       ),
+       TP_printk(NETDEV_PR_FMT ", index:%d, bssid: " MAC_PR_FMT ", pre auth: %s",
+                 NETDEV_PR_ARG, __entry->index, MAC_PR_ARG(bssid),
+                 BOOL_TO_STR(__entry->preauth))
+);
+
+TRACE_EVENT(cfg80211_report_obss_beacon,
+       TP_PROTO(struct wiphy *wiphy, const u8 *frame, size_t len,
+                int freq, int sig_dbm),
+       TP_ARGS(wiphy, frame, len, freq, sig_dbm),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               __field(int, freq)
+               __field(int, sig_dbm)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               __entry->freq = freq;
+               __entry->sig_dbm = sig_dbm;
+       ),
+       TP_printk(WIPHY_PR_FMT ", freq: %d, sig_dbm: %d",
+                 WIPHY_PR_ARG, __entry->freq, __entry->sig_dbm)
+);
+
+TRACE_EVENT(cfg80211_scan_done,
+       TP_PROTO(struct cfg80211_scan_request *request, bool aborted),
+       TP_ARGS(request, aborted),
+       TP_STRUCT__entry(
+               __field(u32, n_channels)
+               __dynamic_array(u8, ie, request ? request->ie_len : 0)
+               __array(u32, rates, IEEE80211_NUM_BANDS)
+               __field(u32, wdev_id)
+               MAC_ENTRY(wiphy_mac)
+               __field(bool, no_cck)
+               __field(bool, aborted)
+       ),
+       TP_fast_assign(
+               if (request) {
+                       memcpy(__get_dynamic_array(ie), request->ie,
+                              request->ie_len);
+                       memcpy(__entry->rates, request->rates,
+                              IEEE80211_NUM_BANDS);
+                       __entry->wdev_id = request->wdev ?
+                                       request->wdev->identifier : 0;
+                       if (request->wiphy)
+                               MAC_ASSIGN(wiphy_mac,
+                                          request->wiphy->perm_addr);
+                       __entry->no_cck = request->no_cck;
+               }
+               __entry->aborted = aborted;
+       ),
+       TP_printk("aborted: %s", BOOL_TO_STR(__entry->aborted))
+);
+
+DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_results,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_stopped,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+);
+
+TRACE_EVENT(cfg80211_get_bss,
+       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
+                const u8 *bssid, const u8 *ssid, size_t ssid_len,
+                u16 capa_mask, u16 capa_val),
+       TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               CHAN_ENTRY
+               MAC_ENTRY(bssid)
+               __dynamic_array(u8, ssid, ssid_len)
+               __field(u16, capa_mask)
+               __field(u16, capa_val)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               CHAN_ASSIGN(channel);
+               MAC_ASSIGN(bssid, bssid);
+               memcpy(__get_dynamic_array(ssid), ssid, ssid_len);
+               __entry->capa_mask = capa_mask;
+               __entry->capa_val = capa_val;
+       ),
+       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT MAC_PR_FMT ", buf: %#.2x, "
+                 "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG,
+                 MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0],
+                 __entry->capa_mask, __entry->capa_val)
+);
+
+TRACE_EVENT(cfg80211_inform_bss_frame,
+       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
+                struct ieee80211_mgmt *mgmt, size_t len,
+                s32 signal),
+       TP_ARGS(wiphy, channel, mgmt, len, signal),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               CHAN_ENTRY
+               __dynamic_array(u8, mgmt, len)
+               __field(s32, signal)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               CHAN_ASSIGN(channel);
+               if (mgmt)
+                       memcpy(__get_dynamic_array(mgmt), mgmt, len);
+               __entry->signal = signal;
+       ),
+       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT "signal: %d",
+                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal)
+);
+
+DECLARE_EVENT_CLASS(cfg80211_bss_evt,
+       TP_PROTO(struct cfg80211_bss *pub),
+       TP_ARGS(pub),
+       TP_STRUCT__entry(
+               MAC_ENTRY(bssid)
+               CHAN_ENTRY
+       ),
+       TP_fast_assign(
+               MAC_ASSIGN(bssid, pub->bssid);
+               CHAN_ASSIGN(pub->channel);
+       ),
+       TP_printk(MAC_PR_FMT CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG)
+);
+
+DEFINE_EVENT(cfg80211_bss_evt, cfg80211_return_bss,
+       TP_PROTO(struct cfg80211_bss *pub),
+       TP_ARGS(pub)
+);
+
+TRACE_EVENT(cfg80211_return_uint,
+       TP_PROTO(unsigned int ret),
+       TP_ARGS(ret),
+       TP_STRUCT__entry(
+               __field(unsigned int, ret)
+       ),
+       TP_fast_assign(
+               __entry->ret = ret;
+       ),
+       TP_printk("ret: %d", __entry->ret)
+);
+
+TRACE_EVENT(cfg80211_return_u32,
+       TP_PROTO(u32 ret),
+       TP_ARGS(ret),
+       TP_STRUCT__entry(
+               __field(u32, ret)
+       ),
+       TP_fast_assign(
+               __entry->ret = ret;
+       ),
+       TP_printk("ret: %u", __entry->ret)
+);
+
+#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
index 2762e83..5b6c1df 100644 (file)
@@ -11,6 +11,8 @@
 #include <net/ip.h>
 #include <net/dsfield.h>
 #include "core.h"
+#include "rdev-ops.h"
+
 
 struct ieee80211_rate *
 ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
@@ -705,19 +707,18 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
        for (i = 0; i < 6; i++) {
                if (!wdev->connect_keys->params[i].cipher)
                        continue;
-               if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL,
-                                       &wdev->connect_keys->params[i])) {
+               if (rdev_add_key(rdev, dev, i, false, NULL,
+                                &wdev->connect_keys->params[i])) {
                        netdev_err(dev, "failed to set key %d\n", i);
                        continue;
                }
                if (wdev->connect_keys->def == i)
-                       if (rdev->ops->set_default_key(wdev->wiphy, dev,
-                                                      i, true, true)) {
+                       if (rdev_set_default_key(rdev, dev, i, true, true)) {
                                netdev_err(dev, "failed to set defkey %d\n", i);
                                continue;
                        }
                if (wdev->connect_keys->defmgmt == i)
-                       if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
+                       if (rdev_set_default_mgmt_key(rdev, dev, i))
                                netdev_err(dev, "failed to set mgtdef %d\n", i);
        }
 
@@ -850,8 +851,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                cfg80211_process_rdev_events(rdev);
        }
 
-       err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
-                                            ntype, flags, params);
+       err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params);
 
        WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 
index 494379e..6488d2d 100644 (file)
@@ -19,6 +19,7 @@
 #include <net/cfg80211-wext.h>
 #include "wext-compat.h"
 #include "core.h"
+#include "rdev-ops.h"
 
 int cfg80211_wext_giwname(struct net_device *dev,
                          struct iw_request_info *info,
@@ -301,8 +302,7 @@ int cfg80211_wext_siwrts(struct net_device *dev,
        else
                wdev->wiphy->rts_threshold = rts->value;
 
-       err = rdev->ops->set_wiphy_params(wdev->wiphy,
-                                         WIPHY_PARAM_RTS_THRESHOLD);
+       err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_RTS_THRESHOLD);
        if (err)
                wdev->wiphy->rts_threshold = orts;
 
@@ -342,8 +342,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev,
                wdev->wiphy->frag_threshold = frag->value & ~0x1;
        }
 
-       err = rdev->ops->set_wiphy_params(wdev->wiphy,
-                                         WIPHY_PARAM_FRAG_THRESHOLD);
+       err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_FRAG_THRESHOLD);
        if (err)
                wdev->wiphy->frag_threshold = ofrag;
 
@@ -396,7 +395,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev,
        if (!changed)
                return 0;
 
-       err = rdev->ops->set_wiphy_params(wdev->wiphy, changed);
+       err = rdev_set_wiphy_params(rdev, changed);
        if (err) {
                wdev->wiphy->retry_short = oshort;
                wdev->wiphy->retry_long = olong;
@@ -490,8 +489,8 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
                            !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
                                err = -ENOENT;
                        else
-                               err = rdev->ops->del_key(&rdev->wiphy, dev, idx,
-                                                        pairwise, addr);
+                               err = rdev_del_key(rdev, dev, idx, pairwise,
+                                                  addr);
                }
                wdev->wext.connect.privacy = false;
                /*
@@ -525,8 +524,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 
        err = 0;
        if (wdev->current_bss)
-               err = rdev->ops->add_key(&rdev->wiphy, dev, idx,
-                                        pairwise, addr, params);
+               err = rdev_add_key(rdev, dev, idx, pairwise, addr, params);
        if (err)
                return err;
 
@@ -552,8 +550,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
                                __cfg80211_leave_ibss(rdev, wdev->netdev, true);
                                rejoin = true;
                        }
-                       err = rdev->ops->set_default_key(&rdev->wiphy, dev,
-                                                        idx, true, true);
+                       err = rdev_set_default_key(rdev, dev, idx, true, true);
                }
                if (!err) {
                        wdev->wext.default_key = idx;
@@ -566,8 +563,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
        if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
            (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
                if (wdev->current_bss)
-                       err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
-                                                             dev, idx);
+                       err = rdev_set_default_mgmt_key(rdev, dev, idx);
                if (!err)
                        wdev->wext.default_mgmt_key = idx;
                return err;
@@ -631,8 +627,8 @@ static int cfg80211_wext_siwencode(struct net_device *dev,
                err = 0;
                wdev_lock(wdev);
                if (wdev->current_bss)
-                       err = rdev->ops->set_default_key(&rdev->wiphy, dev,
-                                                        idx, true, true);
+                       err = rdev_set_default_key(rdev, dev, idx, true,
+                                                  true);
                if (!err)
                        wdev->wext.default_key = idx;
                wdev_unlock(wdev);
@@ -839,7 +835,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                if (!rdev->ops->get_channel)
                        return -EINVAL;
 
-               chan = rdev->ops->get_channel(wdev->wiphy, wdev, &channel_type);
+               chan = rdev_get_channel(rdev, wdev, &channel_type);
                if (!chan)
                        return -EINVAL;
                freq->m = chan->center_freq;
@@ -899,7 +895,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,
                return 0;
        }
 
-       return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm));
+       return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm));
 }
 
 static int cfg80211_wext_giwtxpower(struct net_device *dev,
@@ -918,7 +914,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
        if (!rdev->ops->get_tx_power)
                return -EOPNOTSUPP;
 
-       err = rdev->ops->get_tx_power(wdev->wiphy, &val);
+       err = rdev_get_tx_power(rdev, &val);
        if (err)
                return err;
 
@@ -1158,7 +1154,7 @@ static int cfg80211_wext_siwpower(struct net_device *dev,
                        timeout = wrq->value / 1000;
        }
 
-       err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout);
+       err = rdev_set_power_mgmt(rdev, dev, ps, timeout);
        if (err)
                return err;
 
@@ -1200,7 +1196,7 @@ static int cfg80211_wds_wext_siwap(struct net_device *dev,
        if (!rdev->ops->set_wds_peer)
                return -EOPNOTSUPP;
 
-       err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data);
+       err = rdev_set_wds_peer(rdev, dev, (u8 *)&addr->sa_data);
        if (err)
                return err;
 
@@ -1272,7 +1268,7 @@ static int cfg80211_wext_siwrate(struct net_device *dev,
        if (!match)
                return -EINVAL;
 
-       return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
+       return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
 }
 
 static int cfg80211_wext_giwrate(struct net_device *dev,
@@ -1302,7 +1298,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
        if (err)
                return err;
 
-       err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
+       err = rdev_get_station(rdev, dev, addr, &sinfo);
        if (err)
                return err;
 
@@ -1339,7 +1335,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
        memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
        wdev_unlock(wdev);
 
-       if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo))
+       if (rdev_get_station(rdev, dev, bssid, &sinfo))
                return NULL;
 
        memset(&wstats, 0, sizeof(wstats));
@@ -1474,19 +1470,19 @@ static int cfg80211_wext_siwpmksa(struct net_device *dev,
                if (!rdev->ops->set_pmksa)
                        return -EOPNOTSUPP;
 
-               return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
+               return rdev_set_pmksa(rdev, dev, &cfg_pmksa);
 
        case IW_PMKSA_REMOVE:
                if (!rdev->ops->del_pmksa)
                        return -EOPNOTSUPP;
 
-               return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
+               return rdev_del_pmksa(rdev, dev, &cfg_pmksa);
 
        case IW_PMKSA_FLUSH:
                if (!rdev->ops->flush_pmksa)
                        return -EOPNOTSUPP;
 
-               return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
+               return rdev_flush_pmksa(rdev, dev);
 
        default:
                return -EOPNOTSUPP;