#
-# Copyright (C) 2007-2012 OpenWrt.org
+# Copyright (C) 2007-2013 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
PKG_NAME:=mac80211
-PKG_VERSION:=2013-06-27
+PKG_VERSION:=2014-01-23.1
PKG_RELEASE:=1
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
-PKG_BACKPORT_VERSION:=.1
-PKG_MD5SUM:=73bd220c64c5c6fdc22b3bb7f180644f
+PKG_BACKPORT_VERSION:=
+PKG_MD5SUM:=8db16edbdaf4abc2e9c2f3b6c86736a6
PKG_SOURCE:=compat-wireless-$(PKG_VERSION)$(PKG_BACKPORT_VERSION).tar.bz2
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
PKG_DRIVERS = \
adm8211 ath5k libertas-usb libertas-sd p54-common p54-pci p54-usb p54-spi \
- rt2x00-lib rt2x00-pci rt2x00-usb rt2x00-soc rt2800-lib rt2400-pci \
- rt2500-pci rt2500-usb rt61-pci rt73-usb rt2800-pci rt2800-usb \
+ rt2x00-lib rt2x00-pci rt2x00-usb rt2800-lib rt2400-pci rt2500-pci \
+ rt2500-usb rt61-pci rt73-usb rt2800-mmio rt2800-pci rt2800-usb rt2800-soc \
rtl8180 rtl8187 zd1211rw mac80211-hwsim carl9170 b43 b43legacy \
- ath9k-common ath9k ath9k-htc ath net-libipw net-ipw2100 net-ipw2200 \
+ ath9k-common ath9k ath9k-htc ath10k ath net-libipw net-ipw2100 net-ipw2200 \
mwl8k net-hermes net-hermes-pci net-hermes-plx net-hermes-pcmcia \
- iwl-legacy iwl3945 iwl4965 iwlagn wl12xx lib80211
+ iwl-legacy iwl3945 iwl4965 iwlagn wlcore wl12xx wl18xx lib80211 \
+ rtlwifi rtlwifi-pci rtlwifi-usb rtl8192c-common rtl8192ce rtl8192se \
+ rtl8192de rtl8192cu
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_kmod-mac80211 \
CONFIG_PACKAGE_B43_DEBUG \
CONFIG_PACKAGE_B43_PIO \
CONFIG_PACKAGE_B43_N_PHY \
+ CONFIG_PACKAGE_RTLWIFI_DEBUG \
CONFIG_ATH_USER_REGD \
-CARL9170_FW_VERSION:=1.9.6
-
include $(INCLUDE_DIR)/package.mk
WMENU:=Wireless Drivers
endef
PKG_LINUX_FIRMWARE_NAME:=linux-firmware
-PKG_LINUX_FIRMWARE_VERSION:=6942dba419d2ebf8c15514972e89734fd7a8cebc
+PKG_LINUX_FIRMWARE_VERSION:=7d0c7a8cfd78388d90cc784a185b19dcbdbce824
PKG_LINUX_FIRMWARE_SOURCE:=$(PKG_LINUX_FIRMWARE_NAME)-$(PKG_LINUX_FIRMWARE_VERSION).tar.bz2
PKG_LINUX_FIRMWARE_PROTO:=git
PKG_LINUX_FIRMWARE_SOURCE_URL:=git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
PKG_LINUX_FIRMWARE_SUBDIR:=$(PKG_LINUX_FIRMWARE_NAME)-$(PKG_LINUX_FIRMWARE_VERSION)
-PKG_LINUX_FIRMWARE_MIRROR_MD5SUM:=a5f8c27af9e43f0ad24d7f821c5a781e
+PKG_LINUX_FIRMWARE_MIRROR_MD5SUM:=837a1a9456c1ec8b428cc0b2b08a331b
define Download/linux-firmware
FILE:=$(PKG_LINUX_FIRMWARE_SOURCE)
endef
$(eval $(call Download,linux-firmware))
+PKG_ATH10K_LINUX_FIRMWARE_NAME:=ath10k-firmware
+PKG_ATH10K_LINUX_FIRMWARE_VERSION:=d86e78e5c6be34329936c8bd73a212700437be2e
+PKG_ATH10K_LINUX_FIRMWARE_SOURCE:=$(PKG_ATH10K_LINUX_FIRMWARE_NAME)-$(PKG_ATH10K_LINUX_FIRMWARE_VERSION).tar.bz2
+PKG_ATH10K_LINUX_FIRMWARE_PROTO:=git
+PKG_ATH10K_LINUX_FIRMWARE_SOURCE_URL:=https://github.com/kvalo/ath10k-firmware.git
+PKG_ATH10K_LINUX_FIRMWARE_SUBDIR:=$(PKG_ATH10K_LINUX_FIRMWARE_NAME)-$(PKG_ATH10K_LINUX_FIRMWARE_VERSION)
+#PKG_ATH10K_LINUX_FIRMWARE_MIRROR_MD5SUM:=?
+
+define Download/ath10k-firmware
+ FILE:=$(PKG_ATH10K_LINUX_FIRMWARE_SOURCE)
+ URL:=$(PKG_ATH10K_LINUX_FIRMWARE_SOURCE_URL)
+ PROTO:=$(PKG_ATH10K_LINUX_FIRMWARE_PROTO)
+ VERSION:=$(PKG_ATH10K_LINUX_FIRMWARE_VERSION)
+ SUBDIR:=$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)
+ #MIRROR_MD5SUM:=$(PKG_ATH10K_LINUX_FIRMWARE_MIRROR_MD5SUM)
+endef
+$(eval $(call Download,ath10k-firmware))
+
# Prism54 drivers
P54PCIFW:=2.13.12.0.arm
P54USBFW:=2.13.24.0.lm87.arm
P54SPIFW:=2.13.0.0.a.13.14.arm
-CARL9170_FW:=carl9170-1.fw
define Download/p54usb
FILE:=$(P54USBFW)
endef
$(eval $(call Download,p54spi))
-define Download/carl9170
- FILE:=$(CARL9170_FW)-$(CARL9170_FW_VERSION)
- URL:=http://downloads.openwrt.org/sources/
- MD5SUM:=2fa6ed98d53d0b5fbcc136d1cf5e9609
-endef
-$(eval $(call Download,carl9170))
-
define KernelPackage/p54/Default
$(call KernelPackage/mac80211/Default)
TITLE:=Prism54 Drivers
define KernelPackage/rt2x00-mmio
$(call KernelPackage/rt2x00/Default)
DEPENDS+= @(PCI_SUPPORT||TARGET_ramips) +kmod-rt2x00-lib +kmod-eeprom-93cx6
+ HIDDEN:=1
TITLE+= (MMIO)
FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2x00mmio.ko
AUTOLOAD:=$(call AutoLoad,25,rt2x00mmio)
define KernelPackage/rt2x00-pci
$(call KernelPackage/rt2x00/Default)
DEPENDS+= @PCI_SUPPORT +kmod-rt2x00-mmio +kmod-rt2x00-lib
+ HIDDEN:=1
TITLE+= (PCI)
FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2x00pci.ko
AUTOLOAD:=$(call AutoLoad,26,rt2x00pci)
define KernelPackage/rt2x00-usb
$(call KernelPackage/rt2x00/Default)
DEPENDS+= @USB_SUPPORT +kmod-rt2x00-lib +kmod-usb-core
+ HIDDEN:=1
TITLE+= (USB)
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2x00usb.ko
AUTOLOAD:=$(call AutoLoad,26,rt2x00usb)
endef
-define KernelPackage/rt2x00-soc
-$(call KernelPackage/rt2x00/Default)
- DEPENDS+= @TARGET_ramips @!TARGET_ramips_mt7620a @!TARGET_ramips_rt3883 +kmod-rt2x00-mmio +kmod-rt2x00-lib
- TITLE+= (SoC)
- FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2x00soc.ko
- AUTOLOAD:=$(call AutoLoad,26,rt2x00soc)
-endef
-
define KernelPackage/rt2800-lib
$(call KernelPackage/rt2x00/Default)
- DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT||TARGET_ramips) +kmod-rt2x00-lib +TARGET_ramips:kmod-rt2x00-soc +@DRIVER_11N_SUPPORT
+ DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT||TARGET_ramips) +kmod-rt2x00-lib +kmod-lib-crc-ccitt +@DRIVER_11N_SUPPORT
+ HIDDEN:=1
TITLE+= (rt2800 LIB)
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2800lib.ko
AUTOLOAD:=$(call AutoLoad,27,rt2800lib)
AUTOLOAD:=$(call AutoLoad,27,rt73usb)
endef
+define KernelPackage/rt2800-mmio
+$(call KernelPackage/rt2x00/Default)
+ TITLE += (RT28xx/RT3xxx MMIO)
+ DEPENDS += +kmod-rt2800-lib +kmod-rt2x00-mmio
+ HIDDEN:=1
+ FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2800mmio.ko
+ AUTOLOAD:=$(call AutoLoad,28,rt2800mmio)
+endef
+
+define KernelPackage/rt2800-soc
+$(call KernelPackage/rt2x00/Default)
+ DEPENDS += @TARGET_ramips_rt305x +kmod-rt2800-mmio +kmod-rt2800-lib
+ TITLE += (RT28xx/RT3xxx SoC)
+ FILES := \
+ $(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2x00soc.ko \
+ $(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2800soc.ko
+ AUTOLOAD:=$(call AutoLoad,29,rt2x00soc rt2800soc)
+endef
+
define KernelPackage/rt2800-pci
$(call KernelPackage/rt2x00/Default)
- DEPENDS+= @(PCI_SUPPORT||TARGET_ramips) +PCI_SUPPORT:kmod-rt2x00-pci +kmod-rt2800-lib +kmod-lib-crc-ccitt +TARGET_ramips:kmod-rt2x00-soc
+ DEPENDS+= @PCI_SUPPORT +kmod-rt2x00-pci +kmod-rt2800-lib +kmod-rt2800-mmio
TITLE+= (RT2860 PCI)
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rt2x00/rt2800pci.ko
- AUTOLOAD:=$(call AutoLoad,28,rt2800pci)
+ AUTOLOAD:=$(call AutoLoad,29,rt2800pci)
endef
define KernelPackage/rt2800-usb
AUTOLOAD:=$(call AutoLoad,27,rtl8187)
endef
+define KernelPackage/rtlwifi/config
+ menu "Configuration"
+ depends on PACKAGE_kmod-rtlwifi
+
+ config PACKAGE_RTLWIFI_DEBUG
+ bool "Realtek wireless debugging"
+ help
+ Say Y, if you want to debug realtek wireless drivers.
+
+ endmenu
+endef
+
+define KernelPackage/rtlwifi
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek common driver part
+ DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT) +kmod-mac80211 +@DRIVER_11N_SUPPORT
+ FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtlwifi.ko
+ AUTOLOAD:=$(call AutoLoad,60,rtlwifi)
+ MENU:=1
+endef
+
+define KernelPackage/rtlwifi-pci
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek common driver part (PCI support)
+ DEPENDS+= @PCI_SUPPORT +kmod-rtlwifi
+ FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtl_pci.ko
+ AUTOLOAD:=$(call AutoLoad,61,rtl_pci)
+ HIDDEN:=1
+endef
+
+define KernelPackage/rtlwifi-usb
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek common driver part (USB support)
+ DEPENDS+= @USB_SUPPORT +kmod-usb-core +kmod-rtlwifi
+ FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtl_usb.ko
+ AUTOLOAD:=$(call AutoLoad,61,rtl_usb)
+ HIDDEN:=1
+endef
+
+define KernelPackage/rtl8192c-common
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek RTL8192CE/RTL8192CU common support module
+ DEPENDS+= +kmod-rtlwifi
+ FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtl8192c/rtl8192c-common.ko
+ AUTOLOAD:=$(call AutoLoad,62,rtl8192c-common)
+ HIDDEN:=1
+endef
+
+define KernelPackage/rtl8192ce
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek RTL8192CE/RTL8188CE support
+ DEPENDS+= +kmod-rtlwifi-pci +kmod-rtl8192c-common
+ FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192ce.ko
+ AUTOLOAD:=$(call AutoLoad,63,rtl8192ce)
+endef
+
+define KernelPackage/rtl8192ce/install
+ $(INSTALL_DIR) $(1)/lib/firmware/rtlwifi
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/rtlwifi/rtl8192cfw.bin $(1)/lib/firmware/rtlwifi
+endef
+
+define KernelPackage/rtl8192se
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek RTL8192SE/RTL8191SE support
+ DEPENDS+= +kmod-rtlwifi-pci
+ FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtl8192se/rtl8192se.ko
+ AUTOLOAD:=$(call AutoLoad,63,rtl8192se)
+endef
+
+define KernelPackage/rtl8192se/install
+ $(INSTALL_DIR) $(1)/lib/firmware/rtlwifi
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/rtlwifi/rtl8192sefw.bin $(1)/lib/firmware/rtlwifi
+endef
+
+define KernelPackage/rtl8192de
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek RTL8192DE/RTL8188DE support
+ DEPENDS+= +kmod-rtlwifi-pci
+ FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtl8192de/rtl8192de.ko
+ AUTOLOAD:=$(call AutoLoad,63,rtl8192de)
+endef
+
+define KernelPackage/rtl8192de/install
+ $(INSTALL_DIR) $(1)/lib/firmware/rtlwifi
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/rtlwifi/rtl8192defw.bin $(1)/lib/firmware/rtlwifi
+endef
+
+define KernelPackage/rtl8192cu
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Realtek RTL8192CU/RTL8188CU support
+ DEPENDS+= +kmod-rtlwifi-usb +kmod-rtl8192c-common
+ FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/rtlwifi/rtl8192cu/rtl8192cu.ko
+ AUTOLOAD:=$(call AutoLoad,63,rtl8192cu)
+endef
+
+define KernelPackage/rtl8192cu/install
+ $(INSTALL_DIR) $(1)/lib/firmware/rtlwifi
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/rtlwifi/rtl8192cufw.bin $(1)/lib/firmware/rtlwifi
+endef
+
ZD1211FW_NAME:=zd1211-firmware
ZD1211FW_VERSION:=1.4
define Download/zd1211rw
Atheros USB AR9271 and AR7010 family of chipsets.
endef
+define KernelPackage/ath10k
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Atheros 802.11ac wireless cards support
+ URL:=http://wireless.kernel.org/en/users/Drivers/ath10k
+ DEPENDS+= @PCI_SUPPORT +kmod-ath +@DRIVER_11N_SUPPORT
+ FILES:= \
+ $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath10k/ath10k_core.ko \
+ $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath10k/ath10k_pci.ko
+ AUTOLOAD:=$(call AutoLoad,55,ath10k_core ath10k_pci)
+endef
+
+define KernelPackage/ath10k/description
+This module adds support for wireless adapters based on
+Atheros IEEE 802.11ac family of chipsets. For now only
+PCI is supported.
+endef
+
define KernelPackage/carl9170
$(call KernelPackage/mac80211/Default)
TITLE:=Driver for Atheros AR9170 USB sticks
AUTOLOAD:=$(call AutoLoad,60,carl9170)
endef
-define KernelPackage/carl9170/install
- $(INSTALL_DIR) $(1)/lib/firmware
- $(INSTALL_DATA) $(DL_DIR)/$(CARL9170_FW)-$(CARL9170_FW_VERSION) $(1)/lib/firmware/$(CARL9170_FW)
-endef
-
define KernelPackage/lib80211
$(call KernelPackage/mac80211/Default)
TITLE:=802.11 Networking stack
+ DEPENDS:=+kmod-cfg80211
FILES:= \
$(PKG_BUILD_DIR)/net/wireless/lib80211.ko \
$(PKG_BUILD_DIR)/net/wireless/lib80211_crypt_wep.ko \
$(call KernelPackage/mac80211/Default)
DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT
TITLE:=Intel AGN Wireless support
- FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/iwlwifi/iwlwifi.ko
- AUTOLOAD:=$(call AutoLoad,60,iwlwifi)
+ FILES:= \
+ $(PKG_BUILD_DIR)/drivers/net/wireless/iwlwifi/iwlwifi.ko \
+ $(PKG_BUILD_DIR)/drivers/net/wireless/iwlwifi/dvm/iwldvm.ko
+ AUTOLOAD:=$(call AutoLoad,60,iwlwifi iwldvm)
MENU:=1
endef
endef
-define KernelPackage/wl12xx
+define KernelPackage/wlcore
$(call KernelPackage/mac80211/Default)
- TITLE:=Driver for TI WL12xx
- URL:=http://wireless.kernel.org/en/users/Drivers/wl12xx
- DEPENDS+= @TARGET_omap4 +kmod-mac80211
+ TITLE:=TI common driver part
+ DEPENDS+= @TARGET_omap +kmod-mac80211 +@DRIVER_11N_SUPPORT
FILES:= \
- $(PKG_BUILD_DIR)/drivers/net/wireless/ti/wl12xx/wl12xx.ko \
$(PKG_BUILD_DIR)/drivers/net/wireless/ti/wlcore/wlcore.ko \
$(PKG_BUILD_DIR)/drivers/net/wireless/ti/wlcore/wlcore_sdio.ko
- AUTOLOAD:=$(call AutoLoad,61,wlcore wlcore_sdio wl12xx)
+ AUTOLOAD:=$(call AutoLoad,61,wlcore wlcore_sdio)
+endef
+
+define KernelPackage/wlcore/description
+ This module contains some common parts needed by TI Wireless drivers.
+endef
+
+define KernelPackage/wl12xx
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Driver for TI WL12xx
+ URL:=http://wireless.kernel.org/en/users/Drivers/wl12xx
+ DEPENDS+= +kmod-wlcore
+ FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ti/wl12xx/wl12xx.ko
+ AUTOLOAD:=$(call AutoLoad,62,wl12xx)
endef
define KernelPackage/wl12xx/description
Kernel modules for TI WL12xx
endef
+define KernelPackage/wl18xx
+ $(call KernelPackage/mac80211/Default)
+ TITLE:=Driver for TI WL18xx
+ URL:=http://wireless.kernel.org/en/users/Drivers/wl18xx
+ DEPENDS+= +kmod-wlcore
+ FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ti/wl18xx/wl18xx.ko
+ AUTOLOAD:=$(call AutoLoad,62,wl18xx)
+endef
+
+define KernelPackage/wl18xx/description
+ Kernel modules for TI WL18xx
+endef
+
+
#Broadcom firmware
ifneq ($(CONFIG_B43_FW_5_10),)
PKG_B43_FWV4_NAME:=broadcom-wl
MAC80211_DEBUGFS \
ATH9K_DEBUGFS \
ATH9K_HTC_DEBUGFS \
+ ATH10K_DEBUGFS \
CARL9170_DEBUGFS \
ATH5K_DEBUG
endif
config-$(call config_package,lib80211) += LIB80211 LIB80211_CRYPT_WEP LIB80211_CRYPT_CCMP LIB80211_CRYPT_TKIP
config-$(call config_package,ath) += ATH_CARDS ATH_COMMON
-config-$(CONFIG_PACKAGE_ATH_DEBUG) += ATH_DEBUG
+config-$(CONFIG_PACKAGE_ATH_DEBUG) += ATH_DEBUG ATH10K_DEBUG
config-$(call config_package,ath9k) += ATH9K
config-$(call config_package,ath9k-common) += ATH9K_COMMON
config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD
config-$(call config_package,ath9k-htc) += ATH9K_HTC
+config-$(call config_package,ath10k) += ATH10K ATH10K_PCI
config-$(call config_package,ath5k) += ATH5K
ifdef CONFIG_TARGET_atheros
config-$(call config_package,brcmutil) += BRCMUTIL
config-$(call config_package,brcmsmac) += BRCMSMAC
-config-$(call config_package,brcmfmac) += BRCMFMAC BRCMFMAC_USB
+config-$(call config_package,brcmfmac) += BRCMFMAC
+config-y += BRCMFMAC_USB
config-$(CONFIG_PACKAGE_BRCM80211_DEBUG) += BRCMDBG
config-$(call config_package,mac80211-hwsim) += MAC80211_HWSIM
config-$(call config_package,rt2x00-pci) += RT2X00_LIB_PCI
config-$(call config_package,rt2x00-mmio) += RT2X00_LIB_MMIO
config-$(call config_package,rt2x00-usb) += RT2X00_LIB_USB
-config-$(call config_package,rt2x00-soc) += RT2X00_LIB_SOC
config-$(CONFIG_PACKAGE_RT2X00_LIB_DEBUGFS) += RT2X00_LIB_DEBUGFS
config-$(CONFIG_PACKAGE_RT2X00_DEBUG) += RT2X00_DEBUG
config-$(call config_package,rt73-usb) += RT73USB
config-$(call config_package,rt2800-lib) += RT2800_LIB
-config-y += RT2800PCI_RT33XX RT2800PCI_RT35XX RT2800PCI_RT53XX RT2800PCI_RT3290
+config-$(call config_package,rt2800-soc) += RT2800SOC
config-$(call config_package,rt2800-pci) += RT2800PCI
+config-y += RT2800PCI_RT33XX RT2800PCI_RT35XX RT2800PCI_RT53XX RT2800PCI_RT3290
+
config-$(call config_package,rt2800-usb) += RT2800USB
+config-y += RT2800USB_RT33XX RT2800USB_RT35XX RT2800USB_RT3573 RT2800USB_RT53XX RT2800USB_RT55XX
config-$(call config_package,iwl-legacy) += IWLEGACY
config-$(call config_package,iwl3945) += IWL3945
config-$(call config_package,iwl4965) += IWL4965
-config-$(call config_package,iwlagn) += IWLWIFI
+config-$(call config_package,iwlagn) += IWLWIFI IWLDVM
config-$(call config_package,net-libipw) += LIBIPW
config-$(call config_package,net-ipw2100) += IPW2100
config-$(call config_package,mwl8k) += MWL8K
config-$(call config_package,rtl8180) += RTL8180
config-$(call config_package,rtl8187) += RTL8187
-config-$(call config_package,wl12xx) += WL_TI WLCORE WLCORE_SDIO WL12XX
+config-$(call config_package,wlcore) += WLCORE WLCORE_SDIO
+config-$(call config_package,wl12xx) += WL12XX
+config-$(call config_package,wl18xx) += WL18XX
+config-y += WL_TI WILINK_PLATFORM_DATA
config-$(call config_package,zd1211rw) += ZD1211RW
+config-$(call config_package,rtlwifi) += RTL_CARDS RTLWIFI
+config-$(call config_package,rtlwifi-pci) += RTLWIFI_PCI
+config-$(call config_package,rtlwifi-usb) += RTLWIFI_USB
+config-$(call config_package,rtl8192c-common) += RTL8192C_COMMON
+config-$(call config_package,rtl8192ce) += RTL8192CE
+config-$(call config_package,rtl8192se) += RTL8192SE
+config-$(call config_package,rtl8192de) += RTL8192DE
+config-$(call config_package,rtl8192cu) += RTL8192CU
+config-$(CONFIG_PACKAGE_RTLWIFI_DEBUG) += RTLWIFI_DEBUG
+
config-$(CONFIG_LEDS_TRIGGERS) += MAC80211_LEDS B43_LEDS B43LEGACY_LEDS
MAKE_OPTS:= -C "$(PKG_BUILD_DIR)" \
KERNEL_SUBLEVEL=$(lastword $(subst ., ,$(KERNEL_PATCHVER))) \
KBUILD_LDFLAGS_MODULE_PREREQ=
+ifneq ($(findstring c,$(OPENWRT_VERBOSE)),)
+ MAKE_OPTS += V=1
+endif
+
define ConfigVars
$(subst $(space),,$(foreach opt,$(config-$(1)),CPTCFG_$(opt)=$(1)
))
$(TAR) -C $(PKG_BUILD_DIR) -xzf $(DL_DIR)/$(IPW2200_NAME)-$(IPW2200_VERSION).tgz
$(TAR) -C $(PKG_BUILD_DIR) -xjf $(DL_DIR)/$(ZD1211FW_NAME)-$(ZD1211FW_VERSION).tar.bz2
$(TAR) -C $(PKG_BUILD_DIR) -xjf $(DL_DIR)/$(PKG_LINUX_FIRMWARE_SOURCE)
+ $(TAR) -C $(PKG_BUILD_DIR) -xjf $(DL_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SOURCE)
rm -rf \
$(PKG_BUILD_DIR)/include/linux/ssb \
$(PKG_BUILD_DIR)/include/linux/bcma \
$(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl127x-fw-5-plt.bin \
$(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl127x-fw-5-sr.bin \
$(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl1271-nvs.bin \
+ $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl128x-fw-5-mr.bin \
+ $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl128x-fw-5-plt.bin \
+ $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl128x-fw-5-sr.bin \
+ $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl128x-nvs.bin \
$(1)/lib/firmware/ti-connectivity
endef
+define KernelPackage/wl18xx/install
+ $(INSTALL_DIR) $(1)/lib/firmware/ti-connectivity
+ $(INSTALL_DATA) \
+ $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl18xx-conf.bin \
+ $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl18xx-fw.bin \
+ $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl18xx-fw-2.bin \
+ $(1)/lib/firmware/ti-connectivity
+endef
define KernelPackage/zd1211rw/install
$(INSTALL_DIR) $(1)/lib/firmware/zd1211
$(INSTALL_DATA) $(PKG_BUILD_DIR)/$(ZD1211FW_NAME)/zd1211* $(1)/lib/firmware/zd1211
endef
+define KernelPackage/carl9170/install
+ $(INSTALL_DIR) $(1)/lib/firmware
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/carl9170-1.fw $(1)/lib/firmware
+endef
+
define KernelPackage/ath9k-htc/install
$(INSTALL_DIR) $(1)/lib/firmware
$(INSTALL_DATA) \
$(1)/lib/firmware/
endef
+define KernelPackage/ath10k/install
+ $(INSTALL_DIR) $(1)/lib/firmware/ath10k/QCA988X/hw2.0
+ $(INSTALL_DATA) \
+ $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/ath10k/QCA988X/hw2.0/board.bin \
+ $(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/ath10k/QCA988X/hw2.0/firmware-2.bin \
+ $(1)/lib/firmware/ath10k/QCA988X/hw2.0/
+endef
+
define KernelPackage/mwl8k/install
$(INSTALL_DIR) $(1)/lib/firmware/mwl8k
$(INSTALL_DATA) \
$(eval $(call KernelPackage,rt2x00-mmio))
$(eval $(call KernelPackage,rt2x00-pci))
$(eval $(call KernelPackage,rt2x00-usb))
-$(eval $(call KernelPackage,rt2x00-soc))
$(eval $(call KernelPackage,rt2800-lib))
$(eval $(call KernelPackage,rt2400-pci))
$(eval $(call KernelPackage,rt2500-pci))
$(eval $(call KernelPackage,rt2500-usb))
$(eval $(call KernelPackage,rt61-pci))
$(eval $(call KernelPackage,rt73-usb))
+$(eval $(call KernelPackage,rt2800-mmio))
+$(eval $(call KernelPackage,rt2800-soc))
$(eval $(call KernelPackage,rt2800-pci))
$(eval $(call KernelPackage,rt2800-usb))
$(eval $(call KernelPackage,rtl8180))
$(eval $(call KernelPackage,rtl8187))
+$(eval $(call KernelPackage,rtlwifi))
+$(eval $(call KernelPackage,rtlwifi-pci))
+$(eval $(call KernelPackage,rtlwifi-usb))
+$(eval $(call KernelPackage,rtl8192c-common))
+$(eval $(call KernelPackage,rtl8192ce))
+$(eval $(call KernelPackage,rtl8192se))
+$(eval $(call KernelPackage,rtl8192de))
+$(eval $(call KernelPackage,rtl8192cu))
$(eval $(call KernelPackage,zd1211rw))
$(eval $(call KernelPackage,mac80211-hwsim))
$(eval $(call KernelPackage,ath9k-common))
$(eval $(call KernelPackage,ath9k))
$(eval $(call KernelPackage,ath9k-htc))
+$(eval $(call KernelPackage,ath10k))
$(eval $(call KernelPackage,ath))
$(eval $(call KernelPackage,carl9170))
$(eval $(call KernelPackage,b43))
$(eval $(call KernelPackage,net-hermes-pci))
$(eval $(call KernelPackage,net-hermes-plx))
$(eval $(call KernelPackage,net-hermes-pcmcia))
+$(eval $(call KernelPackage,wlcore))
$(eval $(call KernelPackage,wl12xx))
+$(eval $(call KernelPackage,wl18xx))
[ -n "$channel" -a -z "$hwmode" ] && wifi_fixup_hwmode "$device"
- [ "$channel" = auto ] && {
- channel=$(iw phy "$phy" info | \
- sed -ne '/MHz/ { /disabled\|passive\|radar/d; s/.*\[//; s/\].*//; p; q }')
- config_set "$device" channel "$channel"
- }
+ hostapd_channel=$channel
+ [ "$channel" = auto -o "$channel" = 0 ] && hostapd_channel=acs_survey
[ -n "$hwmode" ] && {
config_get hwmode_11n "$device" hwmode_11n
tx_queue_data0_cwmax=7
tx_queue_data0_burst=1.5
${hwmode:+hw_mode=$hwmode}
-${channel:+channel=$channel}
+${hostapd_channel:+channel=$hostapd_channel}
${beacon_int:+beacon_int=$beacon_int}
${country:+country_code=$country}
${noscan:+noscan=$noscan}
mac80211_hostapd_setup_bss() {
local phy="$1"
local vif="$2"
+ local staidx="$3"
hostapd_cfg=
cfgfile="/var/run/hostapd-$phy.conf"
config_get_bool wds "$vif" wds 0
[ "$wds" -gt 0 ] && append hostapd_cfg "wds_sta=1" "$N"
+ [ "$staidx" -gt 0 ] && append hostapd_cfg "start_disabled=1" "$N"
+
local macaddr hidden maxassoc wmm
config_get macaddr "$vif" macaddr
config_get maxassoc "$vif" maxassoc
include /lib/network
for wdev in $(list_phy_interfaces "$phy"); do
[ -f "/var/run/$wdev.pid" ] && kill $(cat /var/run/$wdev.pid) >&/dev/null 2>&1
- for pid in `pidof wpa_supplicant`; do
+ for pid in `pidof wpa_supplicant meshd-nl80211`; do
grep "$wdev" /proc/$pid/cmdline >/dev/null && \
kill $pid
done
local i=0
local macidx=0
local apidx=0
+ local staidx=0
fixed=""
local hostapd_ctrl=""
[ "$apidx" -gt 1 ] || iw phy "$phy" interface add "$ifname" type managed
;;
mesh)
- config_get mesh_id "$vif" mesh_id
- iw phy "$phy" interface add "$ifname" type mp mesh_id "$mesh_id"
+ config_get key "$vif" key ""
+ if [ -n "$key" ]; then
+ iw phy "$phy" interface add "$ifname" type mp
+ else
+ config_get mesh_id "$vif" mesh_id
+ iw phy "$phy" interface add "$ifname" type mp mesh_id "$mesh_id"
+ fi
;;
monitor)
iw phy "$phy" interface add "$ifname" type monitor
;;
sta)
local wdsflag
+ staidx="$(($staidx + 1))"
config_get_bool wds "$vif" wds 0
[ "$wds" -gt 0 ] && wdsflag="4addr on"
iw phy "$phy" interface add "$ifname" type managed $wdsflag
rm -f /var/run/hostapd-$phy.conf
for vif in $vifs; do
config_get mode "$vif" mode
- [ "$mode" = "ap" ] || continue
- mac80211_hostapd_setup_bss "$phy" "$vif"
- start_hostapd=1
+ case "$mode" in
+ ap)
+ mac80211_hostapd_setup_bss "$phy" "$vif" "$staidx"
+ start_hostapd=1
+ ;;
+ mesh)
+ config_get key "$vif" key ""
+ [ -n "$key" ] && authsae_start_interface "$device" "$vif"
+ ;;
+ esac
done
[ -n "$start_hostapd" ] && {
# This is the world regulatory domain
country 00:
(2402 - 2472 @ 40), (3, 20)
- # Channel 12 - 13. No HT40 channel fits here
- (2457 - 2482 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS
- # Channel 14. Only JP enables this and for 802.11b only
- (2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM
- # Channel 36 - 48
- (5170 - 5250 @ 40), (3, 20)
- # NB: 5260 MHz - 5700 MHz requies DFS
- # Channel 149 - 165
- (5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
-
+ # Channel 12 - 13.
+ (2457 - 2482 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+ # Channel 14. Only JP enables this and for 802.11b only
+ (2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM
+ # Channel 36 - 48
+ (5170 - 5250 @ 80), (3, 20)
+ # NB: 5260 MHz - 5700 MHz requies DFS
+ # Channel 149 - 165
+ (5735 - 5835 @ 80), (3, 20), PASSIVE-SCAN, NO-IBSS
+ # IEEE 802.11ad (60GHz), channels 1..3
+ (57240 - 63720 @ 2160), (N/A, 0)
+
+
+country AD:
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country AE:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country AL:
(2402 - 2482 @ 20), (N/A, 20)
country AR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country AT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country AU:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 23)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country AW:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country BB:
(2402 - 2482 @ 40), (N/A, 20)
country BE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country BG: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 23)
(5250 - 5290 @ 40), (N/A, 23), DFS
(5490 - 5710 @ 40), (N/A, 30), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country BH:
(2402 - 2482 @ 40), (N/A, 20)
country BR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country BY:
(2402 - 2482 @ 40), (N/A, 20)
country CA:
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country CH: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country CL:
(2402 - 2482 @ 40), (N/A, 20)
country CN:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
+ # 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
+ # ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
+ (57240 - 59400 @ 2160), (N/A, 28)
+ (59400 - 63720 @ 2160), (N/A, 44)
+ (63720 - 65880 @ 2160), (N/A, 28)
country CO:
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country CR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
-
-country CS:
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country CY: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf
# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf
# implemented.
country CZ: DFS-ETSI
(2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
- (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
- (5470 - 5725 @ 40), (N/A, 500 mW), DFS
+ (5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+ (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from
# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf
# entries 279004 and 280006
(2400 - 2483.5 @ 40), (N/A, 100 mW)
# entry 303005
- (5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
+ (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
# entries 304002 and 305002
- (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+ (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
# entries 308002, 309001 and 310003
- (5470 - 5725 @ 40), (N/A, 500 mW), DFS
+ (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country DK: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country DO:
(2402 - 2472 @ 40), (3, 27)
country EC:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country EE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country EG:
(2402 - 2482 @ 40), (N/A, 20)
(5250 - 5330 @ 20), (N/A, 20), DFS
country ES: DFS-ETSI
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (2400 - 2483.5 @ 40), (N/A, 100 mW)
+ (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+ (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country FI: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country FR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country GE:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 18)
(5250 - 5330 @ 40), (N/A, 18), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country GB: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country GD:
(2402 - 2472 @ 40), (3, 27)
country GR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country GL: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
country GU:
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country HN:
(2402 - 2482 @ 40), (N/A, 20)
country HK:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country HR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country HT:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country ID:
+ # ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
(2402 - 2482 @ 40), (N/A, 20)
+ (5735 - 5815 @ 80), (N/A, 20)
country IE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country IL:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
- (5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS
+ (5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 200 mW), NO-OUTDOOR, DFS
country IN:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country IR:
(2402 - 2482 @ 40), (N/A, 20)
country IT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country JM:
(2402 - 2482 @ 40), (N/A, 20)
(5735 - 5835 @ 40), (3, 30)
country JP:
- (2402 - 2472 @ 40), (N/A, 20)
- (2457 - 2482 @ 20), (N/A, 20)
+ (2402 - 2482 @ 40), (N/A, 20)
(2474 - 2494 @ 20), (N/A, 20), NO-OFDM
- (4910 - 4930 @ 10), (N/A, 23)
(4910 - 4990 @ 40), (N/A, 23)
- (4930 - 4950 @ 10), (N/A, 23)
- (5030 - 5045 @ 10), (N/A, 23)
(5030 - 5090 @ 40), (N/A, 23)
- (5050 - 5060 @ 10), (N/A, 23)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 23), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 160), (N/A, 23), DFS
country JO:
(2402 - 2482 @ 40), (N/A, 20)
country KR:
(2402 - 2482 @ 20), (N/A, 20)
- (5170 - 5250 @ 20), (3, 20)
- (5250 - 5330 @ 20), (3, 20), DFS
- (5490 - 5630 @ 20), (3, 30), DFS
- (5735 - 5815 @ 20), (3, 30)
+ (5170 - 5250 @ 80), (3, 20)
+ (5250 - 5330 @ 80), (3, 20), DFS
+ (5490 - 5630 @ 80), (3, 30), DFS
+ (5735 - 5815 @ 80), (3, 30)
country KW:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
country KZ:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country LU: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country LV: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country MC: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
country MA:
(2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 23)
+ (5735 - 5835 @ 80), (N/A, 23)
country MO:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country MT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country MY:
(2402 - 2482 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 30), DFS
- (5735 - 5835 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (N/A, 17)
+ (5250 - 5330 @ 80), (N/A, 23), DFS
+ (5735 - 5835 @ 80), (N/A, 30)
country MX:
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country NL: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
- (5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20), NO-OUTDOOR
+ (5250 - 5330 @ 80), (N/A, 20), NO-OUTDOOR, DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country NO: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country NP:
(2402 - 2482 @ 40), (N/A, 20)
country NZ:
(2402 - 2482 @ 40), (N/A, 30)
- (5170 - 5250 @ 20), (3, 23)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country OM:
(2402 - 2482 @ 40), (N/A, 20)
country PE:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country PG:
(2402 - 2482 @ 40), (N/A, 20)
country PH:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country PK:
(2402 - 2482 @ 40), (N/A, 20)
country PL: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country PT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country PR:
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country QA:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+
+# Source:
+# http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf
+country RS:
+ (2400 - 2483.5 @ 40), (N/A, 100 mW)
+ (5150 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR
+ (5470 - 5725 @ 20), (3, 1000 mW), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country RU:
(2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 20), (N/A, 30)
+ (5170 - 5330 @ 40), (N/A, 20)
+ (5650 - 5710 @ 40), (N/A, 30)
+ (5735 - 5835 @ 40), (N/A, 30)
+
+country RW:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5735 - 5835 @ 40), (N/A, 30)
country SA:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 23)
- (5250 - 5330 @ 20), (3, 23), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country SE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country SG:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5735 - 5835 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country SI: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (N/A, 20)
(5250 - 5330 @ 40), (N/A, 20), DFS
(5490 - 5710 @ 40), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country SK: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country SV:
(2402 - 2482 @ 40), (N/A, 20)
country TW:
(2402 - 2472 @ 40), (3, 27)
(5270 - 5330 @ 40), (3, 17), DFS
- (5735 - 5815 @ 40), (3, 30)
+ (5490 - 5710 @ 80), (3, 30), DFS
+ (5735 - 5815 @ 80), (3, 30)
country TH:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country TT:
(2402 - 2482 @ 40), (N/A, 20)
country TR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (N/A, 20)
- (5250 - 5330 @ 20), (N/A, 20), DFS
-
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+# Source:
+# #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874
+# #1174 / 23 Oct 2008: http://www.nkrz.gov.ua/uk/activities/ruling/1225269361
+# (appendix 8)
+# Listed 5GHz range is a lowest common denominator for all related
+# rules in the referenced laws. Such a range is used because of
+# disputable definitions there.
country UA:
- (2402 - 2482 @ 40), (N/A, 20)
+ (2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR
+ (5150 - 5350 @ 40), (N/A, 20), NO-OUTDOOR
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country US: DFS-FCC
(2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5600 @ 40), (3, 20), DFS
- (5650 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5600 @ 80), (3, 24), DFS
+ (5650 - 5710 @ 40), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+ # 60g band
+ # reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
+ # channels 1,2,3, EIRP=40dBm(43dBm peak)
+ (57240 - 63720 @ 2160), (N/A, 40)
country UY:
(2402 - 2482 @ 40), (N/A, 20)
country VN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country YE:
(2402 - 2482 @ 40), (N/A, 20)
country ZA:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country ZW:
(2402 - 2482 @ 40), (N/A, 20)
+ @$(MAKE) Kconfig.versions
@$(MAKE) -f Makefile.real "$@"
- else
+ .PHONY: defconfig-help
--- a/Makefile.real
+++ b/Makefile.real
@@ -54,7 +54,7 @@ defconfig-%::
--- /dev/null
+From 88e75363ff9c00cc2e7768ca23ded79bf8d6bf08 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 7 Feb 2014 19:13:11 +0100
+Subject: [PATCH 1/8] backports: add led_trigger_blink{_oneshot}()
+
+When led support is deactivated in the kernel and
+CPTCFG_BACKPORT_BUILD_LEDS is set mac80211 references
+led_trigger_blink_oneshot() but it is not declared anywhere.
+
+This fixes the following build error:
+net/mac80211/led.c: In function 'ieee80211_led_rx':
+net/mac80211/led.c:25:2: error: implicit declaration of function 'led_trigger_blink_oneshot' [-Werror=implicit-function-declaration]
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ backport-include/backport/leds-disabled.h | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/backport-include/backport/leds-disabled.h
++++ b/backport-include/backport/leds-disabled.h
+@@ -163,6 +163,19 @@ static inline void led_trigger_event(str
+ enum led_brightness event)
+ {
+ }
++
++static inline void led_trigger_blink(struct led_trigger *trigger,
++ unsigned long *delay_on,
++ unsigned long *delay_off)
++{
++}
++
++static inline void led_trigger_blink_oneshot(struct led_trigger *trigger,
++ unsigned long *delay_on,
++ unsigned long *delay_off,
++ int invert)
++{
++}
+ #endif
+
+ #endif /* __BACKPORT_LED_DISABLED_SUPPORT */
+#ifdef CONFIG_COMPAT_BLUETOOTH
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+ #ifdef CONFIG_TTY
/*
- * Termios Helper Methods
-@@ -112,4 +113,4 @@ int tty_set_termios(struct tty_struct *t
- }
+@@ -114,4 +115,4 @@ int tty_set_termios(struct tty_struct *t
EXPORT_SYMBOL_GPL(tty_set_termios);
+ #endif /* CONFIG_TTY */
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) */
-
+#endif
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
-@@ -202,25 +202,28 @@ config RT2800USB_UNKNOWN
- endif
+@@ -225,36 +225,37 @@ config RT2800SOC
+
config RT2800_LIB
- tristate
+ tristate "RT2800 USB/PCI support"
depends on m
+ config RT2800_LIB_MMIO
+- tristate
++ tristate "RT2800 MMIO support"
+ depends on m
+ select RT2X00_LIB_MMIO
+ select RT2800_LIB
+
config RT2X00_LIB_MMIO
- tristate
+ tristate "RT2x00 MMIO support"
config RT2X00_LIB_PCI
- tristate
+ tristate "RT2x00 PCI support"
-+ depends on PCI
depends on m
select RT2X00_LIB
config RT2X00_LIB_USB
- tristate
+ tristate "RT2x00 USB support"
-+ depends on USB
depends on m
select RT2X00_LIB
+ config RT2X00_LIB
+- tristate
++ tristate "RT2x00 support"
+ depends on m
+ select BACKPORT_AVERAGE
+
--- a/.local-symbols
+++ b/.local-symbols
-@@ -363,42 +363,6 @@ USB_CDC_PHONET=
+@@ -379,42 +379,6 @@ USB_CDC_PHONET=
USB_IPHETH=
USB_SIERRA_NET=
USB_VL600=
-BCMA_DRIVER_GMAC_CMN=
-BCMA_DRIVER_GPIO=
-BCMA_DEBUG=
- DRM=
- DRM_USB=
- DRM_KMS_HELPER=
+ NFC=
+ NFC_DIGITAL=
+ NFC_NCI=
--- a/Kconfig
+++ b/Kconfig
@@ -33,9 +33,6 @@ source drivers/net/wireless/Kconfig
-source drivers/ssb/Kconfig
-source drivers/bcma/Kconfig
-
- source drivers/gpu/drm/Kconfig
-
source net/nfc/Kconfig
+
+ source drivers/regulator/Kconfig
--- a/Makefile.kernel
+++ b/Makefile.kernel
-@@ -26,8 +26,6 @@ obj-$(CPTCFG_MAC80211) += net/mac80211/
+@@ -25,8 +25,6 @@ obj-$(CPTCFG_MAC80211) += net/mac80211/
obj-$(CPTCFG_WLAN) += drivers/net/wireless/
obj-$(CPTCFG_BT) += net/bluetooth/
obj-$(CPTCFG_BT) += drivers/bluetooth/
-obj-$(CPTCFG_BCMA) += drivers/bcma/
obj-$(CPTCFG_ETHERNET) += drivers/net/ethernet/
obj-$(CPTCFG_USB_NET_RNDIS_WLAN) += drivers/net/usb/
- obj-$(CPTCFG_DRM) += drivers/gpu/drm/
+ obj-$(CPTCFG_NFC) += net/nfc/
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
-@@ -2729,7 +2729,7 @@ static struct ssb_device *b43_ssb_gpio_d
+@@ -2734,7 +2734,7 @@ static struct ssb_device *b43_ssb_gpio_d
{
struct ssb_bus *bus = dev->dev->sdev->bus;
return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
#else
return bus->chipco.dev;
-@@ -4735,7 +4735,7 @@ static int b43_wireless_core_init(struct
+@@ -4751,7 +4751,7 @@ static int b43_wireless_core_init(struct
}
if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
--- /dev/null
+--- a/net/mac80211/Kconfig
++++ b/net/mac80211/Kconfig
+@@ -5,7 +5,6 @@ config MAC80211
+ depends on CRYPTO
+ depends on CRYPTO_ARC4
+ depends on CRYPTO_AES
+- depends on CRYPTO_CCM
+ depends on CRC32
+ select BACKPORT_AVERAGE
+ ---help---
+--- a/net/mac80211/aes_ccm.c
++++ b/net/mac80211/aes_ccm.c
+@@ -2,8 +2,6 @@
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+- * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
+- *
+ * 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.
+@@ -19,75 +17,134 @@
+ #include "key.h"
+ #include "aes_ccm.h"
+
+-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+- u8 *data, size_t data_len, u8 *mic)
++static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a)
+ {
+- struct scatterlist assoc, pt, ct[2];
+- struct {
+- struct aead_request req;
+- u8 priv[crypto_aead_reqsize(tfm)];
+- } aead_req;
+-
+- memset(&aead_req, 0, sizeof(aead_req));
+-
+- sg_init_one(&pt, data, data_len);
+- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
+- sg_init_table(ct, 2);
+- sg_set_buf(&ct[0], data, data_len);
+- sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
+-
+- aead_request_set_tfm(&aead_req.req, tfm);
+- aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
+- aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0);
++ int i;
++ u8 *b_0, *aad, *b, *s_0;
+
+- crypto_aead_encrypt(&aead_req.req);
++ b_0 = scratch + 3 * AES_BLOCK_SIZE;
++ aad = scratch + 4 * AES_BLOCK_SIZE;
++ b = scratch;
++ s_0 = scratch + AES_BLOCK_SIZE;
++
++ crypto_cipher_encrypt_one(tfm, b, b_0);
++
++ /* Extra Authenticate-only data (always two AES blocks) */
++ for (i = 0; i < AES_BLOCK_SIZE; i++)
++ aad[i] ^= b[i];
++ crypto_cipher_encrypt_one(tfm, b, aad);
++
++ aad += AES_BLOCK_SIZE;
++
++ for (i = 0; i < AES_BLOCK_SIZE; i++)
++ aad[i] ^= b[i];
++ crypto_cipher_encrypt_one(tfm, a, aad);
++
++ /* Mask out bits from auth-only-b_0 */
++ b_0[0] &= 0x07;
++
++ /* S_0 is used to encrypt T (= MIC) */
++ b_0[14] = 0;
++ b_0[15] = 0;
++ crypto_cipher_encrypt_one(tfm, s_0, b_0);
+ }
+
+-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+- u8 *data, size_t data_len, u8 *mic)
++
++void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
++ u8 *data, size_t data_len,
++ u8 *cdata, u8 *mic)
+ {
+- struct scatterlist assoc, pt, ct[2];
+- struct {
+- struct aead_request req;
+- u8 priv[crypto_aead_reqsize(tfm)];
+- } aead_req;
+-
+- memset(&aead_req, 0, sizeof(aead_req));
+-
+- sg_init_one(&pt, data, data_len);
+- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
+- sg_init_table(ct, 2);
+- sg_set_buf(&ct[0], data, data_len);
+- sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
+-
+- aead_request_set_tfm(&aead_req.req, tfm);
+- aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
+- aead_request_set_crypt(&aead_req.req, ct, &pt,
+- data_len + IEEE80211_CCMP_MIC_LEN, b_0);
++ int i, j, last_len, num_blocks;
++ u8 *pos, *cpos, *b, *s_0, *e, *b_0;
++
++ b = scratch;
++ s_0 = scratch + AES_BLOCK_SIZE;
++ e = scratch + 2 * AES_BLOCK_SIZE;
++ b_0 = scratch + 3 * AES_BLOCK_SIZE;
++
++ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
++ last_len = data_len % AES_BLOCK_SIZE;
++ aes_ccm_prepare(tfm, scratch, b);
++
++ /* Process payload blocks */
++ pos = data;
++ cpos = cdata;
++ for (j = 1; j <= num_blocks; j++) {
++ int blen = (j == num_blocks && last_len) ?
++ last_len : AES_BLOCK_SIZE;
++
++ /* Authentication followed by encryption */
++ for (i = 0; i < blen; i++)
++ b[i] ^= pos[i];
++ crypto_cipher_encrypt_one(tfm, b, b);
++
++ b_0[14] = (j >> 8) & 0xff;
++ b_0[15] = j & 0xff;
++ crypto_cipher_encrypt_one(tfm, e, b_0);
++ for (i = 0; i < blen; i++)
++ *cpos++ = *pos++ ^ e[i];
++ }
+
+- return crypto_aead_decrypt(&aead_req.req);
++ for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++)
++ mic[i] = b[i] ^ s_0[i];
+ }
+
+-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[])
++
++int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
++ u8 *cdata, size_t data_len, u8 *mic, u8 *data)
+ {
+- struct crypto_aead *tfm;
+- int err;
++ int i, j, last_len, num_blocks;
++ u8 *pos, *cpos, *b, *s_0, *a, *b_0;
+
+- tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
+- if (IS_ERR(tfm))
+- return tfm;
+-
+- err = crypto_aead_setkey(tfm, key, WLAN_KEY_LEN_CCMP);
+- if (!err)
+- err = crypto_aead_setauthsize(tfm, IEEE80211_CCMP_MIC_LEN);
+- if (!err)
+- return tfm;
++ b = scratch;
++ s_0 = scratch + AES_BLOCK_SIZE;
++ a = scratch + 2 * AES_BLOCK_SIZE;
++ b_0 = scratch + 3 * AES_BLOCK_SIZE;
++
++ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
++ last_len = data_len % AES_BLOCK_SIZE;
++ aes_ccm_prepare(tfm, scratch, a);
++
++ /* Process payload blocks */
++ cpos = cdata;
++ pos = data;
++ for (j = 1; j <= num_blocks; j++) {
++ int blen = (j == num_blocks && last_len) ?
++ last_len : AES_BLOCK_SIZE;
++
++ /* Decryption followed by authentication */
++ b_0[14] = (j >> 8) & 0xff;
++ b_0[15] = j & 0xff;
++ crypto_cipher_encrypt_one(tfm, b, b_0);
++ for (i = 0; i < blen; i++) {
++ *pos = *cpos++ ^ b[i];
++ a[i] ^= *pos++;
++ }
++ crypto_cipher_encrypt_one(tfm, a, a);
++ }
++
++ for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) {
++ if ((mic[i] ^ s_0[i]) != a[i])
++ return -1;
++ }
+
+- crypto_free_aead(tfm);
+- return ERR_PTR(err);
++ return 0;
+ }
+
+-void ieee80211_aes_key_free(struct crypto_aead *tfm)
++
++struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
++{
++ struct crypto_cipher *tfm;
++
++ tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
++ if (!IS_ERR(tfm))
++ crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP);
++
++ return tfm;
++}
++
++
++void ieee80211_aes_key_free(struct crypto_cipher *tfm)
+ {
+- crypto_free_aead(tfm);
++ crypto_free_cipher(tfm);
+ }
+--- a/net/mac80211/aes_ccm.h
++++ b/net/mac80211/aes_ccm.h
+@@ -12,11 +12,13 @@
+
+ #include <linux/crypto.h>
+
+-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]);
+-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+- u8 *data, size_t data_len, u8 *mic);
+-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+- u8 *data, size_t data_len, u8 *mic);
+-void ieee80211_aes_key_free(struct crypto_aead *tfm);
++struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
++void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
++ u8 *data, size_t data_len,
++ u8 *cdata, u8 *mic);
++int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
++ u8 *cdata, size_t data_len,
++ u8 *mic, u8 *data);
++void ieee80211_aes_key_free(struct crypto_cipher *tfm);
+
+ #endif /* AES_CCM_H */
+--- a/net/mac80211/key.h
++++ b/net/mac80211/key.h
+@@ -84,7 +84,7 @@ struct ieee80211_key {
+ * Management frames.
+ */
+ u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
+- struct crypto_aead *tfm;
++ struct crypto_cipher *tfm;
+ u32 replays; /* dot11RSNAStatsCCMPReplays */
+ } ccmp;
+ struct {
+--- a/net/mac80211/wpa.c
++++ b/net/mac80211/wpa.c
+@@ -301,16 +301,22 @@ ieee80211_crypto_tkip_decrypt(struct iee
+ }
+
+
+-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
++static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
+ int encrypted)
+ {
+ __le16 mask_fc;
+ int a4_included, mgmt;
+ u8 qos_tid;
+- u16 len_a;
++ u8 *b_0, *aad;
++ u16 data_len, len_a;
+ unsigned int hdrlen;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
++ memset(scratch, 0, 6 * AES_BLOCK_SIZE);
++
++ b_0 = scratch + 3 * AES_BLOCK_SIZE;
++ aad = scratch + 4 * AES_BLOCK_SIZE;
++
+ /*
+ * Mask FC: zero subtype b4 b5 b6 (if not mgmt)
+ * Retry, PwrMgt, MoreData; set Protected
+@@ -332,21 +338,20 @@ static void ccmp_special_blocks(struct s
+ else
+ qos_tid = 0;
+
+- /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
+- * mode authentication are not allowed to collide, yet both are derived
+- * from this vector b_0. We only set L := 1 here to indicate that the
+- * data size can be represented in (L+1) bytes. The CCM layer will take
+- * care of storing the data length in the top (L+1) bytes and setting
+- * and clearing the other bits as is required to derive the two IVs.
+- */
+- b_0[0] = 0x1;
++ data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN;
++ if (encrypted)
++ data_len -= IEEE80211_CCMP_MIC_LEN;
+
++ /* First block, b_0 */
++ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
+ /* Nonce: Nonce Flags | A2 | PN
+ * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
+ */
+ b_0[1] = qos_tid | (mgmt << 4);
+ memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
+ memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
++ /* l(m) */
++ put_unaligned_be16(data_len, &b_0[14]);
+
+ /* AAD (extra authenticate-only data) / masked 802.11 header
+ * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
+@@ -402,8 +407,7 @@ static int ccmp_encrypt_skb(struct ieee8
+ u8 *pos;
+ u8 pn[6];
+ u64 pn64;
+- u8 aad[2 * AES_BLOCK_SIZE];
+- u8 b_0[AES_BLOCK_SIZE];
++ u8 scratch[6 * AES_BLOCK_SIZE];
+
+ if (info->control.hw_key &&
+ !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
+@@ -456,9 +460,9 @@ static int ccmp_encrypt_skb(struct ieee8
+ return 0;
+
+ pos += IEEE80211_CCMP_HDR_LEN;
+- ccmp_special_blocks(skb, pn, b_0, aad, 0);
+- ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
+- skb_put(skb, IEEE80211_CCMP_MIC_LEN));
++ ccmp_special_blocks(skb, pn, scratch, 0);
++ ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len,
++ pos, skb_put(skb, IEEE80211_CCMP_MIC_LEN));
+
+ return 0;
+ }
+@@ -521,16 +525,16 @@ ieee80211_crypto_ccmp_decrypt(struct iee
+ }
+
+ if (!(status->flag & RX_FLAG_DECRYPTED)) {
+- u8 aad[2 * AES_BLOCK_SIZE];
+- u8 b_0[AES_BLOCK_SIZE];
++ u8 scratch[6 * AES_BLOCK_SIZE];
+ /* hardware didn't decrypt/verify MIC */
+- ccmp_special_blocks(skb, pn, b_0, aad, 1);
++ ccmp_special_blocks(skb, pn, scratch, 1);
+
+ if (ieee80211_aes_ccm_decrypt(
+- key->u.ccmp.tfm, b_0, aad,
++ key->u.ccmp.tfm, scratch,
+ skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
+ data_len,
+- skb->data + skb->len - IEEE80211_CCMP_MIC_LEN))
++ skb->data + skb->len - IEEE80211_CCMP_MIC_LEN,
++ skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN))
+ return RX_DROP_UNUSABLE;
+ }
+
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -300,7 +300,7 @@ void ieee80211_restart_hw(struct ieee802
+@@ -287,7 +287,7 @@ void ieee80211_restart_hw(struct ieee802
}
EXPORT_SYMBOL(ieee80211_restart_hw);
static int ieee80211_ifa_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
-@@ -359,7 +359,7 @@ static int ieee80211_ifa_changed(struct
+@@ -346,7 +346,7 @@ static int ieee80211_ifa_changed(struct
}
#endif
static int ieee80211_ifa6_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
-@@ -990,14 +990,14 @@ int ieee80211_register_hw(struct ieee802
+@@ -1031,14 +1031,14 @@ int ieee80211_register_hw(struct ieee802
goto fail_pm_qos;
}
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
result = register_inet6addr_notifier(&local->ifa6_notifier);
if (result)
-@@ -1006,13 +1006,13 @@ int ieee80211_register_hw(struct ieee802
+@@ -1047,13 +1047,13 @@ int ieee80211_register_hw(struct ieee802
return 0;
fail_ifa:
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
-@@ -1045,10 +1045,10 @@ void ieee80211_unregister_hw(struct ieee
+@@ -1086,10 +1086,10 @@ void ieee80211_unregister_hw(struct ieee
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
{ AR5K_RXNOFRM, 8 },
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
-@@ -860,10 +860,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah)
+@@ -869,10 +869,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah)
* guess we can tweak it and see how it goes ;-)
*/
if (ah->ah_version != AR5K_AR5210) {
---- a/net/mac80211/agg-rx.c
-+++ b/net/mac80211/agg-rx.c
-@@ -204,6 +204,8 @@ static void ieee80211_send_addba_resp(st
- memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
- else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
-+ else if (sdata->vif.type == NL80211_IFTYPE_WDS)
-+ memcpy(mgmt->bssid, da, ETH_ALEN);
-
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
+commit 584d297fd29fb39c76af25ae74ff9d5fe74c8a14
+Author: Helmut Schaa <helmut.schaa@googlemail.com>
+Date: Wed Mar 12 10:37:55 2014 +0100
+
+ ath9k: Fix sequence number assignment for non-data frames
+
+ Since commit 558ff225de80ac95b132d3a115ddadcd64498b4f (ath9k: fix
+ ps-poll responses under a-mpdu sessions) non-data frames would have
+ gotten a sequence number from a TIDs sequence counter instead of
+ using the global sequence counter.
+
+ This can lead to instable connections.
+
+ To fix this only select the correct TID if we are processing a
+ data frame. Furthermore, prevent non-data frames to get a sequence
+ number from a TID sequence counter by adding a check to
+ ath_tx_setup_buffer.
+
+ Cc: Felix Fietkau <nbd@openwrt.org>
+ Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
+
+commit 3a0f984b1cdcd6a9f8c441635ef3b05d58547f4e
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Tue Mar 11 14:03:32 2014 +0100
+
+ ath9k_hw: set ANI firstep as absolute values instead of relative
+
+ On older chips, the INI value differ in similar ways as cycpwr_thr1, so
+ convert it to absolute values as well.
+
+ Since the ANI algorithm is different here compared to the old
+ implementation (fewer steps, controlled at a different point in time),
+ it makes sense to use values similar to what would be applied for newer
+ chips, just without relying on INI defaults.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 91d70d40400c569b49605b78fd7c43e9405694f4
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Tue Mar 11 14:00:37 2014 +0100
+
+ ath9k_hw: set ANI cycpwr_thr1 as absolute values instead of relative
+
+ The table was copied from the ANI implementation of AR9300. It assumes
+ that the INI values contain a baseline value that is usable as reference
+ from which to increase/decrease based on the noise immunity value.
+
+ On older chips, the differences are bigger and especially AR5008/AR9001
+ are configured to much more sensitive values than what is useful.
+
+ Improve ANI behavior by reverting to the absolute values used in the
+ previous implementation (expressed as a simple formula instead of the
+ old table).
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit c977493766310a825f406836636ffd66e1447783
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Mon Mar 10 19:52:56 2014 +0100
+
+ ath9k_hw: remove ANI function restrictions for AP mode
+
+ The primary purpose of this piece of code was to selectively disable
+ OFDM weak signal detection. The checks for this are elsewhere, and an
+ earlier commit relaxed the restrictions for older chips, which are more
+ sensitive to interference.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 8d804f1af11e4e058b1e8453327777d73a585cb8
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Sun Mar 9 11:25:43 2014 +0100
+
+ ath9k: clean up and enhance ANI debugfs file
+
+ Unify scnprintf calls and include the current OFDM/CCK immunity level.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 22e298b5a3a8a49e33805d4e351965123dede35b
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Sun Mar 9 10:58:47 2014 +0100
+
+ ath9k: fix ready time of the multicast buffer queue
+
+ qi->tqi_readyTime is written directly to registers that expect
+ microseconds as unit instead of TU.
+ When setting the CABQ ready time, cur_conf->beacon_interval is in TU, so
+ convert it to microseconds before passing it to ath9k_hw.
+
+ This should hopefully fix some Tx DMA issues with buffered multicast
+ frames in AP mode.
+
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit fcb064fdd5a27bec8d24099bc0172468f34c97cb
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Sun Mar 9 09:43:09 2014 +0100
+
+ ath9k_hw: fix unreachable code in baseband hang detection code
+
+ The commit "ath9k: reduce baseband hang detection false positive rate"
+ added a delay in the loop checking the baseband state, however it was
+ unreachable due to previous 'continue' statements.
+
+ Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 31959d8df39319e32c6d5ba9c135727be90cfad7
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date: Fri Mar 7 08:09:38 2014 +0100
+
+ mac80211: fix possible NULL dereference
+
+ If chanctx is missing on a given vif then the band
+ is assumed to be 2GHz. However if hw doesn't
+ support 2GHz band then mac80211 ended up with a
+ NULL dereference.
+
+ This fixes a splat:
+
+ [ 4605.207223] BUG: unable to handle kernel NULL pointer dereference at 0000000000000018
+ [ 4605.210789] IP: [<ffffffffa07b5635>] ieee80211_parse_bitrates+0x65/0x110 [mac80211]
+
+ The splat was preceeded by WARN_ON(!chanctx_conf)
+ in ieee80211_get_sdata_band().
+
+ Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+
+commit 6c5a3ffa0a2d22c091a2717f427259bacf77ac5e
+Author: Michael Braun <michael-dev@fami-braun.de>
+Date: Thu Mar 6 15:08:43 2014 +0100
+
+ mac80211: fix WPA with VLAN on AP side with ps-sta again
+
+ commit de74a1d9032f4d37ea453ad2a647e1aff4cd2591
+ "mac80211: fix WPA with VLAN on AP side with ps-sta"
+ fixed an issue where queued multicast packets would
+ be sent out encrypted with the key of an other bss.
+
+ commit "7cbf9d017dbb5e3276de7d527925d42d4c11e732"
+ "mac80211: fix oops on mesh PS broadcast forwarding"
+ essentially reverted it, because vif.type cannot be AP_VLAN
+ due to the check to vif.type in ieee80211_get_buffered_bc before.
+
+ As the later commit intended to fix the MESH case, fix it
+ by checking for IFTYPE_AP instead of IFTYPE_AP_VLAN.
+
+ Fixes: 7cbf9d017dbb
+ Cc: <stable@vger.kernel.org> # 3.10.x
+ Cc: <stable@vger.kernel.org> # 3.11.x
+ Cc: <stable@vger.kernel.org> # 3.12.x
+ Cc: <stable@vger.kernel.org> # 3.13.x
+ Cc: <linux-wireless@vger.kernel.org>
+ Cc: <projekt-wlan@fem.tu-ilmenau.de>
+ Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
+
+commit 9d6ab9bdb9b368a6cf9519f0f92509b5b2c297ec
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Mon Mar 3 14:19:08 2014 +0100
+
+ cfg80211: remove racy beacon_interval assignment
+
+ In case of AP mode, the beacon interval is already reset to
+ zero inside cfg80211_stop_ap(), and in the other modes it
+ isn't relevant. Remove the assignment to remove a potential
+ race since the assignment isn't properly locked.
+
+ Reported-by: Michal Kazior <michal.kazior@tieto.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 1abdeca3c6fb9cf1f84f85e78ed8d1c33bd69db0
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Fri Feb 28 18:52:56 2014 +0100
+
+ ath9k_hw: tweak noise immunity thresholds for older chipsets
+
+ Older chipsets are more sensitive to high PHY error counts, and the
+ current noise immunity thresholds were based on tests run at QCA with
+ newer chipsets.
+
+ This patch brings back the values from the old ANI implementation for
+ old chipsets, and it also disables weak signal detection on an earlier
+ noise immunity level, to improve overall radio stability on affected
+ devices.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 431e506da5953adc3b65af25f4b90873d528c115
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Fri Feb 28 18:44:13 2014 +0100
+
+ ath9k_hw: toggle weak signal detection in AP mode on older chipsets
+
+ The commit 80b4205b "ath9k: Fix OFDM weak signal detection for AP mode"
+ prevented weak signal detection changes from taking effect in AP mode on
+ all chipsets, claiming it is "not allowed".
+
+ The main reason for not disabling weak signal detection in AP mode is
+ that typically beacon RSSI is used to track whether it is needed to
+ boost range, and this is unavailable in AP mode for obvious reasons.
+
+ The problem with not disabling weak signal detection is that older
+ chipsets are very sensitive to high PHY error counts. When faced with
+ heavy noise, this can lead to an excessive amount of "Failed to stop
+ TX DMA" errors in the field.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 98d1a6c5b14688ed030e81b889f607be308e0df9
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Mon Feb 24 22:20:32 2014 +0100
+
+ ath9k: fix invalid descriptor discarding
+
+ Only set sc->rx.discard_next to rx_stats->rs_more when actually
+ discarding the current descriptor.
+
+ Also, fix a detection of broken descriptors:
+ First the code checks if the current descriptor is not done.
+ Then it checks if the next descriptor is done.
+ Add a check that afterwards checks the first descriptor again, because
+ it might have been completed in the mean time.
+
+ This fixes a regression introduced in
+ commit 723e711356b5a8a95728a890e254e8b0d47b55cf
+ "ath9k: fix handling of broken descriptors"
+
+ Cc: stable@vger.kernel.org
+ Reported-by: Marco André Dinis <marcoandredinis@gmail.com>
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 52a46300e782fe6994466523eb2b0b59091ea59f
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Mon Feb 24 11:43:50 2014 +0100
+
+ ath9k: reduce baseband hang detection false positive rate
+
+ Check if the baseband state remains stable, and add a small delay
+ between register reads.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 118945bb12082e9d4edddc868d88143164e0f440
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Sat Feb 22 14:55:23 2014 +0100
+
+ ath5k: set SURVEY_INFO_IN_USE on get_survey
+
+ Only one channel is returned - the one currently being used.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit ee41f72476e1ea44283dfe1cbf75b9543a1e15c8
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Sat Feb 22 14:44:52 2014 +0100
+
+ ath9k: make some hardware reset log messages debug-only
+
+ On some chips, baseband watchdog hangs are more common than others, and
+ the driver has support for handling them.
+ Interrupts even after a watchdog hang are also quite common, so there's
+ not much point in spamming the user's logfiles.
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit b14fbb554fc65a2e0b5c41a319269b0350f187e7
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Sat Feb 22 14:35:25 2014 +0100
+
+ ath9k: do not set half/quarter channel flags in AR_PHY_MODE
+
+ 5/10 MHz channel bandwidth is configured via the PLL clock, instead of
+ the AR_PHY_MODE register. Using that register is AR93xx specific, and
+ makes the mode incompatible with earlier chipsets.
+
+ In some early versions, these flags were apparently applied at the wrong
+ point in time and thus did not cause connectivity issues, however now
+ they are causing problems, as pointed out in this OpenWrt ticket:
+
+ https://dev.openwrt.org/ticket/14916
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 0f1cb7be2551b30b02cd54c897e0e29e483cfda5
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Sat Feb 22 13:43:29 2014 +0100
+
+ ath9k: fix ps-poll responses under a-mpdu sessions
+
+ When passing tx frames to the U-APSD queue for powersave poll responses,
+ the ath_atx_tid pointer needs to be passed to ath_tx_setup_buffer for
+ proper sequence number accounting.
+
+ This fixes high latency and connection stability issues with ath9k
+ running as AP and a few kinds of mobile phones as client, when PS-Poll
+ is heavily used
+
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit d5d87a37bbd6066b2c3c5d0bd0fe2a6e2ea45cc5
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Fri Feb 21 11:39:59 2014 +0100
+
+ ath9k: list more reset causes in debugfs
+
+ Number of MAC hangs and stuck beacons were missing
+
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit d84856012e0f10fe598a5ad3b7b869397a089e07
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Thu Feb 20 11:19:58 2014 +0100
+
+ mac80211: fix station wakeup powersave race
+
+ Consider the following (relatively unlikely) scenario:
+ 1) station goes to sleep while frames are buffered in driver
+ 2) driver blocks wakeup (until no more frames are buffered)
+ 3) station wakes up again
+ 4) driver unblocks wakeup
+
+ In this case, the current mac80211 code will do the following:
+ 1) WLAN_STA_PS_STA set
+ 2) WLAN_STA_PS_DRIVER set
+ 3) - nothing -
+ 4) WLAN_STA_PS_DRIVER cleared
+
+ As a result, no frames will be delivered to the client, even
+ though it is awake, until it sends another frame to us that
+ triggers ieee80211_sta_ps_deliver_wakeup() in sta_ps_end().
+
+ Since we now take the PS spinlock, we can fix this while at
+ the same time removing the complexity with the pending skb
+ queue function. This was broken since my commit 50a9432daeec
+ ("mac80211: fix powersaving clients races") due to removing
+ the clearing of WLAN_STA_PS_STA in the RX path.
+
+ While at it, fix a cleanup path issue when a station is
+ removed while the driver is still blocking its wakeup.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 798f2786602cbe93e6b928299614aa36ebf50692
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Mon Feb 17 20:49:03 2014 +0100
+
+ mac80211: insert stations before adding to driver
+
+ There's a race condition in mac80211 because we add stations
+ to the internal lists after adding them to the driver, which
+ means that (for example) the following can happen:
+ 1. a station connects and is added
+ 2. first, it is added to the driver
+ 3. then, it is added to the mac80211 lists
+
+ If the station goes to sleep between steps 2 and 3, and the
+ firmware/hardware records it as being asleep, mac80211 will
+ never instruct the driver to wake it up again as it never
+ realized it went to sleep since the RX path discarded the
+ frame as a "spurious class 3 frame", no station entry was
+ present yet.
+
+ Fix this by adding the station in software first, and only
+ then adding it to the driver. That way, any state that the
+ driver changes will be reflected properly in mac80211's
+ station state. The problematic part is the roll-back if the
+ driver fails to add the station, in that case a bit more is
+ needed. To not make that overly complex prevent starting BA
+ sessions in the meantime.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit b9ba6a520cb07ab3aa7aaaf9ce4a0bc7a6bc06fe
+Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Date: Thu Feb 20 09:22:11 2014 +0200
+
+ mac80211: fix AP powersave TX vs. wakeup race
+
+ There is a race between the TX path and the STA wakeup: while
+ a station is sleeping, mac80211 buffers frames until it wakes
+ up, then the frames are transmitted. However, the RX and TX
+ path are concurrent, so the packet indicating wakeup can be
+ processed while a packet is being transmitted.
+
+ This can lead to a situation where the buffered frames list
+ is emptied on the one side, while a frame is being added on
+ the other side, as the station is still seen as sleeping in
+ the TX path.
+
+ As a result, the newly added frame will not be send anytime
+ soon. It might be sent much later (and out of order) when the
+ station goes to sleep and wakes up the next time.
+
+ Additionally, it can lead to the crash below.
+
+ Fix all this by synchronising both paths with a new lock.
+ Both path are not fastpath since they handle PS situations.
+
+ In a later patch we'll remove the extra skb queue locks to
+ reduce locking overhead.
+
+ BUG: unable to handle kernel
+ NULL pointer dereference at 000000b0
+ IP: [<ff6f1791>] ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
+ *pde = 00000000
+ Oops: 0000 [#1] SMP DEBUG_PAGEALLOC
+ EIP: 0060:[<ff6f1791>] EFLAGS: 00210282 CPU: 1
+ EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
+ EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000
+ ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0
+ DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
+ CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0
+ DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
+ DR6: ffff0ff0 DR7: 00000400
+ Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000)
+ iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9
+ Stack:
+ e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0
+ ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210
+ ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002
+ Call Trace:
+ [<ff6f1b75>] ieee80211_free_txskb+0x15/0x20 [mac80211]
+ [<ff723dc1>] invoke_tx_handlers+0x1661/0x1780 [mac80211]
+ [<ff7248a5>] ieee80211_tx+0x75/0x100 [mac80211]
+ [<ff7249bf>] ieee80211_xmit+0x8f/0xc0 [mac80211]
+ [<ff72550e>] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211]
+ [<c149ef70>] dev_hard_start_xmit+0x450/0x950
+ [<c14b9aa9>] sch_direct_xmit+0xa9/0x250
+ [<c14b9c9b>] __qdisc_run+0x4b/0x150
+ [<c149f732>] dev_queue_xmit+0x2c2/0xca0
+
+ Cc: stable@vger.kernel.org
+ Reported-by: Yaara Rozenblum <yaara.rozenblum@intel.com>
+ Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+ Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com>
+ [reword commit log, use a separate lock]
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 80e419de0dff38436b30d363311c625766193f86
+Author: Inbal Hacohen <Inbal.Hacohen@intel.com>
+Date: Wed Feb 12 09:32:27 2014 +0200
+
+ cfg80211: bugfix in regulatory user hint process
+
+ After processing hint_user, we would want to schedule the
+ timeout work only if we are actually waiting to CRDA. This happens
+ when the status is not "IGNORE" nor "ALREADY_SET".
+
+ Signed-off-by: Inbal Hacohen <Inbal.Hacohen@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 6514c93afede55284e2cb63359aadedb85884c80
+Author: Jouni Malinen <jouni@qca.qualcomm.com>
+Date: Tue Feb 18 20:41:08 2014 +0200
+
+ ath9k: Enable U-APSD AP mode support
+
+ mac80211 handles the actual operations, so ath9k can just indicate
+ support for this. Based on initial tests, this combination seems to
+ work fine.
+
+ Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
+
+commit a63caf0a357ad5c1f08d6b7827dc76c451445017
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date: Wed Feb 19 13:15:17 2014 +0100
+
+ ath9k: protect tid->sched check
+
+ We check tid->sched without a lock taken on ath_tx_aggr_sleep(). That
+ is race condition which can result of doing list_del(&tid->list) twice
+ (second time with poisoned list node) and cause crash like shown below:
+
+ [424271.637220] BUG: unable to handle kernel paging request at 00100104
+ [424271.637328] IP: [<f90fc072>] ath_tx_aggr_sleep+0x62/0xe0 [ath9k]
+ ...
+ [424271.639953] Call Trace:
+ [424271.639998] [<f90f6900>] ? ath9k_get_survey+0x110/0x110 [ath9k]
+ [424271.640083] [<f90f6942>] ath9k_sta_notify+0x42/0x50 [ath9k]
+ [424271.640177] [<f809cfef>] sta_ps_start+0x8f/0x1c0 [mac80211]
+ [424271.640258] [<c10f730e>] ? free_compound_page+0x2e/0x40
+ [424271.640346] [<f809e915>] ieee80211_rx_handlers+0x9d5/0x2340 [mac80211]
+ [424271.640437] [<c112f048>] ? kmem_cache_free+0x1d8/0x1f0
+ [424271.640510] [<c1345a84>] ? kfree_skbmem+0x34/0x90
+ [424271.640578] [<c10fc23c>] ? put_page+0x2c/0x40
+ [424271.640640] [<c1345a84>] ? kfree_skbmem+0x34/0x90
+ [424271.640706] [<c1345a84>] ? kfree_skbmem+0x34/0x90
+ [424271.640787] [<f809dde3>] ? ieee80211_rx_handlers_result+0x73/0x1d0 [mac80211]
+ [424271.640897] [<f80a07a0>] ieee80211_prepare_and_rx_handle+0x520/0xad0 [mac80211]
+ [424271.641009] [<f809e22d>] ? ieee80211_rx_handlers+0x2ed/0x2340 [mac80211]
+ [424271.641104] [<c13846ce>] ? ip_output+0x7e/0xd0
+ [424271.641182] [<f80a1057>] ieee80211_rx+0x307/0x7c0 [mac80211]
+ [424271.641266] [<f90fa6ee>] ath_rx_tasklet+0x88e/0xf70 [ath9k]
+ [424271.641358] [<f80a0f2c>] ? ieee80211_rx+0x1dc/0x7c0 [mac80211]
+ [424271.641445] [<f90f82db>] ath9k_tasklet+0xcb/0x130 [ath9k]
+
+ Bug report:
+ https://bugzilla.kernel.org/show_bug.cgi?id=70551
+
+ Reported-and-tested-by: Max Sydorenko <maxim.stargazer@gmail.com>
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+
+commit 82ed9e3ccc02797df2ffe4b78127c4cd5f799a41
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Tue Feb 11 15:54:13 2014 +0100
+
+ mac80211: send control port protocol frames to the VO queue
+
+ Improves reliability of wifi connections with WPA, since authentication
+ frames are prioritized over normal traffic and also typically exempt
+ from aggregation.
+
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit d4426800f71e972feaa33e04c5801fc730627bdd
+Author: Stanislaw Gruszka <stf_xl@wp.pl>
+Date: Mon Feb 10 22:38:28 2014 +0100
+
+ rtl8187: fix regression on MIPS without coherent DMA
+
+ This patch fixes regression caused by commit a16dad77634 "MIPS: Fix
+ potencial corruption". That commit fixes one corruption scenario in
+ cost of adding another one, which actually start to cause crashes
+ on Yeeloong laptop when rtl8187 driver is used.
+
+ For correct DMA read operation on machines without DMA coherence, kernel
+ have to invalidate cache, such it will refill later with new data that
+ device wrote to memory, when that data is needed to process. We can only
+ invalidate full cache line. Hence when cache line includes both dma
+ buffer and some other data (written in cache, but not yet in main
+ memory), the other data can not hit memory due to invalidation. That
+ happen on rtl8187 where struct rtl8187_priv fields are located just
+ before and after small buffers that are passed to USB layer and DMA
+ is performed on them.
+
+ To fix the problem we align buffers and reserve space after them to make
+ them match cache line.
+
+ This patch does not resolve all possible MIPS problems entirely, for
+ that we have to assure that we always map cache aligned buffers for DMA,
+ what can be complex or even not possible. But patch fixes visible and
+ reproducible regression and seems other possible corruptions do not
+ happen in practice, since Yeeloong laptop works stable without rtl8187
+ driver.
+
+ Bug report:
+ https://bugzilla.kernel.org/show_bug.cgi?id=54391
+
+ Reported-by: Petr Pisar <petr.pisar@atlas.cz>
+ Bisected-by: Tom Li <biergaizi2009@gmail.com>
+ Reported-and-tested-by: Tom Li <biergaizi2009@gmail.com>
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
+
+commit e2f141d67ad1e7fe10aaab61811e8a409dfb2442
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri Feb 7 10:29:55 2014 +0530
+
+ ath9k: Calculate IQ-CAL median
+
+ This patch adds a routine to calculate the median IQ correction
+ values for AR955x, which is used for outlier detection.
+ The normal method which is used for all other chips is
+ bypassed for AR955x.
+
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit c52a6fce0820c8d0687443ab86058ae03b478c8f
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri Feb 7 10:29:54 2014 +0530
+
+ ath9k: Expand the IQ coefficient array
+
+ This will be used for storing data for mutiple
+ IQ calibration runs, for AR955x.
+
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit 034969ff5c2b6431d10e07c1938f0b916da85cc3
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri Feb 7 10:29:53 2014 +0530
+
+ ath9k: Modify IQ calibration for AR955x
+
+ IQ calibration post-processing for AR955x is different
+ from other chips - instead of just doing it as part
+ of AGC calibration once, it is triggered 3 times and
+ a median is determined. This patch adds initial support
+ for changing the calibration behavior for AR955x.
+
+ Also, to simplify things, a helper routine to issue/poll
+ AGC calibration is used.
+
+ For non-AR955x chips, the iqcal_idx (which will be used
+ in subsequent patches) is set to zero.
+
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit 9b1ed6454e6f3511f24266be99b4e403f243f6a8
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri Feb 7 10:29:52 2014 +0530
+
+ ath9k: Fix magnitude/phase calculation
+
+ Incorrect values are programmed in the registers
+ containing the IQ correction coefficients by the IQ-CAL
+ post-processing code. Fix this.
+
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit 36f93484f96f79171dcecb67c5ef0c3de22531a6
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri Feb 7 10:29:51 2014 +0530
+
+ ath9k: Rename ar9003_hw_tx_iqcal_load_avg_2_passes
+
+ Use ar9003_hw_tx_iq_cal_outlier_detection instead.
+
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit 3af09a7f5d21dd5fd15b973ce6a91a575da30417
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri Feb 7 10:29:50 2014 +0530
+
+ ath9k: Check explicitly for IQ calibration
+
+ In chips like AR955x, the initvals contain the information
+ whether IQ calibration is to be done in the HW when an
+ AGC calibration is triggered. Check if IQ-CAL is enabled
+ in the initvals before flagging 'txiqcal_done' as true.
+
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit cb4969634b93c4643a32cc3fbd27d2b288b25771
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri Feb 7 10:29:49 2014 +0530
+
+ ath9k: Fix IQ cal post processing for SoC
+
+ Calibration data is not reused for SoC chips, so
+ call ar9003_hw_tx_iq_cal_post_proc() with the correct
+ argument. The 'is_reusable' flag is currently used
+ only for PC-OEM chips, but it makes things clearer to
+ specify it explicity.
+
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit e138e0ef9560c46ce93dbb22a728a57888e94d1c
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Mon Feb 3 13:31:37 2014 +0530
+
+ ath9k: Fix TX power calculation
+
+ The commit, "ath9k_hw: Fix incorrect Tx control power in AR9003 template"
+ fixed the incorrect values in the eeprom templates, but if
+ boards have already been calibrated with incorrect values,
+ they would still be using the wrong TX power. Fix this by assigning
+ a default value in such cases.
+
+ Cc: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit b9f268b5b01331c3c82179abca551429450e9417
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date: Wed Jan 29 14:22:27 2014 +0100
+
+ cfg80211: consider existing DFS interfaces
+
+ It was possible to break interface combinations in
+ the following way:
+
+ combo 1: iftype = AP, num_ifaces = 2, num_chans = 2,
+ combo 2: iftype = AP, num_ifaces = 1, num_chans = 1, radar = HT20
+
+ With the above interface combinations it was
+ possible to:
+
+ step 1. start AP on DFS channel by matching combo 2
+ step 2. start AP on non-DFS channel by matching combo 1
+
+ This was possible beacuse (step 2) did not consider
+ if other interfaces require radar detection.
+
+ The patch changes how cfg80211 tracks channels -
+ instead of channel itself now a complete chandef
+ is stored.
+
+ Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit bc9c62f5f511cc395c62dbf4cdd437f23db53b28
+Author: Antonio Quartulli <antonio@open-mesh.com>
+Date: Wed Jan 29 17:53:43 2014 +0100
+
+ cfg80211: fix channel configuration in IBSS join
+
+ When receiving an IBSS_JOINED event select the BSS object
+ based on the {bssid, channel} couple rather than the bssid
+ only.
+ With the current approach if another cell having the same
+ BSSID (but using a different channel) exists then cfg80211
+ picks up the wrong BSS object.
+ The result is a mismatching channel configuration between
+ cfg80211 and the driver, that can lead to any sort of
+ problem.
+
+ The issue can be triggered by having an IBSS sitting on
+ given channel and then asking the driver to create a new
+ cell using the same BSSID but with a different frequency.
+ By passing the channel to cfg80211_get_bss() we can solve
+ this ambiguity and retrieve/create the correct BSS object.
+ All the users of cfg80211_ibss_joined() have been changed
+ accordingly.
+
+ Moreover WARN when cfg80211_ibss_joined() gets a NULL
+ channel as argument and remove a bogus call of the same
+ function in ath6kl (it does not make sense to call
+ cfg80211_ibss_joined() with a zero BSSID on ibss-leave).
+
+ Cc: Kalle Valo <kvalo@qca.qualcomm.com>
+ Cc: Arend van Spriel <arend@broadcom.com>
+ Cc: Bing Zhao <bzhao@marvell.com>
+ Cc: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ Cc: libertas-dev@lists.infradead.org
+ Acked-by: Kalle Valo <kvalo@qca.qualcomm.com>
+ Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
+ [minor code cleanup in ath6kl]
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 7e0c41cb41f215aba2c39b1c237bb4d42ec49a85
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Fri Jan 24 14:41:44 2014 +0100
+
+ mac80211: fix bufferable MMPDU RX handling
+
+ Action, disassoc and deauth frames are bufferable, and as such don't
+ have the PM bit in the frame control field reserved which means we
+ need to react to the bit when receiving in such a frame.
+
+ Fix this by introducing a new helper ieee80211_is_bufferable_mmpdu()
+ and using it for the RX path that currently ignores the PM bit in
+ any non-data frames for doze->wake transitions, but listens to it in
+ all frames for wake->doze transitions, both of which are wrong.
+
+ Also use the new helper in the TX path to clean up the code.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit fc0df6d2343636e3f48a069330d5b972e3d8659d
+Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+Date: Fri Jan 24 14:29:21 2014 +0100
+
+ cfg80211: set preset_chandef after channel switch
+
+ Set preset_chandef in channel switch notification.
+ In other case we will have old preset_chandef.
+
+ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit cdec895e2344987ff171cece96e25d7407a3ebf6
+Author: Simon Wunderlich <simon@open-mesh.com>
+Date: Fri Jan 24 23:48:29 2014 +0100
+
+ mac80211: send ibss probe responses with noack flag
+
+ Responding to probe requests for scanning clients will often create
+ excessive retries, as it happens quite often that the scanning client
+ already left the channel. Therefore do it like hostapd and send probe
+ responses for wildcard SSID only once by using the noack flag.
+
+ Signed-off-by: Simon Wunderlich <simon@open-mesh.com>
+ [fix typo & 'wildcard SSID' in commit log]
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 0b865d1e6b9c05052adae9315df7cb195dc60c3b
+Author: Luciano Coelho <luciano.coelho@intel.com>
+Date: Tue Jan 28 17:09:08 2014 +0200
+
+ mac80211: ibss: remove unnecessary call to release channel
+
+ The ieee80211_vif_use_channel() function calls
+ ieee80211_vif_release_channel(), so there's no need to call it
+ explicitly in __ieee80211_sta_join_ibss().
+
+ Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit e1b6c17e971f0a51ff86c2dac2584c63cd999cd7
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date: Wed Jan 29 07:56:21 2014 +0100
+
+ mac80211: add missing CSA locking
+
+ The patch adds a missing sdata lock and adds a few
+ lockdeps for easier maintenance.
+
+ Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit ad17ba7d14d225b109b73c177cd446afb8050598
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date: Wed Jan 29 07:56:20 2014 +0100
+
+ mac80211: fix sdata->radar_required locking
+
+ radar_required setting wasn't protected by
+ local->mtx in some places. This should prevent
+ from scanning/radar detection/roc colliding.
+
+ Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 5fcd5f1808813a3d9e502fd756e01bee8a79c85d
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date: Wed Jan 29 07:56:19 2014 +0100
+
+ mac80211: move csa_active setting in STA CSA
+
+ The sdata->vif.csa_active could be left set after,
+ e.g. channel context constraints check fail in STA
+ mode leaving the interface in a strange state for
+ a brief period of time until it is disconnected.
+ This was harmless but ugly.
+
+ Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+ Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit e486da4b7eed71821c6b4c1bb9ac62ffd3ab13e9
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date: Wed Jan 29 07:56:18 2014 +0100
+
+ mac80211: fix possible memory leak on AP CSA failure
+
+ If CSA for AP interface failed and the interface
+ was not stopped afterwards another CSA request
+ would leak sdata->u.ap.next_beacon.
+
+ Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+ Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 3a77ba08940682bf3d52cf14f980337324af9d4a
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Sat Feb 1 00:33:29 2014 +0100
+
+ mac80211: fix fragmentation code, particularly for encryption
+
+ The "new" fragmentation code (since my rewrite almost 5 years ago)
+ erroneously sets skb->len rather than using skb_trim() to adjust
+ the length of the first fragment after copying out all the others.
+ This leaves the skb tail pointer pointing to after where the data
+ originally ended, and thus causes the encryption MIC to be written
+ at that point, rather than where it belongs: immediately after the
+ data.
+
+ The impact of this is that if software encryption is done, then
+ a) encryption doesn't work for the first fragment, the connection
+ becomes unusable as the first fragment will never be properly
+ verified at the receiver, the MIC is practically guaranteed to
+ be wrong
+ b) we leak up to 8 bytes of plaintext (!) of the packet out into
+ the air
+
+ This is only mitigated by the fact that many devices are capable
+ of doing encryption in hardware, in which case this can't happen
+ as the tail pointer is irrelevant in that case. Additionally,
+ fragmentation is not used very frequently and would normally have
+ to be configured manually.
+
+ Fix this by using skb_trim() properly.
+
+ Cc: stable@vger.kernel.org
+ Fixes: 2de8e0d999b8 ("mac80211: rewrite fragmentation")
+ Reported-by: Jouni Malinen <j@w1.fi>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit de5f242e0c10e841017e37eb8c38974a642dbca8
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Tue Jan 28 06:21:59 2014 +0530
+
+ ath9k: Fix build error on ARM
+
+ Use mdelay instead of udelay to fix this error:
+
+ ERROR: "__bad_udelay" [drivers/net/wireless/ath/ath9k/ath9k_hw.ko] undefined!
+ make[1]: *** [__modpost] Error 1
+ make: *** [modules] Error 2
+
+ Reported-by: Josh Boyer <jwboyer@fedoraproject.org>
+ Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+
+commit 8e3ea7a51dfc61810fcefd947f6edcf61125252a
+Author: Geert Uytterhoeven <geert@linux-m68k.org>
+Date: Sun Jan 26 11:53:21 2014 +0100
+
+ ath9k: Fix uninitialized variable in ath9k_has_tx_pending()
+
+ drivers/net/wireless/ath/ath9k/main.c: In function ‘ath9k_has_tx_pending’:
+ drivers/net/wireless/ath/ath9k/main.c:1869: warning: ‘npend’ may be used uninitialized in this function
+
+ Introduced by commit 10e2318103f5941aa70c318afe34bc41f1b98529 ("ath9k:
+ optimize ath9k_flush").
+
+ Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+
+commit a4a634a6937ebdd827fa58e8fcdb8ca49a3769f6
+Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Date: Mon Jan 27 11:07:42 2014 +0200
+
+ mac80211: release the channel in error path in start_ap
+
+ When the driver cannot start the AP or when the assignement
+ of the beacon goes wrong, we need to unassign the vif.
+
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit dfb6889a75c601aedb7450b7e606668e77da6679
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Wed Jan 22 11:14:19 2014 +0200
+
+ cfg80211: send scan results from work queue
+
+ Due to the previous commit, when a scan finishes, it is in theory
+ possible to hit the following sequence:
+ 1. interface starts being removed
+ 2. scan is cancelled by driver and cfg80211 is notified
+ 3. scan done work is scheduled
+ 4. interface is removed completely, rdev->scan_req is freed,
+ event sent to userspace but scan done work remains pending
+ 5. new scan is requested on another virtual interface
+ 6. scan done work runs, freeing the still-running scan
+
+ To fix this situation, hang on to the scan done message and block
+ new scans while that is the case, and only send the message from
+ the work function, regardless of whether the scan_req is already
+ freed from interface removal. This makes step 5 above impossible
+ and changes step 6 to be
+ 5. scan done work runs, sending the scan done message
+
+ As this can't work for wext, so we send the message immediately,
+ but this shouldn't be an issue since we still return -EBUSY.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 45b7ab41fc08627d9a8428cb413d5d84662a9707
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Wed Jan 22 11:14:18 2014 +0200
+
+ cfg80211: fix scan done race
+
+ When an interface/wdev is removed, any ongoing scan should be
+ cancelled by the driver. This will make it call cfg80211, which
+ only queues a work struct. If interface/wdev removal is quick
+ enough, this can leave the scan request pending and processed
+ only after the interface is gone, causing a use-after-free.
+
+ Fix this by making sure the scan request is not pending after
+ the interface is destroyed. We can't flush or cancel the work
+ item due to locking concerns, but when it'll run it shouldn't
+ find anything to do. This leaves a potential issue, if a new
+ scan gets requested before the work runs, it prematurely stops
+ the running scan, potentially causing another crash. I'll fix
+ that in the next patch.
+
+ This was particularly observed with P2P_DEVICE wdevs, likely
+ because freeing them is quicker than freeing netdevs.
+
+ Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
+ Fixes: 4a58e7c38443 ("cfg80211: don't "leak" uncompleted scans")
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit ae04fa489ab31b5a10d3cc8399f52761175d4321
+Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Date: Thu Jan 23 14:28:16 2014 +0200
+
+ mac80211: avoid deadlock revealed by lockdep
+
+ sdata->u.ap.request_smps_work can’t be flushed synchronously
+ under wdev_lock(wdev) since ieee80211_request_smps_ap_work
+ itself locks the same lock.
+ While at it, reset the driver_smps_mode when the ap is
+ stopped to its default: OFF.
+
+ This solves:
+
+ ======================================================
+ [ INFO: possible circular locking dependency detected ]
+ 3.12.0-ipeer+ #2 Tainted: G O
+ -------------------------------------------------------
+ rmmod/2867 is trying to acquire lock:
+ ((&sdata->u.ap.request_smps_work)){+.+...}, at: [<c105b8d0>] flush_work+0x0/0x90
+
+ but task is already holding lock:
+ (&wdev->mtx){+.+.+.}, at: [<f9b32626>] cfg80211_stop_ap+0x26/0x230 [cfg80211]
+
+ which lock already depends on the new lock.
+
+ the existing dependency chain (in reverse order) is:
+
+ -> #1 (&wdev->mtx){+.+.+.}:
+ [<c10aefa9>] lock_acquire+0x79/0xe0
+ [<c1607a1a>] mutex_lock_nested+0x4a/0x360
+ [<fb06288b>] ieee80211_request_smps_ap_work+0x2b/0x50 [mac80211]
+ [<c105cdd8>] process_one_work+0x198/0x450
+ [<c105d469>] worker_thread+0xf9/0x320
+ [<c10669ff>] kthread+0x9f/0xb0
+ [<c1613397>] ret_from_kernel_thread+0x1b/0x28
+
+ -> #0 ((&sdata->u.ap.request_smps_work)){+.+...}:
+ [<c10ae9df>] __lock_acquire+0x183f/0x1910
+ [<c10aefa9>] lock_acquire+0x79/0xe0
+ [<c105b917>] flush_work+0x47/0x90
+ [<c105d867>] __cancel_work_timer+0x67/0xe0
+ [<c105d90f>] cancel_work_sync+0xf/0x20
+ [<fb0765cc>] ieee80211_stop_ap+0x8c/0x340 [mac80211]
+ [<f9b3268c>] cfg80211_stop_ap+0x8c/0x230 [cfg80211]
+ [<f9b0d8f9>] cfg80211_leave+0x79/0x100 [cfg80211]
+ [<f9b0da72>] cfg80211_netdev_notifier_call+0xf2/0x4f0 [cfg80211]
+ [<c160f2c9>] notifier_call_chain+0x59/0x130
+ [<c106c6de>] __raw_notifier_call_chain+0x1e/0x30
+ [<c106c70f>] raw_notifier_call_chain+0x1f/0x30
+ [<c14f8213>] call_netdevice_notifiers_info+0x33/0x70
+ [<c14f8263>] call_netdevice_notifiers+0x13/0x20
+ [<c14f82a4>] __dev_close_many+0x34/0xb0
+ [<c14f83fe>] dev_close_many+0x6e/0xc0
+ [<c14f9c77>] rollback_registered_many+0xa7/0x1f0
+ [<c14f9dd4>] unregister_netdevice_many+0x14/0x60
+ [<fb06f4d9>] ieee80211_remove_interfaces+0xe9/0x170 [mac80211]
+ [<fb055116>] ieee80211_unregister_hw+0x56/0x110 [mac80211]
+ [<fa3e9396>] iwl_op_mode_mvm_stop+0x26/0xe0 [iwlmvm]
+ [<f9b9d8ca>] _iwl_op_mode_stop+0x3a/0x70 [iwlwifi]
+ [<f9b9d96f>] iwl_opmode_deregister+0x6f/0x90 [iwlwifi]
+ [<fa405179>] __exit_compat+0xd/0x19 [iwlmvm]
+ [<c10b8bf9>] SyS_delete_module+0x179/0x2b0
+ [<c1613421>] sysenter_do_call+0x12/0x32
+
+ Fixes: 687da132234f ("mac80211: implement SMPS for AP")
+ Cc: <stable@vger.kernel.org> [3.13]
+ Reported-by: Ilan Peer <ilan.peer@intel.com>
+ Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 178b205e96217164fd7c30113464250d0b6f5eca
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Thu Jan 23 16:32:29 2014 +0100
+
+ cfg80211: re-enable 5/10 MHz support
+
+ Unfortunately I forgot this during the merge window, but the
+ patch seems small enough to go in as a fix. The userspace API
+ bug that was the reason for disabling it has long been fixed.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 110a1c79acda14edc83b7c8dc5af9c7ddd23eb61
+Author: Pontus Fuchs <pontus.fuchs@gmail.com>
+Date: Thu Jan 16 15:00:40 2014 +0100
+
+ nl80211: Reset split_start when netlink skb is exhausted
+
+ When the netlink skb is exhausted split_start is left set. In the
+ subsequent retry, with a larger buffer, the dump is continued from the
+ failing point instead of from the beginning.
+
+ This was causing my rt28xx based USB dongle to now show up when
+ running "iw list" with an old iw version without split dump support.
+
+ Cc: stable@vger.kernel.org
+ Fixes: 3713b4e364ef ("nl80211: allow splitting wiphy information in dumps")
+ Signed-off-by: Pontus Fuchs <pontus.fuchs@gmail.com>
+ [avoid the entire workaround when state->split is set]
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit b4c31b45ffc7ef110fa9ecc34d7878fe7c5b9da4
+Author: Eliad Peller <eliad@wizery.com>
+Date: Sun Jan 12 11:06:37 2014 +0200
+
+ mac80211: move roc cookie assignment earlier
+
+ ieee80211_start_roc_work() might add a new roc
+ to existing roc, and tell cfg80211 it has already
+ started.
+
+ However, this might happen before the roc cookie
+ was set, resulting in REMAIN_ON_CHANNEL (started)
+ event with null cookie. Consequently, it can make
+ wpa_supplicant go out of sync.
+
+ Fix it by setting the roc cookie earlier.
+
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Eliad Peller <eliad@wizery.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit cfdc9157bfd7bcf88ab4dae08873a9907eba984c
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Fri Jan 24 14:06:29 2014 +0100
+
+ nl80211: send event when AP operation is stopped
+
+ There are a few cases, e.g. suspend, where an AP interface is
+ stopped by the kernel rather than by userspace request, most
+ commonly when suspending. To let userspace know about this,
+ send the NL80211_CMD_STOP_AP command as an event every time
+ an AP interface is stopped. This also happens when userspace
+ did in fact request the AP stop, but that's not a problem.
+
+ For full-MAC drivers this may need to be extended to also
+ cover cases where the device stopped the AP operation for
+ some reason, this a bit more complicated because then all
+ cfg80211 state also needs to be reset; such API is not part
+ of this patch.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit d5d567eda7704f190379ca852a8f9a4112e3eee3
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Thu Jan 23 16:20:29 2014 +0100
+
+ mac80211: add length check in ieee80211_is_robust_mgmt_frame()
+
+ A few places weren't checking that the frame passed to the
+ function actually has enough data even though the function
+ clearly documents it must have a payload byte. Make this
+ safer by changing the function to take an skb and checking
+ the length inside. The old version is preserved for now as
+ the rtl* drivers use it and don't have a correct skb.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit f8f6d212a047fc65c7d3442dfc038f65517236fc
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Fri Jan 24 10:53:53 2014 +0100
+
+ nl80211: fix scheduled scan RSSI matchset attribute confusion
+
+ The scheduled scan matchsets were intended to be a list of filters,
+ with the found BSS having to pass at least one of them to be passed
+ to the host. When the RSSI attribute was added, however, this was
+ broken and currently wpa_supplicant adds that attribute in its own
+ matchset; however, it doesn't intend that to mean that anything
+ that passes the RSSI filter should be passed to the host, instead
+ it wants it to mean that everything needs to also have higher RSSI.
+
+ This is semantically problematic because we have a list of filters
+ like [ SSID1, SSID2, SSID3, RSSI ] with no real indication which
+ one should be OR'ed and which one AND'ed.
+
+ To fix this, move the RSSI filter attribute into each matchset. As
+ we need to stay backward compatible, treat a matchset with only the
+ RSSI attribute as a "default RSSI filter" for all other matchsets,
+ but only if there are other matchsets (an RSSI-only matchset by
+ itself is still desirable.)
+
+ To make driver implementation easier, keep a global min_rssi_thold
+ for the entire request as well. The only affected driver is ath6kl.
+
+ I found this when I looked into the code after Raja Mani submitted
+ a patch fixing the n_match_sets calculation to disregard the RSSI,
+ but that patch didn't address the semantic issue.
+
+ Reported-by: Raja Mani <rmani@qti.qualcomm.com>
+ Acked-by: Luciano Coelho <luciano.coelho@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit de553e8545e65a6dc4e45f43df7e1443d4291922
+Author: Johannes Berg <johannes.berg@intel.com>
+Date: Fri Jan 24 10:17:47 2014 +0100
+
+ nl80211: check nla_parse() return values
+
+ If there's a policy, then nla_parse() return values must be
+ checked, otherwise the policy is useless and there's nothing
+ that ensures the attributes are actually what we expect them
+ to be.
+
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+
+commit 652204a0733e9e1c54661d6f9d36e2e1e3b22bb1
+Author: Karl Beldan <karl.beldan@rivierawaves.com>
+Date: Thu Jan 23 20:06:34 2014 +0100
+
+ mac80211: send {ADD,DEL}BA on AC_VO like other mgmt frames, as per spec
+
+ ATM, {ADD,DEL}BA and BAR frames are sent on the AC matching the TID of
+ the BA parameters. In the discussion [1] about this patch, Johannes
+ recalled that it fixed some races with the DELBA and indeed this
+ behavior was introduced in [2].
+ While [2] is right for the BARs, the part queueing the {ADD,DEL}BAs on
+ their BA params TID AC violates the spec and is more a workaround for
+ some drivers. Helmut expressed some concerns wrt such drivers, in
+ particular DELBAs in rt2x00.
+
+ ATM, DELBAs are sent after a driver has called (hence "purposely")
+ ieee80211_start_tx_ba_cb_irqsafe and Johannes and Emmanuel gave some
+ details wrt intentions behind the split of the IEEE80211_AMPDU_TX_STOP_*
+ given to the driver ampdu_action supposed to call this function, which
+ could prove handy to people trying to do the right thing in faulty
+ drivers (if their fw/hw don't get in their way).
+
+ [1] http://mid.gmane.org/1390391564-18481-1-git-send-email-karl.beldan@gmail.com
+ [2] Commit: cf6bb79ad828 ("mac80211: Use appropriate TID for sending BAR, ADDBA and DELBA frames")
+
+ Signed-off-by: Karl Beldan <karl.beldan@rivierawaves.com>
+ Cc: Helmut Schaa <helmut.schaa@googlemail.com>
+ Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
++++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
+@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struc
+ if (nw_type & ADHOC_NETWORK) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
+ nw_type & ADHOC_CREATOR ? "creator" : "joiner");
+- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
++ cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
+ cfg80211_put_bss(ar->wiphy, bss);
+ return;
+ }
+@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(st
+ }
+
+ if (vif->nw_type & ADHOC_NETWORK) {
+- if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
++ if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: ath6k not in ibss mode\n", __func__);
+- return;
+- }
+- memset(bssid, 0, ETH_ALEN);
+- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
+ return;
+ }
+
+@@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(s
+ struct ath6kl_vif *vif = netdev_priv(dev);
+ u16 interval;
+ int ret, rssi_thold;
++ int n_match_sets = request->n_match_sets;
++
++ /*
++ * If there's a matchset w/o an SSID, then assume it's just for
++ * the RSSI (nothing else is currently supported) and ignore it.
++ * The device only supports a global RSSI filter that we set below.
++ */
++ if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
++ n_match_sets = 0;
+
+ if (ar->state != ATH6KL_STATE_ON)
+ return -EIO;
+@@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(s
+ ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
+ request->n_ssids,
+ request->match_sets,
+- request->n_match_sets);
++ n_match_sets);
+ if (ret < 0)
+ return ret;
+
+- if (!request->n_match_sets) {
++ if (!n_match_sets) {
+ ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+ ALL_BSS_FILTER, 0);
+ if (ret < 0)
+@@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(s
+
+ if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
+ ar->fw_capabilities)) {
+- if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
++ if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
+ rssi_thold = 0;
+- else if (request->rssi_thold < -127)
++ else if (request->min_rssi_thold < -127)
+ rssi_thold = -127;
+ else
+- rssi_thold = request->rssi_thold;
++ rssi_thold = request->min_rssi_thold;
+
+ ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
+ rssi_thold);
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1316,7 +1316,7 @@ static bool ath9k_hw_set_reset(struct at
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ udelay(50);
+ else if (AR_SREV_9100(ah))
+- udelay(10000);
++ mdelay(10);
+ else
+ udelay(100);
+
+@@ -1534,7 +1534,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
+ bool ath9k_hw_check_alive(struct ath_hw *ah)
+ {
+ int count = 50;
+- u32 reg;
++ u32 reg, last_val;
+
+ if (AR_SREV_9300(ah))
+ return !ath9k_hw_detect_mac_hang(ah);
+@@ -1542,9 +1542,14 @@ bool ath9k_hw_check_alive(struct ath_hw
+ if (AR_SREV_9285_12_OR_LATER(ah))
+ return true;
+
++ last_val = REG_READ(ah, AR_OBS_BUS_1);
+ do {
+ reg = REG_READ(ah, AR_OBS_BUS_1);
++ if (reg != last_val)
++ return true;
+
++ udelay(1);
++ last_val = reg;
+ if ((reg & 0x7E7FFFEF) == 0x00702400)
+ continue;
+
+@@ -2051,9 +2056,8 @@ static bool ath9k_hw_set_power_awake(str
+
+ REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+-
+ if (AR_SREV_9100(ah))
+- udelay(10000);
++ mdelay(10);
+ else
+ udelay(50);
+
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data)
+ * interrupts are enabled in the reset routine.
+ */
+ atomic_inc(&ah->intr_ref_cnt);
+- ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
++ ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
+ goto out;
+ }
+
+@@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data)
+ * interrupts are enabled in the reset routine.
+ */
+ atomic_inc(&ah->intr_ref_cnt);
+- ath_dbg(common, ANY,
++ ath_dbg(common, RESET,
+ "BB_WATCHDOG: Skipping interrupts\n");
+ goto out;
+ }
+@@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data)
+ type = RESET_TYPE_TX_GTT;
+ ath9k_queue_reset(sc, type);
+ atomic_inc(&ah->intr_ref_cnt);
+- ath_dbg(common, ANY,
++ ath_dbg(common, RESET,
+ "GTT: Skipping interrupts\n");
+ goto out;
+ }
+@@ -1866,7 +1866,7 @@ static void ath9k_set_coverage_class(str
+
+ static bool ath9k_has_tx_pending(struct ath_softc *sc)
+ {
+- int i, npend;
++ int i, npend = 0;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (!ATH_TXQ_SETUP(sc, i))
+--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
++++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
+@@ -595,6 +595,9 @@ static void iwl_scan_offload_build_ssid(
+ * config match list.
+ */
+ for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
++ /* skip empty SSID matchsets */
++ if (!req->match_sets[i].ssid.ssid_len)
++ continue;
+ scan->direct_scan[i].id = WLAN_EID_SSID;
+ scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
+ memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
+--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
++++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
+@@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80
+ /* During testing, hdr was NULL */
+ return false;
+ }
+- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
++ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
++++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+@@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80
+ /* In testing, hdr was NULL here */
+ return false;
+ }
+- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
++ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
++++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+@@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80
+ /* during testing, hdr was NULL here */
+ return false;
+ }
+- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
++ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
++++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+@@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee
+ /* during testing, hdr could be NULL here */
+ return false;
+ }
+- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
++ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+--- a/include/linux/ieee80211.h
++++ b/include/linux/ieee80211.h
+@@ -597,6 +597,20 @@ static inline int ieee80211_is_qos_nullf
+ }
+
+ /**
++ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
++ * @fc: frame control field in little-endian byteorder
++ */
++static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc)
++{
++ /* IEEE 802.11-2012, definition of "bufferable management frame";
++ * note that this ignores the IBSS special case. */
++ return ieee80211_is_mgmt(fc) &&
++ (ieee80211_is_action(fc) ||
++ ieee80211_is_disassoc(fc) ||
++ ieee80211_is_deauth(fc));
++}
++
++/**
+ * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set
+ * @seq_ctrl: frame sequence control bytes in little-endian byteorder
+ */
+@@ -2192,10 +2206,10 @@ static inline u8 *ieee80211_get_DA(struc
+ }
+
+ /**
+- * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
++ * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
+ * @hdr: the frame (buffer must include at least the first octet of payload)
+ */
+-static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
++static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
+ {
+ if (ieee80211_is_disassoc(hdr->frame_control) ||
+ ieee80211_is_deauth(hdr->frame_control))
+@@ -2224,6 +2238,17 @@ static inline bool ieee80211_is_robust_m
+ }
+
+ /**
++ * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame
++ * @skb: the skb containing the frame, length will be checked
++ */
++static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
++{
++ if (skb->len < 25)
++ return false;
++ return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
++}
++
++/**
+ * ieee80211_is_public_action - check if frame is a public action frame
+ * @hdr: the frame
+ * @len: length of the frame
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -1395,9 +1395,11 @@ struct cfg80211_scan_request {
+ * struct cfg80211_match_set - sets of attributes to match
+ *
+ * @ssid: SSID to be matched
++ * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
+ */
+ struct cfg80211_match_set {
+ struct cfg80211_ssid ssid;
++ s32 rssi_thold;
+ };
+
+ /**
+@@ -1420,7 +1422,8 @@ struct cfg80211_match_set {
+ * @dev: the interface
+ * @scan_start: start time of the scheduled scan
+ * @channels: channels to scan
+- * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
++ * @min_rssi_thold: for drivers only supporting a single threshold, this
++ * contains the minimum over all matchsets
+ */
+ struct cfg80211_sched_scan_request {
+ struct cfg80211_ssid *ssids;
+@@ -1433,7 +1436,7 @@ struct cfg80211_sched_scan_request {
+ u32 flags;
+ struct cfg80211_match_set *match_sets;
+ int n_match_sets;
+- s32 rssi_thold;
++ s32 min_rssi_thold;
+
+ /* internal */
+ struct wiphy *wiphy;
+@@ -3130,8 +3133,8 @@ struct cfg80211_cached_keys;
+ * @identifier: (private) Identifier used in nl80211 to identify this
+ * wireless device if it has no netdev
+ * @current_bss: (private) Used by the internal configuration code
+- * @channel: (private) Used by the internal configuration code to track
+- * the user-set AP, monitor and WDS channel
++ * @chandef: (private) Used by the internal configuration code to track
++ * the user-set channel definition.
+ * @preset_chandef: (private) Used by the internal configuration code to
+ * track the channel to be used for AP later
+ * @bssid: (private) Used by the internal configuration code
+@@ -3195,9 +3198,7 @@ struct wireless_dev {
+
+ struct cfg80211_internal_bss *current_bss; /* associated / joined */
+ struct cfg80211_chan_def preset_chandef;
+-
+- /* for AP and mesh channel tracking */
+- struct ieee80211_channel *channel;
++ struct cfg80211_chan_def chandef;
+
+ bool ibss_fixed;
+ bool ibss_dfs_possible;
+@@ -3879,6 +3880,7 @@ void cfg80211_michael_mic_failure(struct
+ *
+ * @dev: network device
+ * @bssid: the BSSID of the IBSS joined
++ * @channel: the channel of the IBSS joined
+ * @gfp: allocation flags
+ *
+ * This function notifies cfg80211 that the device joined an IBSS or
+@@ -3888,7 +3890,8 @@ void cfg80211_michael_mic_failure(struct
+ * with the locally generated beacon -- this guarantees that there is
+ * always a scan result for this IBSS. cfg80211 will handle the rest.
+ */
+-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
++void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
++ struct ieee80211_channel *channel, gfp_t gfp);
+
+ /**
+ * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -2442,9 +2442,15 @@ enum nl80211_reg_rule_attr {
+ * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
+- * only report BSS with matching SSID.
++ * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
+- * BSS in scan results. Filtering is turned off if not specified.
++ * BSS in scan results. Filtering is turned off if not specified. Note that
++ * if this attribute is in a match set of its own, then it is treated as
++ * the default value for all matchsets with an SSID, rather than being a
++ * matchset of its own without an RSSI filter. This is due to problems with
++ * how this API was implemented in the past. Also, due to the same problem,
++ * the only way to create a matchset with only an RSSI filter (with this
++ * attribute) is if there's only a single matchset with the RSSI attribute.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
+ * attribute number currently defined
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
-@@ -81,7 +81,8 @@ static void ieee80211_send_addba_request
- memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
- if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-- sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
-+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
-+ sdata->vif.type == NL80211_IFTYPE_WDS)
- memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
- else if (sdata->vif.type == NL80211_IFTYPE_STATION)
- memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
-@@ -527,6 +528,7 @@ int ieee80211_start_tx_ba_session(struct
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
- sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- sdata->vif.type != NL80211_IFTYPE_AP &&
-+ sdata->vif.type != NL80211_IFTYPE_WDS &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC)
- return -EINVAL;
+@@ -107,7 +107,7 @@ static void ieee80211_send_addba_request
+ mgmt->u.action.u.addba_req.start_seq_num =
+ cpu_to_le16(start_seq_num << 4);
+
+- ieee80211_tx_skb_tid(sdata, skb, tid);
++ ieee80211_tx_skb(sdata, skb);
+ }
+
+ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -970,9 +970,9 @@ static int ieee80211_start_ap(struct wip
+ /* TODO: make hostapd tell us what it wants */
+ sdata->smps_mode = IEEE80211_SMPS_OFF;
+ sdata->needed_rx_chains = sdata->local->rx_chains;
+- sdata->radar_required = params->radar_required;
+
+ mutex_lock(&local->mtx);
++ sdata->radar_required = params->radar_required;
+ err = ieee80211_vif_use_channel(sdata, ¶ms->chandef,
+ IEEE80211_CHANCTX_SHARED);
+ mutex_unlock(&local->mtx);
+@@ -1021,8 +1021,10 @@ static int ieee80211_start_ap(struct wip
+ IEEE80211_P2P_OPPPS_ENABLE_BIT;
+
+ err = ieee80211_assign_beacon(sdata, ¶ms->beacon);
+- if (err < 0)
++ if (err < 0) {
++ ieee80211_vif_release_channel(sdata);
+ return err;
++ }
+ changed |= err;
+
+ err = drv_start_ap(sdata->local, sdata);
+@@ -1032,6 +1034,7 @@ static int ieee80211_start_ap(struct wip
+ if (old)
+ kfree_rcu(old, rcu_head);
+ RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
++ ieee80211_vif_release_channel(sdata);
+ return err;
+ }
+
+@@ -1053,6 +1056,7 @@ static int ieee80211_change_beacon(struc
+ int err;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++ sdata_assert_lock(sdata);
+
+ /* don't allow changing the beacon while CSA is in place - offset
+ * of channel switch counter may change
+@@ -1080,6 +1084,8 @@ static int ieee80211_stop_ap(struct wiph
+ struct probe_resp *old_probe_resp;
+ struct cfg80211_chan_def chandef;
+
++ sdata_assert_lock(sdata);
++
+ old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
+ if (!old_beacon)
+ return -ENOENT;
+@@ -1090,8 +1096,6 @@ static int ieee80211_stop_ap(struct wiph
+ kfree(sdata->u.ap.next_beacon);
+ sdata->u.ap.next_beacon = NULL;
+
+- cancel_work_sync(&sdata->u.ap.request_smps_work);
+-
+ /* turn off carrier for this interface and dependent VLANs */
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ netif_carrier_off(vlan->dev);
+@@ -1103,6 +1107,7 @@ static int ieee80211_stop_ap(struct wiph
+ kfree_rcu(old_beacon, rcu_head);
+ if (old_probe_resp)
+ kfree_rcu(old_probe_resp, rcu_head);
++ sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
+
+ __sta_info_flush(sdata, true);
+ ieee80211_free_keys(sdata, true);
+@@ -1988,6 +1993,9 @@ static int ieee80211_change_bss(struct w
+
+ band = ieee80211_get_sdata_band(sdata);
+
++ if (WARN_ON(!wiphy->bands[band]))
++ return -EINVAL;
++
+ if (params->use_cts_prot >= 0) {
+ sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
+ changed |= BSS_CHANGED_ERP_CTS_PROT;
+@@ -2638,6 +2646,24 @@ static int ieee80211_start_roc_work(stru
+ INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
+ INIT_LIST_HEAD(&roc->dependents);
+
++ /*
++ * cookie is either the roc cookie (for normal roc)
++ * or the SKB (for mgmt TX)
++ */
++ if (!txskb) {
++ /* local->mtx protects this */
++ local->roc_cookie_counter++;
++ roc->cookie = local->roc_cookie_counter;
++ /* wow, you wrapped 64 bits ... more likely a bug */
++ if (WARN_ON(roc->cookie == 0)) {
++ roc->cookie = 1;
++ local->roc_cookie_counter++;
++ }
++ *cookie = roc->cookie;
++ } else {
++ *cookie = (unsigned long)txskb;
++ }
++
+ /* if there's one pending or we're scanning, queue this one */
+ if (!list_empty(&local->roc_list) ||
+ local->scanning || local->radar_detect_enabled)
+@@ -2772,24 +2798,6 @@ static int ieee80211_start_roc_work(stru
+ if (!queued)
+ list_add_tail(&roc->list, &local->roc_list);
+
+- /*
+- * cookie is either the roc cookie (for normal roc)
+- * or the SKB (for mgmt TX)
+- */
+- if (!txskb) {
+- /* local->mtx protects this */
+- local->roc_cookie_counter++;
+- roc->cookie = local->roc_cookie_counter;
+- /* wow, you wrapped 64 bits ... more likely a bug */
+- if (WARN_ON(roc->cookie == 0)) {
+- roc->cookie = 1;
+- local->roc_cookie_counter++;
+- }
+- *cookie = roc->cookie;
+- } else {
+- *cookie = (unsigned long)txskb;
+- }
+-
+ return 0;
+ }
+
+@@ -3004,8 +3012,10 @@ void ieee80211_csa_finalize_work(struct
+ if (!ieee80211_sdata_running(sdata))
+ goto unlock;
+
+- sdata->radar_required = sdata->csa_radar_required;
++ sdata_assert_lock(sdata);
++
+ mutex_lock(&local->mtx);
++ sdata->radar_required = sdata->csa_radar_required;
+ err = ieee80211_vif_change_channel(sdata, &changed);
+ mutex_unlock(&local->mtx);
+ if (WARN_ON(err < 0))
+@@ -3022,13 +3032,13 @@ void ieee80211_csa_finalize_work(struct
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
++ kfree(sdata->u.ap.next_beacon);
++ sdata->u.ap.next_beacon = NULL;
++
+ if (err < 0)
+ goto unlock;
+
+ changed |= err;
+- kfree(sdata->u.ap.next_beacon);
+- sdata->u.ap.next_beacon = NULL;
+-
+ ieee80211_bss_info_change_notify(sdata, err);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+@@ -3066,7 +3076,7 @@ int ieee80211_channel_switch(struct wiph
+ struct ieee80211_if_mesh __maybe_unused *ifmsh;
+ int err, num_chanctx;
+
+- lockdep_assert_held(&sdata->wdev.mtx);
++ sdata_assert_lock(sdata);
+
+ if (!list_empty(&local->roc_list) || local->scanning)
+ return -EBUSY;
+--- a/net/mac80211/ht.c
++++ b/net/mac80211/ht.c
+@@ -375,7 +375,7 @@ void ieee80211_send_delba(struct ieee802
+ mgmt->u.action.u.delba.params = cpu_to_le16(params);
+ mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
+
+- ieee80211_tx_skb_tid(sdata, skb, tid);
++ ieee80211_tx_skb(sdata, skb);
+ }
+
+ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
+@@ -466,7 +466,9 @@ void ieee80211_request_smps_ap_work(stru
+ u.ap.request_smps_work);
+
+ sdata_lock(sdata);
+- __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode);
++ if (sdata_dereference(sdata->u.ap.beacon, sdata))
++ __ieee80211_request_smps_ap(sdata,
++ sdata->u.ap.driver_smps_mode);
+ sdata_unlock(sdata);
+ }
---- a/net/mac80211/debugfs_sta.c
-+++ b/net/mac80211/debugfs_sta.c
-@@ -66,11 +66,11 @@ static ssize_t sta_flags_read(struct fil
- test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
-
- int res = scnprintf(buf, sizeof(buf),
-- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
-+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
- TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
- TEST(PS_DRIVER), TEST(AUTHORIZED),
- TEST(SHORT_PREAMBLE),
-- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
-+ TEST(WME), TEST(CLEAR_PS_FILT),
- TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
- TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
- TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -463,7 +463,6 @@ int ieee80211_do_open(struct wireless_de
- struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
- struct net_device *dev = wdev->netdev;
- struct ieee80211_local *local = sdata->local;
-- struct sta_info *sta;
- u32 changed = 0;
- int res;
- u32 hw_reconf_flags = 0;
-@@ -629,30 +628,8 @@ int ieee80211_do_open(struct wireless_de
-
- set_bit(SDATA_STATE_RUNNING, &sdata->state);
-
-- if (sdata->vif.type == NL80211_IFTYPE_WDS) {
-- /* Create STA entry for the WDS peer */
-- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
-- GFP_KERNEL);
-- if (!sta) {
-- res = -ENOMEM;
-- goto err_del_interface;
-- }
+@@ -770,12 +770,19 @@ static void ieee80211_do_stop(struct iee
+
+ ieee80211_roc_purge(local, sdata);
+
+- if (sdata->vif.type == NL80211_IFTYPE_STATION)
++ switch (sdata->vif.type) {
++ case NL80211_IFTYPE_STATION:
+ ieee80211_mgd_stop(sdata);
-
-- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
-- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
-- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
+- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
++ break;
++ case NL80211_IFTYPE_ADHOC:
+ ieee80211_ibss_stop(sdata);
-
-- res = sta_info_insert(sta);
-- if (res) {
-- /* STA has been freed */
-- goto err_del_interface;
-- }
++ break;
++ case NL80211_IFTYPE_AP:
++ cancel_work_sync(&sdata->u.ap.request_smps_work);
++ break;
++ default:
++ break;
++ }
+
+ /*
+ * Remove all stations associated with this interface.
+@@ -827,7 +834,9 @@ static void ieee80211_do_stop(struct iee
+ cancel_work_sync(&local->dynamic_ps_enable_work);
+
+ cancel_work_sync(&sdata->recalc_smps);
++ sdata_lock(sdata);
+ sdata->vif.csa_active = false;
++ sdata_unlock(sdata);
+ cancel_work_sync(&sdata->csa_finalize_work);
+
+ cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -599,10 +599,10 @@ static int ieee80211_is_unicast_robust_m
+ {
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+- if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1))
++ if (is_multicast_ether_addr(hdr->addr1))
+ return 0;
+
+- return ieee80211_is_robust_mgmt_frame(hdr);
++ return ieee80211_is_robust_mgmt_frame(skb);
+ }
+
+
+@@ -610,10 +610,10 @@ static int ieee80211_is_multicast_robust
+ {
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+- if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1))
++ if (!is_multicast_ether_addr(hdr->addr1))
+ return 0;
+
+- return ieee80211_is_robust_mgmt_frame(hdr);
++ return ieee80211_is_robust_mgmt_frame(skb);
+ }
+
+
+@@ -626,7 +626,7 @@ static int ieee80211_get_mmie_keyidx(str
+ if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
+ return -1;
+
+- if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
++ if (!ieee80211_is_robust_mgmt_frame(skb))
+ return -1; /* not a robust management frame */
+
+ mmie = (struct ieee80211_mmie *)
+@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *
+ sta->sta.addr, sta->sta.aid);
+
+ if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
++ /*
++ * Clear the flag only if the other one is still set
++ * so that the TX path won't start TX'ing new frames
++ * directly ... In the case that the driver flag isn't
++ * set ieee80211_sta_ps_deliver_wakeup() will clear it.
++ */
++ clear_sta_flag(sta, WLAN_STA_PS_STA);
+ ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
+ sta->sta.addr, sta->sta.aid);
+ return;
+@@ -1311,18 +1318,15 @@ ieee80211_rx_h_sta_process(struct ieee80
+ !ieee80211_has_morefrags(hdr->frame_control) &&
+ !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
+ (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
+- rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
++ rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
++ /* PM bit is only checked in frames where it isn't reserved,
++ * in AP mode it's reserved in non-bufferable management frames
++ * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field)
++ */
++ (!ieee80211_is_mgmt(hdr->frame_control) ||
++ ieee80211_is_bufferable_mmpdu(hdr->frame_control))) {
+ if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
+- /*
+- * Ignore doze->wake transitions that are
+- * indicated by non-data frames, the standard
+- * is unclear here, but for example going to
+- * PS mode and then scanning would cause a
+- * doze->wake transition for the probe request,
+- * and that is clearly undesirable.
+- */
+- if (ieee80211_is_data(hdr->frame_control) &&
+- !ieee80211_has_pm(hdr->frame_control))
++ if (!ieee80211_has_pm(hdr->frame_control))
+ sta_ps_end(sta);
+ } else {
+ if (ieee80211_has_pm(hdr->frame_control))
+@@ -1845,8 +1849,7 @@ static int ieee80211_drop_unencrypted_mg
+ * having configured keys.
+ */
+ if (unlikely(ieee80211_is_action(fc) && !rx->key &&
+- ieee80211_is_robust_mgmt_frame(
+- (struct ieee80211_hdr *) rx->skb->data)))
++ ieee80211_is_robust_mgmt_frame(rx->skb)))
+ return -EACCES;
+ }
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -452,8 +452,7 @@ static int ieee80211_use_mfp(__le16 fc,
+ if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
+ return 0;
+
+- if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
+- skb->data))
++ if (!ieee80211_is_robust_mgmt_frame(skb))
+ return 0;
+
+ return 1;
+@@ -478,6 +477,20 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
+ sta->sta.addr, sta->sta.aid, ac);
+ if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+ purge_old_ps_buffers(tx->local);
++
++ /* sync with ieee80211_sta_ps_deliver_wakeup */
++ spin_lock(&sta->ps_lock);
++ /*
++ * STA woke up the meantime and all the frames on ps_tx_buf have
++ * been queued to pending queue. No reordering can happen, go
++ * ahead and Tx the packet.
++ */
++ if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
++ !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
++ spin_unlock(&sta->ps_lock);
++ return TX_CONTINUE;
++ }
++
+ if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
+ struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
+ ps_dbg(tx->sdata,
+@@ -492,6 +505,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
+ skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
++ spin_unlock(&sta->ps_lock);
+
+ if (!timer_pending(&local->sta_cleanup))
+ mod_timer(&local->sta_cleanup,
+@@ -525,9 +539,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_t
+
+ /* only deauth, disassoc and action are bufferable MMPDUs */
+ if (ieee80211_is_mgmt(hdr->frame_control) &&
+- !ieee80211_is_deauth(hdr->frame_control) &&
+- !ieee80211_is_disassoc(hdr->frame_control) &&
+- !ieee80211_is_action(hdr->frame_control)) {
++ !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
+ if (tx->flags & IEEE80211_TX_UNICAST)
+ info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+ return TX_CONTINUE;
+@@ -567,7 +579,7 @@ ieee80211_tx_h_select_key(struct ieee802
+ tx->key = key;
+ else if (ieee80211_is_mgmt(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr1) &&
+- ieee80211_is_robust_mgmt_frame(hdr) &&
++ ieee80211_is_robust_mgmt_frame(tx->skb) &&
+ (key = rcu_dereference(tx->sdata->default_mgmt_key)))
+ tx->key = key;
+ else if (is_multicast_ether_addr(hdr->addr1) &&
+@@ -582,12 +594,12 @@ ieee80211_tx_h_select_key(struct ieee802
+ tx->key = NULL;
+ else if (tx->skb->protocol == tx->sdata->control_port_protocol)
+ tx->key = NULL;
+- else if (ieee80211_is_robust_mgmt_frame(hdr) &&
++ else if (ieee80211_is_robust_mgmt_frame(tx->skb) &&
+ !(ieee80211_is_action(hdr->frame_control) &&
+ tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
+ tx->key = NULL;
+ else if (ieee80211_is_mgmt(hdr->frame_control) &&
+- !ieee80211_is_robust_mgmt_frame(hdr))
++ !ieee80211_is_robust_mgmt_frame(tx->skb))
+ tx->key = NULL;
+ else {
+ I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
+@@ -878,7 +890,7 @@ static int ieee80211_fragment(struct iee
+ }
+
+ /* adjust first fragment's length */
+- skb->len = hdrlen + per_fragm;
++ skb_trim(skb, hdrlen + per_fragm);
+ return 0;
+ }
+
+@@ -2900,7 +2912,7 @@ ieee80211_get_buffered_bc(struct ieee802
+ cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+ }
+
+- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
++ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
+ if (!ieee80211_tx_prepare(sdata, &tx, skb))
+ break;
+--- a/net/mac80211/wpa.c
++++ b/net/mac80211/wpa.c
+@@ -499,7 +499,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ if (!ieee80211_is_data(hdr->frame_control) &&
+- !ieee80211_is_robust_mgmt_frame(hdr))
++ !ieee80211_is_robust_mgmt_frame(skb))
+ return RX_CONTINUE;
+
+ data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN -
+--- a/net/wireless/ap.c
++++ b/net/wireless/ap.c
+@@ -27,9 +27,10 @@ static int __cfg80211_stop_ap(struct cfg
+ err = rdev_stop_ap(rdev, dev);
+ if (!err) {
+ wdev->beacon_interval = 0;
+- wdev->channel = NULL;
++ memset(&wdev->chandef, 0, sizeof(wdev->chandef));
+ wdev->ssid_len = 0;
+ rdev_set_qos_map(rdev, dev, NULL);
++ nl80211_send_ap_stopped(wdev);
+ }
+
+ return err;
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg
+
+ rdev->opencount--;
+
+- WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
+- !rdev->scan_req->notified);
++ if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
++ if (WARN_ON(!rdev->scan_req->notified))
++ rdev->scan_req->aborted = true;
++ ___cfg80211_scan_done(rdev, false);
++ }
+ }
+
+ static int cfg80211_rfkill_set_block(void *data, bool blocked)
+@@ -447,9 +450,6 @@ int wiphy_register(struct wiphy *wiphy)
+ int i;
+ u16 ifmodes = wiphy->interface_modes;
+
+- /* support for 5/10 MHz is broken due to nl80211 API mess - disable */
+- wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ;
+-
+ /*
+ * There are major locking problems in nl80211/mac80211 for CSA,
+ * disable for all drivers until this has been reworked.
+@@ -795,8 +795,6 @@ void cfg80211_leave(struct cfg80211_regi
+ default:
+ break;
+ }
+-
+- wdev->beacon_interval = 0;
+ }
+
+ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
+@@ -875,8 +873,11 @@ static int cfg80211_netdev_notifier_call
+ break;
+ case NETDEV_DOWN:
+ cfg80211_update_iface_num(rdev, wdev->iftype, -1);
+- WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
+- !rdev->scan_req->notified);
++ if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
++ if (WARN_ON(!rdev->scan_req->notified))
++ rdev->scan_req->aborted = true;
++ ___cfg80211_scan_done(rdev, false);
++ }
+
+ if (WARN_ON(rdev->sched_scan_req &&
+ rdev->sched_scan_req->dev == wdev->netdev)) {
+--- a/net/wireless/core.h
++++ b/net/wireless/core.h
+@@ -62,6 +62,7 @@ struct cfg80211_registered_device {
+ struct rb_root bss_tree;
+ u32 bss_generation;
+ struct cfg80211_scan_request *scan_req; /* protected by RTNL */
++ struct sk_buff *scan_msg;
+ struct cfg80211_sched_scan_request *sched_scan_req;
+ unsigned long suspend_at;
+ struct work_struct scan_done_wk;
+@@ -210,6 +211,7 @@ struct cfg80211_event {
+ } dc;
+ struct {
+ u8 bssid[ETH_ALEN];
++ struct ieee80211_channel *channel;
+ } ij;
+ };
+ };
+@@ -257,7 +259,8 @@ int __cfg80211_leave_ibss(struct cfg8021
+ struct net_device *dev, bool nowext);
+ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, bool nowext);
+-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
++void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
++ struct ieee80211_channel *channel);
+ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
+
+@@ -361,7 +364,8 @@ int cfg80211_validate_key_settings(struc
+ struct key_params *params, int key_idx,
+ bool pairwise, const u8 *mac_addr);
+ void __cfg80211_scan_done(struct work_struct *wk);
+-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev);
++void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
++ bool send_message);
+ void __cfg80211_sched_scan_results(struct work_struct *wk);
+ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
+ bool driver_initiated);
+@@ -441,7 +445,8 @@ static inline unsigned int elapsed_jiffi
+ void
+ cfg80211_get_chan_state(struct wireless_dev *wdev,
+ struct ieee80211_channel **chan,
+- enum cfg80211_chan_mode *chanmode);
++ enum cfg80211_chan_mode *chanmode,
++ u8 *radar_detect);
+
+ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ struct cfg80211_chan_def *chandef);
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -1723,9 +1723,10 @@ static int nl80211_dump_wiphy(struct sk_
+ * We can then retry with the larger buffer.
+ */
+ if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
+- !skb->len &&
++ !skb->len && !state->split &&
+ cb->min_dump_alloc < 4096) {
+ cb->min_dump_alloc = 4096;
++ state->split_start = 0;
+ rtnl_unlock();
+ return 1;
+ }
+@@ -2047,10 +2048,12 @@ static int nl80211_set_wiphy(struct sk_b
+ nla_for_each_nested(nl_txq_params,
+ info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
+ rem_txq_params) {
+- nla_parse(tb, NL80211_TXQ_ATTR_MAX,
+- nla_data(nl_txq_params),
+- nla_len(nl_txq_params),
+- txq_params_policy);
++ result = nla_parse(tb, NL80211_TXQ_ATTR_MAX,
++ nla_data(nl_txq_params),
++ nla_len(nl_txq_params),
++ txq_params_policy);
++ if (result)
++ goto bad_res;
+ result = parse_txq_params(tb, &txq_params);
+ if (result)
+ goto bad_res;
+@@ -3289,7 +3292,7 @@ static int nl80211_start_ap(struct sk_bu
+ if (!err) {
+ wdev->preset_chandef = params.chandef;
+ wdev->beacon_interval = params.beacon_interval;
+- wdev->channel = params.chandef.chan;
++ wdev->chandef = params.chandef;
+ wdev->ssid_len = params.ssid_len;
+ memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
+ }
+@@ -5210,9 +5213,11 @@ static int nl80211_set_reg(struct sk_buf
+
+ nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
+ rem_reg_rules) {
+- nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
+- nla_data(nl_reg_rule), nla_len(nl_reg_rule),
+- reg_rule_policy);
++ r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
++ nla_data(nl_reg_rule), nla_len(nl_reg_rule),
++ reg_rule_policy);
++ if (r)
++ goto bad_reg;
+ r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
+ if (r)
+ goto bad_reg;
+@@ -5277,7 +5282,7 @@ static int nl80211_trigger_scan(struct s
+ if (!rdev->ops->scan)
+ return -EOPNOTSUPP;
+
+- if (rdev->scan_req) {
++ if (rdev->scan_req || rdev->scan_msg) {
+ err = -EBUSY;
+ goto unlock;
+ }
+@@ -5475,6 +5480,7 @@ static int nl80211_start_sched_scan(stru
+ enum ieee80211_band band;
+ size_t ie_len;
+ struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
++ s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
+
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
+ !rdev->ops->sched_scan_start)
+@@ -5509,11 +5515,40 @@ static int nl80211_start_sched_scan(stru
+ if (n_ssids > wiphy->max_sched_scan_ssids)
+ return -EINVAL;
+
+- if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH])
++ /*
++ * First, count the number of 'real' matchsets. Due to an issue with
++ * the old implementation, matchsets containing only the RSSI attribute
++ * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
++ * RSSI for all matchsets, rather than their own matchset for reporting
++ * all APs with a strong RSSI. This is needed to be compatible with
++ * older userspace that treated a matchset with only the RSSI as the
++ * global RSSI for all other matchsets - if there are other matchsets.
++ */
++ if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
+ nla_for_each_nested(attr,
+ info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
+- tmp)
+- n_match_sets++;
++ tmp) {
++ struct nlattr *rssi;
++
++ err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
++ nla_data(attr), nla_len(attr),
++ nl80211_match_policy);
++ if (err)
++ return err;
++ /* add other standalone attributes here */
++ if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
++ n_match_sets++;
++ continue;
++ }
++ rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
++ if (rssi)
++ default_match_rssi = nla_get_s32(rssi);
++ }
++ }
++
++ /* However, if there's no other matchset, add the RSSI one */
++ if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
++ n_match_sets = 1;
+
+ if (n_match_sets > wiphy->max_match_sets)
+ return -EINVAL;
+@@ -5634,11 +5669,22 @@ static int nl80211_start_sched_scan(stru
+ tmp) {
+ struct nlattr *ssid, *rssi;
+
+- nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
+- nla_data(attr), nla_len(attr),
+- nl80211_match_policy);
++ err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
++ nla_data(attr), nla_len(attr),
++ nl80211_match_policy);
++ if (err)
++ goto out_free;
+ ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
+ if (ssid) {
++ if (WARN_ON(i >= n_match_sets)) {
++ /* this indicates a programming error,
++ * the loop above should have verified
++ * things properly
++ */
++ err = -EINVAL;
++ goto out_free;
++ }
++
+ if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
+ err = -EINVAL;
+ goto out_free;
+@@ -5647,15 +5693,28 @@ static int nl80211_start_sched_scan(stru
+ nla_data(ssid), nla_len(ssid));
+ request->match_sets[i].ssid.ssid_len =
+ nla_len(ssid);
++ /* special attribute - old implemenation w/a */
++ request->match_sets[i].rssi_thold =
++ default_match_rssi;
++ rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
++ if (rssi)
++ request->match_sets[i].rssi_thold =
++ nla_get_s32(rssi);
+ }
+- rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
+- if (rssi)
+- request->rssi_thold = nla_get_u32(rssi);
+- else
+- request->rssi_thold =
+- NL80211_SCAN_RSSI_THOLD_OFF;
+ i++;
+ }
++
++ /* there was no other matchset, so the RSSI one is alone */
++ if (i == 0)
++ request->match_sets[0].rssi_thold = default_match_rssi;
++
++ request->min_rssi_thold = INT_MAX;
++ for (i = 0; i < n_match_sets; i++)
++ request->min_rssi_thold =
++ min(request->match_sets[i].rssi_thold,
++ request->min_rssi_thold);
++ } else {
++ request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
+ }
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+@@ -5751,7 +5810,7 @@ static int nl80211_start_radar_detection
+
+ err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
+ if (!err) {
+- wdev->channel = chandef.chan;
++ wdev->chandef = chandef;
+ wdev->cac_started = true;
+ wdev->cac_start_time = jiffies;
+ }
+@@ -7502,16 +7561,19 @@ static int nl80211_set_tx_bitrate_mask(s
+ * directly to the enum ieee80211_band values used in cfg80211.
+ */
+ BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
+- nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
+- {
++ nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
+ enum ieee80211_band band = nla_type(tx_rates);
++ int err;
++
+ if (band < 0 || band >= IEEE80211_NUM_BANDS)
+ return -EINVAL;
+ sband = rdev->wiphy.bands[band];
+ if (sband == NULL)
+ return -EINVAL;
+- nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
+- nla_len(tx_rates), nl80211_txattr_policy);
++ err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
++ nla_len(tx_rates), nl80211_txattr_policy);
++ if (err)
++ return err;
+ if (tb[NL80211_TXRATE_LEGACY]) {
+ mask.control[band].legacy = rateset_to_mask(
+ sband,
+@@ -10054,40 +10116,31 @@ void nl80211_send_scan_start(struct cfg8
+ NL80211_MCGRP_SCAN, GFP_KERNEL);
+ }
+
+-void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+- struct wireless_dev *wdev)
++struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
++ struct wireless_dev *wdev, bool aborted)
+ {
+ struct sk_buff *msg;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+- return;
++ return NULL;
+
+ if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
+- NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
++ aborted ? NL80211_CMD_SCAN_ABORTED :
++ NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
+ nlmsg_free(msg);
+- return;
++ return NULL;
+ }
+
+- genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+- NL80211_MCGRP_SCAN, GFP_KERNEL);
++ return msg;
+ }
+
+-void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+- struct wireless_dev *wdev)
++void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
++ struct sk_buff *msg)
+ {
+- struct sk_buff *msg;
-
-- rate_control_rate_init(sta);
-- netif_carrier_on(dev);
-- } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
-+ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
- rcu_assign_pointer(local->p2p_sdata, sdata);
+- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+- if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
+- NL80211_CMD_SCAN_ABORTED) < 0) {
+- nlmsg_free(msg);
+- return;
- }
+-
+ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+ NL80211_MCGRP_SCAN, GFP_KERNEL);
+ }
+@@ -11158,7 +11211,8 @@ void cfg80211_ch_switch_notify(struct ne
+ wdev->iftype != NL80211_IFTYPE_MESH_POINT))
+ return;
- /*
- * set_multicast_list will be invoked by the networking core
-@@ -1116,6 +1093,74 @@ static void ieee80211_if_setup(struct ne
- dev->destructor = free_netdev;
+- wdev->channel = chandef->chan;
++ wdev->chandef = *chandef;
++ wdev->preset_chandef = *chandef;
+ nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
+ }
+ EXPORT_SYMBOL(cfg80211_ch_switch_notify);
+@@ -11673,6 +11727,35 @@ void cfg80211_crit_proto_stopped(struct
}
+ EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
-+static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
-+ struct sk_buff *skb)
++void nl80211_send_ap_stopped(struct wireless_dev *wdev)
+{
-+ struct ieee80211_local *local = sdata->local;
-+ struct ieee80211_rx_status *rx_status;
-+ struct ieee802_11_elems elems;
-+ struct ieee80211_mgmt *mgmt;
-+ struct sta_info *sta;
-+ size_t baselen;
-+ u32 rates = 0;
-+ u16 stype;
-+ bool new = false;
-+ enum ieee80211_band band;
-+ struct ieee80211_supported_band *sband;
-+
-+ rx_status = IEEE80211_SKB_RXCB(skb);
-+ band = rx_status->band;
-+ sband = local->hw.wiphy->bands[band];
-+ mgmt = (struct ieee80211_mgmt *) skb->data;
-+ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
-+
-+ if (stype != IEEE80211_STYPE_BEACON)
-+ return;
++ struct wiphy *wiphy = wdev->wiphy;
++ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
++ struct sk_buff *msg;
++ void *hdr;
+
-+ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
-+ if (baselen > skb->len)
++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
++ if (!msg)
+ return;
+
-+ ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
-+ skb->len - baselen, false, &elems);
++ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
++ if (!hdr)
++ goto out;
+
-+ rates = ieee80211_sta_get_rates(local, &elems, band, NULL);
++ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
++ nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
++ nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
++ goto out;
+
-+ rcu_read_lock();
++ genlmsg_end(msg, hdr);
+
-+ sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
++ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
++ NL80211_MCGRP_MLME, GFP_KERNEL);
++ return;
++ out:
++ nlmsg_free(msg);
++}
+
-+ if (!sta) {
-+ rcu_read_unlock();
-+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
-+ GFP_KERNEL);
-+ if (!sta)
-+ return;
+ /* initialisation/exit functions */
+
+ int nl80211_init(void)
+--- a/net/wireless/nl80211.h
++++ b/net/wireless/nl80211.h
+@@ -8,10 +8,10 @@ void nl80211_exit(void);
+ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
+ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
+-void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+- struct wireless_dev *wdev);
+-void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+- struct wireless_dev *wdev);
++struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
++ struct wireless_dev *wdev, bool aborted);
++void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
++ struct sk_buff *msg);
+ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u32 cmd);
+ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
+@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_reg
+ enum nl80211_radar_event event,
+ struct net_device *netdev, gfp_t gfp);
+
++void nl80211_send_ap_stopped(struct wireless_dev *wdev);
+
-+ new = true;
+ void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
+
+ #endif /* __NET_WIRELESS_NL80211_H */
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct
+ dev->bss_generation++;
+ }
+
+-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
++void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
++ bool send_message)
+ {
+ struct cfg80211_scan_request *request;
+ struct wireless_dev *wdev;
++ struct sk_buff *msg;
+ #ifdef CPTCFG_CFG80211_WEXT
+ union iwreq_data wrqu;
+ #endif
+
+ ASSERT_RTNL();
+
+- request = rdev->scan_req;
++ if (rdev->scan_msg) {
++ nl80211_send_scan_result(rdev, rdev->scan_msg);
++ rdev->scan_msg = NULL;
++ return;
+ }
+
++ request = rdev->scan_req;
+ if (!request)
+ return;
+
+@@ -186,18 +193,16 @@ void ___cfg80211_scan_done(struct cfg802
+ if (wdev->netdev)
+ cfg80211_sme_scan_done(wdev->netdev);
+
+- if (request->aborted) {
+- nl80211_send_scan_aborted(rdev, wdev);
+- } 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);
++ if (!request->aborted &&
++ 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);
+ }
+
++ msg = nl80211_build_scan_msg(rdev, wdev, request->aborted);
+
-+ sta->last_rx = jiffies;
-+ sta->sta.supp_rates[band] = rates;
+ #ifdef CPTCFG_CFG80211_WEXT
+ if (wdev->netdev && !request->aborted) {
+ memset(&wrqu, 0, sizeof(wrqu));
+@@ -211,6 +216,11 @@ void ___cfg80211_scan_done(struct cfg802
+
+ rdev->scan_req = NULL;
+ kfree(request);
+
-+ if (elems.ht_cap_elem)
-+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
-+ elems.ht_cap_elem, sta);
++ if (!send_message)
++ rdev->scan_msg = msg;
++ else
++ nl80211_send_scan_result(rdev, msg);
+ }
+
+ void __cfg80211_scan_done(struct work_struct *wk)
+@@ -221,7 +231,7 @@ void __cfg80211_scan_done(struct work_st
+ scan_done_wk);
+
+ rtnl_lock();
+- ___cfg80211_scan_done(rdev);
++ ___cfg80211_scan_done(rdev, true);
+ rtnl_unlock();
+ }
+
+@@ -1079,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_dev
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+- if (rdev->scan_req) {
++ if (rdev->scan_req || rdev->scan_msg) {
+ err = -EBUSY;
+ goto out;
+ }
+@@ -1481,7 +1491,7 @@ int cfg80211_wext_giwscan(struct net_dev
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+- if (rdev->scan_req)
++ if (rdev->scan_req || rdev->scan_msg)
+ return -EAGAIN;
+
+ res = ieee80211_scan_results(rdev, info, extra, data->length);
+--- a/net/wireless/sme.c
++++ b/net/wireless/sme.c
+@@ -67,7 +67,7 @@ static int cfg80211_conn_scan(struct wir
+ ASSERT_RDEV_LOCK(rdev);
+ ASSERT_WDEV_LOCK(wdev);
+
+- if (rdev->scan_req)
++ if (rdev->scan_req || rdev->scan_msg)
+ return -EBUSY;
+
+ if (wdev->conn->params.channel)
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -1001,7 +1001,6 @@ ieee80211_sta_process_chanswitch(struct
+ }
+
+ ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+- sdata->vif.csa_active = true;
+
+ mutex_lock(&local->chanctx_mtx);
+ if (local->use_chanctx) {
+@@ -1039,6 +1038,7 @@ ieee80211_sta_process_chanswitch(struct
+ mutex_unlock(&local->chanctx_mtx);
+
+ sdata->csa_chandef = csa_ie.chandef;
++ sdata->vif.csa_active = true;
+
+ if (csa_ie.mode)
+ ieee80211_stop_queues_by_reason(&local->hw,
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -196,6 +196,8 @@ static bool ieee80211_is_radar_required(
+ {
+ struct ieee80211_sub_if_data *sdata;
+
++ lockdep_assert_held(&local->mtx);
++
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (sdata->radar_required) {
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -294,7 +294,6 @@ static void __ieee80211_sta_join_ibss(st
+ }
+
+ mutex_lock(&local->mtx);
+- ieee80211_vif_release_channel(sdata);
+ if (ieee80211_vif_use_channel(sdata, &chandef,
+ ifibss->fixed_channel ?
+ IEEE80211_CHANCTX_SHARED :
+@@ -303,6 +302,7 @@ static void __ieee80211_sta_join_ibss(st
+ mutex_unlock(&local->mtx);
+ return;
+ }
++ sdata->radar_required = radar_required;
+ mutex_unlock(&local->mtx);
+
+ memcpy(ifibss->bssid, bssid, ETH_ALEN);
+@@ -318,7 +318,6 @@ static void __ieee80211_sta_join_ibss(st
+ rcu_assign_pointer(ifibss->presp, presp);
+ mgmt = (void *)presp->head;
+
+- sdata->radar_required = radar_required;
+ sdata->vif.bss_conf.enable_beacon = true;
+ sdata->vif.bss_conf.beacon_int = beacon_int;
+ sdata->vif.bss_conf.basic_rates = basic_rates;
+@@ -386,7 +385,7 @@ static void __ieee80211_sta_join_ibss(st
+ presp->head_len, 0, GFP_KERNEL);
+ cfg80211_put_bss(local->hw.wiphy, bss);
+ netif_carrier_on(sdata->dev);
+- cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
++ cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL);
+ }
+
+ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+@@ -802,6 +801,8 @@ ieee80211_ibss_process_chanswitch(struct
+ int err;
+ u32 sta_flags;
+
++ sdata_assert_lock(sdata);
+
-+ if (elems.wmm_param)
-+ set_sta_flag(sta, WLAN_STA_WME);
+ sta_flags = IEEE80211_STA_DISABLE_VHT;
+ switch (ifibss->chandef.width) {
+ case NL80211_CHAN_WIDTH_5:
+@@ -1471,6 +1472,11 @@ static void ieee80211_rx_mgmt_probe_req(
+ memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN);
+ ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa);
+ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
-+ if (new) {
-+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
-+ sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
-+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
-+ rate_control_rate_init(sta);
-+ sta_info_insert_rcu(sta);
-+ }
++ /* avoid excessive retries for probe request to wildcard SSIDs */
++ if (pos[1] == 0)
++ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_NO_ACK;
+
-+ rcu_read_unlock();
-+}
+ ieee80211_tx_skb(sdata, skb);
+ }
+
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -872,6 +872,8 @@ ieee80211_mesh_process_chnswitch(struct
+ if (!ifmsh->mesh_id)
+ return false;
+
++ sdata_assert_lock(sdata);
+
- static void ieee80211_iface_work(struct work_struct *work)
+ sta_flags = IEEE80211_STA_DISABLE_VHT;
+ switch (sdata->vif.bss_conf.chandef.width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+@@ -4658,6 +4658,7 @@ brcmf_notify_connect_status(struct brcmf
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct net_device *ndev = ifp->ndev;
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
++ struct ieee80211_channel *chan;
+ s32 err = 0;
+
+ if (ifp->vif->mode == WL_MODE_AP) {
+@@ -4665,9 +4666,10 @@ brcmf_notify_connect_status(struct brcmf
+ } else if (brcmf_is_linkup(e)) {
+ brcmf_dbg(CONN, "Linkup\n");
+ if (brcmf_is_ibssmode(ifp->vif)) {
++ chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
+ memcpy(profile->bssid, e->addr, ETH_ALEN);
+ wl_inform_ibss(cfg, ndev, e->addr);
+- cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
++ cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
+ clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+ &ifp->vif->sme_state);
+ set_bit(BRCMF_VIF_STATUS_CONNECTED,
+--- a/drivers/net/wireless/libertas/cfg.c
++++ b/drivers/net/wireless/libertas/cfg.c
+@@ -1766,7 +1766,8 @@ static void lbs_join_post(struct lbs_pri
+ memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
+ priv->wdev->ssid_len = params->ssid_len;
+
+- cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
++ cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
++ GFP_KERNEL);
+
+ /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
+ priv->connect_status = LBS_CONNECTED;
+--- a/drivers/net/wireless/mwifiex/cfg80211.c
++++ b/drivers/net/wireless/mwifiex/cfg80211.c
+@@ -1881,7 +1881,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy
+ params->privacy);
+ done:
+ if (!ret) {
+- cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
++ cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
++ params->chandef.chan, GFP_KERNEL);
+ dev_dbg(priv->adapter->dev,
+ "info: joined/created adhoc network with bssid"
+ " %pM successfully\n", priv->cfg_bssid);
+--- a/drivers/net/wireless/rndis_wlan.c
++++ b/drivers/net/wireless/rndis_wlan.c
+@@ -2835,7 +2835,9 @@ static void rndis_wlan_do_link_up_work(s
+ bssid, req_ie, req_ie_len,
+ resp_ie, resp_ie_len, GFP_KERNEL);
+ } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
+- cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
++ cfg80211_ibss_joined(usbdev->net, bssid,
++ get_current_channel(usbdev, NULL),
++ GFP_KERNEL);
+
+ kfree(info);
+
+--- a/net/wireless/ibss.c
++++ b/net/wireless/ibss.c
+@@ -14,7 +14,8 @@
+ #include "rdev-ops.h"
+
+
+-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
++void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
++ struct ieee80211_channel *channel)
+ {
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_bss *bss;
+@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_d
+ if (!wdev->ssid_len)
+ return;
+
+- bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+- wdev->ssid, wdev->ssid_len,
++ bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
+ WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+
+ if (WARN_ON(!bss))
+@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_d
+ #endif
+ }
+
+-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
++void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
++ struct ieee80211_channel *channel, gfp_t gfp)
{
- struct ieee80211_sub_if_data *sdata =
-@@ -1220,6 +1265,9 @@ static void ieee80211_iface_work(struct
- break;
- ieee80211_mesh_rx_queued_mgmt(sdata, skb);
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+- trace_cfg80211_ibss_joined(dev, bssid);
++ trace_cfg80211_ibss_joined(dev, bssid, channel);
++
++ if (WARN_ON(!channel))
++ return;
+
+ ev = kzalloc(sizeof(*ev), gfp);
+ if (!ev)
+ return;
+
+ ev->type = EVENT_IBSS_JOINED;
+- memcpy(ev->cr.bssid, bssid, ETH_ALEN);
++ memcpy(ev->ij.bssid, bssid, ETH_ALEN);
++ ev->ij.channel = channel;
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+@@ -117,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211
+
+ wdev->ibss_fixed = params->channel_fixed;
+ wdev->ibss_dfs_possible = params->userspace_handles_dfs;
++ wdev->chandef = params->chandef;
+ #ifdef CPTCFG_CFG80211_WEXT
+ wdev->wext.ibss.chandef = params->chandef;
+ #endif
+@@ -200,6 +206,7 @@ static void __cfg80211_clear_ibss(struct
+
+ wdev->current_bss = NULL;
+ wdev->ssid_len = 0;
++ memset(&wdev->chandef, 0, sizeof(wdev->chandef));
+ #ifdef CPTCFG_CFG80211_WEXT
+ if (!nowext)
+ wdev->wext.ibss.ssid_len = 0;
+--- a/net/wireless/trace.h
++++ b/net/wireless/trace.h
+@@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt,
+ 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)
+@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_r
+ TP_ARGS(netdev, addr)
+ );
+
++TRACE_EVENT(cfg80211_ibss_joined,
++ TP_PROTO(struct net_device *netdev, const u8 *bssid,
++ struct ieee80211_channel *channel),
++ TP_ARGS(netdev, bssid, channel),
++ TP_STRUCT__entry(
++ NETDEV_ENTRY
++ MAC_ENTRY(bssid)
++ CHAN_ENTRY
++ ),
++ TP_fast_assign(
++ NETDEV_ASSIGN;
++ MAC_ASSIGN(bssid, bssid);
++ CHAN_ASSIGN(channel);
++ ),
++ TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT,
++ NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
++);
++
+ TRACE_EVENT(cfg80211_probe_status,
+ TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie,
+ bool acked),
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct
+ ev->dc.reason, true);
break;
-+ case NL80211_IFTYPE_WDS:
-+ ieee80211_wds_rx_queued_mgmt(sdata, skb);
-+ break;
- default:
- WARN(1, "frame for unexpected interface type");
+ case EVENT_IBSS_JOINED:
+- __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
++ __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
++ ev->ij.channel);
break;
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct
-
- sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-+ rate->count = 1;
-+
-+ if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
-+ int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
-+ rate->idx = mp->cck_rates[idx];
-+ rate->flags = 0;
-+ return;
-+ }
+ }
+ wdev_unlock(wdev);
+@@ -1356,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct
+ */
+ mutex_lock_nested(&wdev_iter->mtx, 1);
+ __acquire(wdev_iter->mtx);
+- cfg80211_get_chan_state(wdev_iter, &ch, &chmode);
++ cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect);
+ wdev_unlock(wdev_iter);
+
+ switch (chmode) {
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct
+ void
+ cfg80211_get_chan_state(struct wireless_dev *wdev,
+ struct ieee80211_channel **chan,
+- enum cfg80211_chan_mode *chanmode)
++ enum cfg80211_chan_mode *chanmode,
++ u8 *radar_detect)
+ {
+ *chan = NULL;
+ *chanmode = CHAN_MODE_UNDEFINED;
+@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_
+ !wdev->ibss_dfs_possible)
+ ? CHAN_MODE_SHARED
+ : CHAN_MODE_EXCLUSIVE;
+
- rate->idx = sample_idx % MCS_GROUP_RATES +
- (sample_group->streams - 1) * MCS_GROUP_RATES;
- rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
-- rate->count = 1;
- }
++ /* consider worst-case - IBSS can try to return to the
++ * original user-specified channel as creator */
++ if (wdev->ibss_dfs_possible)
++ *radar_detect |= BIT(wdev->chandef.width);
+ return;
+ }
+ break;
+@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ if (wdev->cac_started) {
+- *chan = wdev->channel;
++ *chan = wdev->chandef.chan;
+ *chanmode = CHAN_MODE_SHARED;
++ *radar_detect |= BIT(wdev->chandef.width);
+ } else if (wdev->beacon_interval) {
+- *chan = wdev->channel;
++ *chan = wdev->chandef.chan;
+ *chanmode = CHAN_MODE_SHARED;
++
++ if (cfg80211_chandef_dfs_required(wdev->wiphy,
++ &wdev->chandef))
++ *radar_detect |= BIT(wdev->chandef.width);
+ }
+ return;
+ case NL80211_IFTYPE_MESH_POINT:
+ if (wdev->mesh_id_len) {
+- *chan = wdev->channel;
++ *chan = wdev->chandef.chan;
+ *chanmode = CHAN_MODE_SHARED;
++
++ if (cfg80211_chandef_dfs_required(wdev->wiphy,
++ &wdev->chandef))
++ *radar_detect |= BIT(wdev->chandef.width);
+ }
+ return;
+ case NL80211_IFTYPE_MONITOR:
+--- a/net/wireless/mesh.c
++++ b/net/wireless/mesh.c
+@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211
+ if (!err) {
+ memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
+ wdev->mesh_id_len = setup->mesh_id_len;
+- wdev->channel = setup->chandef.chan;
++ wdev->chandef = setup->chandef;
+ }
- static void
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -936,8 +936,14 @@ ieee80211_rx_h_check(struct ieee80211_rx
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
- struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+ return err;
+@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg
+ err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
+ chandef->chan);
+ if (!err)
+- wdev->channel = chandef->chan;
++ wdev->chandef = *chandef;
-- /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
-- if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
-+ /*
-+ * Drop duplicate 802.11 retransmissions
-+ * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
-+ */
-+ if (rx->skb->len >= 24 && rx->sta &&
-+ !ieee80211_is_ctl(hdr->frame_control) &&
-+ !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
-+ !is_multicast_ether_addr(hdr->addr1)) {
- if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
- rx->sta->last_seq_ctrl[rx->seqno_idx] ==
- hdr->seq_ctrl)) {
-@@ -2369,6 +2375,7 @@ ieee80211_rx_h_action(struct ieee80211_r
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
- sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- sdata->vif.type != NL80211_IFTYPE_AP &&
-+ sdata->vif.type != NL80211_IFTYPE_WDS &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ return err;
+ }
+@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct
+ err = rdev_leave_mesh(rdev, dev);
+ if (!err) {
+ wdev->mesh_id_len = 0;
+- wdev->channel = NULL;
++ memset(&wdev->chandef, 0, sizeof(wdev->chandef));
+ rdev_set_qos_map(rdev, dev, NULL);
+ }
+
+--- a/net/wireless/mlme.c
++++ b/net/wireless/mlme.c
+@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_devic
+ if (WARN_ON(!wdev->cac_started))
+ return;
+
+- if (WARN_ON(!wdev->channel))
++ if (WARN_ON(!wdev->chandef.chan))
+ return;
+
+ switch (event) {
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -5065,6 +5065,10 @@ static u16 ar9003_hw_get_max_edge_power(
break;
+ }
+ }
++
++ if (is2GHz && !twiceMaxEdgePower)
++ twiceMaxEdgePower = 60;
++
+ return twiceMaxEdgePower;
+ }
-@@ -2720,14 +2727,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
-
- if (!ieee80211_vif_is_mesh(&sdata->vif) &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-- sdata->vif.type != NL80211_IFTYPE_STATION)
-+ sdata->vif.type != NL80211_IFTYPE_STATION &&
-+ sdata->vif.type != NL80211_IFTYPE_WDS)
- return RX_DROP_MONITOR;
-
- switch (stype) {
- case cpu_to_le16(IEEE80211_STYPE_AUTH):
- case cpu_to_le16(IEEE80211_STYPE_BEACON):
- case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
-- /* process for all: mesh, mlme, ibss */
-+ /* process for all: mesh, mlme, ibss, wds */
- break;
- case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
- case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
-@@ -3008,6 +3016,9 @@ static int prepare_for_handlers(struct i
- case NL80211_IFTYPE_ADHOC:
- if (!bssid)
- return 0;
-+ if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
-+ ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2))
-+ return 0;
- if (ieee80211_is_beacon(hdr->frame_control)) {
- return 1;
- } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
-@@ -3059,10 +3070,16 @@ static int prepare_for_handlers(struct i
+--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+@@ -23,10 +23,11 @@
+ #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
+ #define MAX_MAG_DELTA 11
+ #define MAX_PHS_DELTA 10
++#define MAXIQCAL 3
+
+ struct coeff {
+- int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
+- int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
++ int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
++ int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
+ int iqc_coeff[2];
+ };
+
+@@ -800,7 +801,7 @@ static bool ar9003_hw_calc_iq_corr(struc
+ if (q_q_coff > 63)
+ q_q_coff = 63;
+
+- iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
++ iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
+
+ ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
+ chain_idx, iqc_coeff[0]);
+@@ -831,7 +832,7 @@ static bool ar9003_hw_calc_iq_corr(struc
+ if (q_q_coff > 63)
+ q_q_coff = 63;
+
+- iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
++ iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
+
+ ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
+ chain_idx, iqc_coeff[1]);
+@@ -839,7 +840,8 @@ static bool ar9003_hw_calc_iq_corr(struc
+ return true;
+ }
+
+-static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
++static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL],
++ int nmeasurement,
+ int max_delta)
+ {
+ int mp_max = -64, max_idx = 0;
+@@ -848,20 +850,20 @@ static void ar9003_hw_detect_outlier(int
+
+ /* find min/max mismatch across all calibrated gains */
+ for (i = 0; i < nmeasurement; i++) {
+- if (mp_coeff[i] > mp_max) {
+- mp_max = mp_coeff[i];
++ if (mp_coeff[i][0] > mp_max) {
++ mp_max = mp_coeff[i][0];
+ max_idx = i;
+- } else if (mp_coeff[i] < mp_min) {
+- mp_min = mp_coeff[i];
++ } else if (mp_coeff[i][0] < mp_min) {
++ mp_min = mp_coeff[i][0];
+ min_idx = i;
}
- break;
- case NL80211_IFTYPE_WDS:
-- if (bssid || !ieee80211_is_data(hdr->frame_control))
-- return 0;
- if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
- return 0;
-+
-+ if (ieee80211_is_data(hdr->frame_control) ||
-+ ieee80211_is_action(hdr->frame_control)) {
-+ if (compare_ether_addr(sdata->vif.addr, hdr->addr1))
-+ return 0;
-+ } else if (!ieee80211_is_beacon(hdr->frame_control))
-+ return 0;
+ }
+
+ /* find average (exclude max abs value) */
+ for (i = 0; i < nmeasurement; i++) {
+- if ((abs(mp_coeff[i]) < abs(mp_max)) ||
+- (abs(mp_coeff[i]) < abs(mp_min))) {
+- mp_avg += mp_coeff[i];
++ if ((abs(mp_coeff[i][0]) < abs(mp_max)) ||
++ (abs(mp_coeff[i][0]) < abs(mp_min))) {
++ mp_avg += mp_coeff[i][0];
+ mp_count++;
+ }
+ }
+@@ -873,7 +875,7 @@ static void ar9003_hw_detect_outlier(int
+ if (mp_count)
+ mp_avg /= mp_count;
+ else
+- mp_avg = mp_coeff[nmeasurement - 1];
++ mp_avg = mp_coeff[nmeasurement - 1][0];
+
+ /* detect outlier */
+ if (abs(mp_max - mp_min) > max_delta) {
+@@ -882,15 +884,16 @@ static void ar9003_hw_detect_outlier(int
+ else
+ outlier_idx = min_idx;
+
+- mp_coeff[outlier_idx] = mp_avg;
++ mp_coeff[outlier_idx][0] = mp_avg;
+ }
+ }
+
+-static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
+- struct coeff *coeff,
+- bool is_reusable)
++static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah,
++ struct coeff *coeff,
++ bool is_reusable)
+ {
+ int i, im, nmeasurement;
++ int magnitude, phase;
+ u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+@@ -920,21 +923,30 @@ static void ar9003_hw_tx_iqcal_load_avg_
+ if (nmeasurement > MAX_MEASUREMENT)
+ nmeasurement = MAX_MEASUREMENT;
+
+- /* detect outlier only if nmeasurement > 1 */
+- if (nmeasurement > 1) {
+- /* Detect magnitude outlier */
+- ar9003_hw_detect_outlier(coeff->mag_coeff[i],
+- nmeasurement, MAX_MAG_DELTA);
+-
+- /* Detect phase outlier */
+- ar9003_hw_detect_outlier(coeff->phs_coeff[i],
+- nmeasurement, MAX_PHS_DELTA);
++ /*
++ * Skip normal outlier detection for AR9550.
++ */
++ if (!AR_SREV_9550(ah)) {
++ /* detect outlier only if nmeasurement > 1 */
++ if (nmeasurement > 1) {
++ /* Detect magnitude outlier */
++ ar9003_hw_detect_outlier(coeff->mag_coeff[i],
++ nmeasurement,
++ MAX_MAG_DELTA);
+
- break;
- case NL80211_IFTYPE_P2P_DEVICE:
- if (!ieee80211_is_public_action(hdr, skb->len) &&
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -32,7 +32,6 @@
- * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
- * frames.
- * @WLAN_STA_WME: Station is a QoS-STA.
-- * @WLAN_STA_WDS: Station is one of our WDS peers.
- * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
- * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
- * frame to this station is transmitted.
-@@ -66,7 +65,6 @@ enum ieee80211_sta_info_flags {
- WLAN_STA_AUTHORIZED,
- WLAN_STA_SHORT_PREAMBLE,
- WLAN_STA_WME,
-- WLAN_STA_WDS,
- WLAN_STA_CLEAR_PS_FILT,
- WLAN_STA_MFP,
- WLAN_STA_BLOCK_BA,
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee802
- ARRAY_SIZE(bf->rates));
++ /* Detect phase outlier */
++ ar9003_hw_detect_outlier(coeff->phs_coeff[i],
++ nmeasurement,
++ MAX_PHS_DELTA);
++ }
+ }
+
+ for (im = 0; im < nmeasurement; im++) {
++ magnitude = coeff->mag_coeff[i][im][0];
++ phase = coeff->phs_coeff[i][im][0];
+
+- coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
+- ((coeff->phs_coeff[i][im] & 0x7f) << 7);
++ coeff->iqc_coeff[0] =
++ (phase & 0x7f) | ((magnitude & 0x7f) << 7);
+
+ if ((im % 2) == 0)
+ REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+@@ -991,7 +1003,63 @@ static bool ar9003_hw_tx_iq_cal_run(stru
+ return true;
+ }
+
+-static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
++static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah,
++ struct coeff *coeff,
++ int i, int nmeasurement)
++{
++ struct ath_common *common = ath9k_hw_common(ah);
++ int im, ix, iy, temp;
++
++ for (im = 0; im < nmeasurement; im++) {
++ for (ix = 0; ix < MAXIQCAL - 1; ix++) {
++ for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) {
++ if (coeff->mag_coeff[i][im][iy] <
++ coeff->mag_coeff[i][im][ix]) {
++ temp = coeff->mag_coeff[i][im][ix];
++ coeff->mag_coeff[i][im][ix] =
++ coeff->mag_coeff[i][im][iy];
++ coeff->mag_coeff[i][im][iy] = temp;
++ }
++ if (coeff->phs_coeff[i][im][iy] <
++ coeff->phs_coeff[i][im][ix]) {
++ temp = coeff->phs_coeff[i][im][ix];
++ coeff->phs_coeff[i][im][ix] =
++ coeff->phs_coeff[i][im][iy];
++ coeff->phs_coeff[i][im][iy] = temp;
++ }
++ }
++ }
++ coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2];
++ coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2];
++
++ ath_dbg(common, CALIBRATE,
++ "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n",
++ i, im,
++ coeff->mag_coeff[i][im][0],
++ coeff->phs_coeff[i][im][0]);
++ }
++}
++
++static bool ar955x_tx_iq_cal_median(struct ath_hw *ah,
++ struct coeff *coeff,
++ int iqcal_idx,
++ int nmeasurement)
++{
++ int i;
++
++ if ((iqcal_idx + 1) != MAXIQCAL)
++ return false;
++
++ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
++ __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement);
++ }
++
++ return true;
++}
++
++static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
++ int iqcal_idx,
++ bool is_reusable)
+ {
+ struct ath_common *common = ath9k_hw_common(ah);
+ const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+@@ -1004,10 +1072,11 @@ static void ar9003_hw_tx_iq_cal_post_pro
+ AR_PHY_CHAN_INFO_TAB_1,
+ AR_PHY_CHAN_INFO_TAB_2,
+ };
+- struct coeff coeff;
++ static struct coeff coeff;
+ s32 iq_res[6];
+ int i, im, j;
+- int nmeasurement;
++ int nmeasurement = 0;
++ bool outlier_detect = true;
+
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->txchainmask & (1 << i)))
+@@ -1065,17 +1134,23 @@ static void ar9003_hw_tx_iq_cal_post_pro
+ goto tx_iqcal_fail;
+ }
+
+- coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
+- coeff.phs_coeff[i][im] =
++ coeff.phs_coeff[i][im][iqcal_idx] =
++ coeff.iqc_coeff[0] & 0x7f;
++ coeff.mag_coeff[i][im][iqcal_idx] =
+ (coeff.iqc_coeff[0] >> 7) & 0x7f;
+
+- if (coeff.mag_coeff[i][im] > 63)
+- coeff.mag_coeff[i][im] -= 128;
+- if (coeff.phs_coeff[i][im] > 63)
+- coeff.phs_coeff[i][im] -= 128;
++ if (coeff.mag_coeff[i][im][iqcal_idx] > 63)
++ coeff.mag_coeff[i][im][iqcal_idx] -= 128;
++ if (coeff.phs_coeff[i][im][iqcal_idx] > 63)
++ coeff.phs_coeff[i][im][iqcal_idx] -= 128;
+ }
+ }
+- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
++
++ if (AR_SREV_9550(ah))
++ outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,
++ iqcal_idx, nmeasurement);
++ if (outlier_detect)
++ ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);
+
+ return;
+
+@@ -1409,7 +1484,7 @@ skip_tx_iqcal:
+ }
+
+ if (txiqcal_done)
+- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
++ ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
+ else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
+ ar9003_hw_tx_iq_cal_reload(ah);
+
+@@ -1455,14 +1530,38 @@ skip_tx_iqcal:
+ return true;
}
-+static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
-+ struct sk_buff *skb)
++static bool do_ar9003_agc_cal(struct ath_hw *ah)
+{
-+ int q;
-+
-+ q = skb_get_queue_mapping(skb);
-+ if (txq == sc->tx.uapsdq)
-+ txq = sc->tx.txq_map[q];
-+
-+ if (txq != sc->tx.txq_map[q])
-+ return;
++ struct ath_common *common = ath9k_hw_common(ah);
++ bool status;
+
-+ if (WARN_ON(--txq->pending_frames < 0))
-+ txq->pending_frames = 0;
++ REG_WRITE(ah, AR_PHY_AGC_CONTROL,
++ REG_READ(ah, AR_PHY_AGC_CONTROL) |
++ AR_PHY_AGC_CONTROL_CAL);
+
-+ if (txq->stopped &&
-+ txq->pending_frames < sc->tx.txq_max_pending[q]) {
-+ ieee80211_wake_queue(sc->hw, q);
-+ txq->stopped = false;
++ status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
++ AR_PHY_AGC_CONTROL_CAL,
++ 0, AH_WAIT_TIMEOUT);
++ if (!status) {
++ ath_dbg(common, CALIBRATE,
++ "offset calibration failed to complete in %d ms,"
++ "noisy environment?\n",
++ AH_WAIT_TIMEOUT / 1000);
++ return false;
+ }
++
++ return true;
+}
+
- static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
+ struct ath9k_channel *chan)
{
- struct ath_txq *txq = tid->ac->txq;
-@@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_
- if (!bf) {
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
-+ ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
-@@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc
-
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
-+ ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
-@@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ bool txiqcal_done = false;
+- bool is_reusable = true, status = true;
++ bool status = true;
+ bool run_agc_cal = false, sep_iq_cal = false;
++ int i = 0;
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
-+ ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- return;
- }
-@@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw
+ /* Use chip chainmask only for calibration */
+ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
+@@ -1485,7 +1584,12 @@ static bool ar9003_hw_init_cal_soc(struc
+ * AGC calibration. Specifically, AR9550 in SoC chips.
+ */
+ if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
+- txiqcal_done = true;
++ if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
++ AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) {
++ txiqcal_done = true;
++ } else {
++ txiqcal_done = false;
++ }
+ run_agc_cal = true;
+ } else {
+ sep_iq_cal = true;
+@@ -1512,27 +1616,37 @@ skip_tx_iqcal:
+ if (AR_SREV_9330_11(ah))
+ ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
-+ ath_txq_skb_done(sc, txq, skb);
- if (txctl->paprd)
- dev_kfree_skb_any(skb);
- else
-@@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_s
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
-- int q, padpos, padsize;
-+ int padpos, padsize;
- unsigned long flags;
+- /* Calibrate the AGC */
+- REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+- REG_READ(ah, AR_PHY_AGC_CONTROL) |
+- AR_PHY_AGC_CONTROL_CAL);
+-
+- /* Poll for offset calibration complete */
+- status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+- AR_PHY_AGC_CONTROL_CAL,
+- 0, AH_WAIT_TIMEOUT);
+- }
++ /*
++ * For non-AR9550 chips, we just trigger AGC calibration
++ * in the HW, poll for completion and then process
++ * the results.
++ *
++ * For AR955x, we run it multiple times and use
++ * median IQ correction.
++ */
++ if (!AR_SREV_9550(ah)) {
++ status = do_ar9003_agc_cal(ah);
++ if (!status)
++ return false;
- ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
-@@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_s
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+- if (!status) {
+- ath_dbg(common, CALIBRATE,
+- "offset calibration failed to complete in %d ms; noisy environment?\n",
+- AH_WAIT_TIMEOUT / 1000);
+- return false;
++ if (txiqcal_done)
++ ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
++ } else {
++ if (!txiqcal_done) {
++ status = do_ar9003_agc_cal(ah);
++ if (!status)
++ return false;
++ } else {
++ for (i = 0; i < MAXIQCAL; i++) {
++ status = do_ar9003_agc_cal(ah);
++ if (!status)
++ return false;
++ ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
++ }
++ }
++ }
+ }
- __skb_queue_tail(&txq->complete_q, skb);
--
-- q = skb_get_queue_mapping(skb);
-- if (txq == sc->tx.uapsdq)
-- txq = sc->tx.txq_map[q];
+- if (txiqcal_done)
+- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
-
-- if (txq == sc->tx.txq_map[q]) {
-- if (WARN_ON(--txq->pending_frames < 0))
-- txq->pending_frames = 0;
--
-- if (txq->stopped &&
-- txq->pending_frames < sc->tx.txq_max_pending[q]) {
-- ieee80211_wake_queue(sc->hw, q);
-- txq->stopped = false;
-- }
-- }
-+ ath_txq_skb_done(sc, txq, skb);
- }
+ /* Revert chainmask to runtime parameters */
+ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
- static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -209,6 +209,7 @@ static bool ath_complete_reset(struct at
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- unsigned long flags;
-+ int i;
+--- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
++++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
+@@ -15,6 +15,8 @@
+ #ifndef RTL8187_H
+ #define RTL8187_H
- if (ath_startrecv(sc) != 0) {
- ath_err(common, "Unable to restart recv logic\n");
-@@ -236,6 +237,15 @@ static bool ath_complete_reset(struct at
- }
- work:
- ath_restart_work(sc);
++#include <linux/cache.h>
+
-+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-+ if (!ATH_TXQ_SETUP(sc, i))
-+ continue;
-+
-+ spin_lock_bh(&sc->tx.txq[i].axq_lock);
-+ ath_txq_schedule(sc, &sc->tx.txq[i]);
-+ spin_unlock_bh(&sc->tx.txq[i].axq_lock);
-+ }
- }
+ #include "rtl818x.h"
+ #include "leds.h"
- if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
-@@ -543,21 +553,10 @@ chip_reset:
+@@ -139,7 +141,10 @@ struct rtl8187_priv {
+ u8 aifsn[4];
+ u8 rfkill_mask;
+ struct {
+- __le64 buf;
++ union {
++ __le64 buf;
++ u8 dummy1[L1_CACHE_BYTES];
++ } ____cacheline_aligned;
+ struct sk_buff_head queue;
+ } b_tx_status; /* This queue is used by both -b and non-b devices */
+ struct mutex io_mutex;
+@@ -147,7 +152,8 @@ struct rtl8187_priv {
+ u8 bits8;
+ __le16 bits16;
+ __le32 bits32;
+- } *io_dmabuf;
++ u8 dummy2[L1_CACHE_BYTES];
++ } *io_dmabuf ____cacheline_aligned;
+ bool rfkill_off;
+ u16 seqno;
+ };
+--- a/net/mac80211/wme.c
++++ b/net/mac80211/wme.c
+@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80
+ return IEEE80211_AC_BE;
+ }
- static int ath_reset(struct ath_softc *sc)
- {
-- int i, r;
-+ int r;
++ if (skb->protocol == sdata->control_port_protocol) {
++ skb->priority = 7;
++ return ieee80211_downgrade_queue(sdata, skb);
++ }
++
+ /* use the data classifier to determine what 802.1d tag the
+ * data frame has */
+ rcu_read_lock();
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -1444,14 +1444,16 @@ void ath_tx_aggr_sleep(struct ieee80211_
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
- ath9k_ps_wakeup(sc);
--
- r = ath_reset_internal(sc, NULL);
--
-- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-- if (!ATH_TXQ_SETUP(sc, i))
+- if (!tid->sched)
- continue;
-
-- spin_lock_bh(&sc->tx.txq[i].axq_lock);
-- ath_txq_schedule(sc, &sc->tx.txq[i]);
-- spin_unlock_bh(&sc->tx.txq[i].axq_lock);
-- }
--
- ath9k_ps_restore(sc);
+ ac = tid->ac;
+ txq = ac->txq;
- return r;
-@@ -2094,7 +2093,7 @@ static void ath9k_wow_add_pattern(struct
- {
- struct ath_hw *ah = sc->sc_ah;
- struct ath9k_wow_pattern *wow_pattern = NULL;
-- struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns;
-+ struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
- int mask_len;
- s8 i = 0;
+ ath_txq_lock(sc, txq);
---- a/drivers/net/wireless/mwifiex/cfg80211.c
-+++ b/drivers/net/wireless/mwifiex/cfg80211.c
-@@ -2298,8 +2298,7 @@ EXPORT_SYMBOL_GPL(mwifiex_del_virtual_in
++ if (!tid->sched) {
++ ath_txq_unlock(sc, txq);
++ continue;
++ }
++
+ buffered = ath_tid_has_buffered(tid);
- #ifdef CONFIG_PM
- static bool
--mwifiex_is_pattern_supported(struct cfg80211_wowlan_trig_pkt_pattern *pat,
-- s8 *byte_seq)
-+mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq)
- {
- int j, k, valid_byte_cnt = 0;
- bool dont_care_byte = false;
---- a/drivers/net/wireless/ti/wlcore/main.c
-+++ b/drivers/net/wireless/ti/wlcore/main.c
-@@ -1315,7 +1315,7 @@ static struct sk_buff *wl12xx_alloc_dumm
-
- #ifdef CONFIG_PM
- static int
--wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
-+wl1271_validate_wowlan_pattern(struct cfg80211_pkt_pattern *p)
- {
- int num_fields = 0, in_field = 0, fields_size = 0;
- int i, pattern_len = 0;
-@@ -1458,9 +1458,9 @@ void wl1271_rx_filter_flatten_fields(str
- * Allocates an RX filter returned through f
- * which needs to be freed using rx_filter_free()
- */
--static int wl1271_convert_wowlan_pattern_to_rx_filter(
-- struct cfg80211_wowlan_trig_pkt_pattern *p,
-- struct wl12xx_rx_filter **f)
-+static int
-+wl1271_convert_wowlan_pattern_to_rx_filter(struct cfg80211_pkt_pattern *p,
-+ struct wl12xx_rx_filter **f)
- {
- int i, j, ret = 0;
- struct wl12xx_rx_filter *filter;
-@@ -1562,7 +1562,7 @@ static int wl1271_configure_wowlan(struc
+ tid->sched = false;
+@@ -1696,7 +1698,7 @@ int ath_cabq_update(struct ath_softc *sc
- /* Translate WoWLAN patterns into filters */
- for (i = 0; i < wow->n_patterns; i++) {
-- struct cfg80211_wowlan_trig_pkt_pattern *p;
-+ struct cfg80211_pkt_pattern *p;
- struct wl12xx_rx_filter *filter = NULL;
+ ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
- p = &wow->patterns[i];
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -1698,7 +1698,7 @@ struct cfg80211_pmksa {
- };
+- qi.tqi_readyTime = (cur_conf->beacon_interval *
++ qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) *
+ ATH_CABQ_READY_TIME) / 100;
+ ath_txq_update(sc, qnum, &qi);
- /**
-- * struct cfg80211_wowlan_trig_pkt_pattern - packet pattern
-+ * struct cfg80211_pkt_pattern - packet pattern
- * @mask: bitmask where to match pattern and where to ignore bytes,
- * one bit per byte, in same format as nl80211
- * @pattern: bytes to match where bitmask is 1
-@@ -1708,7 +1708,7 @@ struct cfg80211_pmksa {
- * Internal note: @mask and @pattern are allocated in one chunk of
- * memory, free @mask only!
- */
--struct cfg80211_wowlan_trig_pkt_pattern {
-+struct cfg80211_pkt_pattern {
- u8 *mask, *pattern;
- int pattern_len;
- int pkt_offset;
-@@ -1770,7 +1770,7 @@ struct cfg80211_wowlan {
- bool any, disconnect, magic_pkt, gtk_rekey_failure,
- eap_identity_req, four_way_handshake,
- rfkill_release;
-- struct cfg80211_wowlan_trig_pkt_pattern *patterns;
-+ struct cfg80211_pkt_pattern *patterns;
- struct cfg80211_wowlan_tcp *tcp;
- int n_patterns;
- };
---- a/include/uapi/linux/nl80211.h
-+++ b/include/uapi/linux/nl80211.h
-@@ -3060,11 +3060,11 @@ enum nl80211_tx_power_setting {
- };
+@@ -2061,7 +2063,7 @@ static struct ath_buf *ath_tx_setup_buff
- /**
-- * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
-- * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
-- * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
-+ * enum nl80211_packet_pattern_attr - packet pattern attribute
-+ * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
-+ * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
- * a zero bit are ignored
-- * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
-+ * @NL80211_PKTPAT_MASK: pattern mask, must be long enough to have
- * a bit for each byte in the pattern. The lowest-order bit corresponds
- * to the first byte of the pattern, but the bytes of the pattern are
- * in a little-endian-like format, i.e. the 9th byte of the pattern
-@@ -3075,23 +3075,23 @@ enum nl80211_tx_power_setting {
- * Note that the pattern matching is done as though frames were not
- * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
- * first (including SNAP header unpacking) and then matched.
-- * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
-+ * @NL80211_PKTPAT_OFFSET: packet offset, pattern is matched after
- * these fixed number of bytes of received packet
-- * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
-- * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
-+ * @NUM_NL80211_PKTPAT: number of attributes
-+ * @MAX_NL80211_PKTPAT: max attribute number
- */
--enum nl80211_wowlan_packet_pattern_attr {
-- __NL80211_WOWLAN_PKTPAT_INVALID,
-- NL80211_WOWLAN_PKTPAT_MASK,
-- NL80211_WOWLAN_PKTPAT_PATTERN,
-- NL80211_WOWLAN_PKTPAT_OFFSET,
-+enum nl80211_packet_pattern_attr {
-+ __NL80211_PKTPAT_INVALID,
-+ NL80211_PKTPAT_MASK,
-+ NL80211_PKTPAT_PATTERN,
-+ NL80211_PKTPAT_OFFSET,
-
-- NUM_NL80211_WOWLAN_PKTPAT,
-- MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
-+ NUM_NL80211_PKTPAT,
-+ MAX_NL80211_PKTPAT = NUM_NL80211_PKTPAT - 1,
- };
+ ATH_TXBUF_RESET(bf);
- /**
-- * struct nl80211_wowlan_pattern_support - pattern support information
-+ * struct nl80211_pattern_support - packet pattern support information
- * @max_patterns: maximum number of patterns supported
- * @min_pattern_len: minimum length of each pattern
- * @max_pattern_len: maximum length of each pattern
-@@ -3101,13 +3101,22 @@ enum nl80211_wowlan_packet_pattern_attr
- * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
- * capability information given by the kernel to userspace.
- */
--struct nl80211_wowlan_pattern_support {
-+struct nl80211_pattern_support {
- __u32 max_patterns;
- __u32 min_pattern_len;
- __u32 max_pattern_len;
- __u32 max_pkt_offset;
- } __attribute__((packed));
-
-+/* only for backward compatibility */
-+#define __NL80211_WOWLAN_PKTPAT_INVALID __NL80211_PKTPAT_INVALID
-+#define NL80211_WOWLAN_PKTPAT_MASK NL80211_PKTPAT_MASK
-+#define NL80211_WOWLAN_PKTPAT_PATTERN NL80211_PKTPAT_PATTERN
-+#define NL80211_WOWLAN_PKTPAT_OFFSET NL80211_PKTPAT_OFFSET
-+#define NUM_NL80211_WOWLAN_PKTPAT NUM_NL80211_PKTPAT
-+#define MAX_NL80211_WOWLAN_PKTPAT MAX_NL80211_PKTPAT
-+#define nl80211_wowlan_pattern_support nl80211_pattern_support
-+
- /**
- * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
- * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
-@@ -3127,7 +3136,7 @@ struct nl80211_wowlan_pattern_support {
- * pattern matching is done after the packet is converted to the MSDU.
- *
- * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
-- * carrying a &struct nl80211_wowlan_pattern_support.
-+ * carrying a &struct nl80211_pattern_support.
- *
- * When reporting wakeup. it is a u32 attribute containing the 0-based
- * index of the pattern that caused the wakeup, in the patterns passed
-@@ -3284,7 +3293,7 @@ struct nl80211_wowlan_tcp_data_token_fea
- * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
- * u32 attribute holding the maximum length
- * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
-- * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK
-+ * feature advertising. The mask works like @NL80211_PKTPAT_MASK
- * but on the TCP payload only.
- * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes
- * @MAX_NL80211_WOWLAN_TCP: highest attribute number
---- a/net/mac80211/mesh_ps.c
-+++ b/net/mac80211/mesh_ps.c
-@@ -229,6 +229,10 @@ void ieee80211_mps_sta_status_update(str
- enum nl80211_mesh_power_mode pm;
- bool do_buffer;
-
-+ /* For non-assoc STA, prevent buffering or frame transmission */
-+ if (sta->sta_state < IEEE80211_STA_ASSOC)
-+ return;
+- if (tid) {
++ if (tid && ieee80211_is_data_present(hdr->frame_control)) {
+ fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
+ seqno = tid->seq_next;
+ hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
+@@ -2184,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw
+ txq->stopped = true;
+ }
+
++ if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
++ tid = ath_get_skb_tid(sc, txctl->an, skb);
+
- /*
- * use peer-specific power mode if peering is established and the
- * peer's power mode is known
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -441,10 +441,12 @@ static int nl80211_prepare_wdev_dump(str
- goto out_unlock;
- }
- *rdev = wiphy_to_dev((*wdev)->wiphy);
-- cb->args[0] = (*rdev)->wiphy_idx;
-+ /* 0 is the first index - add 1 to parse only once */
-+ cb->args[0] = (*rdev)->wiphy_idx + 1;
- cb->args[1] = (*wdev)->identifier;
- } else {
-- struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]);
-+ /* subtract the 1 again here */
-+ struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
- struct wireless_dev *tmp;
-
- if (!wiphy) {
-@@ -974,7 +976,7 @@ static int nl80211_send_wowlan(struct sk
- return -ENOBUFS;
-
- if (dev->wiphy.wowlan->n_patterns) {
-- struct nl80211_wowlan_pattern_support pat = {
-+ struct nl80211_pattern_support pat = {
- .max_patterns = dev->wiphy.wowlan->n_patterns,
- .min_pattern_len = dev->wiphy.wowlan->pattern_min_len,
- .max_pattern_len = dev->wiphy.wowlan->pattern_max_len,
-@@ -1568,8 +1570,10 @@ static int nl80211_dump_wiphy(struct sk_
- rtnl_lock();
- if (!state) {
- state = kzalloc(sizeof(*state), GFP_KERNEL);
-- if (!state)
-+ if (!state) {
-+ rtnl_unlock();
- return -ENOMEM;
-+ }
- state->filter_wiphy = -1;
- ret = nl80211_dump_wiphy_parse(skb, cb, state);
- if (ret) {
-@@ -6615,12 +6619,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_ev
+ if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
+ ath_txq_unlock(sc, txq);
+ txq = sc->tx.uapsdq;
+ ath_txq_lock(sc, txq);
+ } else if (txctl->an &&
+ ieee80211_is_data_present(hdr->frame_control)) {
+- tid = ath_get_skb_tid(sc, txctl->an, skb);
+-
+ WARN_ON(tid->ac->txq != txctl->txq);
- void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
- {
-+ struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
- void *hdr = ((void **)skb->cb)[1];
- struct nlattr *data = ((void **)skb->cb)[2];
-
- nla_nest_end(skb, data);
- genlmsg_end(skb, hdr);
-- genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
-+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
-+ nl80211_testmode_mcgrp.id, gfp);
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -943,6 +943,7 @@ static void ath9k_set_hw_capab(struct at
+ hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
+ hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
++ hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+
+ hw->queues = 4;
+ hw->max_rates = 4;
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1700,14 +1700,8 @@ void ieee80211_stop_queue_by_reason(stru
+ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
+ void ieee80211_add_pending_skb(struct ieee80211_local *local,
+ struct sk_buff *skb);
+-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
+- struct sk_buff_head *skbs,
+- void (*fn)(void *data), void *data);
+-static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+- struct sk_buff_head *skbs)
+-{
+- ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
+-}
++void ieee80211_add_pending_skbs(struct ieee80211_local *local,
++ struct sk_buff_head *skbs);
+ void ieee80211_flush_queues(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata);
+
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee
+ return -ENOENT;
}
- EXPORT_SYMBOL(cfg80211_testmode_event);
- #endif
-@@ -7593,12 +7599,11 @@ static int nl80211_send_wowlan_patterns(
- if (!nl_pat)
- return -ENOBUFS;
- pat_len = wowlan->patterns[i].pattern_len;
-- if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK,
-- DIV_ROUND_UP(pat_len, 8),
-+ if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
- wowlan->patterns[i].mask) ||
-- nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
-- pat_len, wowlan->patterns[i].pattern) ||
-- nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET,
-+ nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
-+ wowlan->patterns[i].pattern) ||
-+ nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
- wowlan->patterns[i].pkt_offset))
- return -ENOBUFS;
- nla_nest_end(msg, nl_pat);
-@@ -7939,7 +7944,7 @@ static int nl80211_set_wowlan(struct sk_
- struct nlattr *pat;
- int n_patterns = 0;
- int rem, pat_len, mask_len, pkt_offset;
-- struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT];
-+ struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
-
- nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
- rem)
-@@ -7958,26 +7963,25 @@ static int nl80211_set_wowlan(struct sk_
-
- nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
- rem) {
-- nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT,
-- nla_data(pat), nla_len(pat), NULL);
-+ nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
-+ nla_len(pat), NULL);
- err = -EINVAL;
-- if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] ||
-- !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN])
-+ if (!pat_tb[NL80211_PKTPAT_MASK] ||
-+ !pat_tb[NL80211_PKTPAT_PATTERN])
- goto error;
-- pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]);
-+ pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
- mask_len = DIV_ROUND_UP(pat_len, 8);
-- if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) !=
-- mask_len)
-+ if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
- goto error;
- if (pat_len > wowlan->pattern_max_len ||
- pat_len < wowlan->pattern_min_len)
- goto error;
-
-- if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET])
-+ if (!pat_tb[NL80211_PKTPAT_OFFSET])
- pkt_offset = 0;
- else
- pkt_offset = nla_get_u32(
-- pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]);
-+ pat_tb[NL80211_PKTPAT_OFFSET]);
- if (pkt_offset > wowlan->max_pkt_offset)
- goto error;
- new_triggers.patterns[i].pkt_offset = pkt_offset;
-@@ -7991,11 +7995,11 @@ static int nl80211_set_wowlan(struct sk_
- new_triggers.patterns[i].pattern =
- new_triggers.patterns[i].mask + mask_len;
- memcpy(new_triggers.patterns[i].mask,
-- nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]),
-+ nla_data(pat_tb[NL80211_PKTPAT_MASK]),
- mask_len);
- new_triggers.patterns[i].pattern_len = pat_len;
- memcpy(new_triggers.patterns[i].pattern,
-- nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]),
-+ nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
- pat_len);
- i++;
- }
-@@ -10066,7 +10070,8 @@ void cfg80211_mgmt_tx_status(struct wire
- genlmsg_end(msg, hdr);
+-static void cleanup_single_sta(struct sta_info *sta)
++static void __cleanup_single_sta(struct sta_info *sta)
+ {
+ int ac, i;
+ struct tid_ampdu_tx *tid_tx;
+@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct st
+ struct ieee80211_local *local = sdata->local;
+ struct ps_data *ps;
-- genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
-+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-+ nl80211_mlme_mcgrp.id, gfp);
- return;
+- if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
++ if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
++ test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+ if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
+ sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ ps = &sdata->bss->ps;
+@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct st
+ return;
- nla_put_failure:
---- a/net/wireless/reg.c
-+++ b/net/wireless/reg.c
-@@ -2247,10 +2247,13 @@ int reg_device_uevent(struct device *dev
+ clear_sta_flag(sta, WLAN_STA_PS_STA);
++ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
- void wiphy_regulatory_register(struct wiphy *wiphy)
- {
-+ struct regulatory_request *lr;
-+
- if (!reg_dev_ignore_cell_hint(wiphy))
- reg_num_devs_support_basehint++;
+ atomic_dec(&ps->num_sta_ps);
+ sta_info_recalc_tim(sta);
+@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct st
+ ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
+ kfree(tid_tx);
+ }
++}
-- wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
-+ lr = get_last_request();
-+ wiphy_update_regulatory(wiphy, lr->initiator);
++static void cleanup_single_sta(struct sta_info *sta)
++{
++ struct ieee80211_sub_if_data *sdata = sta->sdata;
++ struct ieee80211_local *local = sdata->local;
++
++ __cleanup_single_sta(sta);
+ sta_info_free(local, sta);
}
- void wiphy_regulatory_deregister(struct wiphy *wiphy)
-@@ -2279,7 +2282,9 @@ void wiphy_regulatory_deregister(struct
- static void reg_timeout_work(struct work_struct *work)
- {
- REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
-+ rtnl_lock();
- restore_regulatory_settings(true);
-+ rtnl_unlock();
- }
+@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct i
+ rcu_read_unlock();
- int __init regulatory_init(void)
---- a/net/wireless/sme.c
-+++ b/net/wireless/sme.c
-@@ -34,8 +34,10 @@ struct cfg80211_conn {
- CFG80211_CONN_SCAN_AGAIN,
- CFG80211_CONN_AUTHENTICATE_NEXT,
- CFG80211_CONN_AUTHENTICATING,
-+ CFG80211_CONN_AUTH_FAILED,
- CFG80211_CONN_ASSOCIATE_NEXT,
- CFG80211_CONN_ASSOCIATING,
-+ CFG80211_CONN_ASSOC_FAILED,
- CFG80211_CONN_DEAUTH,
- CFG80211_CONN_CONNECTED,
- } state;
-@@ -164,6 +166,8 @@ static int cfg80211_conn_do_work(struct
- NULL, 0,
- params->key, params->key_len,
- params->key_idx, NULL, 0);
-+ case CFG80211_CONN_AUTH_FAILED:
-+ return -ENOTCONN;
- case CFG80211_CONN_ASSOCIATE_NEXT:
- BUG_ON(!rdev->ops->assoc);
- wdev->conn->state = CFG80211_CONN_ASSOCIATING;
-@@ -188,10 +192,17 @@ static int cfg80211_conn_do_work(struct
- WLAN_REASON_DEAUTH_LEAVING,
- false);
- return err;
-+ case CFG80211_CONN_ASSOC_FAILED:
-+ cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
-+ NULL, 0,
-+ WLAN_REASON_DEAUTH_LEAVING, false);
-+ return -ENOTCONN;
- case CFG80211_CONN_DEAUTH:
- cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
- NULL, 0,
- WLAN_REASON_DEAUTH_LEAVING, false);
-+ /* free directly, disconnected event already sent */
-+ cfg80211_sme_free(wdev);
- return 0;
- default:
- return 0;
-@@ -371,7 +382,7 @@ bool cfg80211_sme_rx_assoc_resp(struct w
- return true;
+ spin_lock_init(&sta->lock);
++ spin_lock_init(&sta->ps_lock);
+ INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
+ INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+ mutex_init(&sta->ampdu_mlme.mtx);
+@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct
+ goto out_err;
}
-- wdev->conn->state = CFG80211_CONN_DEAUTH;
-+ wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
- schedule_work(&rdev->conn_work);
- return false;
- }
-@@ -383,7 +394,13 @@ void cfg80211_sme_deauth(struct wireless
+- /* notify driver */
+- err = sta_info_insert_drv_state(local, sdata, sta);
+- if (err)
+- goto out_err;
+-
+ local->num_sta++;
+ local->sta_generation++;
+ smp_mb();
- void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
- {
-- cfg80211_sme_free(wdev);
-+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-+
-+ if (!wdev->conn)
-+ return;
++ /* simplify things and don't accept BA sessions yet */
++ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+
-+ wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
-+ schedule_work(&rdev->conn_work);
- }
+ /* make the station visible */
+ sta_info_hash_add(local, sta);
- void cfg80211_sme_disassoc(struct wireless_dev *wdev)
-@@ -399,7 +416,13 @@ void cfg80211_sme_disassoc(struct wirele
+ list_add_rcu(&sta->list, &local->sta_list);
- void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
- {
-- cfg80211_sme_disassoc(wdev);
-+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-+
-+ if (!wdev->conn)
-+ return;
++ /* notify driver */
++ err = sta_info_insert_drv_state(local, sdata, sta);
++ if (err)
++ goto out_remove;
+
-+ wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
-+ schedule_work(&rdev->conn_work);
- }
+ set_sta_flag(sta, WLAN_STA_INSERTED);
++ /* accept BA sessions now */
++ clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
- static int cfg80211_sme_connect(struct wireless_dev *wdev,
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct iee
- struct minstrel_rate *msr, *mr;
- unsigned int ndx;
- bool mrr_capable;
-- bool prev_sample = mi->prev_sample;
-+ bool prev_sample;
- int delta;
- int sampling_ratio;
-
-@@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct iee
- (mi->sample_count + mi->sample_deferred / 2);
-
- /* delta < 0: no sampling required */
-+ prev_sample = mi->prev_sample;
- mi->prev_sample = false;
- if (delta < 0 || (!mrr_capable && prev_sample))
- return;
---- a/drivers/net/wireless/rt2x00/rt2x00queue.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
-@@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_
- spin_unlock_irqrestore(&queue->index_lock, irqflags);
+ ieee80211_recalc_min_chandef(sdata);
+ ieee80211_sta_debugfs_add(sta);
+@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct
+ mesh_accept_plinks_update(sdata);
+
+ return 0;
++ out_remove:
++ sta_info_hash_del(local, sta);
++ list_del_rcu(&sta->list);
++ local->num_sta--;
++ synchronize_net();
++ __cleanup_single_sta(sta);
+ out_err:
+ mutex_unlock(&local->sta_mtx);
+ rcu_read_lock();
+@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta
}
+ EXPORT_SYMBOL(ieee80211_find_sta);
--void rt2x00queue_pause_queue(struct data_queue *queue)
-+void rt2x00queue_pause_queue_nocheck(struct data_queue *queue)
+-static void clear_sta_ps_flags(void *_sta)
++/* powersave support code */
++void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
-- if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
-- !test_bit(QUEUE_STARTED, &queue->flags) ||
-- test_and_set_bit(QUEUE_PAUSED, &queue->flags))
-- return;
+- struct sta_info *sta = _sta;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
++ struct ieee80211_local *local = sdata->local;
++ struct sk_buff_head pending;
++ int filtered = 0, buffered = 0, ac;
++ unsigned long flags;
+ struct ps_data *ps;
+
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_st
+ else
+ return;
+
+- clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+- if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
+- atomic_dec(&ps->num_sta_ps);
+-}
-
- switch (queue->qid) {
- case QID_AC_VO:
- case QID_AC_VI:
-@@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data
- break;
+-/* powersave support code */
+-void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
+-{
+- struct ieee80211_sub_if_data *sdata = sta->sdata;
+- struct ieee80211_local *local = sdata->local;
+- struct sk_buff_head pending;
+- int filtered = 0, buffered = 0, ac;
+- unsigned long flags;
+-
+ clear_sta_flag(sta, WLAN_STA_SP);
+
+ BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
+@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(str
+
+ skb_queue_head_init(&pending);
+
++ /* sync with ieee80211_tx_h_unicast_ps_buf */
++ spin_lock(&sta->ps_lock);
+ /* Send all buffered frames to the station */
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ int count = skb_queue_len(&pending), tmp;
+@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(str
+ buffered += tmp - count;
}
- }
-+void rt2x00queue_pause_queue(struct data_queue *queue)
-+{
-+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
-+ !test_bit(QUEUE_STARTED, &queue->flags) ||
-+ test_and_set_bit(QUEUE_PAUSED, &queue->flags))
-+ return;
+
+- ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
++ ieee80211_add_pending_skbs(local, &pending);
++ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
++ clear_sta_flag(sta, WLAN_STA_PS_STA);
++ spin_unlock(&sta->ps_lock);
+
-+ rt2x00queue_pause_queue_nocheck(queue);
-+}
- EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
++ atomic_dec(&ps->num_sta_ps);
- void rt2x00queue_unpause_queue(struct data_queue *queue)
-@@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_
- return;
+ /* This station just woke up and isn't aware of our SMPS state */
+ if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat {
+ * @drv_unblock_wk: used for driver PS unblocking
+ * @listen_interval: listen interval of this station, when we're acting as AP
+ * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
++ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
+ * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
+ * when it leaves power saving state or polls
+ * @tx_filtered: buffers (per AC) of frames we already tried to
+@@ -356,10 +357,8 @@ struct sta_info {
+ /* use the accessors defined below */
+ unsigned long _flags;
+
+- /*
+- * STA powersave frame queues, no more than the internal
+- * locking required.
+- */
++ /* STA powersave lock and frame queues */
++ spinlock_t ps_lock;
+ struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
+ struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
+ unsigned long driver_buffered_tids;
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ie
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+ }
+
+-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
+- struct sk_buff_head *skbs,
+- void (*fn)(void *data), void *data)
++void ieee80211_add_pending_skbs(struct ieee80211_local *local,
++ struct sk_buff_head *skbs)
+ {
+ struct ieee80211_hw *hw = &local->hw;
+ struct sk_buff *skb;
+@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struc
+ __skb_queue_tail(&local->pending[queue], skb);
}
-- rt2x00queue_pause_queue(queue);
-+ rt2x00queue_pause_queue_nocheck(queue);
+- if (fn)
+- fn(data);
+-
+ for (i = 0; i < hw->queues; i++)
+ __ieee80211_wake_queue(hw, i,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regu
+ return;
+ case NL80211_REGDOM_SET_BY_USER:
+ treatment = reg_process_hint_user(reg_request);
+- if (treatment == REG_REQ_OK ||
++ if (treatment == REG_REQ_IGNORE ||
+ treatment == REG_REQ_ALREADY_SET)
+ return;
+ schedule_delayed_work(®_timeout, msecs_to_jiffies(3142));
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -138,43 +138,41 @@ static ssize_t read_file_ani(struct file
+ unsigned int len = 0, size = 1024;
+ ssize_t retval = 0;
+ char *buf;
++ int i;
++ struct {
++ const char *name;
++ unsigned int val;
++ } ani_info[] = {
++ { "ANI RESET", ah->stats.ast_ani_reset },
++ { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel },
++ { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel },
++ { "SPUR UP", ah->stats.ast_ani_spurup },
++ { "SPUR DOWN", ah->stats.ast_ani_spurup },
++ { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon },
++ { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff },
++ { "MRC-CCK ON", ah->stats.ast_ani_ccklow },
++ { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh },
++ { "FIR-STEP UP", ah->stats.ast_ani_stepup },
++ { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown },
++ { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero },
++ { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs },
++ { "CCK ERRORS", ah->stats.ast_ani_cckerrs },
++ };
- queue->rt2x00dev->ops->lib->stop_queue(queue);
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+- if (common->disable_ani) {
+- len += scnprintf(buf + len, size - len, "%s: %s\n",
+- "ANI", "DISABLED");
++ len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI",
++ common->disable_ani ? "DISABLED" : "ENABLED");
++
++ if (common->disable_ani)
+ goto exit;
+- }
+
+- len += scnprintf(buf + len, size - len, "%15s: %s\n",
+- "ANI", "ENABLED");
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "ANI RESET", ah->stats.ast_ani_reset);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "SPUR UP", ah->stats.ast_ani_spurup);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "SPUR DOWN", ah->stats.ast_ani_spurup);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "MRC-CCK ON", ah->stats.ast_ani_ccklow);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "FIR-STEP UP", ah->stats.ast_ani_stepup);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
+- len += scnprintf(buf + len, size - len, "%15s: %u\n",
+- "CCK ERRORS", ah->stats.ast_ani_cckerrs);
++ for (i = 0; i < ARRAY_SIZE(ani_info); i++)
++ len += scnprintf(buf + len, size - len, "%15s: %u\n",
++ ani_info[i].name, ani_info[i].val);
++
+ exit:
+ if (len > size)
+ len = size;
+@@ -866,6 +864,12 @@ static ssize_t read_file_reset(struct fi
+ "%17s: %2d\n", "PLL RX Hang",
+ sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
+ len += scnprintf(buf + len, sizeof(buf) - len,
++ "%17s: %2d\n", "MAC Hang",
++ sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
++ len += scnprintf(buf + len, sizeof(buf) - len,
++ "%17s: %2d\n", "Stuck Beacon",
++ sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
++ len += scnprintf(buf + len, sizeof(buf) - len,
+ "%17s: %2d\n", "MCI Reset",
+ sc->debug.stats.reset[RESET_TYPE_MCI]);
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct
+
+ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+ rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+- if (IS_CHAN_QUARTER_RATE(chan))
+- rfMode |= AR_PHY_MODE_QUARTER;
+- if (IS_CHAN_HALF_RATE(chan))
+- rfMode |= AR_PHY_MODE_HALF;
+
+ if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
+ REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
+--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+@@ -706,6 +706,7 @@ ath5k_get_survey(struct ieee80211_hw *hw
+ survey->channel = conf->chandef.chan;
+ survey->noise = ah->ah_noise_floor;
+ survey->filled = SURVEY_INFO_NOISE_DBM |
++ SURVEY_INFO_IN_USE |
+ SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_RX |
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx
+ return NULL;
---- a/net/mac80211/mlme.c
-+++ b/net/mac80211/mlme.c
-@@ -31,10 +31,12 @@
- #include "led.h"
-
- #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
-+#define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2)
- #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10)
- #define IEEE80211_AUTH_MAX_TRIES 3
- #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5)
- #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
-+#define IEEE80211_ASSOC_TIMEOUT_LONG (HZ / 2)
- #define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10)
- #define IEEE80211_ASSOC_MAX_TRIES 3
-
-@@ -209,8 +211,9 @@ ieee80211_determine_chantype(struct ieee
- struct ieee80211_channel *channel,
- const struct ieee80211_ht_operation *ht_oper,
- const struct ieee80211_vht_operation *vht_oper,
-- struct cfg80211_chan_def *chandef, bool verbose)
-+ struct cfg80211_chan_def *chandef, bool tracking)
- {
-+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct cfg80211_chan_def vht_chandef;
- u32 ht_cfreq, ret;
-
-@@ -229,7 +232,7 @@ ieee80211_determine_chantype(struct ieee
- ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
- channel->band);
- /* check that channel matches the right operating channel */
-- if (channel->center_freq != ht_cfreq) {
-+ if (!tracking && channel->center_freq != ht_cfreq) {
/*
- * It's possible that some APs are confused here;
- * Netgear WNDR3700 sometimes reports 4 higher than
-@@ -237,11 +240,10 @@ ieee80211_determine_chantype(struct ieee
- * since we look at probe response/beacon data here
- * it should be OK.
+- * mark descriptor as zero-length and set the 'more'
+- * flag to ensure that both buffers get discarded
++ * Re-check previous descriptor, in case it has been filled
++ * in the mean time.
*/
-- if (verbose)
-- sdata_info(sdata,
-- "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
-- channel->center_freq, ht_cfreq,
-- ht_oper->primary_chan, channel->band);
-+ sdata_info(sdata,
-+ "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
-+ channel->center_freq, ht_cfreq,
-+ ht_oper->primary_chan, channel->band);
- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
- goto out;
- }
-@@ -295,7 +297,7 @@ ieee80211_determine_chantype(struct ieee
- channel->band);
- break;
- default:
-- if (verbose)
-+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
- sdata_info(sdata,
- "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
- vht_oper->chan_width);
-@@ -304,7 +306,7 @@ ieee80211_determine_chantype(struct ieee
+- rs->rs_datalen = 0;
+- rs->rs_more = true;
++ ret = ath9k_hw_rxprocdesc(ah, ds, rs);
++ if (ret == -EINPROGRESS) {
++ /*
++ * mark descriptor as zero-length and set the 'more'
++ * flag to ensure that both buffers get discarded
++ */
++ rs->rs_datalen = 0;
++ rs->rs_more = true;
++ }
}
- if (!cfg80211_chandef_valid(&vht_chandef)) {
-- if (verbose)
-+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
- sdata_info(sdata,
- "AP VHT information is invalid, disable VHT\n");
- ret = IEEE80211_STA_DISABLE_VHT;
-@@ -317,7 +319,7 @@ ieee80211_determine_chantype(struct ieee
- }
+ list_del(&bf->list);
+@@ -985,32 +992,32 @@ static int ath9k_rx_skb_preprocess(struc
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_hdr *hdr;
+ bool discard_current = sc->rx.discard_next;
+- int ret = 0;
+
+ /*
+ * Discard corrupt descriptors which are marked in
+ * ath_get_next_rx_buf().
+ */
+- sc->rx.discard_next = rx_stats->rs_more;
+ if (discard_current)
+- return -EINVAL;
++ goto corrupt;
++
++ sc->rx.discard_next = false;
- if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
-- if (verbose)
-+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
- sdata_info(sdata,
- "AP VHT information doesn't match HT, disable VHT\n");
- ret = IEEE80211_STA_DISABLE_VHT;
-@@ -333,18 +335,27 @@ out:
- if (ret & IEEE80211_STA_DISABLE_VHT)
- vht_chandef = *chandef;
+ /*
+ * Discard zero-length packets.
+ */
+ if (!rx_stats->rs_datalen) {
+ RX_STAT_INC(rx_len_err);
+- return -EINVAL;
++ goto corrupt;
+ }
+- /*
+- * rs_status follows rs_datalen so if rs_datalen is too large
+- * we can take a hint that hardware corrupted it, so ignore
+- * those frames.
+- */
+ /*
-+ * Ignore the DISABLED flag when we're already connected and only
-+ * tracking the APs beacon for bandwidth changes - otherwise we
-+ * might get disconnected here if we connect to an AP, update our
-+ * regulatory information based on the AP's country IE and the
-+ * information we have is wrong/outdated and disables the channel
-+ * that we're actually using for the connection to the AP.
++ * rs_status follows rs_datalen so if rs_datalen is too large
++ * we can take a hint that hardware corrupted it, so ignore
++ * those frames.
+ */
- while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
-- IEEE80211_CHAN_DISABLED)) {
-+ tracking ? 0 :
-+ IEEE80211_CHAN_DISABLED)) {
- if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
- ret = IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_VHT;
-- goto out;
-+ break;
- }
-
- ret |= chandef_downgrade(chandef);
+ if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
+ RX_STAT_INC(rx_len_err);
+- return -EINVAL;
++ goto corrupt;
}
-- if (chandef->width != vht_chandef.width && verbose)
-+ if (chandef->width != vht_chandef.width && !tracking)
- sdata_info(sdata,
- "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
-
-@@ -384,7 +395,7 @@ static int ieee80211_config_bw(struct ie
+ /* Only use status info from the last fragment */
+@@ -1024,10 +1031,8 @@ static int ath9k_rx_skb_preprocess(struc
+ * This is different from the other corrupt descriptor
+ * condition handled above.
+ */
+- if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
+- ret = -EINVAL;
+- goto exit;
+- }
++ if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
++ goto corrupt;
- /* calculate new channel (type) based on HT/VHT operation IEs */
- flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
-- vht_oper, &chandef, false);
-+ vht_oper, &chandef, true);
+ hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
- /*
- * Downgrade the new channel if we associated with restricted
-@@ -3394,10 +3405,13 @@ static int ieee80211_probe_auth(struct i
-
- if (tx_flags == 0) {
- auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-- ifmgd->auth_data->timeout_started = true;
-+ auth_data->timeout_started = true;
- run_again(sdata, auth_data->timeout);
- } else {
-- auth_data->timeout_started = false;
-+ auth_data->timeout =
-+ round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG);
-+ auth_data->timeout_started = true;
-+ run_again(sdata, auth_data->timeout);
- }
+@@ -1043,18 +1048,15 @@ static int ath9k_rx_skb_preprocess(struc
+ if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
+ RX_STAT_INC(rx_spectral);
- return 0;
-@@ -3434,7 +3448,11 @@ static int ieee80211_do_assoc(struct iee
- assoc_data->timeout_started = true;
- run_again(sdata, assoc_data->timeout);
- } else {
-- assoc_data->timeout_started = false;
-+ assoc_data->timeout =
-+ round_jiffies_up(jiffies +
-+ IEEE80211_ASSOC_TIMEOUT_LONG);
-+ assoc_data->timeout_started = true;
-+ run_again(sdata, assoc_data->timeout);
+- ret = -EINVAL;
+- goto exit;
++ return -EINVAL;
}
- return 0;
-@@ -3829,7 +3847,7 @@ static int ieee80211_prep_channel(struct
- ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
- cbss->channel,
- ht_oper, vht_oper,
-- &chandef, true);
-+ &chandef, false);
-
- sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
- local->rx_chains);
---- a/net/wireless/core.c
-+++ b/net/wireless/core.c
-@@ -772,6 +772,7 @@ void cfg80211_leave(struct cfg80211_regi
- cfg80211_leave_mesh(rdev, dev);
- break;
- case NL80211_IFTYPE_AP:
-+ case NL80211_IFTYPE_P2P_GO:
- cfg80211_stop_ap(rdev, dev);
- break;
- default:
---- a/drivers/net/wireless/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -5404,19 +5404,20 @@ int rt2800_enable_radio(struct rt2x00_de
- rt2800_init_registers(rt2x00dev)))
- return -EIO;
+ /*
+ * everything but the rate is checked here, the rate check is done
+ * separately to avoid doing two lookups for a rate for each frame.
+ */
+- if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) {
+- ret = -EINVAL;
+- goto exit;
+- }
++ if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
++ return -EINVAL;
-+ if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev)))
-+ return -EIO;
-+
+ if (ath_is_mybeacon(common, hdr)) {
+ RX_STAT_INC(rx_beacons);
+@@ -1064,15 +1066,11 @@ static int ath9k_rx_skb_preprocess(struc
/*
- * Send signal to firmware during boot time.
+ * This shouldn't happen, but have a safety check anyway.
*/
- rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
-- if (rt2x00_is_usb(rt2x00dev)) {
-+ if (rt2x00_is_usb(rt2x00dev))
- rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
-- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+- if (WARN_ON(!ah->curchan)) {
+- ret = -EINVAL;
+- goto exit;
- }
-+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
- msleep(1);
++ if (WARN_ON(!ah->curchan))
++ return -EINVAL;
-- if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev) ||
-- rt2800_wait_bbp_ready(rt2x00dev)))
-+ if (unlikely(rt2800_wait_bbp_ready(rt2x00dev)))
- return -EIO;
+- if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
+- ret =-EINVAL;
+- goto exit;
+- }
++ if (ath9k_process_rate(common, hw, rx_stats, rx_status))
++ return -EINVAL;
- rt2800_init_bbp(rt2x00dev);
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -101,7 +101,7 @@ static u32 ieee80211_hw_conf_chan(struct
- struct ieee80211_sub_if_data *sdata;
- struct cfg80211_chan_def chandef = {};
- u32 changed = 0;
-- int power;
-+ int power = 0;
- u32 offchannel_flag;
-
- offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
-@@ -155,16 +155,16 @@ static u32 ieee80211_hw_conf_chan(struct
- changed |= IEEE80211_CONF_CHANGE_SMPS;
- }
+ ath9k_process_rssi(common, hw, rx_stats, rx_status);
-- power = chandef.chan->max_power;
--
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (!rcu_access_pointer(sdata->vif.chanctx_conf))
- continue;
-- power = min(power, sdata->vif.bss_conf.txpower);
-+ power = max(power, sdata->vif.bss_conf.txpower);
- }
- rcu_read_unlock();
+@@ -1087,9 +1085,11 @@ static int ath9k_rx_skb_preprocess(struc
+ sc->rx.num_pkts++;
+ #endif
-+ power = min(power, chandef.chan->max_power);
+-exit:
+- sc->rx.discard_next = false;
+- return ret;
++ return 0;
+
- if (local->hw.conf.power_level != power) {
- changed |= IEEE80211_CONF_CHANGE_POWER;
- local->hw.conf.power_level = power;
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -3332,7 +3332,7 @@ static int ieee80211_probe_client(struct
- return -EINVAL;
- }
- band = chanctx_conf->def.chan->band;
-- sta = sta_info_get(sdata, peer);
-+ sta = sta_info_get_bss(sdata, peer);
- if (sta) {
- qos = test_sta_flag(sta, WLAN_STA_WME);
- } else {
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -180,6 +180,9 @@ static void ieee80211_frame_acked(struct
- struct ieee80211_local *local = sta->local;
- struct ieee80211_sub_if_data *sdata = sta->sdata;
++corrupt:
++ sc->rx.discard_next = rx_stats->rs_more;
++ return -EINVAL;
+ }
-+ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
-+ sta->last_rx = jiffies;
+ static void ath9k_rx_skb_postprocess(struct ath_common *common,
+--- a/drivers/net/wireless/ath/ath9k/ani.c
++++ b/drivers/net/wireless/ath/ath9k/ani.c
+@@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct
+ if (ah->opmode == NL80211_IFTYPE_STATION &&
+ BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
+ weak_sig = true;
+-
+ /*
+- * OFDM Weak signal detection is always enabled for AP mode.
++ * Newer chipsets are better at dealing with high PHY error counts -
++ * keep weak signal detection enabled when no RSSI threshold is
++ * available to determine if it is needed (mode != STA)
+ */
+- if (ah->opmode != NL80211_IFTYPE_AP &&
+- aniState->ofdmWeakSigDetect != weak_sig) {
+- ath9k_hw_ani_control(ah,
+- ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+- entry_ofdm->ofdm_weak_signal_on);
+- }
++ else if (AR_SREV_9300_20_OR_LATER(ah) &&
++ ah->opmode != NL80211_IFTYPE_STATION)
++ weak_sig = true;
+
- if (ieee80211_is_data_qos(mgmt->frame_control)) {
- struct ieee80211_hdr *hdr = (void *) skb->data;
- u8 *qc = ieee80211_get_qos_ctl(hdr);
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1101,7 +1101,8 @@ ieee80211_tx_prepare(struct ieee80211_su
- tx->sta = rcu_dereference(sdata->u.vlan.sta);
- if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
- return TX_DROP;
-- } else if (info->flags & IEEE80211_TX_CTL_INJECTED ||
-+ } else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
-+ IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
- tx->sdata->control_port_protocol == tx->skb->protocol) {
- tx->sta = sta_info_get_bss(sdata, hdr->addr1);
- }
---- a/drivers/net/wireless/ath/ath5k/base.c
-+++ b/drivers/net/wireless/ath/ath5k/base.c
-@@ -1628,15 +1628,15 @@ ath5k_tx_frame_completed(struct ath5k_hw
- ah->stats.tx_bytes_count += skb->len;
- info = IEEE80211_SKB_CB(skb);
-
-+ size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates));
-+ memcpy(info->status.rates, bf->rates, size);
++ /* Older chipsets are more sensitive to high PHY error counts */
++ else if (!AR_SREV_9300_20_OR_LATER(ah) &&
++ aniState->ofdmNoiseImmunityLevel >= 8)
++ weak_sig = false;
+
- tries[0] = info->status.rates[0].count;
- tries[1] = info->status.rates[1].count;
- tries[2] = info->status.rates[2].count;
++ if (aniState->ofdmWeakSigDetect != weak_sig)
++ ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
++ weak_sig);
++
++ if (!AR_SREV_9300_20_OR_LATER(ah))
++ return;
- ieee80211_tx_info_clear_status(info);
+ if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+@@ -308,17 +318,6 @@ void ath9k_ani_reset(struct ath_hw *ah,
+ BUG_ON(aniState == NULL);
+ ah->stats.ast_ani_reset++;
-- size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates));
-- memcpy(info->status.rates, bf->rates, size);
+- /* only allow a subset of functions in AP mode */
+- if (ah->opmode == NL80211_IFTYPE_AP) {
+- if (IS_CHAN_2GHZ(chan)) {
+- ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+- ATH9K_ANI_FIRSTEP_LEVEL);
+- if (AR_SREV_9300_20_OR_LATER(ah))
+- ah->ani_function |= ATH9K_ANI_MRC_CCK;
+- } else
+- ah->ani_function = 0;
+- }
-
- for (i = 0; i < ts->ts_final_idx; i++) {
- struct ieee80211_tx_rate *r =
- &info->status.rates[i];
---- a/drivers/net/wireless/rt2x00/rt2800usb.c
-+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
-@@ -176,8 +176,8 @@ static bool rt2800usb_tx_sta_fifo_read_c
- queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
-
- if (rt2800usb_txstatus_pending(rt2x00dev)) {
-- /* Read register after 250 us */
-- hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 250000),
-+ /* Read register after 1 ms */
-+ hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 1000000),
- HRTIMER_MODE_REL);
- return false;
- }
-@@ -202,8 +202,8 @@ static void rt2800usb_async_read_tx_stat
- if (test_and_set_bit(TX_STATUS_READING, &rt2x00dev->flags))
- return;
+ ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
+ aniState->ofdmNoiseImmunityLevel);
+ cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
+@@ -483,10 +482,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah
-- /* Read TX_STA_FIFO register after 500 us */
-- hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 500000),
-+ /* Read TX_STA_FIFO register after 2 ms */
-+ hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 2000000),
- HRTIMER_MODE_REL);
- }
+ ath_dbg(common, ANI, "Initialize ANI\n");
+
+- ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+- ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
+- ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
+- ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
++ if (AR_SREV_9300_20_OR_LATER(ah)) {
++ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
++ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
++ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
++ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
++ } else {
++ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
++ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
++ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
++ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
++ }
+
+ ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+ ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+--- a/drivers/net/wireless/ath/ath9k/ani.h
++++ b/drivers/net/wireless/ath/ath9k/ani.h
+@@ -22,12 +22,16 @@
+ /* units are errors per second */
+ #define ATH9K_ANI_OFDM_TRIG_HIGH 3500
+ #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
++#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500
+
+ #define ATH9K_ANI_OFDM_TRIG_LOW 400
+ #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
++#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200
+
+ #define ATH9K_ANI_CCK_TRIG_HIGH 600
++#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200
+ #define ATH9K_ANI_CCK_TRIG_LOW 300
++#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100
+
+ #define ATH9K_ANI_SPUR_IMMUNE_LVL 3
+ #define ATH9K_ANI_FIRSTEP_LVL 2
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -26,10 +26,6 @@ static const int firstep_table[] =
+ /* level: 0 1 2 3 4 5 6 7 8 */
+ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
+
+-static const int cycpwrThr1_table[] =
+-/* level: 0 1 2 3 4 5 6 7 8 */
+- { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */
+-
+ /*
+ * register values to turn OFDM weak signal detection OFF
+ */
+@@ -921,7 +917,7 @@ static bool ar5008_hw_ani_control_new(st
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_channel *chan = ah->curchan;
+ struct ar5416AniState *aniState = &ah->ani;
+- s32 value, value2;
++ s32 value;
+
+ switch (cmd & ah->ani_function) {
+ case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+@@ -1008,42 +1004,11 @@ static bool ar5008_hw_ani_control_new(st
+ case ATH9K_ANI_FIRSTEP_LEVEL:{
+ u32 level = param;
+
+- if (level >= ARRAY_SIZE(firstep_table)) {
+- ath_dbg(common, ANI,
+- "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n",
+- level, ARRAY_SIZE(firstep_table));
+- return false;
+- }
+-
+- /*
+- * make register setting relative to default
+- * from INI file & cap value
+- */
+- value = firstep_table[level] -
+- firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
+- aniState->iniDef.firstep;
+- if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+- value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+- if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+- value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
++ value = level * 2;
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+- AR_PHY_FIND_SIG_FIRSTEP,
+- value);
+- /*
+- * we need to set first step low register too
+- * make register setting relative to default
+- * from INI file & cap value
+- */
+- value2 = firstep_table[level] -
+- firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
+- aniState->iniDef.firstepLow;
+- if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+- value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+- if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+- value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+-
++ AR_PHY_FIND_SIG_FIRSTEP, value);
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+- AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
++ AR_PHY_FIND_SIG_FIRSTEP_LOW, value);
+
+ if (level != aniState->firstepLevel) {
+ ath_dbg(common, ANI,
+@@ -1060,7 +1025,7 @@ static bool ar5008_hw_ani_control_new(st
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL,
+- value2,
++ value,
+ aniState->iniDef.firstepLow);
+ if (level > aniState->firstepLevel)
+ ah->stats.ast_ani_stepup++;
+@@ -1073,41 +1038,13 @@ static bool ar5008_hw_ani_control_new(st
+ case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+ u32 level = param;
+
+- if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
+- ath_dbg(common, ANI,
+- "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n",
+- level, ARRAY_SIZE(cycpwrThr1_table));
+- return false;
+- }
+- /*
+- * make register setting relative to default
+- * from INI file & cap value
+- */
+- value = cycpwrThr1_table[level] -
+- cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
+- aniState->iniDef.cycpwrThr1;
+- if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+- value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+- if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+- value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
++ value = (level + 1) * 2;
+ REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+- AR_PHY_TIMING5_CYCPWR_THR1,
+- value);
++ AR_PHY_TIMING5_CYCPWR_THR1, value);
+
+- /*
+- * set AR_PHY_EXT_CCA for extension channel
+- * make register setting relative to default
+- * from INI file & cap value
+- */
+- value2 = cycpwrThr1_table[level] -
+- cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
+- aniState->iniDef.cycpwrThr1Ext;
+- if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+- value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+- if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+- value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+- AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
++ if (IS_CHAN_HT40(ah->curchan))
++ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
++ AR_PHY_EXT_TIMING5_CYCPWR_THR1, value);
+ if (level != aniState->spurImmunityLevel) {
+ ath_dbg(common, ANI,
+@@ -1124,7 +1061,7 @@ static bool ar5008_hw_ani_control_new(st
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL,
+- value2,
++ value,
+ aniState->iniDef.cycpwrThr1Ext);
+ if (level > aniState->spurImmunityLevel)
+ ah->stats.ast_ani_spurup++;
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2092,7 +2092,7 @@ static int ieee80211_scan(struct wiphy *
+@@ -2148,7 +2148,7 @@ static int ieee80211_scan(struct wiphy *
* the frames sent while scanning on other channel will be
* lost)
*/
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
-@@ -11,7 +11,7 @@ obj-$(CPTCFG_ATH_COMMON) += ath.o
- ath-objs := main.o \
+@@ -13,8 +13,8 @@ ath-objs := main.o \
regd.o \
hw.o \
-- key.o
-+ key.o \
-+ debug.o
+ key.o \
++ debug.o \
+ dfs_pattern_detector.o \
+ dfs_pri_detector.o
-ath-$(CPTCFG_ATH_DEBUG) += debug.o
ccflags-y += -D__CHECK_ENDIAN__
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
-@@ -280,13 +280,6 @@ void _ath_dbg(struct ath_common *common,
+@@ -282,13 +282,6 @@ void _ath_dbg(struct ath_common *common,
#endif /* CPTCFG_ATH_DEBUG */
/** Returns string describing opmode, or NULL if unknown mode. */
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -17,6 +17,7 @@
- #include <linux/io.h>
- #include <linux/slab.h>
+@@ -19,6 +19,7 @@
#include <linux/module.h>
+ #include <linux/time.h>
+ #include <linux/bitops.h>
+#include <linux/etherdevice.h>
#include <asm/unaligned.h>
#include "hw.h"
-@@ -518,8 +519,16 @@ static int ath9k_hw_init_macaddr(struct
+@@ -449,8 +450,16 @@ static int ath9k_hw_init_macaddr(struct
common->macaddr[2 * i] = eeval >> 8;
common->macaddr[2 * i + 1] = eeval & 0xff;
}
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
-@@ -196,6 +196,10 @@ ath_reg_apply_beaconing_flags(struct wip
+@@ -341,6 +341,10 @@ ath_reg_apply_beaconing_flags(struct wip
struct ieee80211_channel *ch;
unsigned int i;
+#endif
+
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-
if (!wiphy->bands[band])
-@@ -250,6 +254,10 @@ ath_reg_apply_active_scan_flags(struct w
- struct ieee80211_channel *ch;
- const struct ieee80211_reg_rule *reg_rule;
+ continue;
+@@ -374,6 +378,10 @@ ath_reg_apply_ir_flags(struct wiphy *wip
+ {
+ struct ieee80211_supported_band *sband;
+#ifdef CPTCFG_ATH_USER_REGD
+ return;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
if (!sband)
return;
-@@ -299,6 +307,10 @@ static void ath_reg_apply_radar_flags(st
+@@ -402,6 +410,10 @@ static void ath_reg_apply_radar_flags(st
struct ieee80211_channel *ch;
unsigned int i;
if (!wiphy->bands[IEEE80211_BAND_5GHZ])
return;
-@@ -503,6 +515,10 @@ ath_regd_init_wiphy(struct ath_regulator
+@@ -631,6 +643,10 @@ ath_regd_init_wiphy(struct ath_regulator
{
const struct ieee80211_regdomain *regd;
+#endif
+
wiphy->reg_notifier = reg_notifier;
- wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
-
+ wiphy->regulatory_flags |= REGULATORY_STRICT_REG |
+ REGULATORY_CUSTOM_REG;
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -21,6 +21,9 @@ menuconfig ATH_CARDS
---help---
--- a/.local-symbols
+++ b/.local-symbols
-@@ -123,6 +123,7 @@ RTL8187_LEDS=
+@@ -119,6 +119,7 @@ RTL8187_LEDS=
ATH_COMMON=
ATH_CARDS=
ATH_DEBUG=
+ATH_USER_REGD=
+ ATH_REG_DYNAMIC_USER_REG_HINTS=
+ ATH_REG_DYNAMIC_USER_CERT_TESTING=
ATH5K=
- ATH5K_DEBUG=
- ATH5K_TRACER=
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
-@@ -42,7 +42,8 @@ static int __ath_regd_init(struct ath_re
- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
+@@ -43,7 +43,8 @@ static int __ath_regd_init(struct ath_re
+ NL80211_RRF_NO_OFDM)
/* We allow IBSS on these on a case by case basis by regulatory domain */
-#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
-+#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5250, 80, 0, 30, 0), \
-+ REG_RULE(5250, 5350+10, 80, 0, 30,\
- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
++#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\
++ REG_RULE(5260-10, 5350+10, 80, 0, 30,\
+ NL80211_RRF_NO_IR)
#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
-@@ -60,57 +61,56 @@ static int __ath_regd_init(struct ath_re
+ NL80211_RRF_NO_IR)
+@@ -61,57 +62,56 @@ static int __ath_regd_init(struct ath_re
#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
ATH9K_5GHZ_5725_5850
+ )
};
- static inline bool is_wwr_sku(u16 regd)
+ static bool dynamic_country_user_possible(struct ath_regulatory *reg)
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
-@@ -1696,6 +1696,8 @@ void regulatory_hint_11d(struct wiphy *w
+@@ -1878,6 +1878,8 @@ void regulatory_hint_country_ie(struct w
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request = NULL, *lr;
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
return;
-@@ -1890,6 +1892,7 @@ static void restore_regulatory_settings(
+@@ -2072,6 +2074,7 @@ static void restore_regulatory_settings(
void regulatory_hint_disconnect(void)
{
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -755,6 +755,7 @@ static const struct ieee80211_iface_limi
+@@ -866,6 +866,7 @@ static const struct ieee80211_iface_limi
#endif
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) },
+ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
};
-
+ static const struct ieee80211_iface_limit if_dfs_limits[] = {
goto end;
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
-@@ -1916,7 +1916,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
+@@ -1934,7 +1934,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
}
if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +
ah->opmode == NL80211_IFTYPE_MESH_POINT) {
u64 tsf = ath5k_hw_get_tsf64(ah);
u32 tsftu = TSF_TO_TU(tsf);
-@@ -2002,7 +2002,7 @@ ath5k_beacon_update_timers(struct ath5k_
+@@ -2020,7 +2020,7 @@ ath5k_beacon_update_timers(struct ath5k_
intval = ah->bintval & AR5K_BEACON_PERIOD;
if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs
intval /= ATH_BCBUF; /* staggered multi-bss beacons */
if (intval < 15)
ATH5K_WARN(ah, "intval %u is too low, min 15\n",
-@@ -2469,6 +2469,7 @@ static const struct ieee80211_iface_limi
+@@ -2487,6 +2487,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_AP) },
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
-@@ -811,6 +811,89 @@ static const struct file_operations fops
+@@ -821,6 +821,97 @@ static const struct file_operations fops
.llseek = default_llseek,
};
+ char buf[15];
+ unsigned int len = 0;
+
-+ int cur_ah_bwmode = ah->ah_bwmode;
++ int cur_ah_bwmode = ah->ah_bwmode_debug;
+
+#define print_selected(MODE, LABEL) \
+ if (cur_ah_bwmode == MODE) \
+ bw, tobwmode);
+
+ switch (ah->ah_radio) {
-+ /* TODO: only define radios that actually support 5/10mhz channels */
-+ case AR5K_RF5413: case AR5K_RF5110: case AR5K_RF5111: case AR5K_RF5112: case AR5K_RF2413: case AR5K_RF2316: case AR5K_RF2317: case AR5K_RF2425:
-+ if(ah->ah_bwmode != tobwmode) {
-+ mutex_lock(&ah->lock);
-+ ah->ah_bwmode = tobwmode;
-+ mutex_unlock(&ah->lock);
-+ }
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
++ /* TODO: only define radios that actually support 5/10mhz channels */
++ case AR5K_RF5413:
++ case AR5K_RF5110:
++ case AR5K_RF5111:
++ case AR5K_RF5112:
++ case AR5K_RF2413:
++ case AR5K_RF2316:
++ case AR5K_RF2317:
++ case AR5K_RF2425:
++ if(ah->ah_bwmode_debug != tobwmode) {
++ mutex_lock(&ah->lock);
++ ah->ah_bwmode = tobwmode;
++ ah->ah_bwmode_debug = tobwmode;
++ mutex_unlock(&ah->lock);
++ }
++ break;
++ default:
++ return -EOPNOTSUPP;
+ }
+ return count;
+}
/* debugfs: queues etc */
-@@ -902,6 +985,9 @@ ath5k_debug_init_device(struct ath5k_hw
+@@ -914,6 +1005,9 @@ ath5k_debug_init_device(struct ath5k_hw
debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
&fops_beacon);
debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset);
debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah,
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1369,6 +1369,7 @@ struct ath5k_hw {
+ u8 ah_coverage_class;
+ bool ah_ack_bitrate_high;
+ u8 ah_bwmode;
++ u8 ah_bwmode_debug;
+ bool ah_short_slot;
+
+ /* Antenna Control */
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru
+ return -EINVAL;
+ }
+
++ if (ah->ah_bwmode_debug != AR5K_BWMODE_DEFAULT)
++ ah->ah_bwmode = ah->ah_bwmode_debug;
++
+ /*
+ * To switch channels clear any pending DMA operations;
+ * wait long enough for the RX fifo to drain, reset the
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1735,6 +1735,53 @@ void ath9k_deinit_debug(struct ath_softc
- }
+@@ -1481,6 +1481,53 @@ void ath9k_deinit_debug(struct ath_softc
+ ath9k_spectral_deinit_debug(sc);
}
+static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1752,6 +1799,8 @@ int ath9k_init_debug(struct ath_hw *ah)
-
- ath9k_dfs_init_debug(sc);
+@@ -1500,6 +1547,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ ath9k_tx99_init_debug(sc);
+ ath9k_spectral_init_debug(sc);
+ debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_eeprom);
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -739,6 +739,7 @@ enum ath_cal_list {
+@@ -724,6 +724,7 @@ enum ath_cal_list {
#define AH_USE_EEPROM 0x1
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
#define AH_FASTCC 0x4
struct ath_ops reg_ops;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -613,6 +613,8 @@ static int ath9k_init_softc(u16 devid, s
+@@ -722,6 +722,8 @@ static int ath9k_init_softc(u16 devid, s
ah->is_clk_25mhz = pdata->is_clk_25mhz;
ah->get_mac_revision = pdata->get_mac_revision;
ah->external_reset = pdata->external_reset;
+ ah->ah_flags |= AH_NO_EEP_SWAP;
}
- common = ath9k_hw_common(ah);
+ common->ops = &ah->reg_ops;
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
@@ -31,6 +31,7 @@ struct ath9k_platform_data {
+ bool endian_check;
bool is_clk_25mhz;
- int (*get_mac_revision)(void);
- int (*external_reset)(void);
+ bool tx_gain_buffalo;
+
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -1011,23 +1011,23 @@ static int __init ath9k_init(void)
+@@ -1112,23 +1112,23 @@ static int __init ath9k_init(void)
goto err_out;
}
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2010,8 +2010,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
- REG_WRITE(ah, AR_OBS, 8);
+@@ -359,13 +359,8 @@ static void ath9k_hw_init_config(struct
- if (ah->config.rx_intr_mitigation) {
-- REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
-- REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
-+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 250);
-+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 500);
- }
+ ah->config.rx_intr_mitigation = true;
- if (ah->config.tx_intr_mitigation) {
+- if (AR_SREV_9300_20_OR_LATER(ah)) {
+- ah->config.rimt_last = 500;
+- ah->config.rimt_first = 2000;
+- } else {
+- ah->config.rimt_last = 250;
+- ah->config.rimt_first = 700;
+- }
++ ah->config.rimt_last = 250;
++ ah->config.rimt_first = 500;
+
+ /*
+ * We need this for PCI devices only (Cardbus, PCI, miniPCI)
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -119,7 +119,7 @@ int ath_descdma_setup(struct ath_softc *
- /* RX / TX */
- /***********/
+@@ -90,7 +90,7 @@ int ath_descdma_setup(struct ath_softc *
+ (_l) &= ((_sz) - 1); \
+ } while (0)
-#define ATH_RXBUF 512
+#define ATH_RXBUF 256
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -701,6 +701,7 @@ struct ath_softc {
- struct ieee80211_hw *hw;
- struct device *dev;
-
-+ u32 chan_bw;
- struct survey_info *cur_survey;
- struct survey_info survey[ATH9K_NUM_CHANNELS];
-
-@@ -905,6 +906,7 @@ struct fft_sample_ht20 {
- u8 data[SPECTRAL_HT20_NUM_BINS];
- } __packed;
-
-+int ath9k_config(struct ieee80211_hw *hw, u32 changed);
- void ath9k_tasklet(unsigned long data);
- int ath_cabq_update(struct ath_softc *);
-
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1782,6 +1782,50 @@ static const struct file_operations fops
+@@ -1528,6 +1528,52 @@ static const struct file_operations fops
.owner = THIS_MODULE
};
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
++ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ char buf[32];
+ unsigned int len;
+
-+ len = sprintf(buf, "0x%08x\n", sc->chan_bw);
++ len = sprintf(buf, "0x%08x\n", common->chan_bw);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
++ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ unsigned long chan_bw;
+ char buf[32];
+ ssize_t len;
+ if (kstrtoul(buf, 0, &chan_bw))
+ return -EINVAL;
+
-+ sc->chan_bw = chan_bw;
++ common->chan_bw = chan_bw;
+ if (!test_bit(SC_OP_INVALID, &sc->sc_flags))
-+ ath9k_config(sc->hw, IEEE80211_CONF_CHANGE_CHANNEL);
++ ath9k_ops.config(sc->hw, IEEE80211_CONF_CHANGE_CHANNEL);
+
+ return count;
+}
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1801,6 +1845,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1549,6 +1595,8 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_eeprom);
debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_dma);
debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1138,7 +1138,7 @@ int ath9k_spectral_scan_config(struct ie
- return 0;
- }
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -130,6 +130,7 @@ struct ath_common {
+ struct ieee80211_hw *hw;
+ int debug_mask;
+ enum ath_device_state state;
++ u32 chan_bw;
--static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
-+int ath9k_config(struct ieee80211_hw *hw, u32 changed)
+ struct ath_ani ani;
+
+--- a/drivers/net/wireless/ath/ath9k/common.c
++++ b/drivers/net/wireless/ath/ath9k/common.c
+@@ -52,11 +52,13 @@ EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_ke
+ /*
+ * Update internal channel flags.
+ */
+-static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
++static void ath9k_cmn_update_ichannel(struct ath_common *common,
++ struct ath9k_channel *ichan,
+ struct cfg80211_chan_def *chandef)
{
- struct ath_softc *sc = hw->priv;
- struct ath_hw *ah = sc->sc_ah;
-@@ -1194,9 +1194,11 @@ static int ath9k_config(struct ieee80211
- struct ieee80211_channel *curchan = hw->conf.chandef.chan;
- enum nl80211_channel_type channel_type =
- cfg80211_get_chandef_type(&conf->chandef);
-+ struct ath9k_channel *hchan;
- int pos = curchan->hw_value;
- int old_pos = -1;
- unsigned long flags;
-+ u32 oldflags;
+ struct ieee80211_channel *chan = chandef->chan;
+ u16 flags = 0;
++ int width;
- if (ah->curchan)
- old_pos = ah->curchan - &ah->channels[0];
-@@ -1232,7 +1234,23 @@ static int ath9k_config(struct ieee80211
- memset(&sc->survey[pos], 0, sizeof(struct survey_info));
- }
+ ichan->channel = chan->center_freq;
+ ichan->chan = chan;
+@@ -64,7 +66,19 @@ static void ath9k_cmn_update_ichannel(st
+ if (chan->band == IEEE80211_BAND_5GHZ)
+ flags |= CHANNEL_5GHZ;
-- if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
-+ hchan = &sc->sc_ah->channels[pos];
-+ oldflags = hchan->channelFlags;
-+ switch (sc->chan_bw) {
-+ case 5:
-+ hchan->channelFlags &= ~CHANNEL_HALF;
-+ hchan->channelFlags |= CHANNEL_QUARTER;
-+ break;
-+ case 10:
-+ hchan->channelFlags &= ~CHANNEL_QUARTER;
-+ hchan->channelFlags |= CHANNEL_HALF;
-+ break;
-+ default:
-+ hchan->channelFlags &= ~(CHANNEL_HALF | CHANNEL_QUARTER);
-+ break;
-+ }
+- switch (chandef->width) {
++ switch (common->chan_bw) {
++ case 5:
++ width = NL80211_CHAN_WIDTH_5;
++ break;
++ case 10:
++ width = NL80211_CHAN_WIDTH_10;
++ break;
++ default:
++ width = chandef->width;
++ break;
++ }
+
-+ if (ath_set_channel(sc, hw, hchan) < 0) {
- ath_err(common, "Unable to set channel\n");
- mutex_unlock(&sc->mutex);
- ath9k_ps_restore(sc);
++ switch (width) {
+ case NL80211_CHAN_WIDTH_5:
+ flags |= CHANNEL_QUARTER;
+ break;
+@@ -97,10 +111,11 @@ struct ath9k_channel *ath9k_cmn_get_chan
+ struct cfg80211_chan_def *chandef)
+ {
+ struct ieee80211_channel *curchan = chandef->chan;
++ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_channel *channel;
+
+ channel = &ah->channels[curchan->hw_value];
+- ath9k_cmn_update_ichannel(channel, chandef);
++ ath9k_cmn_update_ichannel(common, channel, chandef);
+
+ return channel;
+ }
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -614,6 +614,7 @@ int ath9k_hw_init(struct ath_hw *ah)
+
+ /* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */
+ switch (ah->hw_version.devid) {
++ case AR9300_DEVID_INVALID:
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ case AR5416_AR9100_DEVID:
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -34,6 +34,7 @@
+
+ #define ATHEROS_VENDOR_ID 0x168c
+
++#define AR9300_DEVID_INVALID 0xabcd
+ #define AR5416_DEVID_PCI 0x0023
+ #define AR5416_DEVID_PCIE 0x0024
+ #define AR9160_DEVID_PCI 0x0027
+--- a/drivers/net/wireless/ath/ath9k/pci.c
++++ b/drivers/net/wireless/ath/ath9k/pci.c
+@@ -658,6 +658,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_i
+ { PCI_VDEVICE(ATHEROS, 0x0036),
+ .driver_data = ATH9K_PCI_BT_ANT_DIV },
+
++ { PCI_VDEVICE(ATHEROS, 0xabcd) }, /* PCI-E internal chip default ID */
+ { 0 }
+ };
+
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -1616,6 +1616,7 @@ struct ieee80211_hw {
+@@ -1711,6 +1711,7 @@ struct ieee80211_hw {
u8 max_tx_aggregation_subframes;
u8 offchannel_tx_hw_queue;
u8 radiotap_mcs_details;
u8 uapsd_queues;
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2273,7 +2273,9 @@ static int ieee80211_get_tx_power(struct
+@@ -2329,7 +2329,9 @@ static int ieee80211_get_tx_power(struct
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
*dbm = sdata->vif.bss_conf.txpower;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -167,6 +167,7 @@ static u32 ieee80211_hw_conf_chan(struct
+@@ -158,6 +158,7 @@ static u32 ieee80211_hw_conf_chan(struct
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1257,6 +1257,8 @@ int ath9k_config(struct ieee80211_hw *hw
- return -EINVAL;
- }
+@@ -308,8 +308,12 @@ static int ath_reset_internal(struct ath
+ (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
+ ath9k_mci_set_txpower(sc, true, false);
-+ hw->cur_power_level = sc->curtxpow / 2;
+- if (!ath_complete_reset(sc, true))
++ if (!ath_complete_reset(sc, true)) {
+ r = -EIO;
++ goto out;
++ }
+
- /*
- * The most recent snapshot of channel->noisefloor for the old
- * channel is only available after the hardware reset. Copy it to
-@@ -1293,6 +1295,7 @@ int ath9k_config(struct ieee80211_hw *hw
++ sc->hw->cur_power_level = sc->curtxpow / 2;
+
+ out:
+ spin_unlock_bh(&sc->sc_pcu_lock);
+@@ -1371,6 +1375,7 @@ static int ath9k_config(struct ieee80211
sc->config.txpowlimit = 2 * conf->power_level;
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->config.txpowlimit, &sc->curtxpow);
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/mac.h
-+++ b/drivers/net/wireless/ath/ath9k/mac.h
-@@ -133,12 +133,8 @@ struct ath_rx_status {
- u8 rs_rate;
- u8 rs_antenna;
- u8 rs_more;
-- int8_t rs_rssi_ctl0;
-- int8_t rs_rssi_ctl1;
-- int8_t rs_rssi_ctl2;
-- int8_t rs_rssi_ext0;
-- int8_t rs_rssi_ext1;
-- int8_t rs_rssi_ext2;
-+ int8_t rs_rssi_ctl[3];
-+ int8_t rs_rssi_ext[3];
- u8 rs_isaggr;
- u8 rs_moreaggr;
- u8 rs_num_delims;
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -939,6 +939,7 @@ static int ath9k_rx_skb_preprocess(struc
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- bool discard_current = sc->rx.discard_next;
-+ int i, j;
-
- sc->rx.discard_next = rx_stats->rs_more;
- if (discard_current)
-@@ -968,6 +969,21 @@ static int ath9k_rx_skb_preprocess(struc
- if (rx_stats->rs_moreaggr)
- rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
-
-+ for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
-+ s8 rssi;
-+
-+ if (!(ah->rxchainmask & BIT(i)))
-+ continue;
-+
-+ rssi = rx_stats->rs_rssi_ctl[i];
-+ if (rssi != ATH9K_RSSI_BAD) {
-+ rx_status->chains |= BIT(j);
-+ rx_status->chain_signal[j] = ah->noise + rssi;
-+ }
-+ j++;
-+ }
-+
-+
- sc->rx.discard_next = false;
- return 0;
- }
-@@ -1077,7 +1093,7 @@ static int ath_process_fft(struct ath_so
- fft_sample.tlv.length = __cpu_to_be16(length);
-
- fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
-- fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
-+ fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
- fft_sample.noise = ah->noise;
-
- switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
---- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -476,12 +476,12 @@ int ath9k_hw_process_rxdesc_edma(struct
-
- /* XXX: Keycache */
- rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
-- rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00);
-- rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01);
-- rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02);
-- rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10);
-- rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11);
-- rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12);
-+ rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00);
-+ rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01);
-+ rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02);
-+ rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10);
-+ rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11);
-+ rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12);
-
- if (rxsp->status11 & AR_RxKeyIdxValid)
- rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx);
---- a/drivers/net/wireless/ath/ath9k/mac.c
-+++ b/drivers/net/wireless/ath/ath9k/mac.c
-@@ -554,25 +554,25 @@ int ath9k_hw_rxprocdesc(struct ath_hw *a
-
- if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
- rs->rs_rssi = ATH9K_RSSI_BAD;
-- rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
-- rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
-- rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
-- rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
-- rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
-- rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
-+ rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD;
-+ rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD;
-+ rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD;
-+ rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD;
-+ rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD;
-+ rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;
- } else {
- rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
-- rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
-+ rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,
- AR_RxRSSIAnt00);
-- rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
-+ rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,
- AR_RxRSSIAnt01);
-- rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
-+ rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,
- AR_RxRSSIAnt02);
-- rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
-+ rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,
- AR_RxRSSIAnt10);
-- rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
-+ rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,
- AR_RxRSSIAnt11);
-- rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
-+ rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,
- AR_RxRSSIAnt12);
- }
- if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
---- a/drivers/net/wireless/ath/ath9k/dfs.c
-+++ b/drivers/net/wireless/ath/ath9k/dfs.c
-@@ -158,8 +158,8 @@ void ath9k_dfs_process_phyerr(struct ath
- return;
- }
-
-- ard.rssi = rs->rs_rssi_ctl0;
-- ard.ext_rssi = rs->rs_rssi_ext0;
-+ ard.rssi = rs->rs_rssi_ctl[0];
-+ ard.ext_rssi = rs->rs_rssi_ext[0];
-
- /*
- * hardware stores this as 8 bit signed value.
---- a/drivers/net/wireless/ath/ath9k/antenna.c
-+++ b/drivers/net/wireless/ath/ath9k/antenna.c
-@@ -546,14 +546,14 @@ void ath_ant_comb_scan(struct ath_softc
- struct ath_ant_comb *antcomb = &sc->ant_comb;
- int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
- int curr_main_set;
-- int main_rssi = rs->rs_rssi_ctl0;
-- int alt_rssi = rs->rs_rssi_ctl1;
-+ int main_rssi = rs->rs_rssi_ctl[0];
-+ int alt_rssi = rs->rs_rssi_ctl[1];
- int rx_ant_conf, main_ant_conf;
- bool short_scan = false;
-
-- rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
-+ rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
- ATH_ANT_RX_MASK;
-- main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
-+ main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
- ATH_ANT_RX_MASK;
-
- /* Record packet only when both main_rssi and alt_rssi is positive */
--- /dev/null
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -2156,6 +2156,7 @@ struct cfg80211_qos_map {
+ * (as advertised by the nl80211 feature flag.)
+ * @get_tx_power: store the current TX power into the dbm variable;
+ * return 0 if successful
++ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
+ *
+ * @set_wds_peer: set the WDS peer for a WDS interface
+ *
+@@ -2380,6 +2381,7 @@ struct cfg80211_ops {
+ enum nl80211_tx_power_setting type, int mbm);
+ int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
+ int *dbm);
++ int (*set_antenna_gain)(struct wiphy *wiphy, int dbi);
+
+ int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *addr);
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1033,6 +1033,7 @@ enum ieee80211_smps_mode {
+ *
+ * @power_level: requested transmit power (in dBm), backward compatibility
+ * value only that is set to the minimum of all interfaces
++ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
+ *
+ * @chandef: the channel definition to tune to
+ * @radar_enabled: whether radar detection is enabled
+@@ -1054,6 +1055,7 @@ struct ieee80211_conf {
+ u32 flags;
+ int power_level, dynamic_ps_timeout;
+ int max_sleep_period;
++ int max_antenna_gain;
+
+ u16 listen_interval;
+ u8 ps_dtim_period;
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -1555,6 +1555,9 @@ enum nl80211_commands {
+ * data is in the format defined for the payload of the QoS Map Set element
+ * in IEEE Std 802.11-2012, 8.4.2.97.
+ *
++ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
++ * transmit power to stay within regulatory limits. u32, dBi.
++ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+@@ -1883,6 +1886,8 @@ enum nl80211_attrs {
+
+ NL80211_ATTR_QOS_MAP,
+
++ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
++
+ /* add attributes here, update the policy in nl80211.c */
+
+ __NL80211_ATTR_AFTER_LAST,
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2339,6 +2339,19 @@ static int ieee80211_get_tx_power(struct
+ return 0;
+ }
+
++static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
++{
++ struct ieee80211_local *local = wiphy_priv(wiphy);
++
++ if (dbi < 0)
++ return -EINVAL;
++
++ local->user_antenna_gain = dbi;
++ ieee80211_hw_config(local, 0);
++
++ return 0;
++}
++
+ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *addr)
+ {
+@@ -3924,6 +3937,7 @@ struct cfg80211_ops mac80211_config_ops
+ .set_wiphy_params = ieee80211_set_wiphy_params,
+ .set_tx_power = ieee80211_set_tx_power,
+ .get_tx_power = ieee80211_get_tx_power,
++ .set_antenna_gain = ieee80211_set_antenna_gain,
+ .set_wds_peer = ieee80211_set_wds_peer,
+ .rfkill_poll = ieee80211_rfkill_poll,
+ CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1221,6 +1221,7 @@ struct ieee80211_local {
+ int dynamic_ps_forced_timeout;
+
+ int user_power_level; /* in dBm, for all interfaces */
++ int user_antenna_gain; /* in dBi */
+
+ enum ieee80211_smps_mode smps_mode;
+
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -101,7 +101,7 @@ static u32 ieee80211_hw_conf_chan(struct
+ struct ieee80211_sub_if_data *sdata;
+ struct cfg80211_chan_def chandef = {};
+ u32 changed = 0;
+- int power;
++ int power, ant_gain, max_power;
+ u32 offchannel_flag;
+
+ offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
+@@ -156,8 +156,21 @@ static u32 ieee80211_hw_conf_chan(struct
+ }
+ rcu_read_unlock();
+
+- if (local->hw.conf.power_level != power) {
++ max_power = chandef.chan->max_reg_power;
++ ant_gain = chandef.chan->max_antenna_gain;
++ if (local->user_antenna_gain > 0) {
++ if (local->user_antenna_gain > ant_gain) {
++ max_power -= local->user_antenna_gain - ant_gain;
++ ant_gain = 0;
++ } else
++ ant_gain -= local->user_antenna_gain;
++ power = min(power, max_power);
++ }
++
++ if (local->hw.conf.power_level != power ||
++ local->hw.conf.max_antenna_gain != ant_gain) {
+ changed |= IEEE80211_CONF_CHANGE_POWER;
++ local->hw.conf.max_antenna_gain = ant_gain;
+ local->hw.cur_power_level = power;
+ local->hw.conf.power_level = power;
+ }
+@@ -584,6 +597,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+ IEEE80211_RADIOTAP_MCS_HAVE_BW;
+ local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
+ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
++ local->user_antenna_gain = 0;
+ local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
+ local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
+ local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -384,6 +384,7 @@ static const struct nla_policy nl80211_p
+ [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
+ [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
+ .len = IEEE80211_QOS_MAP_LEN_MAX },
++ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
+ };
+
+ /* policy for the key attributes */
+@@ -2105,6 +2106,22 @@ static int nl80211_set_wiphy(struct sk_b
+ goto bad_res;
+ }
+
++ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
++ int idx, dbi = 0;
++
++ if (!rdev->ops->set_antenna_gain) {
++ result = -EOPNOTSUPP;
++ goto bad_res;
++ }
++
++ idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN;
++ dbi = nla_get_u32(info->attrs[idx]);
++
++ result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi);
++ if (result)
++ goto bad_res;
++ }
++
+ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
+ info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
+ u32 tx_ant, rx_ant;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -74,6 +74,7 @@ struct ath_regulatory {
+ u16 max_power_level;
+ u16 current_rd;
+ int16_t power_limit;
++ int16_t max_antenna_gain;
+ struct reg_dmn_pair_mapping *regpair;
+ };
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2721,7 +2721,7 @@ void ath9k_hw_apply_txpower(struct ath_h
+ channel = chan->chan;
+ chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
+ new_pwr = min_t(int, chan_pwr, reg->power_limit);
+- max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
++ max_gain = chan_pwr - new_pwr + reg->max_antenna_gain * 2;
+
+ ant_gain = get_antenna_gain(ah, chan);
+ if (ant_gain > max_gain)
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1371,7 +1371,10 @@ static int ath9k_config(struct ieee80211
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
++ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
++
+ ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
++ reg->max_antenna_gain = conf->max_antenna_gain;
+ sc->config.txpowlimit = 2 * conf->power_level;
+ ath9k_cmn_update_txpow(ah, sc->curtxpow,
+ sc->config.txpowlimit, &sc->curtxpow);
+++ /dev/null
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -999,6 +999,7 @@ enum ieee80211_smps_mode {
- *
- * @power_level: requested transmit power (in dBm), backward compatibility
- * value only that is set to the minimum of all interfaces
-+ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
- *
- * @chandef: the channel definition to tune to
- * @radar_enabled: whether radar detection is enabled
-@@ -1020,6 +1021,7 @@ struct ieee80211_conf {
- u32 flags;
- int power_level, dynamic_ps_timeout;
- int max_sleep_period;
-+ int max_antenna_gain;
-
- u16 listen_interval;
- u8 ps_dtim_period;
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1126,6 +1126,7 @@ struct ieee80211_local {
- int dynamic_ps_forced_timeout;
-
- int user_power_level; /* in dBm, for all interfaces */
-+ int user_antenna_gain; /* in dBi */
-
- enum ieee80211_smps_mode smps_mode;
-
---- a/include/uapi/linux/nl80211.h
-+++ b/include/uapi/linux/nl80211.h
-@@ -1736,6 +1736,8 @@ enum nl80211_attrs {
-
- NL80211_ATTR_PEER_AID,
-
-+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
-+
- /* add attributes here, update the policy in nl80211.c */
-
- __NL80211_ATTR_AFTER_LAST,
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -349,6 +349,7 @@ static const struct nla_policy nl80211_p
- [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
- .len = IEEE80211_MAX_DATA_LEN },
- [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
-+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
- };
-
- /* policy for the key attributes */
-@@ -1993,6 +1994,22 @@ static int nl80211_set_wiphy(struct sk_b
- goto bad_res;
- }
-
-+ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
-+ int idx, dbi = 0;
-+
-+ if (!rdev->ops->set_antenna_gain) {
-+ result = -EOPNOTSUPP;
-+ goto bad_res;
-+ }
-+
-+ idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN;
-+ dbi = nla_get_u32(info->attrs[idx]);
-+
-+ result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi);
-+ if (result)
-+ goto bad_res;
-+ }
-+
- if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
- info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
- u32 tx_ant, rx_ant;
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -2283,6 +2283,19 @@ static int ieee80211_get_tx_power(struct
- return 0;
- }
-
-+static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
-+{
-+ struct ieee80211_local *local = wiphy_priv(wiphy);
-+
-+ if (dbi < 0)
-+ return -EINVAL;
-+
-+ local->user_antenna_gain = dbi;
-+ ieee80211_hw_config(local, 0);
-+
-+ return 0;
-+}
-+
- static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
- const u8 *addr)
- {
-@@ -3474,6 +3487,7 @@ struct cfg80211_ops mac80211_config_ops
- .set_wiphy_params = ieee80211_set_wiphy_params,
- .set_tx_power = ieee80211_set_tx_power,
- .get_tx_power = ieee80211_get_tx_power,
-+ .set_antenna_gain = ieee80211_set_antenna_gain,
- .set_wds_peer = ieee80211_set_wds_peer,
- .rfkill_poll = ieee80211_rfkill_poll,
- CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -1970,6 +1970,7 @@ struct cfg80211_update_ft_ies_params {
- * (as advertised by the nl80211 feature flag.)
- * @get_tx_power: store the current TX power into the dbm variable;
- * return 0 if successful
-+ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
- *
- * @set_wds_peer: set the WDS peer for a WDS interface
- *
-@@ -2189,6 +2190,7 @@ struct cfg80211_ops {
- enum nl80211_tx_power_setting type, int mbm);
- int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int *dbm);
-+ int (*set_antenna_gain)(struct wiphy *wiphy, int dbi);
-
- int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
- const u8 *addr);
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -102,6 +102,7 @@ static u32 ieee80211_hw_conf_chan(struct
- struct cfg80211_chan_def chandef = {};
- u32 changed = 0;
- int power = 0;
-+ int ant_gain, max_power;
- u32 offchannel_flag;
-
- offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
-@@ -165,8 +166,21 @@ static u32 ieee80211_hw_conf_chan(struct
-
- power = min(power, chandef.chan->max_power);
-
-- if (local->hw.conf.power_level != power) {
-+ max_power = chandef.chan->max_reg_power;
-+ ant_gain = chandef.chan->max_antenna_gain;
-+ if (local->user_antenna_gain > 0) {
-+ if (local->user_antenna_gain > ant_gain) {
-+ max_power -= local->user_antenna_gain - ant_gain;
-+ ant_gain = 0;
-+ } else
-+ ant_gain -= local->user_antenna_gain;
-+ power = min(power, max_power);
-+ }
-+
-+ if (local->hw.conf.power_level != power ||
-+ local->hw.conf.max_antenna_gain != ant_gain) {
- changed |= IEEE80211_CONF_CHANGE_POWER;
-+ local->hw.conf.max_antenna_gain = ant_gain;
- local->hw.cur_power_level = power;
- local->hw.conf.power_level = power;
- }
-@@ -597,6 +611,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
- IEEE80211_RADIOTAP_MCS_HAVE_BW;
- local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
- IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
-+ local->user_antenna_gain = 0;
- local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
- local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
- local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+++ /dev/null
---- a/drivers/net/wireless/ath/ath.h
-+++ b/drivers/net/wireless/ath/ath.h
-@@ -73,6 +73,7 @@ struct ath_regulatory {
- u16 max_power_level;
- u16 current_rd;
- int16_t power_limit;
-+ int16_t max_antenna_gain;
- struct reg_dmn_pair_mapping *regpair;
- };
-
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2847,7 +2847,7 @@ void ath9k_hw_apply_txpower(struct ath_h
- channel = chan->chan;
- chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
- new_pwr = min_t(int, chan_pwr, reg->power_limit);
-- max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
-+ max_gain = chan_pwr - new_pwr + reg->max_antenna_gain * 2;
-
- ant_gain = get_antenna_gain(ah, chan);
- if (ant_gain > max_gain)
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1291,7 +1291,10 @@ int ath9k_config(struct ieee80211_hw *hw
- }
-
- if (changed & IEEE80211_CONF_CHANGE_POWER) {
-+ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
-+
- ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
-+ reg->max_antenna_gain = conf->max_antenna_gain;
- sc->config.txpowlimit = 2 * conf->power_level;
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
- sc->config.txpowlimit, &sc->curtxpow);
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -557,6 +557,9 @@ struct ath9k_wow_pattern {
+@@ -563,6 +563,9 @@ static inline int ath9k_dump_btcoex(stru
void ath_init_leds(struct ath_softc *sc);
void ath_deinit_leds(struct ath_softc *sc);
void ath_fill_led_pin(struct ath_softc *sc);
#else
static inline void ath_init_leds(struct ath_softc *sc)
{
-@@ -697,6 +700,13 @@ enum spectral_mode {
- SPECTRAL_CHANSCAN,
- };
+@@ -710,6 +713,13 @@ enum sc_op_flags {
+ #define PS_BEACON_SYNC BIT(4)
+ #define PS_WAIT_FOR_ANI BIT(5)
+struct ath_led {
+ struct list_head list;
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
-@@ -739,9 +749,8 @@ struct ath_softc {
+@@ -751,9 +761,8 @@ struct ath_softc {
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
#ifdef CPTCFG_MAC80211_LEDS
void ath_fill_led_pin(struct ath_softc *sc)
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -918,7 +918,7 @@ int ath9k_init_device(u16 devid, struct
+@@ -1018,7 +1018,7 @@ int ath9k_init_device(u16 devid, struct
#ifdef CPTCFG_MAC80211_LEDS
/* must be initialized before ieee80211_register_hw */
#endif
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1825,6 +1825,61 @@ static const struct file_operations fops
+@@ -1573,6 +1573,61 @@ static const struct file_operations fops
.llseek = default_llseek,
};
int ath9k_init_debug(struct ath_hw *ah)
{
-@@ -1847,6 +1902,10 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1597,6 +1652,10 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_eeprom);
debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
sc, &fops_chanbw);
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
-@@ -35,6 +35,9 @@ struct ath9k_platform_data {
- bool is_clk_25mhz;
+@@ -37,6 +37,9 @@ struct ath9k_platform_data {
+
int (*get_mac_revision)(void);
int (*external_reset)(void);
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ani.h
++++ b/drivers/net/wireless/ath/ath9k/ani.h
+@@ -42,7 +42,7 @@
+ #define ATH9K_ANI_PERIOD 300
+
+ /* in ms */
+-#define ATH9K_ANI_POLLINTERVAL 1000
++#define ATH9K_ANI_POLLINTERVAL 300
+
+ #define ATH9K_SIG_FIRSTEP_SETTING_MIN 0
+ #define ATH9K_SIG_FIRSTEP_SETTING_MAX 20
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -241,21 +241,19 @@ static bool ar9003_hw_get_isr(struct ath
-
- *masked = isr & ATH9K_INT_COMMON;
-
-- if (ah->config.rx_intr_mitigation)
-+ if (ah->config.rx_intr_mitigation) {
- if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
- *masked |= ATH9K_INT_RXLP;
--
-- if (ah->config.tx_intr_mitigation)
-- if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
-- *masked |= ATH9K_INT_TX;
--
-- if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
-+ } else if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
- *masked |= ATH9K_INT_RXLP;
-
- if (isr & AR_ISR_HP_RXOK)
- *masked |= ATH9K_INT_RXHP;
-
-- if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
-+ if (ah->config.tx_intr_mitigation) {
-+ if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
-+ *masked |= ATH9K_INT_TX;
-+ } else if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
- *masked |= ATH9K_INT_TX;
-
- if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -700,7 +700,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
+ {
+ #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
+ struct ath_common *common = ath9k_hw_common(ah);
+- u32 mac_status, last_mac_status = 0;
++ u32 mac_status = 0, last_mac_status = 0;
+ int i;
+
+ /* Enable access to the DMA observation bus */
+@@ -730,6 +730,16 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
+ }
+
+ if (i == 0) {
++ if (!AR_SREV_9300_20_OR_LATER(ah) &&
++ (mac_status & 0x700) == 0) {
++ /*
++ * DMA is idle but the MAC is still stuck
++ * processing events
++ */
++ *reset = true;
++ return true;
++ }
++
+ ath_err(common,
+ "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
+ AH_RX_STOP_DMA_TIMEOUT / 1000,
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1629,6 +1629,50 @@ static const struct file_operations fops
+ #endif
+
+
++static ssize_t read_file_diag(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ struct ath_hw *ah = sc->sc_ah;
++ char buf[32];
++ unsigned int len;
++
++ len = sprintf(buf, "0x%08lx\n", ah->diag);
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_diag(struct file *file, const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ struct ath_hw *ah = sc->sc_ah;
++ unsigned long diag;
++ char buf[32];
++ ssize_t len;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ if (kstrtoul(buf, 0, &diag))
++ return -EINVAL;
++
++ ah->diag = diag;
++ ath9k_hw_update_diag(ah);
++
++ return count;
++}
++
++static const struct file_operations fops_diag = {
++ .read = read_file_diag,
++ .write = write_file_diag,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++
+ int ath9k_init_debug(struct ath_hw *ah)
+ {
+ struct ath_common *common = ath9k_hw_common(ah);
+@@ -1656,6 +1700,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ debugfs_create_file("gpio_led", S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_gpio_led);
+ #endif
++ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
++ sc, &fops_diag);
+ debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_dma);
+ debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -482,6 +482,12 @@ enum {
+ ATH9K_RESET_COLD,
+ };
+
++enum {
++ ATH_DIAG_DISABLE_RX,
++ ATH_DIAG_DISABLE_TX,
++ ATH_DIAG_TRIGGER_ERROR,
++};
++
+ struct ath9k_hw_version {
+ u32 magic;
+ u16 devid;
+@@ -762,6 +768,8 @@ struct ath_hw {
+ u32 rfkill_polarity;
+ u32 ah_flags;
+
++ unsigned long diag;
++
+ bool reset_power_on;
+ bool htc_reset_init;
+
+@@ -1013,6 +1021,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
+ bool ath9k_hw_check_alive(struct ath_hw *ah);
+
+ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
++void ath9k_hw_update_diag(struct ath_hw *ah);
+
+ /* Generic hw timer primitives */
+ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1735,6 +1735,20 @@ fail:
+ return -EINVAL;
+ }
+
++void ath9k_hw_update_diag(struct ath_hw *ah)
++{
++ if (test_bit(ATH_DIAG_DISABLE_RX, &ah->diag))
++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
++ else
++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
++
++ if (test_bit(ATH_DIAG_DISABLE_TX, &ah->diag))
++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
++ else
++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
++}
++EXPORT_SYMBOL(ath9k_hw_update_diag);
++
+ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+ struct ath9k_hw_cal_data *caldata, bool fastcc)
+ {
+@@ -1940,6 +1954,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ ar9003_hw_disable_phy_restart(ah);
+
+ ath9k_hw_apply_gpio_override(ah);
++ ath9k_hw_update_diag(ah);
+
+ if (AR_SREV_9565(ah) && common->bt_ant_diversity)
+ REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -602,6 +602,11 @@ irqreturn_t ath_isr(int irq, void *dev)
+ ath9k_debug_sync_cause(sc, sync_cause);
+ status &= ah->imask; /* discard unasked-for bits */
+
++ if (test_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag)) {
++ status |= ATH9K_INT_FATAL;
++ clear_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag);
++ }
++
+ /*
+ * If there are no status bits set, then this interrupt was not
+ * for me (should have been caught above).
--- /dev/null
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -34,6 +34,8 @@ struct ath9k_platform_data {
+ bool endian_check;
+ bool is_clk_25mhz;
+ bool tx_gain_buffalo;
++ bool disable_2ghz;
++ bool disable_5ghz;
+
+ int (*get_mac_revision)(void);
+ int (*external_reset)(void);
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2328,17 +2328,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw
+ }
+
+ eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
+- if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
+- ath_err(common,
+- "no band has been marked as supported in EEPROM\n");
+- return -EINVAL;
++
++ if (eeval & AR5416_OPFLAGS_11A) {
++ if (ah->disable_5ghz)
++ ath_warn(common, "disabling 5GHz band\n");
++ else
++ pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
+ }
+
+- if (eeval & AR5416_OPFLAGS_11A)
+- pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
++ if (eeval & AR5416_OPFLAGS_11G) {
++ if (ah->disable_2ghz)
++ ath_warn(common, "disabling 2GHz band\n");
++ else
++ pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
++ }
+
+- if (eeval & AR5416_OPFLAGS_11G)
+- pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
++ if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) {
++ ath_err(common, "both bands are disabled\n");
++ return -EINVAL;
++ }
+
+ if (AR_SREV_9485(ah) ||
+ AR_SREV_9285(ah) ||
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -932,6 +932,8 @@ struct ath_hw {
+ bool is_clk_25mhz;
+ int (*get_mac_revision)(void);
+ int (*external_reset)(void);
++ bool disable_2ghz;
++ bool disable_5ghz;
+
+ const struct firmware *eeprom_blob;
+ };
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -722,6 +722,8 @@ static int ath9k_init_softc(u16 devid, s
+ ah->is_clk_25mhz = pdata->is_clk_25mhz;
+ ah->get_mac_revision = pdata->get_mac_revision;
+ ah->external_reset = pdata->external_reset;
++ ah->disable_2ghz = pdata->disable_2ghz;
++ ah->disable_5ghz = pdata->disable_5ghz;
+ if (!pdata->endian_check)
+ ah->ah_flags |= AH_NO_EEP_SWAP;
+ }
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -678,6 +678,7 @@ struct ath_spec_scan {
+ * @config_pci_powersave:
+ * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ *
++ * @get_adc_entropy: get entropy from the raw ADC I/Q output
+ * @spectral_scan_config: set parameters for spectral scan and enable/disable it
+ * @spectral_scan_trigger: trigger a spectral scan run
+ * @spectral_scan_wait: wait for a spectral scan run to finish
+@@ -701,6 +702,7 @@ struct ath_hw_ops {
+ struct ath_hw_antcomb_conf *antconf);
+ void (*antdiv_comb_conf_set)(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf);
++ void (*get_adc_entropy)(struct ath_hw *ah, u8 *buf, size_t len);
+ void (*spectral_scan_config)(struct ath_hw *ah,
+ struct ath_spec_scan *param);
+ void (*spectral_scan_trigger)(struct ath_hw *ah);
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -1764,6 +1764,26 @@ static void ar9003_hw_tx99_set_txpower(s
+ ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14], 0));
+ }
+
++static void ar9003_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len)
++{
++ int i, j;
++
++ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
++ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
++ REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0);
++
++ memset(buf, 0, len);
++ for (i = 0; i < len; i++) {
++ for (j = 0; j < 4; j++) {
++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC);
++
++ buf[i] <<= 2;
++ buf[i] |= (regval & 1) | ((regval & BIT(10)) >> 9);
++ udelay(1);
++ }
++ }
++}
++
+ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
+ {
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+@@ -1794,6 +1814,7 @@ void ar9003_hw_attach_phy_ops(struct ath
+ priv_ops->set_radar_params = ar9003_hw_set_radar_params;
+ priv_ops->fast_chan_change = ar9003_hw_fast_chan_change;
+
++ ops->get_adc_entropy = ar9003_hw_get_adc_entropy;
+ ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
+ ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
+ ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -846,7 +846,8 @@ static void ath9k_init_txpower_limits(st
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+ ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
+
+- ah->curchan = curchan;
++ if (curchan)
++ ah->curchan = curchan;
+ }
+
+ void ath9k_reload_chainmask_settings(struct ath_softc *sc)
+@@ -980,6 +981,18 @@ static void ath9k_set_hw_capab(struct at
+ SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
+ }
+
++static void ath_get_initial_entropy(struct ath_softc *sc)
++{
++ struct ath_hw *ah = sc->sc_ah;
++ char buf[256];
++
++ /* reuse last channel initialized by the tx power test */
++ ath9k_hw_reset(ah, ah->curchan, NULL, false);
++
++ ath9k_hw_get_adc_entropy(ah, buf, sizeof(buf));
++ add_device_randomness(buf, sizeof(buf));
++}
++
+ int ath9k_init_device(u16 devid, struct ath_softc *sc,
+ const struct ath_bus_ops *bus_ops)
+ {
+@@ -1025,6 +1038,8 @@ int ath9k_init_device(u16 devid, struct
+ ARRAY_SIZE(ath9k_tpt_blink));
+ #endif
+
++ ath_get_initial_entropy(sc);
++
+ /* Register with mac80211 */
+ error = ieee80211_register_hw(hw);
+ if (error)
+--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
+@@ -95,6 +95,12 @@ static inline void ath9k_hw_tx99_set_txp
+ ath9k_hw_ops(ah)->tx99_set_txpower(ah, power);
+ }
+
++static inline void ath9k_hw_get_adc_entropy(struct ath_hw *ah,
++ u8 *buf, size_t len)
++{
++ ath9k_hw_ops(ah)->get_adc_entropy(ah, buf, len);
++}
++
+ #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
+
+ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
+--- a/drivers/net/wireless/ath/ath9k/link.c
++++ b/drivers/net/wireless/ath/ath9k/link.c
+@@ -307,6 +307,11 @@ void ath_ani_calibrate(unsigned long dat
+ unsigned int timestamp = jiffies_to_msecs(jiffies);
+ u32 cal_interval, short_cal_interval, long_cal_interval;
+ unsigned long flags;
++ char buf[256];
++
++ /* gather entropy */
++ ath9k_hw_get_adc_entropy(ah, buf, sizeof(buf));
++ add_device_randomness(buf, sizeof(buf));
+
+ if (ah->caldata && test_bit(NFCAL_INTF, &ah->caldata->cal_flags))
+ long_cal_interval = ATH_LONG_CALINTERVAL_INT;
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -1233,9 +1233,30 @@ static void ar5008_hw_set_radar_conf(str
+ conf->radar_inband = 8;
+ }
+
++static void ar5008_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len)
++{
++ int i, j;
++
++ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
++ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
++ REG_RMW_FIELD(ah, AR_PHY_TEST2, AR_PHY_TEST2_RX_OBS_SEL, 0);
++
++ memset(buf, 0, len);
++ for (i = 0; i < len; i++) {
++ for (j = 0; j < 4; j++) {
++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC);
++
++ buf[i] <<= 2;
++ buf[i] |= (regval & 1) | ((regval & BIT(9)) >> 8);
++ udelay(1);
++ }
++ }
++}
++
+ int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+ {
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
++ struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+ static const u32 ar5416_cca_regs[6] = {
+ AR_PHY_CCA,
+ AR_PHY_CH1_CCA,
+@@ -1250,6 +1271,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
+ if (ret)
+ return ret;
+
++ ops->get_adc_entropy = ar5008_hw_get_adc_entropy;
++
+ priv_ops->rf_set_freq = ar5008_hw_set_channel;
+ priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
+
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+@@ -20,6 +20,12 @@
+ #define PHY_AGC_CLR 0x10000000
+ #define RFSILENT_BB 0x00002000
+
++#define AR_PHY_TEST_BBB_OBS_SEL 0x780000
++#define AR_PHY_TEST_BBB_OBS_SEL_S 19
++
++#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23
++#define AR_PHY_TEST_RX_OBS_SEL_BIT5 (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S)
++
+ #define AR_PHY_TURBO 0x9804
+ #define AR_PHY_FC_TURBO_MODE 0x00000001
+ #define AR_PHY_FC_TURBO_SHORT 0x00000002
+@@ -36,6 +42,9 @@
+
+ #define AR_PHY_TEST2 0x9808
+
++#define AR_PHY_TEST2_RX_OBS_SEL 0x3C00
++#define AR_PHY_TEST2_RX_OBS_SEL_S 10
++
+ #define AR_PHY_TIMING2 0x9810
+ #define AR_PHY_TIMING3 0x9814
+ #define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000
+@@ -390,6 +399,8 @@
+ #define AR_PHY_RFBUS_GRANT 0x9C20
+ #define AR_PHY_RFBUS_GRANT_EN 0x00000001
+
++#define AR_PHY_TST_ADC 0x9C24
++
+ #define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4
+ #define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
+
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ani.h
-+++ b/drivers/net/wireless/ath/ath9k/ani.h
-@@ -38,7 +38,7 @@
- #define ATH9K_ANI_PERIOD 300
-
- /* in ms */
--#define ATH9K_ANI_POLLINTERVAL 1000
-+#define ATH9K_ANI_POLLINTERVAL 300
-
- #define ATH9K_SIG_FIRSTEP_SETTING_MIN 0
- #define ATH9K_SIG_FIRSTEP_SETTING_MAX 20
--- /dev/null
+From c997a1da25fe7c717ed099888b8eb35d4e139e70 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sun, 8 Dec 2013 08:52:52 +0100
+Subject: [PATCH] ath9k: support only one P2P interface
+
+Preparation for adding P2P powersave and multi-channel support.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+ drivers/net/wireless/ath/ath9k/init.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -863,15 +863,15 @@ void ath9k_reload_chainmask_settings(str
+
+ static const struct ieee80211_iface_limit if_limits[] = {
+ { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
+- BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_WDS) },
+ { .max = 8, .types =
+ #ifdef CPTCFG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ #endif
+- BIT(NL80211_IFTYPE_AP) |
+- BIT(NL80211_IFTYPE_P2P_GO) },
++ BIT(NL80211_IFTYPE_AP) },
+ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
++ { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
++ BIT(NL80211_IFTYPE_P2P_GO) },
+ };
+
+ static const struct ieee80211_iface_limit if_dfs_limits[] = {
--- /dev/null
+From 6744d0a7ea037c7d65e13ca906da93009b241d00 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Tue, 11 Feb 2014 11:16:24 +0100
+Subject: [PATCH] ath9k: implement p2p client powersave support
+
+Use generic TSF timers to trigger powersave state changes based
+information from the P2P NoA attribute.
+Opportunistic Powersave is not handled, because the driver does not
+support powersave at the moment.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+ drivers/net/wireless/ath/ath9k/ath9k.h | 12 ++++
+ drivers/net/wireless/ath/ath9k/init.c | 6 ++
+ drivers/net/wireless/ath/ath9k/main.c | 104 +++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath9k/recv.c | 3 +
+ 4 files changed, 125 insertions(+)
+
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -261,6 +261,8 @@ static bool ath_complete_reset(struct at
+ sc->gtt_cnt = 0;
+ ieee80211_wake_queues(sc->hw);
+
++ ath9k_p2p_ps_timer(sc);
++
+ return true;
+ }
+
+@@ -1126,6 +1128,8 @@ static int ath9k_add_interface(struct ie
+ if (ath9k_uses_beacons(vif->type))
+ ath9k_beacon_assign_slot(sc, vif);
+
++ avp->vif = vif;
++
+ an->sc = sc;
+ an->sta = NULL;
+ an->vif = vif;
+@@ -1170,6 +1174,29 @@ static int ath9k_change_interface(struct
+ return 0;
+ }
+
++static void
++ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
++{
++ struct ath_hw *ah = sc->sc_ah;
++ s32 tsf, target_tsf;
++
++ if (!avp || !avp->noa.has_next_tsf)
++ return;
++
++ ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
++
++ tsf = ath9k_hw_gettsf32(sc->sc_ah);
++
++ target_tsf = avp->noa.next_tsf;
++ if (!avp->noa.absent)
++ target_tsf -= ATH_P2P_PS_STOP_TIME;
++
++ if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
++ target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
++
++ ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
++}
++
+ static void ath9k_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+ {
+@@ -1181,6 +1208,13 @@ static void ath9k_remove_interface(struc
+
+ mutex_lock(&sc->mutex);
+
++ spin_lock_bh(&sc->sc_pcu_lock);
++ if (avp == sc->p2p_ps_vif) {
++ sc->p2p_ps_vif = NULL;
++ ath9k_update_p2p_ps_timer(sc, NULL);
++ }
++ spin_unlock_bh(&sc->sc_pcu_lock);
++
+ sc->nvifs--;
+ sc->tx99_vif = NULL;
+
+@@ -1649,6 +1683,70 @@ static void ath9k_bss_assoc_iter(void *d
+ ath9k_set_assoc_state(sc, vif);
+ }
+
++void ath9k_p2p_ps_timer(void *priv)
++{
++ struct ath_softc *sc = priv;
++ struct ath_vif *avp = sc->p2p_ps_vif;
++ struct ieee80211_vif *vif;
++ struct ieee80211_sta *sta;
++ struct ath_node *an;
++ u32 tsf;
++
++ if (!avp)
++ return;
++
++ tsf = ath9k_hw_gettsf32(sc->sc_ah);
++ if (!avp->noa.absent)
++ tsf += ATH_P2P_PS_STOP_TIME;
++
++ if (!avp->noa.has_next_tsf ||
++ avp->noa.next_tsf - tsf > BIT(31))
++ ieee80211_update_p2p_noa(&avp->noa, tsf);
++
++ ath9k_update_p2p_ps_timer(sc, avp);
++
++ rcu_read_lock();
++
++ vif = avp->vif;
++ sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
++ if (!sta)
++ goto out;
++
++ an = (void *) sta->drv_priv;
++ if (an->sleeping == !!avp->noa.absent)
++ goto out;
++
++ an->sleeping = avp->noa.absent;
++ if (an->sleeping)
++ ath_tx_aggr_sleep(sta, sc, an);
++ else
++ ath_tx_aggr_wakeup(sc, an);
++
++out:
++ rcu_read_unlock();
++}
++
++void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
++{
++ struct ath_vif *avp = (void *)vif->drv_priv;
++ u32 tsf;
++
++ if (!sc->p2p_ps_timer)
++ return;
++
++ if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
++ return;
++
++ sc->p2p_ps_vif = avp;
++
++ if (sc->ps_flags & PS_BEACON_SYNC)
++ return;
++
++ tsf = ath9k_hw_gettsf32(sc->sc_ah);
++ ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
++ ath9k_update_p2p_ps_timer(sc, avp);
++}
++
+ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+@@ -1723,6 +1821,12 @@ static void ath9k_bss_info_changed(struc
+ }
+ }
+
++ if (changed & BSS_CHANGED_P2P_PS) {
++ spin_lock_bh(&sc->sc_pcu_lock);
++ ath9k_update_p2p_ps(sc, vif);
++ spin_unlock_bh(&sc->sc_pcu_lock);
++ }
++
+ if (changed & CHECK_ANI)
+ ath_check_ani(sc);
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -115,6 +115,9 @@ int ath_descdma_setup(struct ath_softc *
+ #define ATH_TXFIFO_DEPTH 8
+ #define ATH_TX_ERROR 0x01
+
++/* Stop tx traffic 1ms before the GO goes away */
++#define ATH_P2P_PS_STOP_TIME 1000
++
+ #define IEEE80211_SEQ_SEQ_SHIFT 4
+ #define IEEE80211_SEQ_MAX 4096
+ #define IEEE80211_WEP_IVLEN 3
+@@ -363,11 +366,15 @@ void ath9k_release_buffered_frames(struc
+ /********/
+
+ struct ath_vif {
++ struct ieee80211_vif *vif;
+ struct ath_node mcast_node;
+ int av_bslot;
+ bool primary_sta_vif;
+ __le64 tsf_adjust; /* TSF adjustment for staggered beacons */
+ struct ath_buf *av_bcbuf;
++
++ /* P2P Client */
++ struct ieee80211_noa_data noa;
+ };
+
+ struct ath9k_vif_iter_data {
+@@ -472,6 +479,8 @@ int ath_update_survey_stats(struct ath_s
+ void ath_update_survey_nf(struct ath_softc *sc, int channel);
+ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
+ void ath_ps_full_sleep(unsigned long data);
++void ath9k_p2p_ps_timer(void *priv);
++void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
+
+ /**********/
+ /* BTCOEX */
+@@ -741,6 +750,9 @@ struct ath_softc {
+ struct completion paprd_complete;
+ wait_queue_head_t tx_wait;
+
++ struct ath_gen_timer *p2p_ps_timer;
++ struct ath_vif *p2p_ps_vif;
++
+ unsigned long sc_flags;
+ unsigned long driver_data;
+
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -797,6 +797,9 @@ static int ath9k_init_softc(u16 devid, s
+ if (ret)
+ goto err_btcoex;
+
++ sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
++ NULL, sc, AR_FIRST_NDP_TIMER);
++
+ ath9k_cmn_init_crypto(sc->sc_ah);
+ ath9k_init_misc(sc);
+ ath_fill_led_pin(sc);
+@@ -1082,6 +1085,9 @@ static void ath9k_deinit_softc(struct at
+ {
+ int i = 0;
+
++ if (sc->p2p_ps_timer)
++ ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
++
+ ath9k_deinit_btcoex(sc);
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -539,6 +539,9 @@ static void ath_rx_ps_beacon(struct ath_
+ ath_dbg(common, PS,
+ "Reconfigure beacon timers based on synchronized timestamp\n");
+ ath9k_set_beacon(sc);
++
++ if (sc->p2p_ps_vif)
++ ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+ }
+
+ if (ath_beacon_dtim_pending_cab(skb)) {
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/mac.c
-+++ b/drivers/net/wireless/ath/ath9k/mac.c
-@@ -705,7 +705,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
- {
- #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
- struct ath_common *common = ath9k_hw_common(ah);
-- u32 mac_status, last_mac_status = 0;
-+ u32 mac_status = 0, last_mac_status = 0;
- int i;
-
- /* Enable access to the DMA observation bus */
-@@ -735,6 +735,16 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
- }
-
- if (i == 0) {
-+ if (!AR_SREV_9300_20_OR_LATER(ah) &&
-+ (mac_status & 0x700) == 0) {
-+ /*
-+ * DMA is idle but the MAC is still stuck
-+ * processing events
-+ */
-+ *reset = true;
-+ return true;
-+ }
-+
- ath_err(common,
- "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
- AH_RX_STOP_DMA_TIMEOUT / 1000,
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1881,6 +1881,50 @@ static const struct file_operations fops
- #endif
-
-
-+static ssize_t read_file_diag(struct file *file, char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct ath_softc *sc = file->private_data;
-+ struct ath_hw *ah = sc->sc_ah;
-+ char buf[32];
-+ unsigned int len;
-+
-+ len = sprintf(buf, "0x%08lx\n", ah->diag);
-+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+}
-+
-+static ssize_t write_file_diag(struct file *file, const char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct ath_softc *sc = file->private_data;
-+ struct ath_hw *ah = sc->sc_ah;
-+ unsigned long diag;
-+ char buf[32];
-+ ssize_t len;
-+
-+ len = min(count, sizeof(buf) - 1);
-+ if (copy_from_user(buf, user_buf, len))
-+ return -EFAULT;
-+
-+ buf[len] = '\0';
-+ if (kstrtoul(buf, 0, &diag))
-+ return -EINVAL;
-+
-+ ah->diag = diag;
-+ ath9k_hw_update_diag(ah);
-+
-+ return count;
-+}
-+
-+static const struct file_operations fops_diag = {
-+ .read = read_file_diag,
-+ .write = write_file_diag,
-+ .open = simple_open,
-+ .owner = THIS_MODULE,
-+ .llseek = default_llseek,
-+};
-+
-+
- int ath9k_init_debug(struct ath_hw *ah)
- {
- struct ath_common *common = ath9k_hw_common(ah);
-@@ -1906,6 +1950,8 @@ int ath9k_init_debug(struct ath_hw *ah)
- debugfs_create_file("gpio_led", S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_gpio_led);
- #endif
-+ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-+ sc, &fops_diag);
- debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_dma);
- debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -499,6 +499,12 @@ enum {
- ATH9K_RESET_COLD,
- };
-
-+enum {
-+ ATH_DIAG_DISABLE_RX,
-+ ATH_DIAG_DISABLE_TX,
-+ ATH_DIAG_TRIGGER_ERROR,
-+};
-+
- struct ath9k_hw_version {
- u32 magic;
- u16 devid;
-@@ -777,6 +783,8 @@ struct ath_hw {
- u32 rfkill_polarity;
- u32 ah_flags;
-
-+ unsigned long diag;
-+
- bool reset_power_on;
- bool htc_reset_init;
-
-@@ -1027,6 +1035,7 @@ void ath9k_hw_set_sta_beacon_timers(stru
- bool ath9k_hw_check_alive(struct ath_hw *ah);
-
- bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
-+void ath9k_hw_update_diag(struct ath_hw *ah);
-
- #ifdef CPTCFG_ATH9K_DEBUGFS
- void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause);
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1853,6 +1853,20 @@ fail:
- return -EINVAL;
- }
-
-+void ath9k_hw_update_diag(struct ath_hw *ah)
-+{
-+ if (test_bit(ATH_DIAG_DISABLE_RX, &ah->diag))
-+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
-+ else
-+ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
-+
-+ if (test_bit(ATH_DIAG_DISABLE_TX, &ah->diag))
-+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
-+ else
-+ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
-+}
-+EXPORT_SYMBOL(ath9k_hw_update_diag);
-+
- int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
- struct ath9k_hw_cal_data *caldata, bool fastcc)
- {
-@@ -2055,6 +2069,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
- }
-
- ath9k_hw_apply_gpio_override(ah);
-+ ath9k_hw_update_diag(ah);
-
- if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv)
- REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -472,6 +472,11 @@ irqreturn_t ath_isr(int irq, void *dev)
- ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
- status &= ah->imask; /* discard unasked-for bits */
-
-+ if (test_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag)) {
-+ status |= ATH9K_INT_FATAL;
-+ clear_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag);
-+ }
-+
- /*
- * If there are no status bits set, then this interrupt was not
- * for me (should have been caught above).
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -1173,6 +1173,10 @@ skip_ws_det:
- * is_on == 0 means MRC CCK is OFF (more noise imm)
- */
- bool is_on = param ? 1 : 0;
-+
-+ if (ah->caps.rx_chainmask == 1)
-+ break;
-+
- REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
- AR_PHY_MRC_CCK_ENABLE, is_on);
- REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
+++ /dev/null
---- a/include/linux/ath9k_platform.h
-+++ b/include/linux/ath9k_platform.h
-@@ -33,6 +33,9 @@ struct ath9k_platform_data {
-
- bool endian_check;
- bool is_clk_25mhz;
-+ bool disable_2ghz;
-+ bool disable_5ghz;
-+
- int (*get_mac_revision)(void);
- int (*external_reset)(void);
-
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2448,17 +2448,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw
- }
-
- eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
-- if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
-- ath_err(common,
-- "no band has been marked as supported in EEPROM\n");
-- return -EINVAL;
-+
-+ if (eeval & AR5416_OPFLAGS_11A) {
-+ if (ah->disable_5ghz)
-+ ath_warn(common, "disabling 5GHz band\n");
-+ else
-+ pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
- }
-
-- if (eeval & AR5416_OPFLAGS_11A)
-- pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
-+ if (eeval & AR5416_OPFLAGS_11G) {
-+ if (ah->disable_2ghz)
-+ ath_warn(common, "disabling 2GHz band\n");
-+ else
-+ pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
-+ }
-
-- if (eeval & AR5416_OPFLAGS_11G)
-- pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
-+ if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) {
-+ ath_err(common, "both bands are disabled\n");
-+ return -EINVAL;
-+ }
-
- if (AR_SREV_9485(ah) ||
- AR_SREV_9285(ah) ||
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -947,6 +947,8 @@ struct ath_hw {
- bool is_clk_25mhz;
- int (*get_mac_revision)(void);
- int (*external_reset)(void);
-+ bool disable_2ghz;
-+ bool disable_5ghz;
-
- const struct firmware *eeprom_blob;
- };
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -613,6 +613,8 @@ static int ath9k_init_softc(u16 devid, s
- ah->is_clk_25mhz = pdata->is_clk_25mhz;
- ah->get_mac_revision = pdata->get_mac_revision;
- ah->external_reset = pdata->external_reset;
-+ ah->disable_2ghz = pdata->disable_2ghz;
-+ ah->disable_5ghz = pdata->disable_5ghz;
- if (!pdata->endian_check)
- ah->ah_flags |= AH_NO_EEP_SWAP;
- }
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -79,10 +79,6 @@ struct ath_config {
- sizeof(struct ath_buf_state)); \
- } while (0)
-
--#define ATH_RXBUF_RESET(_bf) do { \
-- (_bf)->bf_stale = false; \
-- } while (0)
--
- /**
- * enum buffer_type - Buffer type flags
- *
-@@ -317,6 +313,7 @@ struct ath_rx {
- struct ath_descdma rxdma;
- struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
-
-+ struct ath_buf *buf_hold;
- struct sk_buff *frag;
-
- u32 ampdu_ref;
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -42,8 +42,6 @@ static void ath_rx_buf_link(struct ath_s
- struct ath_desc *ds;
- struct sk_buff *skb;
-
-- ATH_RXBUF_RESET(bf);
--
- ds = bf->bf_desc;
- ds->ds_link = 0; /* link to null */
- ds->ds_data = bf->bf_buf_addr;
-@@ -70,6 +68,14 @@ static void ath_rx_buf_link(struct ath_s
- sc->rx.rxlink = &ds->ds_link;
- }
-
-+static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf)
-+{
-+ if (sc->rx.buf_hold)
-+ ath_rx_buf_link(sc, sc->rx.buf_hold);
-+
-+ sc->rx.buf_hold = bf;
-+}
-+
- static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
- {
- /* XXX block beacon interrupts */
-@@ -117,7 +123,6 @@ static bool ath_rx_edma_buf_link(struct
-
- skb = bf->bf_mpdu;
-
-- ATH_RXBUF_RESET(bf);
- memset(skb->data, 0, ah->caps.rx_status_len);
- dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
- ah->caps.rx_status_len, DMA_TO_DEVICE);
-@@ -432,6 +437,7 @@ int ath_startrecv(struct ath_softc *sc)
- if (list_empty(&sc->rx.rxbuf))
- goto start_recv;
-
-+ sc->rx.buf_hold = NULL;
- sc->rx.rxlink = NULL;
- list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
- ath_rx_buf_link(sc, bf);
-@@ -677,6 +683,9 @@ static struct ath_buf *ath_get_next_rx_b
- }
-
- bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
-+ if (bf == sc->rx.buf_hold)
-+ return NULL;
-+
- ds = bf->bf_desc;
-
- /*
-@@ -1391,7 +1400,7 @@ requeue:
- if (edma) {
- ath_rx_edma_buf_link(sc, qtype);
- } else {
-- ath_rx_buf_link(sc, bf);
-+ ath_rx_buf_relink(sc, bf);
- ath9k_hw_rxena(ah);
- }
- } while (1);
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -133,7 +133,6 @@ int ath_descdma_setup(struct ath_softc *
- #define ATH_AGGR_ENCRYPTDELIM 10
- /* minimum h/w qdepth to be sustained to maximize aggregation */
- #define ATH_AGGR_MIN_QDEPTH 2
--#define ATH_AMPDU_SUBFRAME_DEFAULT 32
-
- #define IEEE80211_SEQ_SEQ_SHIFT 4
- #define IEEE80211_SEQ_MAX 4096
-@@ -208,8 +207,9 @@ struct ath_frame_info {
- int framelen;
- enum ath9k_key_type keytype;
- u8 keyix;
-- u8 retries;
- u8 rtscts_rate;
-+ u8 retries : 7;
-+ u8 baw_tracked : 1;
- };
-
- struct ath_buf_state {
-@@ -237,6 +237,7 @@ struct ath_buf {
- struct ath_atx_tid {
- struct list_head list;
- struct sk_buff_head buf_q;
-+ struct sk_buff_head retry_q;
- struct ath_node *an;
- struct ath_atx_ac *ac;
- unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -607,6 +607,28 @@ static ssize_t read_file_xmit(struct fil
- return retval;
- }
-
-+static ssize_t print_queue(struct ath_softc *sc, struct ath_txq *txq,
-+ char *buf, ssize_t size)
-+{
-+ ssize_t len = 0;
-+
-+ ath_txq_lock(sc, txq);
-+
-+ len += snprintf(buf + len, size - len, "%s: %d ",
-+ "qnum", txq->axq_qnum);
-+ len += snprintf(buf + len, size - len, "%s: %2d ",
-+ "qdepth", txq->axq_depth);
-+ len += snprintf(buf + len, size - len, "%s: %2d ",
-+ "ampdu-depth", txq->axq_ampdu_depth);
-+ len += snprintf(buf + len, size - len, "%s: %3d ",
-+ "pending", txq->pending_frames);
-+ len += snprintf(buf + len, size - len, "%s: %d\n",
-+ "stopped", txq->stopped);
-+
-+ ath_txq_unlock(sc, txq);
-+ return len;
-+}
-+
- static ssize_t read_file_queues(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
- {
-@@ -624,24 +646,13 @@ static ssize_t read_file_queues(struct f
-
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- txq = sc->tx.txq_map[i];
-- len += snprintf(buf + len, size - len, "(%s): ", qname[i]);
--
-- ath_txq_lock(sc, txq);
--
-- len += snprintf(buf + len, size - len, "%s: %d ",
-- "qnum", txq->axq_qnum);
-- len += snprintf(buf + len, size - len, "%s: %2d ",
-- "qdepth", txq->axq_depth);
-- len += snprintf(buf + len, size - len, "%s: %2d ",
-- "ampdu-depth", txq->axq_ampdu_depth);
-- len += snprintf(buf + len, size - len, "%s: %3d ",
-- "pending", txq->pending_frames);
-- len += snprintf(buf + len, size - len, "%s: %d\n",
-- "stopped", txq->stopped);
--
-- ath_txq_unlock(sc, txq);
-+ len += snprintf(buf + len, size - len, "(%s): ", qname[i]);
-+ len += print_queue(sc, txq, buf + len, size - len);
- }
-
-+ len += snprintf(buf + len, size - len, "(CAB): ");
-+ len += print_queue(sc, sc->beacon.cabq, buf + len, size - len);
-+
- if (len > size)
- len = size;
-
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1402,9 +1402,6 @@ static void ath9k_sta_notify(struct ieee
- struct ath_softc *sc = hw->priv;
- struct ath_node *an = (struct ath_node *) sta->drv_priv;
-
-- if (!sta->ht_cap.ht_supported)
-- return;
--
- switch (cmd) {
- case STA_NOTIFY_SLEEP:
- an->sleeping = true;
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -168,6 +168,36 @@ static void ath_txq_skb_done(struct ath_
- }
- }
-
-+static struct ath_atx_tid *
-+ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
-+{
-+ struct ieee80211_hdr *hdr;
-+ u8 tidno = 0;
-+
-+ hdr = (struct ieee80211_hdr *) skb->data;
-+ if (ieee80211_is_data_qos(hdr->frame_control))
-+ tidno = ieee80211_get_qos_ctl(hdr)[0];
-+
-+ tidno &= IEEE80211_QOS_CTL_TID_MASK;
-+ return ATH_AN_2_TID(an, tidno);
-+}
-+
-+static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
-+{
-+ return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
-+}
-+
-+static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
-+{
-+ struct sk_buff *skb;
-+
-+ skb = __skb_dequeue(&tid->retry_q);
-+ if (!skb)
-+ skb = __skb_dequeue(&tid->buf_q);
-+
-+ return skb;
-+}
-+
- static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
- {
- struct ath_txq *txq = tid->ac->txq;
-@@ -182,7 +212,7 @@ static void ath_tx_flush_tid(struct ath_
-
- memset(&ts, 0, sizeof(ts));
-
-- while ((skb = __skb_dequeue(&tid->buf_q))) {
-+ while ((skb = ath_tid_dequeue(tid))) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
-@@ -195,7 +225,7 @@ static void ath_tx_flush_tid(struct ath_
- }
- }
-
-- if (fi->retries) {
-+ if (fi->baw_tracked) {
- list_add_tail(&bf->list, &bf_head);
- ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
-@@ -232,13 +262,16 @@ static void ath_tx_update_baw(struct ath
- }
-
- static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
-- u16 seqno)
-+ struct ath_buf *bf)
- {
-+ struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
-+ u16 seqno = bf->bf_state.seqno;
- int index, cindex;
-
- index = ATH_BA_INDEX(tid->seq_start, seqno);
- cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
- __set_bit(cindex, tid->tx_buf);
-+ fi->baw_tracked = 1;
-
- if (index >= ((tid->baw_tail - tid->baw_head) &
- (ATH_TID_MAX_BUFS - 1))) {
-@@ -266,7 +299,7 @@ static void ath_tid_drain(struct ath_sof
- memset(&ts, 0, sizeof(ts));
- INIT_LIST_HEAD(&bf_head);
-
-- while ((skb = __skb_dequeue(&tid->buf_q))) {
-+ while ((skb = ath_tid_dequeue(tid))) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
-@@ -403,7 +436,6 @@ static void ath_tx_complete_aggr(struct
- struct ieee80211_tx_rate rates[4];
- struct ath_frame_info *fi;
- int nframes;
-- u8 tidno;
- bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
- int i, retries;
- int bar_index = -1;
-@@ -440,8 +472,7 @@ static void ath_tx_complete_aggr(struct
- }
-
- an = (struct ath_node *)sta->drv_priv;
-- tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
-- tid = ATH_AN_2_TID(an, tidno);
-+ tid = ath_get_skb_tid(sc, an, skb);
- seq_first = tid->seq_start;
- isba = ts->ts_flags & ATH9K_TX_BA;
-
-@@ -453,7 +484,7 @@ static void ath_tx_complete_aggr(struct
- * Only BlockAcks have a TID and therefore normal Acks cannot be
- * checked
- */
-- if (isba && tidno != ts->tid)
-+ if (isba && tid->tidno != ts->tid)
- txok = false;
-
- isaggr = bf_isaggr(bf);
-@@ -489,7 +520,8 @@ static void ath_tx_complete_aggr(struct
- tx_info = IEEE80211_SKB_CB(skb);
- fi = get_frame_info(skb);
-
-- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
-+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno) ||
-+ !tid->active) {
- /*
- * Outside of the current BlockAck window,
- * maybe part of a previous session
-@@ -583,7 +615,7 @@ static void ath_tx_complete_aggr(struct
- if (an->sleeping)
- ieee80211_sta_set_buffered(sta, tid->tidno, true);
-
-- skb_queue_splice(&bf_pending, &tid->buf_q);
-+ skb_queue_splice_tail(&bf_pending, &tid->retry_q);
- if (!an->sleeping) {
- ath_tx_queue_tid(txq, tid);
-
-@@ -641,7 +673,7 @@ static void ath_tx_process_buffer(struct
- } else
- ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
-
-- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush)
-+ if (!flush)
- ath_txq_schedule(sc, txq);
- }
-
-@@ -815,15 +847,20 @@ static int ath_compute_num_delims(struct
-
- static struct ath_buf *
- ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
-- struct ath_atx_tid *tid)
-+ struct ath_atx_tid *tid, struct sk_buff_head **q)
- {
-+ struct ieee80211_tx_info *tx_info;
- struct ath_frame_info *fi;
- struct sk_buff *skb;
- struct ath_buf *bf;
- u16 seqno;
-
- while (1) {
-- skb = skb_peek(&tid->buf_q);
-+ *q = &tid->retry_q;
-+ if (skb_queue_empty(*q))
-+ *q = &tid->buf_q;
-+
-+ skb = skb_peek(*q);
- if (!skb)
- break;
-
-@@ -833,12 +870,22 @@ ath_tx_get_tid_subframe(struct ath_softc
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
-
- if (!bf) {
-- __skb_unlink(skb, &tid->buf_q);
-+ __skb_unlink(skb, *q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
-
-+ bf->bf_next = NULL;
-+ bf->bf_lastbf = bf;
-+
-+ tx_info = IEEE80211_SKB_CB(skb);
-+ tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
-+ if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
-+ bf->bf_state.bf_type = 0;
-+ return bf;
-+ }
-+
- bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
- seqno = bf->bf_state.seqno;
-
-@@ -852,14 +899,12 @@ ath_tx_get_tid_subframe(struct ath_softc
-
- INIT_LIST_HEAD(&bf_head);
- list_add(&bf->list, &bf_head);
-- __skb_unlink(skb, &tid->buf_q);
-+ __skb_unlink(skb, *q);
- ath_tx_update_baw(sc, tid, seqno);
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
- continue;
- }
-
-- bf->bf_next = NULL;
-- bf->bf_lastbf = bf;
- return bf;
- }
-
-@@ -874,16 +919,17 @@ static enum ATH_AGGR_STATUS ath_tx_form_
- {
- #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
- struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
-- int rl = 0, nframes = 0, ndelim, prev_al = 0;
-+ int nframes = 0, ndelim;
- u16 aggr_limit = 0, al = 0, bpad = 0,
-- al_delta, h_baw = tid->baw_size / 2;
-+ al_delta, h_baw = tid->baw_size / 2;
- enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
- struct ieee80211_tx_info *tx_info;
- struct ath_frame_info *fi;
- struct sk_buff *skb;
-+ struct sk_buff_head *tid_q;
-
- do {
-- bf = ath_tx_get_tid_subframe(sc, txq, tid);
-+ bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- status = ATH_AGGR_BAW_CLOSED;
- break;
-@@ -892,33 +938,24 @@ static enum ATH_AGGR_STATUS ath_tx_form_
- skb = bf->bf_mpdu;
- fi = get_frame_info(skb);
-
-- if (!bf_first)
-+ if (!bf_first) {
- bf_first = bf;
--
-- if (!rl) {
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
- aggr_limit = ath_lookup_rate(sc, bf, tid);
-- rl = 1;
- }
-
- /* do not exceed aggregation limit */
- al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
-+ if (nframes) {
-+ if (aggr_limit < al + bpad + al_delta ||
-+ ath_lookup_legacy(bf) || nframes >= h_baw) {
-+ status = ATH_AGGR_LIMITED;
-+ break;
-+ }
-
-- if (nframes &&
-- ((aggr_limit < (al + bpad + al_delta + prev_al)) ||
-- ath_lookup_legacy(bf))) {
-- status = ATH_AGGR_LIMITED;
-- break;
-- }
--
-- tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
-- if (nframes && (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
-- break;
--
-- /* do not exceed subframe limit */
-- if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
-- status = ATH_AGGR_LIMITED;
-- break;
-+ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
-+ if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
-+ break;
- }
-
- /* add padding for previous frame to aggregation length */
-@@ -936,18 +973,18 @@ static enum ATH_AGGR_STATUS ath_tx_form_
- bf->bf_next = NULL;
-
- /* link buffers of this frame to the aggregate */
-- if (!fi->retries)
-- ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
-+ if (!fi->baw_tracked)
-+ ath_tx_addto_baw(sc, tid, bf);
- bf->bf_state.ndelim = ndelim;
-
-- __skb_unlink(skb, &tid->buf_q);
-+ __skb_unlink(skb, tid_q);
- list_add_tail(&bf->list, bf_q);
- if (bf_prev)
- bf_prev->bf_next = bf;
-
- bf_prev = bf;
-
-- } while (!skb_queue_empty(&tid->buf_q));
-+ } while (ath_tid_has_buffered(tid));
-
- *aggr_len = al;
-
-@@ -1222,7 +1259,7 @@ static void ath_tx_sched_aggr(struct ath
- int aggr_len;
-
- do {
-- if (skb_queue_empty(&tid->buf_q))
-+ if (!ath_tid_has_buffered(tid))
- return;
-
- INIT_LIST_HEAD(&bf_q);
-@@ -1301,7 +1338,7 @@ void ath_tx_aggr_stop(struct ath_softc *
-
- ath_txq_lock(sc, txq);
- txtid->active = false;
-- txtid->paused = true;
-+ txtid->paused = false;
- ath_tx_flush_tid(sc, txtid);
- ath_txq_unlock_complete(sc, txq);
- }
-@@ -1326,7 +1363,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
-
- ath_txq_lock(sc, txq);
-
-- buffered = !skb_queue_empty(&tid->buf_q);
-+ buffered = ath_tid_has_buffered(tid);
-
- tid->sched = false;
- list_del(&tid->list);
-@@ -1358,7 +1395,7 @@ void ath_tx_aggr_wakeup(struct ath_softc
- ath_txq_lock(sc, txq);
- ac->clear_ps_filter = true;
-
-- if (!skb_queue_empty(&tid->buf_q) && !tid->paused) {
-+ if (!tid->paused && ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(txq, tid);
- ath_txq_schedule(sc, txq);
- }
-@@ -1383,7 +1420,7 @@ void ath_tx_aggr_resume(struct ath_softc
- tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
- tid->paused = false;
-
-- if (!skb_queue_empty(&tid->buf_q)) {
-+ if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(txq, tid);
- ath_txq_schedule(sc, txq);
- }
-@@ -1403,6 +1440,7 @@ void ath9k_release_buffered_frames(struc
- struct ieee80211_tx_info *info;
- struct list_head bf_q;
- struct ath_buf *bf_tail = NULL, *bf;
-+ struct sk_buff_head *tid_q;
- int sent = 0;
- int i;
-
-@@ -1418,15 +1456,15 @@ void ath9k_release_buffered_frames(struc
- continue;
-
- ath_txq_lock(sc, tid->ac->txq);
-- while (!skb_queue_empty(&tid->buf_q) && nframes > 0) {
-- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
-+ while (nframes > 0) {
-+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
- if (!bf)
- break;
-
-- __skb_unlink(bf->bf_mpdu, &tid->buf_q);
-+ __skb_unlink(bf->bf_mpdu, tid_q);
- list_add_tail(&bf->list, &bf_q);
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
-- ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
-+ ath_tx_addto_baw(sc, tid, bf);
- bf->bf_state.bf_type &= ~BUF_AGGR;
- if (bf_tail)
- bf_tail->bf_next = bf;
-@@ -1436,7 +1474,7 @@ void ath9k_release_buffered_frames(struc
- sent++;
- TX_STAT_INC(txq->axq_qnum, a_queued_hw);
-
-- if (skb_queue_empty(&tid->buf_q))
-+ if (!ath_tid_has_buffered(tid))
- ieee80211_sta_set_buffered(an->sta, i, false);
- }
- ath_txq_unlock_complete(sc, tid->ac->txq);
-@@ -1722,7 +1760,7 @@ void ath_txq_schedule(struct ath_softc *
- * add tid to round-robin queue if more frames
- * are pending for the tid
- */
-- if (!skb_queue_empty(&tid->buf_q))
-+ if (ath_tid_has_buffered(tid))
- ath_tx_queue_tid(txq, tid);
-
- if (tid == last_tid ||
-@@ -1831,7 +1869,7 @@ static void ath_tx_send_ampdu(struct ath
- * - seqno is not within block-ack window
- * - h/w queue depth exceeds low water mark
- */
-- if ((!skb_queue_empty(&tid->buf_q) || tid->paused ||
-+ if ((ath_tid_has_buffered(tid) || tid->paused ||
- !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) ||
- txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) &&
- txq != sc->tx.uapsdq) {
-@@ -1859,7 +1897,7 @@ static void ath_tx_send_ampdu(struct ath
- list_add(&bf->list, &bf_head);
-
- /* Add sub-frame to BAW */
-- ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
-+ ath_tx_addto_baw(sc, tid, bf);
-
- /* Queue to h/w without aggregation */
- TX_STAT_INC(txq->axq_qnum, a_queued_hw);
-@@ -2066,7 +2104,6 @@ int ath_tx_start(struct ieee80211_hw *hw
- struct ath_txq *txq = txctl->txq;
- struct ath_atx_tid *tid = NULL;
- struct ath_buf *bf;
-- u8 tidno;
- int q;
- int ret;
-
-@@ -2097,9 +2134,7 @@ int ath_tx_start(struct ieee80211_hw *hw
- }
-
- if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
-- tidno = ieee80211_get_qos_ctl(hdr)[0] &
-- IEEE80211_QOS_CTL_TID_MASK;
-- tid = ATH_AN_2_TID(txctl->an, tidno);
-+ tid = ath_get_skb_tid(sc, txctl->an, skb);
-
- WARN_ON(tid->ac->txq != txctl->txq);
- }
-@@ -2372,8 +2407,7 @@ static void ath_tx_processq(struct ath_s
-
- if (list_empty(&txq->axq_q)) {
- txq->axq_link = NULL;
-- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
-- ath_txq_schedule(sc, txq);
-+ ath_txq_schedule(sc, txq);
- break;
- }
- bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
-@@ -2595,6 +2629,7 @@ void ath_tx_node_init(struct ath_softc *
- tid->paused = false;
- tid->active = false;
- __skb_queue_head_init(&tid->buf_q);
-+ __skb_queue_head_init(&tid->retry_q);
- acno = TID_TO_WME_AC(tidno);
- tid->ac = &an->ac[acno];
- }
-@@ -2602,6 +2637,7 @@ void ath_tx_node_init(struct ath_softc *
- for (acno = 0, ac = &an->ac[acno];
- acno < IEEE80211_NUM_ACS; acno++, ac++) {
- ac->sched = false;
-+ ac->clear_ps_filter = true;
- ac->txq = sc->tx.txq_map[acno];
- INIT_LIST_HEAD(&ac->tid_q);
- }
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -313,6 +313,19 @@ void ath9k_hw_get_channel_centers(struct
- centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
- }
-
-+static inline void ath9k_hw_disable_pll_lock_detect(struct ath_hw *ah)
-+{
-+ /* On AR9330 and AR9340 devices, some PHY registers must be
-+ * tuned to gain better stability/performance. These registers
-+ * might be changed while doing wlan reset so the registers must
-+ * be reprogrammed after each reset.
-+ */
-+ REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, BIT(20));
-+ REG_RMW(ah, AR_PHY_USB_CTRL2,
-+ (1 << 21) | (0xf << 22),
-+ (1 << 21) | (0x3 << 22));
-+}
-+
- /******************/
- /* Chip Revisions */
- /******************/
-@@ -1397,6 +1410,9 @@ static bool ath9k_hw_set_reset(struct at
- if (AR_SREV_9100(ah))
- udelay(50);
-
-+ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
-+ ath9k_hw_disable_pll_lock_detect(ah);
-+
- return true;
- }
-
-@@ -1498,6 +1514,9 @@ static bool ath9k_hw_chip_reset(struct a
- ath9k_hw_init_pll(ah, chan);
- ath9k_hw_set_rfmode(ah, chan);
-
-+ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
-+ ath9k_hw_disable_pll_lock_detect(ah);
-+
- return true;
- }
-
-@@ -1848,8 +1867,14 @@ static int ath9k_hw_do_fastcc(struct ath
- if (AR_SREV_9271(ah))
- ar9002_hw_load_ani_reg(ah, chan);
-
-+ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
-+ ath9k_hw_disable_pll_lock_detect(ah);
-+
- return 0;
- fail:
-+ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
-+ ath9k_hw_disable_pll_lock_detect(ah);
-+
- return -EINVAL;
- }
-
-@@ -2074,6 +2099,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
- if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv)
- REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
-
-+ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
-+ ath9k_hw_disable_pll_lock_detect(ah);
-+
- return 0;
- }
- EXPORT_SYMBOL(ath9k_hw_reset);
---- a/drivers/net/wireless/ath/ath9k/phy.h
-+++ b/drivers/net/wireless/ath/ath9k/phy.h
-@@ -48,4 +48,7 @@
- #define AR_PHY_PLL_CONTROL 0x16180
- #define AR_PHY_PLL_MODE 0x16184
-
-+#define AR_PHY_USB_CTRL1 0x16c84
-+#define AR_PHY_USB_CTRL2 0x16c88
-+
- #endif
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -217,6 +217,19 @@ void ath9k_hw_get_channel_centers(struct
+ centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
+ }
+
++static inline void ath9k_hw_disable_pll_lock_detect(struct ath_hw *ah)
++{
++ /* On AR9330 and AR9340 devices, some PHY registers must be
++ * tuned to gain better stability/performance. These registers
++ * might be changed while doing wlan reset so the registers must
++ * be reprogrammed after each reset.
++ */
++ REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, BIT(20));
++ REG_RMW(ah, AR_PHY_USB_CTRL2,
++ (1 << 21) | (0xf << 22),
++ (1 << 21) | (0x3 << 22));
++}
++
+ /******************/
+ /* Chip Revisions */
+ /******************/
+@@ -1337,6 +1350,9 @@ static bool ath9k_hw_set_reset(struct at
+ if (AR_SREV_9100(ah))
+ udelay(50);
+
++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++ ath9k_hw_disable_pll_lock_detect(ah);
++
+ return true;
+ }
+
+@@ -1436,6 +1452,9 @@ static bool ath9k_hw_chip_reset(struct a
+ ar9003_hw_internal_regulator_apply(ah);
+ ath9k_hw_init_pll(ah, chan);
+
++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++ ath9k_hw_disable_pll_lock_detect(ah);
++
+ return true;
+ }
+
+@@ -1730,8 +1749,14 @@ static int ath9k_hw_do_fastcc(struct ath
+ if (AR_SREV_9271(ah))
+ ar9002_hw_load_ani_reg(ah, chan);
+
++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++ ath9k_hw_disable_pll_lock_detect(ah);
++
+ return 0;
+ fail:
++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++ ath9k_hw_disable_pll_lock_detect(ah);
++
+ return -EINVAL;
+ }
+
+@@ -1959,6 +1984,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ if (AR_SREV_9565(ah) && common->bt_ant_diversity)
+ REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
+
++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++ ath9k_hw_disable_pll_lock_detect(ah);
++
+ return 0;
+ }
+ EXPORT_SYMBOL(ath9k_hw_reset);
+--- a/drivers/net/wireless/ath/ath9k/phy.h
++++ b/drivers/net/wireless/ath/ath9k/phy.h
+@@ -48,6 +48,9 @@
+ #define AR_PHY_PLL_CONTROL 0x16180
+ #define AR_PHY_PLL_MODE 0x16184
+
++#define AR_PHY_USB_CTRL1 0x16c84
++#define AR_PHY_USB_CTRL2 0x16c88
++
+ enum ath9k_ant_div_comb_lna_conf {
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
+ ATH_ANT_DIV_COMB_LNA2,
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
-@@ -96,8 +96,10 @@ int rt2x00pci_probe(struct pci_dev *pci_
+@@ -94,8 +94,10 @@ int rt2x00pci_probe(struct pci_dev *pci_
pci_set_master(pci_dev);
+#endif /* _RT2X00_PLATFORM_H */
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -39,6 +39,7 @@
- #include <linux/input-polldev.h>
+@@ -38,6 +38,7 @@
#include <linux/kfifo.h>
#include <linux/hrtimer.h>
+ #include <linux/average.h>
+#include <linux/rt2x00_platform.h>
#include <net/mac80211.h>
+--- a/.local-symbols
++++ b/.local-symbols
+@@ -279,6 +279,7 @@ RT2X00_LIB_FIRMWARE=
+ RT2X00_LIB_CRYPTO=
+ RT2X00_LIB_LEDS=
+ RT2X00_LIB_DEBUGFS=
++RT2X00_LIB_EEPROM=
+ RT2X00_DEBUG=
+ RTL_CARDS=
+ RTL8192CE=
+--- a/drivers/net/wireless/rt2x00/Kconfig
++++ b/drivers/net/wireless/rt2x00/Kconfig
+@@ -69,6 +69,7 @@ config RT2800PCI
+ select RT2X00_LIB_MMIO
+ select RT2X00_LIB_PCI
+ select RT2X00_LIB_FIRMWARE
++ select RT2X00_LIB_EEPROM
+ select RT2X00_LIB_CRYPTO
+ depends on CRC_CCITT
+ depends on EEPROM_93CX6
+@@ -215,6 +216,7 @@ config RT2800SOC
+ select RT2X00_LIB_MMIO
+ select RT2X00_LIB_CRYPTO
+ select RT2X00_LIB_FIRMWARE
++ select RT2X00_LIB_EEPROM
+ select RT2800_LIB
+ select RT2800_LIB_MMIO
+ ---help---
+@@ -266,6 +268,9 @@ config RT2X00_LIB_FIRMWARE
+ config RT2X00_LIB_CRYPTO
+ boolean
+
++config RT2X00_LIB_EEPROM
++ boolean
++
+ config RT2X00_LIB_LEDS
+ boolean
+ default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
+--- a/drivers/net/wireless/rt2x00/Makefile
++++ b/drivers/net/wireless/rt2x00/Makefile
+@@ -7,6 +7,7 @@ rt2x00lib-$(CPTCFG_RT2X00_LIB_DEBUGFS) +
+ rt2x00lib-$(CPTCFG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
+ rt2x00lib-$(CPTCFG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
+ rt2x00lib-$(CPTCFG_RT2X00_LIB_LEDS) += rt2x00leds.o
++rt2x00lib-$(CPTCFG_RT2X00_LIB_EEPROM) += rt2x00eeprom.o
+
+ obj-$(CPTCFG_RT2X00_LIB) += rt2x00lib.o
+ obj-$(CPTCFG_RT2X00_LIB_MMIO) += rt2x00mmio.o
+--- a/drivers/net/wireless/rt2x00/rt2800lib.h
++++ b/drivers/net/wireless/rt2x00/rt2800lib.h
+@@ -20,6 +20,8 @@
+ #ifndef RT2800LIB_H
+ #define RT2800LIB_H
+
++#include "rt2800.h"
++
+ struct rt2800_ops {
+ void (*register_read)(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset, u32 *value);
+@@ -119,6 +121,15 @@ static inline int rt2800_read_eeprom(str
+ {
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
++ if (rt2x00dev->eeprom_file) {
++ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data,
++ EEPROM_SIZE);
++ return 0;
++ }
++
++ if (!rt2800ops->read_eeprom)
++ return -EINVAL;
++
+ return rt2800ops->read_eeprom(rt2x00dev);
+ }
+
+--- a/drivers/net/wireless/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/rt2x00/rt2800soc.c
+@@ -95,19 +95,6 @@ static int rt2800soc_set_device_state(st
+ return retval;
+ }
+
+-static int rt2800soc_read_eeprom(struct rt2x00_dev *rt2x00dev)
+-{
+- void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
+-
+- if (!base_addr)
+- return -ENOMEM;
+-
+- memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
+-
+- iounmap(base_addr);
+- return 0;
+-}
+-
+ /* Firmware functions */
+ static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+ {
+@@ -171,7 +158,6 @@ static const struct rt2800_ops rt2800soc
+ .register_multiread = rt2x00mmio_register_multiread,
+ .register_multiwrite = rt2x00mmio_register_multiwrite,
+ .regbusy_read = rt2x00mmio_regbusy_read,
+- .read_eeprom = rt2800soc_read_eeprom,
+ .hwcrypt_disabled = rt2800soc_hwcrypt_disabled,
+ .drv_write_firmware = rt2800soc_write_firmware,
+ .drv_init_registers = rt2800mmio_init_registers,
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -694,6 +694,7 @@ enum rt2x00_capability_flags {
+ REQUIRE_SW_SEQNO,
+ REQUIRE_HT_TX_DESC,
+ REQUIRE_PS_AUTOWAKE,
++ REQUIRE_EEPROM_FILE,
+
+ /*
+ * Capabilities
+@@ -963,6 +964,11 @@ struct rt2x00_dev {
+ const struct firmware *fw;
+
+ /*
++ * EEPROM image.
++ */
++ const struct firmware *eeprom_file;
++
++ /*
+ * FIFO for storing tx status reports between isr and tasklet.
+ */
+ DECLARE_KFIFO_PTR(txstatus_fifo, u32);
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -1324,6 +1324,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
+ INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
+ INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
+
++ retval = rt2x00lib_load_eeprom_file(rt2x00dev);
++ if (retval)
++ goto exit;
++
+ /*
+ * Let the driver probe the device to detect the capabilities.
+ */
+@@ -1454,6 +1458,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
+ */
+ if (rt2x00dev->drv_data)
+ kfree(rt2x00dev->drv_data);
++
++ /*
++ * Free EEPROM image.
++ */
++ rt2x00lib_free_eeprom_file(rt2x00dev);
+ }
+ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
+
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c
-@@ -0,0 +1,98 @@
+@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
++static const char *
++rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
++{
++ struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
++
++ if (pdata && pdata->eeprom_file_name)
++ return pdata->eeprom_file_name;
++
++ return NULL
++}
++
+static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
+{
+ const struct firmware *ee;
-+ char *ee_name;
++ const char *ee_name;
+ int retval;
+
-+ ee_name = rt2x00dev->ops->lib->get_eeprom_file_name(rt2x00dev);
++ ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev);
+ if (!ee_name) {
+ rt2x00_err(rt2x00dev,
+ "Invalid EEPROM filename.\n"
+{
+ int retval;
+
-+ if (!test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags))
++ if (!rt2x00lib_get_eeprom_file_name(rt2x00dev))
+ return 0;
+
++ set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags);
++
+ if (!rt2x00dev->eeprom_file) {
+ retval = rt2x00lib_request_eeprom_file(rt2x00dev);
+ if (retval)
+ release_firmware(rt2x00dev->eeprom_file);
+ rt2x00dev->eeprom_file = NULL;
+}
---- a/drivers/net/wireless/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -549,6 +549,7 @@ struct rt2x00lib_ops {
- const u8 *data, const size_t len);
- int (*load_firmware) (struct rt2x00_dev *rt2x00dev,
- const u8 *data, const size_t len);
-+ char *(*get_eeprom_file_name) (struct rt2x00_dev *rt2x00dev);
-
- /*
- * Device initialization/deinitialization handlers.
-@@ -705,6 +706,7 @@ enum rt2x00_capability_flags {
- REQUIRE_SW_SEQNO,
- REQUIRE_HT_TX_DESC,
- REQUIRE_PS_AUTOWAKE,
-+ REQUIRE_EEPROM_FILE,
-
- /*
- * Capabilities
-@@ -974,6 +976,11 @@ struct rt2x00_dev {
- const struct firmware *fw;
-
- /*
-+ * EEPROM image.
-+ */
-+ const struct firmware *eeprom_file;
-+
-+ /*
- * FIFO for storing tx status reports between isr and tasklet.
- */
- DECLARE_KFIFO_PTR(txstatus_fifo, u32);
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
-@@ -322,6 +322,22 @@ static inline void rt2x00lib_free_firmwa
+@@ -320,6 +320,22 @@ static inline void rt2x00lib_free_firmwa
#endif /* CPTCFG_RT2X00_LIB_FIRMWARE */
/*
* Debugfs handlers.
*/
#ifdef CPTCFG_RT2X00_LIB_DEBUGFS
---- a/drivers/net/wireless/rt2x00/Kconfig
-+++ b/drivers/net/wireless/rt2x00/Kconfig
-@@ -69,6 +69,7 @@ config RT2800PCI
- select RT2X00_LIB_PCI if PCI
- select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X
- select RT2X00_LIB_FIRMWARE
-+ select RT2X00_LIB_EEPROM
- select RT2X00_LIB_CRYPTO
- depends on CRC_CCITT
- depends on EEPROM_93CX6
-@@ -238,6 +239,9 @@ config RT2X00_LIB_FIRMWARE
- config RT2X00_LIB_CRYPTO
- boolean
-
-+config RT2X00_LIB_EEPROM
-+ boolean
-+
- config RT2X00_LIB_LEDS
- depends on !BACKPORT_KERNEL_2_6_25
- boolean
---- a/drivers/net/wireless/rt2x00/Makefile
-+++ b/drivers/net/wireless/rt2x00/Makefile
-@@ -7,6 +7,7 @@ rt2x00lib-$(CPTCFG_RT2X00_LIB_DEBUGFS) +
- rt2x00lib-$(CPTCFG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
- rt2x00lib-$(CPTCFG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
- rt2x00lib-$(CPTCFG_RT2X00_LIB_LEDS) += rt2x00leds.o
-+rt2x00lib-$(CPTCFG_RT2X00_LIB_EEPROM) += rt2x00eeprom.o
-
- obj-$(CPTCFG_RT2X00_LIB) += rt2x00lib.o
- obj-$(CPTCFG_RT2X00_LIB_MMIO) += rt2x00mmio.o
---- a/drivers/net/wireless/rt2x00/rt2800pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -90,25 +90,11 @@ static void rt2800pci_mcu_status(struct
- rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
- }
-
--#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)
- static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
- {
-- void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
--
-- if (!base_addr)
-- return -ENOMEM;
--
-- memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
--
-- iounmap(base_addr);
-+ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, EEPROM_SIZE);
- return 0;
- }
--#else
--static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
--{
-- return -ENOMEM;
--}
--#endif /* CONFIG_SOC_RT288X || CONFIG_SOC_RT305X */
-
- #ifdef CONFIG_PCI
- static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
-@@ -332,6 +318,20 @@ static int rt2800pci_write_firmware(stru
- }
-
- /*
-+ * EEPROM file functions.
-+ */
-+static char *rt2800pci_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct rt2x00_platform_data *pdata;
-+
-+ pdata = rt2x00dev->dev->platform_data;
-+ if (pdata)
-+ return pdata->eeprom_file_name;
-+
-+ return NULL;
-+}
-+
-+/*
- * Initialization functions.
- */
- static bool rt2800pci_get_entry_state(struct queue_entry *entry)
-@@ -1156,6 +1156,7 @@ static const struct rt2x00lib_ops rt2800
- .get_firmware_name = rt2800pci_get_firmware_name,
- .check_firmware = rt2800_check_firmware,
- .load_firmware = rt2800_load_firmware,
-+ .get_eeprom_file_name = rt2800pci_get_eeprom_file_name,
- .initialize = rt2x00mmio_initialize,
- .uninitialize = rt2x00mmio_uninitialize,
- .get_entry_state = rt2800pci_get_entry_state,
---- a/drivers/net/wireless/rt2x00/rt2x00dev.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
-@@ -1325,6 +1325,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
- INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
- INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
-
-+ retval = rt2x00lib_load_eeprom_file(rt2x00dev);
-+ if (retval)
-+ goto exit;
-+
- /*
- * Let the driver probe the device to detect the capabilities.
- */
-@@ -1455,6 +1459,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
- */
- if (rt2x00dev->drv_data)
- kfree(rt2x00dev->drv_data);
-+
-+ /*
-+ * Free EEPROM image.
-+ */
-+ rt2x00lib_free_eeprom_file(rt2x00dev);
- }
- EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
-
--- a/drivers/net/wireless/rt2x00/rt2x00soc.c
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.c
-@@ -94,6 +94,7 @@ int rt2x00soc_probe(struct platform_devi
+@@ -92,6 +92,7 @@ int rt2x00soc_probe(struct platform_devi
rt2x00dev->hw = hw;
rt2x00dev->irq = platform_get_irq(pdev, 0);
rt2x00dev->name = pdev->dev.driver->name;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
---- a/.local-symbols
-+++ b/.local-symbols
-@@ -272,6 +272,7 @@ RT2X00_LIB_FIRMWARE=
- RT2X00_LIB_CRYPTO=
- RT2X00_LIB_LEDS=
- RT2X00_LIB_DEBUGFS=
-+RT2X00_LIB_EEPROM=
- RT2X00_DEBUG=
- RTLWIFI=
- RTLWIFI_DEBUG=
--- /dev/null
+--- a/drivers/net/wireless/rt2x00/rt2x00eeprom.c
++++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c
+@@ -26,6 +26,7 @@
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/of.h>
+
+ #include "rt2x00.h"
+ #include "rt2x00lib.h"
+@@ -34,11 +35,21 @@ static const char *
+ rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
+ {
+ struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
++#ifdef CONFIG_OF
++ struct device_node *np;
++ const char *eep;
++#endif
+
+ if (pdata && pdata->eeprom_file_name)
+ return pdata->eeprom_file_name;
+
+- return NULL
++#ifdef CONFIG_OF
++ np = rt2x00dev->dev->of_node;
++ if (np && of_property_read_string(np, "ralink,eeprom", &eep) == 0)
++ return eep;
++#endif
++
++ return NULL;
+ }
+
+ static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
--- /dev/null
+From 339fe73f340161a624cc08e738d2244814852c3e Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 17 Mar 2013 00:55:04 +0100
+Subject: [PATCH] rt2x00: load eeprom on SoC from a mtd device defines inside
+ OF
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/wireless/rt2x00/Kconfig | 1 +
+ drivers/net/wireless/rt2x00/rt2800pci.c | 44 ++++++++++++++++++++++++++-----
+ 2 files changed, 39 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/rt2x00/Kconfig
++++ b/drivers/net/wireless/rt2x00/Kconfig
+@@ -219,6 +219,7 @@ config RT2800SOC
+ select RT2X00_LIB_EEPROM
+ select RT2800_LIB
+ select RT2800_LIB_MMIO
++ select MTD if SOC_RT288X || SOC_RT305X
+ ---help---
+ This adds support for Ralink WiSoC devices.
+ Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352.
+--- a/drivers/net/wireless/rt2x00/rt2x00eeprom.c
++++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c
+@@ -26,11 +26,66 @@
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
+ #include <linux/of.h>
+
+ #include "rt2x00.h"
+ #include "rt2x00lib.h"
+
++static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev)
++{
++ int ret = -EINVAL;
++#ifdef CONFIG_OF
++ static struct firmware mtd_fw;
++ struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL;
++ size_t retlen, len = rt2x00dev->ops->eeprom_size;
++ int size, offset = 0;
++ struct mtd_info *mtd;
++ const char *part;
++ const __be32 *list;
++ phandle phandle;
++
++ list = of_get_property(np, "ralink,mtd-eeprom", &size);
++ if (!list) {
++ dev_err(rt2x00dev->dev, "failed to load eeprom property\n");
++ return -ENOENT;
++ }
++
++ phandle = be32_to_cpup(list++);
++ if (phandle)
++ mtd_np = of_find_node_by_phandle(phandle);
++ if (!mtd_np) {
++ dev_err(rt2x00dev->dev, "failed to load mtd phandle\n");
++ return -EINVAL;
++ }
++
++ part = of_get_property(mtd_np, "label", NULL);
++ if (!part)
++ part = mtd_np->name;
++
++ mtd = get_mtd_device_nm(part);
++ if (IS_ERR(mtd)) {
++ dev_err(rt2x00dev->dev, "failed to get mtd device \"%s\"\n", part);
++ return PTR_ERR(mtd);
++ }
++
++ if (size > sizeof(*list))
++ offset = be32_to_cpup(list);
++
++ ret = mtd_read(mtd, offset, len, &retlen, (u_char *) rt2x00dev->eeprom);
++ put_mtd_device(mtd);
++
++ if (!ret) {
++ rt2x00dev->eeprom_file = &mtd_fw;
++ mtd_fw.size = len;
++ mtd_fw.data = rt2x00dev->eeprom;
++ }
++#endif
++
++ return ret;
++}
++
+ static const char *
+ rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
+ {
+@@ -58,6 +113,9 @@ static int rt2x00lib_request_eeprom_file
+ const char *ee_name;
+ int retval;
+
++ if (!rt2800lib_read_eeprom_mtd(rt2x00dev))
++ return 0;
++
+ ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev);
+ if (!ee_name) {
+ rt2x00_err(rt2x00dev,
+++ /dev/null
---- a/drivers/net/wireless/rt2x00/rt2800pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -90,7 +90,7 @@ static void rt2800pci_mcu_status(struct
- rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
- }
-
--static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
-+static int rt2800pci_read_eeprom_file(struct rt2x00_dev *rt2x00dev)
- {
- memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, EEPROM_SIZE);
- return 0;
-@@ -1093,8 +1093,9 @@ static int rt2800pci_read_eeprom(struct
- {
- int retval;
-
-- if (rt2x00_is_soc(rt2x00dev))
-- retval = rt2800pci_read_eeprom_soc(rt2x00dev);
-+ if (rt2x00_is_soc(rt2x00dev) ||
-+ test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags))
-+ retval = rt2800pci_read_eeprom_file(rt2x00dev);
- else if (rt2800pci_efuse_detect(rt2x00dev))
- retval = rt2800pci_read_eeprom_efuse(rt2x00dev);
- else
---- a/drivers/net/wireless/rt2x00/rt2x00pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
-@@ -78,6 +78,7 @@ exit:
- int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
- {
- struct ieee80211_hw *hw;
-+ struct rt2x00_platform_data *pdata;
- struct rt2x00_dev *rt2x00dev;
- int retval;
- u16 chip;
-@@ -125,6 +126,12 @@ int rt2x00pci_probe(struct pci_dev *pci_
- rt2x00dev->irq = pci_dev->irq;
- rt2x00dev->name = pci_name(pci_dev);
-
-+ /* if we get passed the name of a eeprom_file_name, then use this in
-+ favour of the eeprom */
-+ pdata = rt2x00dev->dev->platform_data;
-+ if (pdata && pdata->eeprom_file_name)
-+ set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags);
-+
- if (pci_is_pcie(pci_dev))
- rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
- else
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
-@@ -163,36 +163,14 @@ void rt2x00queue_align_frame(struct sk_b
+@@ -161,36 +161,14 @@ void rt2x00queue_align_frame(struct sk_b
void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
{
unsigned int payload_length = skb->len - header_length;
#endif /* _RT2X00_PLATFORM_H */
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
-@@ -938,6 +938,22 @@ static int rt2x00lib_probe_hw_modes(stru
+@@ -937,6 +937,22 @@ static int rt2x00lib_probe_hw_modes(stru
unsigned int num_rates;
unsigned int i;
num_rates += 4;
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -414,6 +414,7 @@ struct hw_mode_spec {
+@@ -403,6 +403,7 @@ struct hw_mode_spec {
unsigned int supported_bands;
#define SUPPORT_BAND_2GHZ 0x00000001
#define SUPPORT_BAND_5GHZ 0x00000002
int disable_5ghz;
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
-@@ -929,6 +929,18 @@ static void rt2x00lib_rate(struct ieee80
+@@ -928,6 +928,18 @@ static void rt2x00lib_rate(struct ieee80
entry->flags |= IEEE80211_RATE_SHORT_PREAMBLE;
}
{
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -1326,6 +1326,7 @@ static inline void rt2x00debug_dump_fram
+@@ -1401,6 +1401,7 @@ static inline void rt2x00debug_dump_fram
*/
u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif);
* Interrupt context handlers.
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
-@@ -2395,6 +2395,7 @@ static int rt61pci_validate_eeprom(struc
+@@ -2392,6 +2392,7 @@ static int rt61pci_validate_eeprom(struc
u32 reg;
u16 word;
u8 *mac;
s8 value;
rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®);
-@@ -2415,7 +2416,11 @@ static int rt61pci_validate_eeprom(struc
+@@ -2412,7 +2413,11 @@ static int rt61pci_validate_eeprom(struc
/*
* Start validation of the data that has been read.
*/
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -2631,15 +2631,18 @@ static void rt2800_config_channel(struct
+@@ -3176,11 +3176,17 @@ static void rt2800_config_channel(struct
/*
* Change BBP settings
*/
rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
+ rt2800_bbp_write(rt2x00dev, 83, 0x6a);
+ } else if (rt2x00_rt(rt2x00dev, RT3593)) {
+ if (rf->channel > 14) {
+ /* Disable CCK Packet detection on 5GHz */
+@@ -3194,14 +3200,8 @@ static void rt2800_config_channel(struct
+ else
+ rt2800_bbp_write(rt2x00dev, 105, 0x34);
+
+- rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+- rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+- rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 77, 0x98);
} else {
- rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
- rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
rt2800_bbp_write(rt2x00dev, 86, 0);
}
-@@ -4971,6 +4974,12 @@ static void rt2800_init_rfcsr_3290(struc
+@@ -6125,6 +6125,12 @@ static void rt2800_init_rfcsr_3290(struc
static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
{
rt2800_rf_init_calibration(rt2x00dev, 30);
rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
-@@ -5006,15 +5015,30 @@ static void rt2800_init_rfcsr_3352(struc
+@@ -6160,15 +6166,30 @@ static void rt2800_init_rfcsr_3352(struc
rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
-@@ -5022,15 +5046,20 @@ static void rt2800_init_rfcsr_3352(struc
+@@ -6176,15 +6197,20 @@ static void rt2800_init_rfcsr_3352(struc
rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
-@@ -5716,6 +5745,7 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7051,6 +7077,7 @@ static int rt2800_init_eeprom(struct rt2
* RT53xx: defined in "EEPROM_CHIP_ID" field
*/
if (rt2x00_rt(rt2x00dev, RT3290) ||
+ rt2x00_rt(rt2x00dev, RT3352) ||
rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392))
- rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
-@@ -5805,7 +5835,8 @@ static int rt2800_init_eeprom(struct rt2
+ rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
+@@ -7142,7 +7169,8 @@ static int rt2800_init_eeprom(struct rt2
/*
* Detect if this device has Bluetooth co-existence.
*/
__set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags);
/*
-@@ -5834,6 +5865,22 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7171,6 +7199,22 @@ static int rt2800_init_eeprom(struct rt2
EIRP_MAX_TX_POWER_LIMIT)
__set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags);
+ /*
+ * Detect if device uses internal or external PA
+ */
-+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
++ rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+
+ if (rt2x00_rt(rt2x00dev, RT3352)) {
+ if (!rt2x00_get_field16(eeprom,
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
-@@ -2153,6 +2153,12 @@ struct mac_iveiv_entry {
- #define RFCSR31_RX_CALIB FIELD8(0x7f)
+@@ -2299,6 +2299,12 @@ struct mac_iveiv_entry {
+ #define RFCSR36_RF_BS FIELD8(0x80)
/*
+ * RFCSR 34:
* RFCSR 38:
*/
#define RFCSR38_RX_LO1_EN FIELD8(0x20)
-@@ -2163,6 +2169,18 @@ struct mac_iveiv_entry {
+@@ -2310,6 +2316,18 @@ struct mac_iveiv_entry {
#define RFCSR39_RX_LO2_EN FIELD8(0x80)
/*
* RFCSR 49:
*/
#define RFCSR49_TX FIELD8(0x3f)
-@@ -2172,6 +2190,8 @@ struct mac_iveiv_entry {
+@@ -2322,6 +2340,8 @@ struct mac_iveiv_entry {
* RFCSR 50:
*/
#define RFCSR50_TX FIELD8(0x3f)
+#define RFCSR50_TX0_EXT_PA FIELD8(0x02)
+#define RFCSR50_TX1_EXT_PA FIELD8(0x10)
#define RFCSR50_EP FIELD8(0xc0)
-
- /*
-@@ -2260,6 +2280,8 @@ struct mac_iveiv_entry {
+ /* bits for RT3593 */
+ #define RFCSR50_TX_LO1_EN FIELD8(0x20)
+@@ -2469,6 +2489,8 @@ enum rt2800_eeprom_word {
* INTERNAL_TX_ALC: 0: disable, 1: enable
* BT_COEXIST: 0: disable, 1: enable
* DAC_TEST: 0: disable, 1: enable
+ * EXTERNAL_TX0_PA: 0: disable, 1: enable (only on RT3352)
+ * EXTERNAL_TX1_PA: 0: disable, 1: enable (only on RT3352)
*/
- #define EEPROM_NIC_CONF1 0x001b
#define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001)
-@@ -2277,6 +2299,8 @@ struct mac_iveiv_entry {
- #define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000)
+ #define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC FIELD16(0x0002)
+@@ -2485,6 +2507,8 @@ enum rt2800_eeprom_word {
+ #define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000)
#define EEPROM_NIC_CONF1_BT_COEXIST FIELD16(0x4000)
#define EEPROM_NIC_CONF1_DAC_TEST FIELD16(0x8000)
+#define EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352 FIELD16(0x4000)
* EEPROM frequency
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -726,6 +726,8 @@ enum rt2x00_capability_flags {
+@@ -714,6 +714,8 @@ enum rt2x00_capability_flags {
CAPABILITY_DOUBLE_ANTENNA,
CAPABILITY_BT_COEXIST,
CAPABILITY_VCO_RECALIBRATION,
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -6157,6 +6157,27 @@ static const struct rf_channel rf_vals_5
+@@ -7491,6 +7491,27 @@ static const struct rf_channel rf_vals_5
{196, 83, 0, 12, 1},
};
static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
-@@ -6235,7 +6256,6 @@ static int rt2800_probe_hw_mode(struct r
- rt2x00_rf(rt2x00dev, RF3022) ||
- rt2x00_rf(rt2x00dev, RF3290) ||
- rt2x00_rf(rt2x00dev, RF3320) ||
-- rt2x00_rf(rt2x00dev, RF3322) ||
- rt2x00_rf(rt2x00dev, RF5360) ||
- rt2x00_rf(rt2x00dev, RF5370) ||
- rt2x00_rf(rt2x00dev, RF5372) ||
-@@ -6243,6 +6263,12 @@ static int rt2800_probe_hw_mode(struct r
- rt2x00_rf(rt2x00dev, RF5392)) {
+@@ -7579,7 +7600,10 @@ static int rt2800_probe_hw_mode(struct r
+ case RF5390:
+ case RF5392:
spec->num_channels = 14;
- spec->channels = rf_vals_3x;
-+ } else if (rt2x00_rf(rt2x00dev, RF3322)) {
-+ spec->num_channels = 14;
+- spec->channels = rf_vals_3x;
+ if (spec->clk_is_20mhz)
+ spec->channels = rf_vals_xtal20mhz_3x;
+ else
+ spec->channels = rf_vals_3x;
- } else if (rt2x00_rf(rt2x00dev, RF3052)) {
- spec->supported_bands |= SUPPORT_BAND_5GHZ;
- spec->num_channels = ARRAY_SIZE(rf_vals_3x);
-@@ -6390,6 +6416,19 @@ static int rt2800_probe_rt(struct rt2x00
+ break;
+
+ case RF3052:
+@@ -7755,6 +7779,19 @@ static int rt2800_probe_rt(struct rt2x00
return 0;
}
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
-@@ -6419,6 +6458,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
+@@ -7784,6 +7821,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r
rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
/*
retval = rt2800_probe_hw_mode(rt2x00dev);
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -409,6 +409,7 @@ static inline struct rt2x00_intf* vif_to
+@@ -398,6 +398,7 @@ static inline struct rt2x00_intf* vif_to
* @channels: Device/chipset specific channel values (See &struct rf_channel).
* @channels_info: Additional information for channels (See &struct channel_info).
* @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap).
*/
struct hw_mode_spec {
unsigned int supported_bands;
-@@ -425,6 +426,7 @@ struct hw_mode_spec {
+@@ -414,6 +415,7 @@ struct hw_mode_spec {
const struct channel_info *channels_info;
struct ieee80211_sta_ht_cap ht;
drivers/net/wireless/rt2x00/rt2800pci.c | 7 +++++++
1 file changed, 7 insertions(+)
---- a/drivers/net/wireless/rt2x00/rt2800pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -1309,11 +1309,18 @@ static int rt2800soc_probe(struct platfo
- return rt2x00soc_probe(pdev, &rt2800pci_ops);
+--- a/drivers/net/wireless/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/rt2x00/rt2800soc.c
+@@ -227,11 +227,18 @@ static int rt2800soc_probe(struct platfo
+ return rt2x00soc_probe(pdev, &rt2800soc_ops);
}
+static const struct of_device_id rt2880_wmac_match[] = {
+++ /dev/null
---- a/drivers/net/wireless/rt2x00/rt2800pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
-@@ -39,6 +39,7 @@
- #include <linux/pci.h>
- #include <linux/platform_device.h>
- #include <linux/eeprom_93cx6.h>
-+#include <linux/of.h>
-
- #include "rt2x00.h"
- #include "rt2x00mmio.h"
-@@ -323,11 +324,17 @@ static int rt2800pci_write_firmware(stru
- static char *rt2800pci_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
- {
- struct rt2x00_platform_data *pdata;
-+ struct device_node *np;
-+ char *eep;
-
- pdata = rt2x00dev->dev->platform_data;
- if (pdata)
- return pdata->eeprom_file_name;
-
-+ np = rt2x00dev->dev->of_node;
-+ if (np && !of_property_read_string(np, "ralink,eeprom", &eep))
-+ return eep;
-+
- return NULL;
- }
-
--- /dev/null
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -36,6 +36,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
++#include <linux/clk.h>
+
+ #include "rt2x00.h"
+ #include "rt2800lib.h"
+@@ -7781,13 +7782,14 @@ static int rt2800_probe_rt(struct rt2x00
+
+ int rt2800_probe_clk(struct rt2x00_dev *rt2x00dev)
+ {
+- struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
++ struct clk *clk = clk_get(rt2x00dev->dev, NULL);
+
+- if (!pdata)
+- return -EINVAL;
++ if (IS_ERR(clk))
++ return PTR_ERR(clk);
+
+- spec->clk_is_20mhz = pdata->clk_is_20mhz;
++ if (clk_get_rate(clk) == 20000000)
++ spec->clk_is_20mhz = 1;
+
+ return 0;
+ }
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -71,6 +71,7 @@
- #define RF3053 0x000d
#define RF5592 0x000f
+ #define RF3070 0x3070
#define RF3290 0x3290
+#define RF5350 0x5350
#define RF5360 0x5360
#define RF5372 0x5372
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -2140,6 +2140,15 @@ static void rt2800_config_channel_rf53xx
- if (rf->channel <= 14) {
- int idx = rf->channel-1;
+@@ -2705,6 +2705,13 @@ static void rt2800_config_channel_rf53xx
-+ if (rt2x00_rt(rt2x00dev, RT5350)) {
-+ static const char r59_non_bt[] = {0x0b, 0x0b,
-+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a,
-+ 0x0a, 0x09, 0x08, 0x07, 0x07, 0x06};
+ rt2800_rfcsr_write(rt2x00dev, 59,
+ r59_non_bt[idx]);
++ } else if (rt2x00_rt(rt2x00dev, RT5350)) {
++ static const char r59_non_bt[] = {0x0b, 0x0b,
++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a,
++ 0x0a, 0x09, 0x08, 0x07, 0x07, 0x06};
+
-+ rt2800_rfcsr_write(rt2x00dev, 59,
-+ r59_non_bt[idx]);
-+ }
-+
- if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
- /* r55/r59 value array of channel 1~14 */
-@@ -2597,6 +2606,7 @@ static void rt2800_config_channel(struct
- case RF3322:
++ rt2800_rfcsr_write(rt2x00dev, 59,
++ r59_non_bt[idx]);
+ }
+ }
+ }
+@@ -3142,6 +3149,7 @@ static void rt2800_config_channel(struct
rt2800_config_channel_rf3322(rt2x00dev, conf, rf, info);
break;
+ case RF3070:
+ case RF5350:
case RF5360:
case RF5370:
case RF5372:
-@@ -2613,6 +2623,7 @@ static void rt2800_config_channel(struct
-
- if (rt2x00_rf(rt2x00dev, RF3290) ||
+@@ -3159,6 +3167,7 @@ static void rt2800_config_channel(struct
+ if (rt2x00_rf(rt2x00dev, RF3070) ||
+ rt2x00_rf(rt2x00dev, RF3290) ||
rt2x00_rf(rt2x00dev, RF3322) ||
+ rt2x00_rf(rt2x00dev, RF5350) ||
rt2x00_rf(rt2x00dev, RF5360) ||
rt2x00_rf(rt2x00dev, RF5370) ||
rt2x00_rf(rt2x00dev, RF5372) ||
-@@ -2777,7 +2788,8 @@ static void rt2800_config_channel(struct
+@@ -3399,7 +3408,8 @@ static void rt2800_config_channel(struct
/*
* Clear update flag
*/
rt2800_bbp_read(rt2x00dev, 49, &bbp);
rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0);
rt2800_bbp_write(rt2x00dev, 49, bbp);
-@@ -3223,6 +3235,7 @@ void rt2800_vco_calibration(struct rt2x0
- rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
- break;
+@@ -4273,6 +4283,7 @@ void rt2800_vco_calibration(struct rt2x0
+ case RF3053:
+ case RF3070:
case RF3290:
+ case RF5350:
case RF5360:
case RF5370:
case RF5372:
-@@ -3562,7 +3575,8 @@ static int rt2800_init_registers(struct
- } else if (rt2x00_rt(rt2x00dev, RT3572)) {
- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-- } else if (rt2x00_rt(rt2x00dev, RT5390) ||
-+ } else if (rt2x00_rt(rt2x00dev, RT5350) ||
-+ rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392) ||
- rt2x00_rt(rt2x00dev, RT5592)) {
+@@ -4669,6 +4680,8 @@ static int rt2800_init_registers(struct
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
-@@ -4215,9 +4229,13 @@ static void rt2800_init_bbp_3352(struct
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
++ } else if (rt2x00_rt(rt2x00dev, RT5350)) {
++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
+ } else {
+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+@@ -5310,9 +5323,13 @@ static void rt2800_init_bbp_3352(struct
rt2800_bbp_write(rt2x00dev, 82, 0x62);
rt2800_bbp_write(rt2x00dev, 86, 0x38);
-@@ -4231,9 +4249,13 @@ static void rt2800_init_bbp_3352(struct
+@@ -5326,9 +5343,13 @@ static void rt2800_init_bbp_3352(struct
rt2800_bbp_write(rt2x00dev, 104, 0x92);
rt2800_bbp_write(rt2x00dev, 120, 0x50);
-@@ -4258,6 +4280,13 @@ static void rt2800_init_bbp_3352(struct
+@@ -5353,6 +5374,13 @@ static void rt2800_init_bbp_3352(struct
rt2800_bbp_write(rt2x00dev, 143, 0xa2);
rt2800_bbp_write(rt2x00dev, 148, 0xc8);
}
static void rt2800_init_bbp_3390(struct rt2x00_dev *rt2x00dev)
-@@ -4542,6 +4571,7 @@ static void rt2800_init_bbp(struct rt2x0
+@@ -5653,6 +5681,7 @@ static void rt2800_init_bbp(struct rt2x0
rt2800_init_bbp_3290(rt2x00dev);
break;
case RT3352:
rt2800_init_bbp_3352(rt2x00dev);
break;
case RT3390:
-@@ -5181,6 +5211,76 @@ static void rt2800_init_rfcsr_3572(struc
- rt2800_normal_mode_setup_3xxx(rt2x00dev);
+@@ -6463,6 +6492,76 @@ static void rt2800_init_rfcsr_3593(struc
+ /* TODO: enable stream mode support */
}
+static void rt2800_init_rfcsr_5350(struct rt2x00_dev *rt2x00dev)
static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
{
rt2800_rf_init_calibration(rt2x00dev, 2);
-@@ -5409,6 +5509,9 @@ static void rt2800_init_rfcsr(struct rt2
- case RT3572:
- rt2800_init_rfcsr_3572(rt2x00dev);
+@@ -6700,6 +6799,9 @@ static void rt2800_init_rfcsr(struct rt2
+ case RT3593:
+ rt2800_init_rfcsr_3593(rt2x00dev);
break;
+ case RT5350:
+ rt2800_init_rfcsr_5350(rt2x00dev);
case RT5390:
rt2800_init_rfcsr_5390(rt2x00dev);
break;
-@@ -5621,6 +5724,12 @@ static int rt2800_validate_eeprom(struct
+@@ -6949,6 +7051,12 @@ static int rt2800_validate_eeprom(struct
rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
+ rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
+ } else if (rt2x00_rt(rt2x00dev, RT5350)) {
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 1);
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2872)) {
/*
-@@ -5749,6 +5858,8 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7082,6 +7190,8 @@ static int rt2800_init_eeprom(struct rt2
rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392))
- rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
+ rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
+ else if (rt2x00_rt(rt2x00dev, RT5350))
+ rf = RF5350;
else
rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
-@@ -5765,6 +5876,7 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7100,6 +7210,7 @@ static int rt2800_init_eeprom(struct rt2
case RF3290:
case RF3320:
case RF3322:
case RF5360:
case RF5370:
case RF5372:
-@@ -6263,7 +6375,8 @@ static int rt2800_probe_hw_mode(struct r
- rt2x00_rf(rt2x00dev, RF5392)) {
- spec->num_channels = 14;
- spec->channels = rf_vals_3x;
-- } else if (rt2x00_rf(rt2x00dev, RF3322)) {
-+ } else if (rt2x00_rf(rt2x00dev, RF3322) ||
-+ rt2x00_rf(rt2x00dev, RF5350)) {
- spec->num_channels = 14;
- if (spec->clk_is_20mhz)
- spec->channels = rf_vals_xtal20mhz_3x;
-@@ -6364,6 +6477,7 @@ static int rt2800_probe_hw_mode(struct r
+@@ -7595,6 +7706,7 @@ static int rt2800_probe_hw_mode(struct r
+ case RF3290:
case RF3320:
- case RF3052:
+ case RF3322:
++ case RF5350:
+ case RF5360:
+ case RF5370:
+ case RF5372:
+@@ -7727,6 +7839,7 @@ static int rt2800_probe_hw_mode(struct r
+ case RF3053:
+ case RF3070:
case RF3290:
+ case RF5350:
case RF5360:
case RF5370:
case RF5372:
-@@ -6401,6 +6515,7 @@ static int rt2800_probe_rt(struct rt2x00
- case RT3352:
+@@ -7765,6 +7878,7 @@ static int rt2800_probe_rt(struct rt2x00
case RT3390:
case RT3572:
+ case RT3593:
+ case RT5350:
case RT5390:
case RT5392:
case RT5592:
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
-@@ -181,6 +181,7 @@ struct rt2x00_chip {
+@@ -169,6 +169,7 @@ struct rt2x00_chip {
#define RT3572 0x3572
#define RT3593 0x3593
#define RT3883 0x3883 /* WSOC */
+++ /dev/null
-From 339fe73f340161a624cc08e738d2244814852c3e Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 17 Mar 2013 00:55:04 +0100
-Subject: [PATCH] rt2x00: load eeprom on SoC from a mtd device defines inside
- OF
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/wireless/rt2x00/Kconfig | 1 +
- drivers/net/wireless/rt2x00/rt2800pci.c | 44 ++++++++++++++++++++++++++-----
- 2 files changed, 39 insertions(+), 6 deletions(-)
-
---- a/drivers/net/wireless/rt2x00/Kconfig
-+++ b/drivers/net/wireless/rt2x00/Kconfig
-@@ -71,6 +71,7 @@ config RT2800PCI
- select RT2X00_LIB_FIRMWARE
- select RT2X00_LIB_EEPROM
- select RT2X00_LIB_CRYPTO
-+ select MTD if SOC_RT288X || SOC_RT305X
- depends on CRC_CCITT
- depends on EEPROM_93CX6
- ---help---
---- a/drivers/net/wireless/rt2x00/rt2x00eeprom.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c
-@@ -30,12 +30,77 @@
- #include "rt2x00.h"
- #include "rt2x00lib.h"
-
-+#ifdef CONFIG_OF
-+#include <linux/of.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+
-+static struct firmware mtd_fw;
-+
-+static int rt2800pci_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev)
-+{
-+ struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL;
-+ size_t retlen, len = rt2x00dev->ops->eeprom_size;
-+ int ret, size, offset = 0;
-+ struct mtd_info *mtd;
-+ const char *part;
-+ const __be32 *list;
-+ phandle phandle;
-+
-+ list = of_get_property(np, "ralink,mtd-eeprom", &size);
-+ if (!list) {
-+ dev_err(rt2x00dev->dev, "failed to load eeprom property\n");
-+ return -ENOENT;
-+ }
-+
-+ phandle = be32_to_cpup(list++);
-+ if (phandle)
-+ mtd_np = of_find_node_by_phandle(phandle);
-+ if (!mtd_np) {
-+ dev_err(rt2x00dev->dev, "failed to load mtd phandle\n");
-+ return -EINVAL;
-+ }
-+
-+ part = of_get_property(mtd_np, "label", NULL);
-+ if (!part)
-+ part = mtd_np->name;
-+
-+ mtd = get_mtd_device_nm(part);
-+ if (IS_ERR(mtd)) {
-+ dev_err(rt2x00dev->dev, "failed to get mtd device \"%s\"\n", part);
-+ return PTR_ERR(mtd);
-+ }
-+
-+ if (size > sizeof(*list))
-+ offset = be32_to_cpup(list);
-+
-+ ret = mtd_read(mtd, offset, len, &retlen, (u_char *) rt2x00dev->eeprom);
-+ put_mtd_device(mtd);
-+
-+ if (!ret) {
-+ rt2x00dev->eeprom_file = &mtd_fw;
-+ mtd_fw.size = len;
-+ mtd_fw.data = rt2x00dev->eeprom;
-+ }
-+
-+ return ret;
-+}
-+#else
-+static inline int rt2800pci_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev)
-+{
-+ return -EINVAL;
-+}
-+#endif
-+
- static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
- {
- const struct firmware *ee;
- char *ee_name;
- int retval;
-
-+ if (!rt2800pci_read_eeprom_mtd(rt2x00dev))
-+ return 0;
-+
- ee_name = rt2x00dev->ops->lib->get_eeprom_file_name(rt2x00dev);
- if (!ee_name) {
- rt2x00_err(rt2x00dev,
+++ /dev/null
---- a/drivers/net/wireless/rt2x00/rt2x00pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
-@@ -108,7 +108,9 @@ int rt2x00pci_probe(struct pci_dev *pci_
- goto exit_release_regions;
- }
-
-+#ifdef CONFIG_PCI_MSI
- pci_enable_msi(pci_dev);
-+#endif
-
- hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
- if (!hw) {
-@@ -162,7 +164,9 @@ exit_free_device:
- ieee80211_free_hw(hw);
-
- exit_disable_msi:
-+#ifdef CONFIG_PCI_SET_MWI
- pci_disable_msi(pci_dev);
-+#endif
-
- exit_release_regions:
- pci_release_regions(pci_dev);
-@@ -188,7 +192,9 @@ void rt2x00pci_remove(struct pci_dev *pc
- rt2x00pci_free_reg(rt2x00dev);
- ieee80211_free_hw(hw);
-
-+#ifdef CONFIG_PCI_MSI
- pci_disable_msi(pci_dev);
-+#endif
-
- /*
- * Free the PCI device data.
--- /dev/null
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -37,6 +37,7 @@
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/clk.h>
++#include <linux/of.h>
+
+ #include "rt2x00.h"
+ #include "rt2800lib.h"
+@@ -7299,6 +7300,17 @@ static int rt2800_init_eeprom(struct rt2
+ rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
+ rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
+
++ {
++ struct device_node *np = rt2x00dev->dev->of_node;
++ unsigned int led_polarity;
++
++ /* Allow overriding polarity from OF */
++ if (!of_property_read_u32(np, "ralink,led-polarity",
++ &led_polarity))
++ rt2x00_set_field16(&eeprom, EEPROM_FREQ_LED_POLARITY,
++ led_polarity);
++ }
++
+ rt2x00dev->led_mcu_reg = eeprom;
+ #endif /* CPTCFG_RT2X00_LIB_LEDS */
+
+--- a/drivers/net/wireless/rt2x00/rt2x00leds.c
++++ b/drivers/net/wireless/rt2x00/rt2x00leds.c
+@@ -109,6 +109,9 @@ static int rt2x00leds_register_led(struc
+ led->led_dev.name = name;
+ led->led_dev.brightness = LED_OFF;
+
++ if (rt2x00_is_soc(rt2x00dev))
++ led->led_dev.brightness_set(&led->led_dev, LED_OFF);
++
+ retval = led_classdev_register(device, &led->led_dev);
+ if (retval) {
+ rt2x00_err(rt2x00dev, "Failed to register led handler\n");
--- /dev/null
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -1262,7 +1262,7 @@ static inline void rt2x00lib_set_if_comb
+ */
+ if_limit = &rt2x00dev->if_limits_ap;
+ if_limit->max = rt2x00dev->ops->max_ap_intf;
+- if_limit->types = BIT(NL80211_IFTYPE_AP);
++ if_limit->types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION);
+ #ifdef CPTCFG_MAC80211_MESH
+ if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT);
+ #endif
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -5854,10 +5854,11 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7187,10 +7187,11 @@ static int rt2800_init_eeprom(struct rt2
* RT53xx: defined in "EEPROM_CHIP_ID" field
*/
if (rt2x00_rt(rt2x00dev, RT3290) ||
- rt2x00_rt(rt2x00dev, RT3352) ||
rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392))
- rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
+ rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
+ else if (rt2x00_rt(rt2x00dev, RT3352))
+ rf = RF3322;
else if (rt2x00_rt(rt2x00dev, RT5350))
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
-@@ -5530,6 +5530,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
+@@ -5529,6 +5529,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
+++ /dev/null
-From 60ce314d1750fef843e9db70050e09e49f838b69 Mon Sep 17 00:00:00 2001
-From: Larry Finger <Larry.Finger@lwfinger.net>
-Date: Thu, 19 Sep 2013 02:21:35 +0000
-Subject: rtlwifi: Align private space in rtl_priv struct
-
-The private array at the end of the rtl_priv struct is not aligned.
-On ARM architecture, this causes an alignment trap and is fixed by aligning
-that array with __align(sizeof(void *)). That should properly align that
-space according to the requirements of all architectures.
-
-Reported-by: Jason Andrews <jasona@cadence.com>
-Tested-by: Jason Andrews <jasona@cadence.com>
-Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
-Cc: Stable <stable@vger.kernel.org>
-Signed-off-by: John W. Linville <linville@tuxdriver.com>
----
---- a/drivers/net/wireless/rtlwifi/wifi.h
-+++ b/drivers/net/wireless/rtlwifi/wifi.h
-@@ -2057,7 +2057,7 @@ struct rtl_priv {
- that it points to the data allocated
- beyond this structure like:
- rtl_pci_priv or rtl_usb_priv */
-- u8 priv[0];
-+ u8 priv[0] __aligned(sizeof(void *));
- };
-
- #define rtl_priv(hw) (((struct rtl_priv *)(hw)->priv))
static int modparam_bad_frames_preempt;
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
MODULE_PARM_DESC(bad_frames_preempt,
-@@ -2742,10 +2747,10 @@ static int b43_gpio_init(struct b43_wlde
+@@ -2747,10 +2752,10 @@ static int b43_gpio_init(struct b43_wlde
u32 mask, set;
b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0);
b43-y += wa.o
b43-y += dma.o
-b43-y += pio.o
-+b43-$(CONFIG_B43_PIO) += pio.o
++b43-$(CPTCFG_B43_PIO) += pio.o
b43-y += rfkill.o
b43-$(CPTCFG_B43_LEDS) += leds.o
b43-$(CPTCFG_B43_PCMCIA) += pcmcia.o
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
-+#ifdef CONFIG_B43_PIO
++#ifdef CPTCFG_B43_PIO
b43err(dev->wl, "This device does not support DMA "
"on your system. It will now be switched to PIO.\n");
/* Fall back to PIO transfers if we get fatal DMA errors! */
}
-
-+#ifdef CONFIG_B43_PIO
++#ifdef CPTCFG_B43_PIO
int b43_pio_init(struct b43_wldev *dev);
void b43_pio_free(struct b43_wldev *dev);
+static inline void b43_pio_tx_resume(struct b43_wldev *dev)
+{
+}
-+#endif /* CONFIG_B43_PIO */
++#endif /* CPTCFG_B43_PIO */
#endif /* B43_PIO_H_ */
--- a/drivers/net/wireless/b43/Kconfig
antenna = b43_antenna_to_phyctl(antenna);
ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
/* We can't send beacons with short preamble. Would get PHY errors. */
-@@ -3100,8 +3100,8 @@ static int b43_chip_init(struct b43_wlde
+@@ -3105,8 +3105,8 @@ static int b43_chip_init(struct b43_wlde
/* Select the antennae */
if (phy->ops->set_rx_antenna)
if (phy->type == B43_PHYTYPE_B) {
value16 = b43_read16(dev, 0x005E);
-@@ -3845,7 +3845,6 @@ static int b43_op_config(struct ieee8021
+@@ -3850,7 +3850,6 @@ static int b43_op_config(struct ieee8021
struct b43_wldev *dev;
struct b43_phy *phy;
struct ieee80211_conf *conf = &hw->conf;
int err = 0;
bool reload_bss = false;
-@@ -3899,11 +3898,9 @@ static int b43_op_config(struct ieee8021
+@@ -3904,11 +3903,9 @@ static int b43_op_config(struct ieee8021
}
/* Antennas for RX and management frame TX. */
if (wl->radio_enabled != phy->radio_on) {
if (wl->radio_enabled) {
-@@ -5028,6 +5025,47 @@ static int b43_op_get_survey(struct ieee
+@@ -5041,6 +5038,47 @@ static int b43_op_get_survey(struct ieee
return 0;
}
static const struct ieee80211_ops b43_hw_ops = {
.tx = b43_op_tx,
.conf_tx = b43_op_conf_tx,
-@@ -5049,6 +5087,8 @@ static const struct ieee80211_ops b43_hw
+@@ -5062,6 +5100,8 @@ static const struct ieee80211_ops b43_hw
.sw_scan_complete = b43_op_sw_scan_complete_notifier,
.get_survey = b43_op_get_survey,
.rfkill_poll = b43_rfkill_poll,
};
/* Hard-reset the chip. Do not call this directly.
-@@ -5295,6 +5335,8 @@ static int b43_one_core_attach(struct b4
+@@ -5308,6 +5348,8 @@ static int b43_one_core_attach(struct b4
if (!wldev)
goto out;
wldev->use_pio = b43_modparam_pio;
wldev->dev = dev;
wldev->wl = wl;
-@@ -5385,6 +5427,9 @@ static struct b43_wl *b43_wireless_init(
+@@ -5398,6 +5440,9 @@ static struct b43_wl *b43_wireless_init(
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
-@@ -1061,6 +1061,32 @@ static inline bool b43_using_pio_transfe
+@@ -1061,6 +1061,31 @@ static inline bool b43_using_pio_transfe
return dev->__using_pio_transfers;
}
+{
+ if (b43_bus_host_is_pci(dev->dev) &&
+ bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA &&
-+ (bcm47xx_bus.bcma.bus.chipinfo.id == 0x4716 ||
-+ bcm47xx_bus.bcma.bus.chipinfo.id == 0x5300)) {
++ bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4716) {
+ b43_write16(dev, offset, value);
+ b43_read16(dev, offset);
+ } else {
+{
+ if (dev->bus_type == B43_BUS_SSB)
+ return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI);
-+#ifdef CONFIG_B43_BCMA
++#ifdef CPTCFG_B43_BCMA
+ if (dev->bus_type == B43_BUS_BCMA)
+ return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI);
+#endif
struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core);
struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev);
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -4437,7 +4437,7 @@ static int b43_phy_versioning(struct b43
+ u16 radio24[3];
+
+ for (tmp = 0; tmp < 3; tmp++) {
+- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
++ b43_wflush16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+ radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
+ }
+
+@@ -4456,10 +4456,10 @@ static int b43_phy_versioning(struct b43
+ else
+ tmp = 0x5205017F;
+ } else {
+- b43_write16(dev, B43_MMIO_RADIO_CONTROL,
++ b43_wflush16(dev, B43_MMIO_RADIO_CONTROL,
+ B43_RADIOCTL_ID);
+ tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+- b43_write16(dev, B43_MMIO_RADIO_CONTROL,
++ b43_wflush16(dev, B43_MMIO_RADIO_CONTROL,
+ B43_RADIOCTL_ID);
+ tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
+ << 16;
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -266,6 +266,12 @@ void b43_phy_write(struct b43_wldev *dev
if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) {
b43_read16(dev, B43_MMIO_PHY_VER);
dev->phy.writes_counter = 0;
+--- a/drivers/net/wireless/b43/phy_ht.c
++++ b/drivers/net/wireless/b43/phy_ht.c
+@@ -1073,20 +1073,20 @@ static unsigned int b43_phy_ht_op_get_de
+
+ static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg)
+ {
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
+ }
+
+ static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+ {
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA, value);
+ }
+
+ static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
+ u16 set)
+ {
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA,
+ (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
+ }
+@@ -1096,14 +1096,14 @@ static u16 b43_phy_ht_op_radio_read(stru
+ /* HT-PHY needs 0x200 for read access */
+ reg |= 0x200;
+
+- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_RADIO24_DATA);
+ }
+
+ static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
+ u16 value)
+ {
+- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
+ }
+
+--- a/drivers/net/wireless/b43/phy_lcn.c
++++ b/drivers/net/wireless/b43/phy_lcn.c
+@@ -845,20 +845,20 @@ static void b43_phy_lcn_op_adjust_txpowe
+
+ static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
+ {
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
+ }
+
+ static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+ {
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA, value);
+ }
+
+ static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
+ u16 set)
+ {
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA,
+ (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
+ }
+@@ -868,14 +868,14 @@ static u16 b43_phy_lcn_op_radio_read(str
+ /* LCN-PHY needs 0x200 for read access */
+ reg |= 0x200;
+
+- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_RADIO24_DATA);
+ }
+
+ static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
+ u16 value)
+ {
+- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
+ }
+
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
-@@ -5417,14 +5417,14 @@ static inline void check_phyreg(struct b
+@@ -5418,14 +5418,14 @@ static inline void check_phyreg(struct b
static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
{
check_phyreg(dev, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
-@@ -5432,7 +5432,7 @@ static void b43_nphy_op_maskset(struct b
+@@ -5433,7 +5433,7 @@ static void b43_nphy_op_maskset(struct b
u16 set)
{
check_phyreg(dev, reg);
b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set);
}
-@@ -5443,7 +5443,7 @@ static u16 b43_nphy_op_radio_read(struct
+@@ -5444,7 +5444,7 @@ static u16 b43_nphy_op_radio_read(struct
/* N-PHY needs 0x100 for read access */
reg |= 0x100;
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
-@@ -5452,7 +5452,7 @@ static void b43_nphy_op_radio_write(stru
+@@ -5453,7 +5453,7 @@ static void b43_nphy_op_radio_write(stru
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
-@@ -2759,6 +2759,14 @@ static int b43_gpio_init(struct b43_wlde
+@@ -2764,6 +2764,14 @@ static int b43_gpio_init(struct b43_wlde
} else if (dev->dev->chip_id == 0x5354) {
/* Don't allow overtaking buttons GPIOs */
set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */
--- /dev/null
+--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+@@ -58,19 +58,12 @@
+ (((c) < 149) ? 3 : 4))))
+
+ #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
+-#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
+- NL80211_RRF_NO_IR)
++#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, 0)
+
+-#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
+- NL80211_RRF_NO_IR)
+-#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
+- NL80211_RRF_DFS | \
+- NL80211_RRF_NO_IR)
+-#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
+- NL80211_RRF_DFS | \
+- NL80211_RRF_NO_IR)
+-#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
+- NL80211_RRF_NO_IR)
++#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, 0)
++#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, 0)
++#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, 0)
++#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, 0)
+
+ static const struct ieee80211_regdomain brcms_regdom_x2 = {
+ .n_reg_rules = 6,
+++ /dev/null
---- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
-+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
-@@ -59,23 +59,16 @@
-
- #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
- #define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
-- NL80211_RRF_PASSIVE_SCAN | \
-- NL80211_RRF_NO_IBSS)
-+ 0)
-
- #define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
-- NL80211_RRF_PASSIVE_SCAN | \
-- NL80211_RRF_NO_IBSS)
-+ 0)
- #define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
-- NL80211_RRF_PASSIVE_SCAN | \
-- NL80211_RRF_DFS | \
-- NL80211_RRF_NO_IBSS)
-+ 0)
- #define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
-- NL80211_RRF_PASSIVE_SCAN | \
-- NL80211_RRF_DFS | \
-- NL80211_RRF_NO_IBSS)
-+ 0)
- #define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
-- NL80211_RRF_PASSIVE_SCAN | \
-- NL80211_RRF_NO_IBSS)
-+ 0)
-
- static const struct ieee80211_regdomain brcms_regdom_x2 = {
- .n_reg_rules = 6,
--- /dev/null
+Move the wl1251 part of the wl12xx platform data structure into a new
+structure specifically for wl1251. Change the platform data built-in
+block and board files accordingly.
+
+Cc: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Acked-by: Tony Lindgren <tony@atomide.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+
+--- a/drivers/net/wireless/ti/wilink_platform_data.c
++++ b/drivers/net/wireless/ti/wilink_platform_data.c
+@@ -23,17 +23,17 @@
+ #include <linux/err.h>
+ #include <linux/wl12xx.h>
+
+-static struct wl12xx_platform_data *platform_data;
++static struct wl12xx_platform_data *wl12xx_platform_data;
+
+ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
+ {
+- if (platform_data)
++ if (wl12xx_platform_data)
+ return -EBUSY;
+ if (!data)
+ return -EINVAL;
+
+- platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+- if (!platform_data)
++ wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
++ if (!wl12xx_platform_data)
+ return -ENOMEM;
+
+ return 0;
+@@ -41,9 +41,34 @@ int __init wl12xx_set_platform_data(cons
+
+ struct wl12xx_platform_data *wl12xx_get_platform_data(void)
+ {
+- if (!platform_data)
++ if (!wl12xx_platform_data)
+ return ERR_PTR(-ENODEV);
+
+- return platform_data;
++ return wl12xx_platform_data;
+ }
+ EXPORT_SYMBOL(wl12xx_get_platform_data);
++
++static struct wl1251_platform_data *wl1251_platform_data;
++
++int __init wl1251_set_platform_data(const struct wl1251_platform_data *data)
++{
++ if (wl1251_platform_data)
++ return -EBUSY;
++ if (!data)
++ return -EINVAL;
++
++ wl1251_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
++ if (!wl1251_platform_data)
++ return -ENOMEM;
++
++ return 0;
++}
++
++struct wl1251_platform_data *wl1251_get_platform_data(void)
++{
++ if (!wl1251_platform_data)
++ return ERR_PTR(-ENODEV);
++
++ return wl1251_platform_data;
++}
++EXPORT_SYMBOL(wl1251_get_platform_data);
+--- a/drivers/net/wireless/ti/wl1251/sdio.c
++++ b/drivers/net/wireless/ti/wl1251/sdio.c
+@@ -227,7 +227,7 @@ static int wl1251_sdio_probe(struct sdio
+ struct wl1251 *wl;
+ struct ieee80211_hw *hw;
+ struct wl1251_sdio *wl_sdio;
+- const struct wl12xx_platform_data *wl12xx_board_data;
++ const struct wl1251_platform_data *wl1251_board_data;
+
+ hw = wl1251_alloc_hw();
+ if (IS_ERR(hw))
+@@ -254,11 +254,11 @@ static int wl1251_sdio_probe(struct sdio
+ wl->if_priv = wl_sdio;
+ wl->if_ops = &wl1251_sdio_ops;
+
+- wl12xx_board_data = wl12xx_get_platform_data();
+- if (!IS_ERR(wl12xx_board_data)) {
+- wl->set_power = wl12xx_board_data->set_power;
+- wl->irq = wl12xx_board_data->irq;
+- wl->use_eeprom = wl12xx_board_data->use_eeprom;
++ wl1251_board_data = wl1251_get_platform_data();
++ if (!IS_ERR(wl1251_board_data)) {
++ wl->set_power = wl1251_board_data->set_power;
++ wl->irq = wl1251_board_data->irq;
++ wl->use_eeprom = wl1251_board_data->use_eeprom;
+ }
+
+ if (wl->irq) {
+--- a/drivers/net/wireless/ti/wl1251/spi.c
++++ b/drivers/net/wireless/ti/wl1251/spi.c
+@@ -241,7 +241,7 @@ static const struct wl1251_if_operations
+
+ static int wl1251_spi_probe(struct spi_device *spi)
+ {
+- struct wl12xx_platform_data *pdata;
++ struct wl1251_platform_data *pdata;
+ struct ieee80211_hw *hw;
+ struct wl1251 *wl;
+ int ret;
--- /dev/null
+The platform_quirk element in the platform data was used to change the
+way the IRQ is triggered. When set, the EDGE_IRQ quirk would change
+the irqflags used and treat edge trigger differently from the rest.
+
+Instead of hiding this irq flag setting behind the quirk, have the
+board files set the flags during initialization. This will be more
+meaningful than driver-specific quirks when we switch to DT.
+
+Additionally, fix missing gpio_request() calls in the boarding files
+(so that setting the flags actually works).
+
+Cc: Tony Lindgren <tony@atomide.com>
+Cc: Sekhar Nori <nsekhar@ti.com>
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+Acked-by: Sekhar Nori <nsekhar@ti.com>
+
+--- a/drivers/net/wireless/ti/wlcore/debugfs.c
++++ b/drivers/net/wireless/ti/wlcore/debugfs.c
+@@ -502,7 +502,7 @@ static ssize_t driver_state_read(struct
+ DRIVER_STATE_PRINT_HEX(irq);
+ /* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */
+ DRIVER_STATE_PRINT_HEX(hw_pg_ver);
+- DRIVER_STATE_PRINT_HEX(platform_quirks);
++ DRIVER_STATE_PRINT_HEX(irq_flags);
+ DRIVER_STATE_PRINT_HEX(chip.id);
+ DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
+ DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str);
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -27,6 +27,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/wl12xx.h>
+ #include <linux/interrupt.h>
++#include <linux/irq.h>
+
+ #include "wlcore.h"
+ #include "debug.h"
+@@ -528,7 +529,7 @@ static int wlcore_irq_locked(struct wl12
+ * In case edge triggered interrupt must be used, we cannot iterate
+ * more than once without introducing race conditions with the hardirq.
+ */
+- if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
++ if (wl->irq_flags & IRQF_TRIGGER_RISING)
+ loopcount = 1;
+
+ wl1271_debug(DEBUG_IRQ, "IRQ work");
+@@ -5934,7 +5935,6 @@ struct ieee80211_hw *wlcore_alloc_hw(siz
+ wl->ap_ps_map = 0;
+ wl->ap_fw_ps_map = 0;
+ wl->quirks = 0;
+- wl->platform_quirks = 0;
+ wl->system_hlid = WL12XX_SYSTEM_HLID;
+ wl->active_sta_count = 0;
+ wl->active_link_count = 0;
+@@ -6075,7 +6075,7 @@ static void wlcore_nvs_cb(const struct f
+ struct platform_device *pdev = wl->pdev;
+ struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
+ struct wl12xx_platform_data *pdata = pdev_data->pdata;
+- unsigned long irqflags;
++
+ int ret;
+ irq_handler_t hardirq_fn = NULL;
+
+@@ -6103,29 +6103,19 @@ static void wlcore_nvs_cb(const struct f
+ wlcore_adjust_conf(wl);
+
+ wl->irq = platform_get_irq(pdev, 0);
+- wl->platform_quirks = pdata->platform_quirks;
+ wl->if_ops = pdev_data->if_ops;
+
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+- irqflags = IRQF_TRIGGER_RISING;
++ wl->irq_flags = irq_get_trigger_type(wl->irq) | IRQF_ONESHOT;
+ hardirq_fn = wlcore_hardirq;
+-#else
+- if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) {
+- irqflags = IRQF_TRIGGER_RISING;
+- hardirq_fn = wlcore_hardirq;
+- } else {
+- irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
+- }
+-#endif
+
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
+ ret = compat_request_threaded_irq(&wl->irq_compat, wl->irq,
+ hardirq_fn, wlcore_irq,
+- irqflags,
++ wl->irqflags,
+ pdev->name, wl);
+ #else
+ ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
+- irqflags, pdev->name, wl);
++ wl->irq_flags, pdev->name, wl);
+ #endif
+ if (ret < 0) {
+ wl1271_error("request_irq() failed: %d", ret);
+--- a/drivers/net/wireless/ti/wlcore/wlcore.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore.h
+@@ -188,6 +188,8 @@ struct wl1271 {
+
+ int irq;
+
++ int irq_flags;
++
+ spinlock_t wl_lock;
+
+ enum wlcore_state state;
+@@ -395,9 +397,6 @@ struct wl1271 {
+ /* Quirks of specific hardware revisions */
+ unsigned int quirks;
+
+- /* Platform limitations */
+- unsigned int platform_quirks;
+-
+ /* number of currently active RX BA sessions */
+ int ba_rx_session_count;
+
--- /dev/null
+The pwr_in_suspend flag depends on the MMC settings which can be
+retrieved from the SDIO subsystem, so it doesn't need to be part of
+the platform data structure. Move it to the platform device data that
+is passed from SDIO to wlcore.
+
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -6074,7 +6074,6 @@ static void wlcore_nvs_cb(const struct f
+ struct wl1271 *wl = context;
+ struct platform_device *pdev = wl->pdev;
+ struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
+- struct wl12xx_platform_data *pdata = pdev_data->pdata;
+
+ int ret;
+ irq_handler_t hardirq_fn = NULL;
+@@ -6127,7 +6126,7 @@ static void wlcore_nvs_cb(const struct f
+ if (!ret) {
+ wl->irq_wake_enabled = true;
+ device_init_wakeup(wl->dev, 1);
+- if (pdata->pwr_in_suspend)
++ if (pdev_data->pwr_in_suspend)
+ wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
+ }
+ #endif
+--- a/drivers/net/wireless/ti/wlcore/sdio.c
++++ b/drivers/net/wireless/ti/wlcore/sdio.c
+@@ -260,7 +260,7 @@ static int wl1271_probe(struct sdio_func
+ dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
+
+ if (mmcflags & MMC_PM_KEEP_POWER)
+- pdev_data->pdata->pwr_in_suspend = true;
++ pdev_data->pwr_in_suspend = true;
+
+ sdio_set_drvdata(func, glue);
+
+--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
+@@ -209,6 +209,7 @@ struct wl1271_if_operations {
+ struct wlcore_platdev_data {
+ struct wl12xx_platform_data *pdata;
+ struct wl1271_if_operations *if_ops;
++ bool pwr_in_suspend;
+ };
+
+ #define MAX_NUM_KEYS 14
--- /dev/null
+Instead of defining an enumeration with the FW specific values for the
+different clock rates, use the actual frequency instead. Also add a
+boolean to specify whether the clock is XTAL or not.
+
+Change all board files to reflect this.
+
+Additionally, this reverts commit 26f45c (ARM: OMAP2+: Legacy support
+for wl12xx when booted with devicetree), since this is not be needed
+anymore, now that DT support for WiLink is implemented.
+
+Cc: Tony Lindgren <tony@atomide.com>
+Cc: Sekhar Nori <nsekhar@ti.com>
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+
+--- a/drivers/net/wireless/ti/wl12xx/main.c
++++ b/drivers/net/wireless/ti/wl12xx/main.c
+@@ -1711,6 +1711,43 @@ static struct ieee80211_sta_ht_cap wl12x
+ },
+ };
+
++static const struct wl12xx_clock wl12xx_refclock_table[] = {
++ { 19200000, false, WL12XX_REFCLOCK_19 },
++ { 26000000, false, WL12XX_REFCLOCK_26 },
++ { 26000000, true, WL12XX_REFCLOCK_26_XTAL },
++ { 38400000, false, WL12XX_REFCLOCK_38 },
++ { 38400000, true, WL12XX_REFCLOCK_38_XTAL },
++ { 52000000, false, WL12XX_REFCLOCK_52 },
++ { 0, false, 0 }
++};
++
++static const struct wl12xx_clock wl12xx_tcxoclock_table[] = {
++ { 16368000, true, WL12XX_TCXOCLOCK_16_368 },
++ { 16800000, true, WL12XX_TCXOCLOCK_16_8 },
++ { 19200000, true, WL12XX_TCXOCLOCK_19_2 },
++ { 26000000, true, WL12XX_TCXOCLOCK_26 },
++ { 32736000, true, WL12XX_TCXOCLOCK_32_736 },
++ { 33600000, true, WL12XX_TCXOCLOCK_33_6 },
++ { 38400000, true, WL12XX_TCXOCLOCK_38_4 },
++ { 52000000, true, WL12XX_TCXOCLOCK_52 },
++ { 0, false, 0 }
++};
++
++static int wl12xx_get_clock_idx(const struct wl12xx_clock *table,
++ u32 freq, bool xtal)
++{
++ int i = 0;
++
++ while(table[i].freq != 0) {
++ if ((table[i].freq == freq) &&
++ (table[i].xtal == xtal))
++ return table[i].hw_idx;
++ i++;
++ };
++
++ return -EINVAL;
++}
++
+ static int wl12xx_setup(struct wl1271 *wl)
+ {
+ struct wl12xx_priv *priv = wl->priv;
+@@ -1732,7 +1769,16 @@ static int wl12xx_setup(struct wl1271 *w
+ wl12xx_conf_init(wl);
+
+ if (!fref_param) {
+- priv->ref_clock = pdata->board_ref_clock;
++ priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table,
++ pdata->ref_clock_freq,
++ pdata->ref_clock_xtal);
++ if (priv->ref_clock < 0) {
++ wl1271_error("Invalid ref_clock frequency (%d Hz, %s)",
++ pdata->ref_clock_freq,
++ pdata->ref_clock_xtal ? "XTAL" : "not XTAL");
++
++ return priv->ref_clock;
++ }
+ } else {
+ if (!strcmp(fref_param, "19.2"))
+ priv->ref_clock = WL12XX_REFCLOCK_19;
+@@ -1751,7 +1797,15 @@ static int wl12xx_setup(struct wl1271 *w
+ }
+
+ if (!tcxo_param) {
+- priv->tcxo_clock = pdata->board_tcxo_clock;
++ priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table,
++ pdata->tcxo_clock_freq,
++ true);
++ if (priv->tcxo_clock < 0) {
++ wl1271_error("Invalid tcxo_clock frequency (%d Hz)",
++ pdata->tcxo_clock_freq);
++
++ return priv->tcxo_clock;
++ }
+ } else {
+ if (!strcmp(tcxo_param, "19.2"))
+ priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
+--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
++++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
+@@ -79,4 +79,32 @@ struct wl12xx_priv {
+ struct wl127x_rx_mem_pool_addr *rx_mem_addr;
+ };
+
++/* Reference clock values */
++enum {
++ WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */
++ WL12XX_REFCLOCK_26 = 1, /* 26 MHz */
++ WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */
++ WL12XX_REFCLOCK_52 = 3, /* 52 MHz */
++ WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */
++ WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */
++};
++
++/* TCXO clock values */
++enum {
++ WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */
++ WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */
++ WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */
++ WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */
++ WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */
++ WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */
++ WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */
++ WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */
++};
++
++struct wl12xx_clock {
++ u32 freq;
++ bool xtal;
++ u8 hw_idx;
++};
++
+ #endif /* __WL12XX_PRIV_H__ */
--- /dev/null
+If platform data is not available, try to get the required information
+from the device tree. Register an OF match table and parse the
+appropriate device tree nodes.
+
+Parse interrupt property only, for now.
+
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+
+--- a/drivers/net/wireless/ti/wlcore/sdio.c
++++ b/drivers/net/wireless/ti/wlcore/sdio.c
+@@ -30,7 +30,7 @@
+ #include <linux/mmc/sdio_ids.h>
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+-#include <linux/gpio.h>
++#include <linux/of_irq.h>
+ #include <linux/wl12xx.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/printk.h>
+@@ -214,6 +214,43 @@ static struct wl1271_if_operations sdio_
+ .set_block_size = wl1271_sdio_set_block_size,
+ };
+
++static struct wl12xx_platform_data *wlcore_get_pdata_from_of(struct device *dev)
++{
++ struct wl12xx_platform_data *pdata;
++ struct device_node *np = dev->of_node;
++
++ if (!np) {
++ np = of_find_matching_node(NULL, dev->driver->of_match_table);
++ if (!np) {
++ dev_notice(dev, "device tree node not available\n");
++ pdata = ERR_PTR(-ENODEV);
++ goto out;
++ }
++ }
++
++ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(dev, "can't allocate platform data\n");
++ pdata = ERR_PTR(-ENODEV);
++ goto out;
++ }
++
++ pdata->irq = irq_of_parse_and_map(np, 0);
++ if (pdata->irq < 0) {
++ dev_err(dev, "can't get interrupt gpio from the device tree\n");
++ goto out_free;
++ }
++
++ goto out;
++
++out_free:
++ kfree(pdata);
++ pdata = ERR_PTR(-ENODEV);
++
++out:
++ return pdata;
++}
++
+ static int wl1271_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+ {
+@@ -248,11 +285,22 @@ static int wl1271_probe(struct sdio_func
+ /* Use block mode for transferring over one block size of data */
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
++ /* The pdata allocated here is freed when the device is freed,
++ * so we don't need an additional out label to free it in case
++ * of error further on.
++ */
++
++ /* Try to get legacy platform data from the board file */
+ pdev_data->pdata = wl12xx_get_platform_data();
+ if (IS_ERR(pdev_data->pdata)) {
+- ret = PTR_ERR(pdev_data->pdata);
+- dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
+- goto out_free_glue;
++ dev_info(&func->dev,
++ "legacy platform data not found, trying device tree\n");
++
++ pdev_data->pdata = wlcore_get_pdata_from_of(&func->dev);
++ if (IS_ERR(pdev_data->pdata)) {
++ dev_err(&func->dev, "can't get platform data\n");
++ goto out_free_glue;
++ }
+ }
+
+ /* if sdio can keep power while host is suspended, enable wow */
+@@ -386,16 +434,25 @@ static const struct dev_pm_ops wl1271_sd
+ };
+ #endif
+
++static const struct of_device_id wlcore_sdio_of_match_table[] = {
++ { .compatible = "ti,wilink6" },
++ { .compatible = "ti,wilink7" },
++ { .compatible = "ti,wilink8" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, wlcore_sdio_of_match_table);
++
+ static struct sdio_driver wl1271_sdio_driver = {
+ .name = "wl1271_sdio",
+ .id_table = wl1271_devices,
+ .probe = wl1271_probe,
+ .remove = wl1271_remove,
+-#ifdef CONFIG_PM
+ .drv = {
++#ifdef CONFIG_PM
+ .pm = &wl1271_sdio_pm_ops,
+- },
+ #endif
++ .of_match_table = of_match_ptr(wlcore_sdio_of_match_table),
++ },
+ };
+
+ static int __init wl1271_init(void)
--- /dev/null
+Add refclock and tcxoclock as clock providers in WiLink. These clocks
+are not accesible outside the WiLink module, but they are registered
+in the clock framework anyway. Only the WiLink chip consumes these
+clocks.
+
+In theory, the WiLink chip could be connected to external clocks
+instead of using these internal clocks, so make the clock consumer
+code generic enough. If external clocks are used, then the internal
+clock device tree nodes are not necessary, but the external ones must
+be specified.
+
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+
+--- a/drivers/net/wireless/ti/wlcore/sdio.c
++++ b/drivers/net/wireless/ti/wlcore/sdio.c
+@@ -34,6 +34,7 @@
+ #include <linux/wl12xx.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/printk.h>
++#include <linux/clk-provider.h>
+
+ #include "wlcore.h"
+ #include "wl12xx_80211.h"
+@@ -214,10 +215,15 @@ static struct wl1271_if_operations sdio_
+ .set_block_size = wl1271_sdio_set_block_size,
+ };
+
++static const struct of_device_id wlcore_sdio_of_clk_match_table[] = {
++ { .compatible = "ti,wilink-clock" },
++};
++
+ static struct wl12xx_platform_data *wlcore_get_pdata_from_of(struct device *dev)
+ {
+ struct wl12xx_platform_data *pdata;
+ struct device_node *np = dev->of_node;
++ struct device_node *clock_node;
+
+ if (!np) {
+ np = of_find_matching_node(NULL, dev->driver->of_match_table);
+@@ -241,6 +247,9 @@ static struct wl12xx_platform_data *wlco
+ goto out_free;
+ }
+
++ for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table)
++ of_fixed_clk_setup(clock_node);
++
+ goto out;
+
+ out_free:
--- /dev/null
+Read the clock nodes from the device tree and use them to set the
+frequency for the refclock and the tcxo clock.
+
+Also, call sdio_set_drvdata() earlier, so the glue is already set in
+the driver data when we call wlcore_get_pdata_from_of() and we don't
+need to pass it as a parameter.
+
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+
+--- a/drivers/net/wireless/ti/wlcore/sdio.c
++++ b/drivers/net/wireless/ti/wlcore/sdio.c
+@@ -53,6 +53,7 @@ static bool dump = false;
+ struct wl12xx_sdio_glue {
+ struct device *dev;
+ struct platform_device *core;
++ struct clk *refclock, *tcxoclock;
+ };
+
+ static const struct sdio_device_id wl1271_devices[] = {
+@@ -224,6 +225,7 @@ static struct wl12xx_platform_data *wlco
+ struct wl12xx_platform_data *pdata;
+ struct device_node *np = dev->of_node;
+ struct device_node *clock_node;
++ struct wl12xx_sdio_glue *glue = sdio_get_drvdata(dev_to_sdio_func(dev));
+
+ if (!np) {
+ np = of_find_matching_node(NULL, dev->driver->of_match_table);
+@@ -250,6 +252,26 @@ static struct wl12xx_platform_data *wlco
+ for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table)
+ of_fixed_clk_setup(clock_node);
+
++ /* TODO: make sure we have this when needed (ie. for WL6 and WL7) */
++ glue->refclock = of_clk_get_by_name(np, "refclock");
++ if (IS_ERR(glue->refclock)) {
++ dev_err(dev, "couldn't find refclock on the device tree\n");
++ glue->refclock = NULL;
++ } else {
++ clk_prepare_enable(glue->refclock);
++ pdata->ref_clock_freq = clk_get_rate(glue->refclock);
++ }
++
++ /* TODO: make sure we have this when needed (ie. for WL7) */
++ glue->tcxoclock = of_clk_get_by_name(np, "tcxoclock");
++ if (IS_ERR(glue->tcxoclock)) {
++ dev_err(dev, "couldn't find tcxoclock on the device tree\n");
++ glue->tcxoclock = NULL;
++ } else {
++ clk_prepare_enable(glue->tcxoclock);
++ pdata->ref_clock_freq = clk_get_rate(glue->tcxoclock);
++ }
++
+ goto out;
+
+ out_free:
+@@ -294,6 +316,8 @@ static int wl1271_probe(struct sdio_func
+ /* Use block mode for transferring over one block size of data */
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
++ sdio_set_drvdata(func, glue);
++
+ /* The pdata allocated here is freed when the device is freed,
+ * so we don't need an additional out label to free it in case
+ * of error further on.
+@@ -319,8 +343,6 @@ static int wl1271_probe(struct sdio_func
+ if (mmcflags & MMC_PM_KEEP_POWER)
+ pdev_data->pwr_in_suspend = true;
+
+- sdio_set_drvdata(func, glue);
+-
+ /* Tell PM core that we don't need the card to be powered now */
+ pm_runtime_put_noidle(&func->dev);
+
+@@ -387,6 +409,16 @@ static void wl1271_remove(struct sdio_fu
+ {
+ struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
+
++ if (glue->refclock) {
++ clk_disable_unprepare(glue->refclock);
++ clk_put(glue->refclock);
++ }
++
++ if (glue->tcxoclock) {
++ clk_disable_unprepare(glue->tcxoclock);
++ clk_put(glue->tcxoclock);
++ }
++
+ /* Undo decrement done above in wl1271_probe */
+ pm_runtime_get_noresume(&func->dev);
+
--- /dev/null
+The fref and the tcxo clocks settings are optional in some platforms.
+WiLink8 doesn't need either, so we don't check the values. WiLink 6
+only needs the fref clock, so we check that it is valid or return with
+an error. WiLink7 needs both clocks, if either is not available we
+return with an error.
+
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+
+--- a/drivers/net/wireless/ti/wl12xx/main.c
++++ b/drivers/net/wireless/ti/wl12xx/main.c
+@@ -930,6 +930,11 @@ static int wl128x_boot_clk(struct wl1271
+ u16 sys_clk_cfg;
+ int ret;
+
++ if ((priv->ref_clock < 0) || (priv->tcxo_clock < 0)) {
++ wl1271_error("Missing fref and/or tcxo clock settings\n");
++ return -EINVAL;
++ }
++
+ /* For XTAL-only modes, FREF will be used after switching from TCXO */
+ if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
+ priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
+@@ -979,6 +984,11 @@ static int wl127x_boot_clk(struct wl1271
+ u32 clk;
+ int ret;
+
++ if (priv->ref_clock < 0) {
++ wl1271_error("Missing fref clock settings\n");
++ return -EINVAL;
++ }
++
+ if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
+ wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
+
+@@ -1768,7 +1778,7 @@ static int wl12xx_setup(struct wl1271 *w
+ wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap);
+ wl12xx_conf_init(wl);
+
+- if (!fref_param) {
++ if (!fref_param && (pdata->ref_clock_freq > 0)) {
+ priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table,
+ pdata->ref_clock_freq,
+ pdata->ref_clock_xtal);
+@@ -1779,6 +1789,8 @@ static int wl12xx_setup(struct wl1271 *w
+
+ return priv->ref_clock;
+ }
++ } else if (!fref_param) {
++ priv->ref_clock = -EINVAL;
+ } else {
+ if (!strcmp(fref_param, "19.2"))
+ priv->ref_clock = WL12XX_REFCLOCK_19;
+@@ -1796,7 +1808,7 @@ static int wl12xx_setup(struct wl1271 *w
+ wl1271_error("Invalid fref parameter %s", fref_param);
+ }
+
+- if (!tcxo_param) {
++ if (!fref_param && (pdata->tcxo_clock_freq > 0)) {
+ priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table,
+ pdata->tcxo_clock_freq,
+ true);
+@@ -1806,7 +1818,9 @@ static int wl12xx_setup(struct wl1271 *w
+
+ return priv->tcxo_clock;
+ }
+- } else {
++ } else if (!fref_param) {
++ priv->tcxo_clock = -EINVAL;
++ }else {
+ if (!strcmp(tcxo_param, "19.2"))
+ priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
+ else if (!strcmp(tcxo_param, "26"))
+--- a/drivers/net/wireless/ti/wlcore/sdio.c
++++ b/drivers/net/wireless/ti/wlcore/sdio.c
+@@ -252,20 +252,16 @@ static struct wl12xx_platform_data *wlco
+ for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table)
+ of_fixed_clk_setup(clock_node);
+
+- /* TODO: make sure we have this when needed (ie. for WL6 and WL7) */
+ glue->refclock = of_clk_get_by_name(np, "refclock");
+ if (IS_ERR(glue->refclock)) {
+- dev_err(dev, "couldn't find refclock on the device tree\n");
+ glue->refclock = NULL;
+ } else {
+ clk_prepare_enable(glue->refclock);
+ pdata->ref_clock_freq = clk_get_rate(glue->refclock);
+ }
+
+- /* TODO: make sure we have this when needed (ie. for WL7) */
+ glue->tcxoclock = of_clk_get_by_name(np, "tcxoclock");
+ if (IS_ERR(glue->tcxoclock)) {
+- dev_err(dev, "couldn't find tcxoclock on the device tree\n");
+ glue->tcxoclock = NULL;
+ } else {
+ clk_prepare_enable(glue->tcxoclock);
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -676,8 +676,7 @@ static int ath9k_init_soc_platform(struc
+ return ret;
+ }
+
+- if (pdata->tx_gain_buffalo)
+- ah->config.tx_gain_buffalo = true;
++ ah->config.tx_gain_buffalo = true;
+
+ return ret;
+ }
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -33,7 +33,6 @@ struct ath9k_platform_data {
+
+ bool endian_check;
+ bool is_clk_25mhz;
+- bool tx_gain_buffalo;
+ bool disable_2ghz;
+ bool disable_5ghz;
+