aboutsummaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches')
-rw-r--r--package/mac80211/patches/000-disable_ethernet.patch12
-rw-r--r--package/mac80211/patches/001-disable_b44.patch13
-rw-r--r--package/mac80211/patches/002-disable_rfkill.patch38
-rw-r--r--package/mac80211/patches/003-disable_bt.patch15
-rw-r--r--package/mac80211/patches/005-disable_ssb_build.patch49
-rw-r--r--package/mac80211/patches/006-disable_bcma_build.patch30
-rw-r--r--package/mac80211/patches/007-remove_misc_drivers.patch61
-rw-r--r--package/mac80211/patches/008-disable_mesh.patch11
-rw-r--r--package/mac80211/patches/009-remove_mac80211_module_dependence.patch11
-rw-r--r--package/mac80211/patches/010-no_pcmcia.patch20
-rw-r--r--package/mac80211/patches/011-no_sdio.patch11
-rw-r--r--package/mac80211/patches/013-disable_b43_nphy.patch13
-rw-r--r--package/mac80211/patches/015-remove-rt2x00-options.patch20
-rw-r--r--package/mac80211/patches/016-remove_pid_algo.patch11
-rw-r--r--package/mac80211/patches/017-remove_ath9k_rc.patch11
-rw-r--r--package/mac80211/patches/018-revert_printk_va_format.patch188
-rw-r--r--package/mac80211/patches/019-remove_ath5k_pci_option.patch11
-rw-r--r--package/mac80211/patches/021-add_include_for_bcma.patch11
-rw-r--r--package/mac80211/patches/022-remove_crc8_and_cordic.patch166
-rw-r--r--package/mac80211/patches/023-ath9k_disable_btcoex.patch11
-rw-r--r--package/mac80211/patches/030-disable_tty_set_termios.patch16
-rw-r--r--package/mac80211/patches/050-compat_firmware.patch78
-rw-r--r--package/mac80211/patches/060-compat_add_module_pci_driver.patch22
-rw-r--r--package/mac80211/patches/070-disable_codel.patch19
-rw-r--r--package/mac80211/patches/071-add_codel_ifdef.patch19
-rw-r--r--package/mac80211/patches/100-disable_pcmcia_compat.patch65
-rw-r--r--package/mac80211/patches/110-disable_usb_compat.patch44
-rw-r--r--package/mac80211/patches/130-mesh_pathtbl_backport.patch10
-rw-r--r--package/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch38
-rw-r--r--package/mac80211/patches/300-pending_work.patch592
-rw-r--r--package/mac80211/patches/310-ap_scan.patch11
-rw-r--r--package/mac80211/patches/400-ath_move_debug_code.patch28
-rw-r--r--package/mac80211/patches/401-ath9k_blink_default.patch11
-rw-r--r--package/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch29
-rw-r--r--package/mac80211/patches/403-ath_regd_optional.patch46
-rw-r--r--package/mac80211/patches/404-world_regd_fixup.patch84
-rw-r--r--package/mac80211/patches/405-regd_no_assoc_hints.patch20
-rw-r--r--package/mac80211/patches/406-ath_regd_us.patch26
-rw-r--r--package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch10
-rw-r--r--package/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch46
-rw-r--r--package/mac80211/patches/412-mac80211_allow_adhoc_and_ap.patch20
-rw-r--r--package/mac80211/patches/420-ath5k_disable_fast_cc.patch18
-rw-r--r--package/mac80211/patches/430-add_ath5k_platform.patch33
-rw-r--r--package/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch56
-rw-r--r--package/mac80211/patches/432-ath5k_add_pciids.patch11
-rw-r--r--package/mac80211/patches/440-ath5k_channel_bw_debugfs.patch113
-rw-r--r--package/mac80211/patches/500-ath9k_eeprom_debugfs.patch65
-rw-r--r--package/mac80211/patches/501-ath9k-eeprom_endianess.patch102
-rw-r--r--package/mac80211/patches/502-ath9k_ahb_init.patch32
-rw-r--r--package/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch13
-rw-r--r--package/mac80211/patches/511-ath9k_reduce_rxbuf.patch11
-rw-r--r--package/mac80211/patches/512-ath9k_channelbw_debugfs.patch128
-rw-r--r--package/mac80211/patches/513-mac80211_reduce_txqueuelen.patch10
-rw-r--r--package/mac80211/patches/520-mac80211_cur_txpower.patch31
-rw-r--r--package/mac80211/patches/521-ath9k_cur_txpower.patch19
-rw-r--r--package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch384
-rw-r--r--package/mac80211/patches/523-cfg80211_fix_antenna_gain.patch12
-rw-r--r--package/mac80211/patches/524-mac80211_configure_antenna_gain.patch179
-rw-r--r--package/mac80211/patches/525-ath9k_use_configured_antenna_gain.patch34
-rw-r--r--package/mac80211/patches/526-cfg80211_fix_max_reg_power.patch21
-rw-r--r--package/mac80211/patches/530-ath9k_fix_initvals.patch208
-rw-r--r--package/mac80211/patches/540-ath9k_extra_leds.patch258
-rw-r--r--package/mac80211/patches/541-ath9k_extra_platform_leds.patch71
-rw-r--r--package/mac80211/patches/550-mac80211_optimize_mcs_rate_mask.patch98
-rw-r--r--package/mac80211/patches/551-ath9k_optimize_interrupt_mitigation.patch30
-rw-r--r--package/mac80211/patches/560-ath9k_reduce_ani_interval.patch11
-rw-r--r--package/mac80211/patches/561-ath9k_revert_initval_change.patch19
-rw-r--r--package/mac80211/patches/562-ath9k_add_idle_hack.patch20
-rw-r--r--package/mac80211/patches/563-ath9k_rx_dma_stop_check.patch28
-rw-r--r--package/mac80211/patches/564-ath9k_debugfs_diag.patch139
-rw-r--r--package/mac80211/patches/565-ath9k_disable_paprd.patch72
-rw-r--r--package/mac80211/patches/566-ath9k_use_ieee80211_free_txskb.patch149
-rw-r--r--package/mac80211/patches/600-rt2x00-disable-pci-code-if-CONFIG_PCI-not-defined.patch18
-rw-r--r--package/mac80211/patches/601-rt2x00-set_pci_mwi.patch13
-rw-r--r--package/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch32
-rw-r--r--package/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch274
-rw-r--r--package/mac80211/patches/604-rt2x00-add-CONFIG_RT2X00_LIB_EEPROM-option.patch10
-rw-r--r--package/mac80211/patches/605-rt2x00-pci-eeprom.patch46
-rw-r--r--package/mac80211/patches/606-rt2x00_no_realign.patch67
-rw-r--r--package/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch47
-rw-r--r--package/mac80211/patches/608-add_platform_data_mac_addr.patch63
-rw-r--r--package/mac80211/patches/620-rt2x00-support-rt3352.patch464
-rw-r--r--package/mac80211/patches/621-rt2x00-fix-rt3352-lnagain.patch30
-rw-r--r--package/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch10
-rw-r--r--package/mac80211/patches/800-b43-gpio-mask-module-option.patch37
-rw-r--r--package/mac80211/patches/810-b43_no_pio.patch75
-rw-r--r--package/mac80211/patches/820-b43-add-antenna-control.patch131
-rw-r--r--package/mac80211/patches/830-b43-workaround-pcie-bcm4716.patch134
-rw-r--r--package/mac80211/patches/849-brcmsmac-add-device-found-on-some-SoCs-like-the-bcm4.patch39
-rw-r--r--package/mac80211/patches/850-brcmsmac-add-support-for-BCM43224.patch29
-rw-r--r--package/mac80211/patches/851-brcmsmac-start-adding-support-for-core-rev-28.patch75
91 files changed, 5916 insertions, 0 deletions
diff --git a/package/mac80211/patches/000-disable_ethernet.patch b/package/mac80211/patches/000-disable_ethernet.patch
new file mode 100644
index 000000000..08f908b10
--- /dev/null
+++ b/package/mac80211/patches/000-disable_ethernet.patch
@@ -0,0 +1,12 @@
+--- a/Makefile
++++ b/Makefile
+@@ -45,9 +45,6 @@ obj-$(CONFIG_COMPAT_WIRELESS_MODULES) +=
+
+ obj-$(CONFIG_COMPAT_NET_USB_MODULES) += drivers/net/usb/
+
+-obj-$(CONFIG_COMPAT_NETWORK_MODULES) += drivers/net/ethernet/atheros/
+-obj-$(CONFIG_COMPAT_NETWORK_MODULES) += drivers/net/ethernet/broadcom/
+-
+ obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/ssb/
+ obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/bcma/
+ obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/misc/eeprom/
diff --git a/package/mac80211/patches/001-disable_b44.patch b/package/mac80211/patches/001-disable_b44.patch
new file mode 100644
index 000000000..389dac1ae
--- /dev/null
+++ b/package/mac80211/patches/001-disable_b44.patch
@@ -0,0 +1,13 @@
+--- a/config.mk
++++ b/config.mk
+@@ -377,8 +377,8 @@ export CONFIG_B43_BCMA_EXTRA=y
+
+ export CONFIG_P54_PCI=m
+
+-export CONFIG_B44=m
+-export CONFIG_B44_PCI=y
++# export CONFIG_B44=m
++# export CONFIG_B44_PCI=y
+
+ export CONFIG_RTL8180=m
+
diff --git a/package/mac80211/patches/002-disable_rfkill.patch b/package/mac80211/patches/002-disable_rfkill.patch
new file mode 100644
index 000000000..685006bd5
--- /dev/null
+++ b/package/mac80211/patches/002-disable_rfkill.patch
@@ -0,0 +1,38 @@
+--- a/config.mk
++++ b/config.mk
+@@ -78,7 +78,7 @@ endif # build check
+ endif # kernel Makefile check
+
+ # These both are needed by 802.11 and bluetooth so enable
+- export CONFIG_COMPAT_RFKILL=y
++# export CONFIG_COMPAT_RFKILL=y
+
+ ifeq ($(CONFIG_MAC80211),y)
+ $(error "ERROR: you have MAC80211 compiled into the kernel, CONFIG_MAC80211=y, as such you cannot replace its mac80211 driver. You need this set to CONFIG_MAC80211=m. If you are using Fedora upgrade your kernel as later version should this set as modular. For further information on Fedora see https://bugzilla.redhat.com/show_bug.cgi?id=470143. If you are using your own kernel recompile it and make mac80211 modular")
+@@ -690,10 +690,10 @@ endif #CONFIG_COMPAT_KERNEL_2_6_27
+ # We need the backported rfkill module on kernel < 2.6.31.
+ # In more recent kernel versions use the in kernel rfkill module.
+ ifdef CONFIG_COMPAT_KERNEL_2_6_31
+-export CONFIG_RFKILL_BACKPORT=m
++#export CONFIG_RFKILL_BACKPORT=m
+ ifdef CONFIG_LEDS_TRIGGERS
+-export CONFIG_RFKILL_BACKPORT_LEDS=y
++#export CONFIG_RFKILL_BACKPORT_LEDS=y
+ endif #CONFIG_LEDS_TRIGGERS
+-export CONFIG_RFKILL_BACKPORT_INPUT=y
++#export CONFIG_RFKILL_BACKPORT_INPUT=y
+ endif #CONFIG_COMPAT_KERNEL_2_6_31
+
+--- a/include/linux/rfkill.h
++++ b/include/linux/rfkill.h
+@@ -3,6 +3,10 @@
+
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))
+
++#undef CONFIG_RFKILL
++#undef CONFIG_RFKILL_LEDS
++#undef CONFIG_RFKILL_MODULE
++
+ #include_next <linux/rfkill.h>
+
+ #else
diff --git a/package/mac80211/patches/003-disable_bt.patch b/package/mac80211/patches/003-disable_bt.patch
new file mode 100644
index 000000000..b56ccbdc6
--- /dev/null
+++ b/package/mac80211/patches/003-disable_bt.patch
@@ -0,0 +1,15 @@
+--- a/config.mk
++++ b/config.mk
+@@ -100,9 +100,9 @@ ifndef CONFIG_COMPAT_KERNEL_2_6_27
+ ifeq ($(CONFIG_BT),y)
+ # we'll ignore compiling bluetooth
+ else
+- export CONFIG_COMPAT_BLUETOOTH=y
+- export CONFIG_COMPAT_BLUETOOTH_MODULES=m
+- export CONFIG_HID_GENERIC=m
++# export CONFIG_COMPAT_BLUETOOTH=y
++# export CONFIG_COMPAT_BLUETOOTH_MODULES=m
++# export CONFIG_HID_GENERIC=m
+ endif
+ endif #CONFIG_COMPAT_KERNEL_2_6_27
+
diff --git a/package/mac80211/patches/005-disable_ssb_build.patch b/package/mac80211/patches/005-disable_ssb_build.patch
new file mode 100644
index 000000000..d42a6121d
--- /dev/null
+++ b/package/mac80211/patches/005-disable_ssb_build.patch
@@ -0,0 +1,49 @@
+--- a/Makefile
++++ b/Makefile
+@@ -45,7 +45,6 @@ obj-$(CONFIG_COMPAT_WIRELESS_MODULES) +=
+
+ obj-$(CONFIG_COMPAT_NET_USB_MODULES) += drivers/net/usb/
+
+-obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/ssb/
+ obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/bcma/
+ obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/misc/eeprom/
+
+--- a/config.mk
++++ b/config.mk
+@@ -3,7 +3,7 @@ ifeq ($(wildcard $(KLIB_BUILD)/.config),
+ export CONFIG_PCI=y
+ export CONFIG_USB=y
+ export CONFIG_PCMCIA=y
+- export CONFIG_SSB=m
++# export CONFIG_SSB=m
+ else
+ include $(KLIB_BUILD)/.config
+ endif
+@@ -353,7 +353,8 @@ export CONFIG_IPW2200_QOS=y
+ # % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
+ endif #CONFIG_WIRELESS_EXT
+
+-ifdef CONFIG_SSB
++# disabled
++ifdef __CONFIG_SSB
+ # Sonics Silicon Backplane
+ export CONFIG_SSB_SPROM=y
+
+@@ -366,7 +367,7 @@ endif #CONFIG_PCMCIA
+ # export CONFIG_SSB_DEBUG=y
+ export CONFIG_SSB_DRIVER_PCICORE=y
+ export CONFIG_B43_SSB=y
+-endif #CONFIG_SSB
++endif #__CONFIG_SSB
+
+ export CONFIG_BCMA=m
+ export CONFIG_BCMA_BLOCKIO=y
+@@ -580,7 +581,7 @@ endif #CONFIG_SPI_MASTER end of SPI driv
+
+ ifdef CONFIG_MMC
+
+-export CONFIG_SSB_SDIOHOST=y
++# export CONFIG_SSB_SDIOHOST=y
+ export CONFIG_B43_SDIO=y
+
+ ifdef CONFIG_CRC7
diff --git a/package/mac80211/patches/006-disable_bcma_build.patch b/package/mac80211/patches/006-disable_bcma_build.patch
new file mode 100644
index 000000000..da11ad455
--- /dev/null
+++ b/package/mac80211/patches/006-disable_bcma_build.patch
@@ -0,0 +1,30 @@
+--- a/Makefile
++++ b/Makefile
+@@ -45,7 +45,6 @@ obj-$(CONFIG_COMPAT_WIRELESS_MODULES) +=
+
+ obj-$(CONFIG_COMPAT_NET_USB_MODULES) += drivers/net/usb/
+
+-obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/bcma/
+ obj-$(CONFIG_COMPAT_VAR_MODULES) += drivers/misc/eeprom/
+
+ ifeq ($(CONFIG_STAGING_EXCLUDE_BUILD),)
+--- a/config.mk
++++ b/config.mk
+@@ -369,12 +369,12 @@ export CONFIG_SSB_DRIVER_PCICORE=y
+ export CONFIG_B43_SSB=y
+ endif #__CONFIG_SSB
+
+-export CONFIG_BCMA=m
+-export CONFIG_BCMA_BLOCKIO=y
+-export CONFIG_BCMA_HOST_PCI=y
++# export CONFIG_BCMA=m
++# export CONFIG_BCMA_BLOCKIO=y
++# export CONFIG_BCMA_HOST_PCI=y
+ # export CONFIG_BCMA_DEBUG=y
+-export CONFIG_B43_BCMA=y
+-export CONFIG_B43_BCMA_EXTRA=y
++# export CONFIG_B43_BCMA=y
++# export CONFIG_B43_BCMA_EXTRA=y
+
+ export CONFIG_P54_PCI=m
+
diff --git a/package/mac80211/patches/007-remove_misc_drivers.patch b/package/mac80211/patches/007-remove_misc_drivers.patch
new file mode 100644
index 000000000..9e7f65166
--- /dev/null
+++ b/package/mac80211/patches/007-remove_misc_drivers.patch
@@ -0,0 +1,61 @@
+--- a/config.mk
++++ b/config.mk
+@@ -241,7 +241,7 @@ $(warning "WARNING: CONFIG_CFG80211_WEXT
+ endif #CONFIG_WIRELESS_EXT
+
+ ifdef CONFIG_STAGING
+-export CONFIG_COMPAT_STAGING=m
++# export CONFIG_COMPAT_STAGING=m
+ endif #CONFIG_STAGING
+
+ # mac80211 test driver
+@@ -406,12 +406,12 @@ endif #CONFIG_CRC_ITU_T
+ export CONFIG_MWL8K=m
+
+ # Ethernet drivers go here
+-export CONFIG_ATL1=m
+-export CONFIG_ATL2=m
+-export CONFIG_ATL1E=m
++# export CONFIG_ATL1=m
++# export CONFIG_ATL2=m
++# export CONFIG_ATL1E=m
+ ifndef CONFIG_COMPAT_KERNEL_2_6_28
+-export CONFIG_ATL1C=m
+-export CONFIG_ALX=m
++# export CONFIG_ATL1C=m
++# export CONFIG_ALX=m
+ endif #CONFIG_COMPAT_KERNEL_2_6_28
+
+ ifdef CONFIG_WIRELESS_EXT
+@@ -472,21 +472,21 @@ endif #CONFIG_COMPAT_KERNEL_2_6_29
+ # Note: this depends on CONFIG_USB_NET_RNDIS_HOST and CONFIG_USB_NET_CDCETHER
+ # it also requires new RNDIS_HOST and CDC_ETHER modules which we add
+ ifdef CONFIG_COMPAT_KERNEL_2_6_29
+-export CONFIG_USB_COMPAT_USBNET=n
+-export CONFIG_USB_NET_COMPAT_RNDIS_HOST=n
+-export CONFIG_USB_NET_COMPAT_RNDIS_WLAN=n
+-export CONFIG_USB_NET_COMPAT_CDCETHER=n
++# export CONFIG_USB_COMPAT_USBNET=n
++# export CONFIG_USB_NET_COMPAT_RNDIS_HOST=n
++# export CONFIG_USB_NET_COMPAT_RNDIS_WLAN=n
++# export CONFIG_USB_NET_COMPAT_CDCETHER=n
+ else #CONFIG_COMPAT_KERNEL_2_6_29
+-export CONFIG_USB_COMPAT_USBNET=m
++# export CONFIG_USB_COMPAT_USBNET=m
+ ifdef CONFIG_USB_NET_CDCETHER
+-export CONFIG_USB_NET_COMPAT_RNDIS_HOST=m
+-export CONFIG_USB_NET_COMPAT_RNDIS_WLAN=m
++# export CONFIG_USB_NET_COMPAT_RNDIS_HOST=m
++# export CONFIG_USB_NET_COMPAT_RNDIS_WLAN=m
+ endif #CONFIG_USB_NET_CDCETHER
+ ifdef CONFIG_USB_NET_CDCETHER_MODULE
+-export CONFIG_USB_NET_COMPAT_RNDIS_HOST=m
+-export CONFIG_USB_NET_COMPAT_RNDIS_WLAN=m
++# export CONFIG_USB_NET_COMPAT_RNDIS_HOST=m
++# export CONFIG_USB_NET_COMPAT_RNDIS_WLAN=m
+ endif #CONFIG_USB_NET_CDCETHER
+-export CONFIG_USB_NET_COMPAT_CDCETHER=m
++# export CONFIG_USB_NET_COMPAT_CDCETHER=m
+ endif #CONFIG_COMPAT_KERNEL_2_6_29
+
+
diff --git a/package/mac80211/patches/008-disable_mesh.patch b/package/mac80211/patches/008-disable_mesh.patch
new file mode 100644
index 000000000..d5a0ac8e6
--- /dev/null
+++ b/package/mac80211/patches/008-disable_mesh.patch
@@ -0,0 +1,11 @@
+--- a/config.mk
++++ b/config.mk
+@@ -177,7 +177,7 @@ export CONFIG_MAC80211_LEDS=y
+ endif #CONFIG_LEDS_TRIGGERS
+
+ # enable mesh networking too
+-export CONFIG_MAC80211_MESH=y
++# export CONFIG_MAC80211_MESH=y
+
+ export CONFIG_CFG80211=m
+ export CONFIG_CFG80211_DEFAULT_PS=y
diff --git a/package/mac80211/patches/009-remove_mac80211_module_dependence.patch b/package/mac80211/patches/009-remove_mac80211_module_dependence.patch
new file mode 100644
index 000000000..2bc46c4ed
--- /dev/null
+++ b/package/mac80211/patches/009-remove_mac80211_module_dependence.patch
@@ -0,0 +1,11 @@
+--- a/config.mk
++++ b/config.mk
+@@ -54,7 +54,7 @@ endif
+ ifeq ($(KERNEL_VERSION),2)
+ ifeq ($(shell test $(KERNEL_VERSION) -eq 2 -a $(KERNEL_26SUBLEVEL) -ge 27 -a $(KERNEL_26SUBLEVEL) -le 31 && echo yes),yes)
+ ifeq ($(CONFIG_MAC80211),)
+-$(error "ERROR: Your >=2.6.27 and <= 2.6.31 kernel has CONFIG_MAC80211 disabled, you should have it CONFIG_MAC80211=m if you want to use this thing.")
++# $(error "ERROR: Your >=2.6.27 and <= 2.6.31 kernel has CONFIG_MAC80211 disabled, you should have it CONFIG_MAC80211=m if you want to use this thing.")
+ endif
+ endif
+ endif
diff --git a/package/mac80211/patches/010-no_pcmcia.patch b/package/mac80211/patches/010-no_pcmcia.patch
new file mode 100644
index 000000000..af6a7545b
--- /dev/null
+++ b/package/mac80211/patches/010-no_pcmcia.patch
@@ -0,0 +1,20 @@
+--- a/config.mk
++++ b/config.mk
+@@ -2,7 +2,7 @@ ifeq ($(wildcard $(KLIB_BUILD)/.config),
+ # These will be ignored by compat autoconf
+ export CONFIG_PCI=y
+ export CONFIG_USB=y
+- export CONFIG_PCMCIA=y
++# export CONFIG_PCMCIA=y
+ # export CONFIG_SSB=m
+ else
+ include $(KLIB_BUILD)/.config
+@@ -304,7 +304,7 @@ export CONFIG_B43=m
+ export CONFIG_B43_HWRNG=y
+ export CONFIG_B43_PCI_AUTOSELECT=y
+ ifdef CONFIG_PCMCIA
+-export CONFIG_B43_PCMCIA=y
++# export CONFIG_B43_PCMCIA=y
+ endif #CONFIG_PCMCIA
+ ifdef CONFIG_MAC80211_LEDS
+ export CONFIG_B43_LEDS=y
diff --git a/package/mac80211/patches/011-no_sdio.patch b/package/mac80211/patches/011-no_sdio.patch
new file mode 100644
index 000000000..4d364e045
--- /dev/null
+++ b/package/mac80211/patches/011-no_sdio.patch
@@ -0,0 +1,11 @@
+--- a/config.mk
++++ b/config.mk
+@@ -582,7 +582,7 @@ endif #CONFIG_SPI_MASTER end of SPI driv
+ ifdef CONFIG_MMC
+
+ # export CONFIG_SSB_SDIOHOST=y
+-export CONFIG_B43_SDIO=y
++# export CONFIG_B43_SDIO=y
+
+ ifdef CONFIG_CRC7
+ ifdef CONFIG_WL12XX_PLATFORM_DATA
diff --git a/package/mac80211/patches/013-disable_b43_nphy.patch b/package/mac80211/patches/013-disable_b43_nphy.patch
new file mode 100644
index 000000000..ba37bad95
--- /dev/null
+++ b/package/mac80211/patches/013-disable_b43_nphy.patch
@@ -0,0 +1,13 @@
+--- a/config.mk
++++ b/config.mk
+@@ -310,8 +310,8 @@ ifdef CONFIG_MAC80211_LEDS
+ export CONFIG_B43_LEDS=y
+ endif #CONFIG_MAC80211_LEDS
+ export CONFIG_B43_PHY_LP=y
+-export CONFIG_B43_PHY_N=y
+-export CONFIG_B43_PHY_HT=y
++# export CONFIG_B43_PHY_N=y
++# export CONFIG_B43_PHY_HT=y
+ # export CONFIG_B43_PHY_LCN=y
+ # export CONFIG_B43_DEBUG=y
+
diff --git a/package/mac80211/patches/015-remove-rt2x00-options.patch b/package/mac80211/patches/015-remove-rt2x00-options.patch
new file mode 100644
index 000000000..66c0d67a5
--- /dev/null
+++ b/package/mac80211/patches/015-remove-rt2x00-options.patch
@@ -0,0 +1,20 @@
+--- a/config.mk
++++ b/config.mk
+@@ -385,7 +385,7 @@ export CONFIG_RTL8180=m
+
+ export CONFIG_ADM8211=m
+
+-export CONFIG_RT2X00_LIB_PCI=m
++# export CONFIG_RT2X00_LIB_PCI=m
+ export CONFIG_RT2400PCI=m
+ export CONFIG_RT2500PCI=m
+ ifdef CONFIG_CRC_CCITT
+@@ -528,7 +528,7 @@ export CONFIG_RT2800USB_RT35XX=y
+ export CONFIG_RT2800USB_RT53XX=y
+ export CONFIG_RT2800USB_UNKNOWN=y
+ endif #CONFIG_CRC_CCITT
+-export CONFIG_RT2X00_LIB_USB=m
++# export CONFIG_RT2X00_LIB_USB=m
+ NEED_RT2X00=y
+ # RT73USB requires firmware
+ ifdef CONFIG_CRC_ITU_T
diff --git a/package/mac80211/patches/016-remove_pid_algo.patch b/package/mac80211/patches/016-remove_pid_algo.patch
new file mode 100644
index 000000000..7180a63ce
--- /dev/null
+++ b/package/mac80211/patches/016-remove_pid_algo.patch
@@ -0,0 +1,11 @@
+--- a/config.mk
++++ b/config.mk
+@@ -169,7 +169,7 @@ export CONFIG_MAC80211_RC_DEFAULT_MINSTR
+ # This is the one used by our compat-drivers net/mac80211/rate.c
+ # in case you have and old kernel which is overriding this to pid.
+ export CONFIG_COMPAT_MAC80211_RC_DEFAULT=minstrel_ht
+-export CONFIG_MAC80211_RC_PID=y
++# export CONFIG_MAC80211_RC_PID=y
+ export CONFIG_MAC80211_RC_MINSTREL=y
+ export CONFIG_MAC80211_RC_MINSTREL_HT=y
+ ifdef CONFIG_LEDS_TRIGGERS
diff --git a/package/mac80211/patches/017-remove_ath9k_rc.patch b/package/mac80211/patches/017-remove_ath9k_rc.patch
new file mode 100644
index 000000000..99b520911
--- /dev/null
+++ b/package/mac80211/patches/017-remove_ath9k_rc.patch
@@ -0,0 +1,11 @@
+--- a/config.mk
++++ b/config.mk
+@@ -265,7 +265,7 @@ export CONFIG_ATH9K_COMMON=m
+ # as default once we get minstrel properly tested and blessed by
+ # our systems engineering team. CCK rates also need to be used
+ # for long range considerations.
+-export CONFIG_COMPAT_ATH9K_RATE_CONTROL=y
++# export CONFIG_COMPAT_ATH9K_RATE_CONTROL=y
+
+ export CONFIG_ATH9K_BTCOEX_SUPPORT=y
+
diff --git a/package/mac80211/patches/018-revert_printk_va_format.patch b/package/mac80211/patches/018-revert_printk_va_format.patch
new file mode 100644
index 000000000..fa2237c95
--- /dev/null
+++ b/package/mac80211/patches/018-revert_printk_va_format.patch
@@ -0,0 +1,188 @@
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -341,83 +341,59 @@ static int b43_ratelimit(struct b43_wl *
+
+ void b43info(struct b43_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ if (b43_modparam_verbose < B43_VERBOSITY_INFO)
+ return;
+ if (!b43_ratelimit(wl))
+ return;
+-
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_INFO "b43-%s: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_INFO "b43-%s: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+
+ void b43err(struct b43_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ if (b43_modparam_verbose < B43_VERBOSITY_ERROR)
+ return;
+ if (!b43_ratelimit(wl))
+ return;
+-
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_ERR "b43-%s ERROR: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_ERR "b43-%s ERROR: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+
+ void b43warn(struct b43_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ if (b43_modparam_verbose < B43_VERBOSITY_WARN)
+ return;
+ if (!b43_ratelimit(wl))
+ return;
+-
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_WARNING "b43-%s warning: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_WARNING "b43-%s warning: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+
+ void b43dbg(struct b43_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
+ return;
+-
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_DEBUG "b43-%s debug: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_DEBUG "b43-%s debug: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+
+--- a/drivers/net/wireless/b43legacy/main.c
++++ b/drivers/net/wireless/b43legacy/main.c
+@@ -179,75 +179,52 @@ static int b43legacy_ratelimit(struct b4
+
+ void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+-
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_INFO "b43legacy-%s: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_INFO "b43legacy-%s: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+
+ void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+-
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_ERR "b43legacy-%s ERROR: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_ERR "b43legacy-%s ERROR: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+
+ void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+-
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_WARNING "b43legacy-%s warning: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_WARNING "b43legacy-%s warning: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+
+ #if B43legacy_DEBUG
+ void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
+ {
+- struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+-
+- vaf.fmt = fmt;
+- vaf.va = &args;
+-
+- printk(KERN_DEBUG "b43legacy-%s debug: %pV",
+- (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);
+-
++ printk(KERN_DEBUG "b43legacy-%s debug: ",
++ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
++ vprintk(fmt, args);
+ va_end(args);
+ }
+ #endif /* DEBUG */
diff --git a/package/mac80211/patches/019-remove_ath5k_pci_option.patch b/package/mac80211/patches/019-remove_ath5k_pci_option.patch
new file mode 100644
index 000000000..d0149d39c
--- /dev/null
+++ b/package/mac80211/patches/019-remove_ath5k_pci_option.patch
@@ -0,0 +1,11 @@
+--- a/config.mk
++++ b/config.mk
+@@ -282,7 +282,7 @@ endif #CONFIG_COMPAT_KERNEL_2_6_27
+ # PCI Drivers
+ ifdef CONFIG_PCI
+
+-export CONFIG_ATH5K_PCI=y
++# export CONFIG_ATH5K_PCI=y
+ export CONFIG_ATH9K_PCI=y
+
+ export CONFIG_IWLWIFI=m
diff --git a/package/mac80211/patches/021-add_include_for_bcma.patch b/package/mac80211/patches/021-add_include_for_bcma.patch
new file mode 100644
index 000000000..e2e856eb0
--- /dev/null
+++ b/package/mac80211/patches/021-add_include_for_bcma.patch
@@ -0,0 +1,11 @@
+--- a/include/linux/compat-3.0.h
++++ b/include/linux/compat-3.0.h
+@@ -36,6 +36,8 @@ static inline struct page *shmem_read_ma
+ #endif
+
+
++#include <linux/mod_devicetable.h>
++
+ /*
+ * since commit 1c5cae815d19ffe02bdfda1260949ef2b1806171
+ * "net: call dev_alloc_name from register_netdevice" dev_alloc_name is
diff --git a/package/mac80211/patches/022-remove_crc8_and_cordic.patch b/package/mac80211/patches/022-remove_crc8_and_cordic.patch
new file mode 100644
index 000000000..13ad2c895
--- /dev/null
+++ b/package/mac80211/patches/022-remove_crc8_and_cordic.patch
@@ -0,0 +1,166 @@
+--- a/compat/Makefile
++++ b/compat/Makefile
+@@ -47,8 +47,6 @@ compat-$(CONFIG_COMPAT_KERNEL_3_3) += \
+ compat-$(CONFIG_COMPAT_KERNEL_3_4) += compat-3.4.o
+ compat-$(CONFIG_COMPAT_KERNEL_3_7) += compat-3.7.o
+
+-compat-$(CONFIG_COMPAT_CORDIC) += cordic.o
+-compat-$(CONFIG_COMPAT_CRC8) += crc8.o
+
+ ifndef CONFIG_64BIT
+ ifndef CONFIG_GENERIC_ATOMIC64
+--- a/include/linux/cordic.h
++++ /dev/null
+@@ -1,48 +0,0 @@
+-/*
+- * Copyright (c) 2011 Broadcom Corporation
+- *
+- * Permission to use, copy, modify, and/or distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+- */
+-#ifndef __CORDIC_H_
+-#define __CORDIC_H_
+-
+-#include <linux/types.h>
+-
+-/**
+- * struct cordic_iq - i/q coordinate.
+- *
+- * @i: real part of coordinate (in phase).
+- * @q: imaginary part of coordinate (quadrature).
+- */
+-struct cordic_iq {
+- s32 i;
+- s32 q;
+-};
+-
+-/**
+- * cordic_calc_iq() - calculates the i/q coordinate for given angle.
+- *
+- * @theta: angle in degrees for which i/q coordinate is to be calculated.
+- * @coord: function output parameter holding the i/q coordinate.
+- *
+- * The function calculates the i/q coordinate for a given angle using
+- * cordic algorithm. The coordinate consists of a real (i) and an
+- * imaginary (q) part. The real part is essentially the cosine of the
+- * angle and the imaginary part is the sine of the angle. The returned
+- * values are scaled by 2^16 for precision. The range for theta is
+- * for -180 degrees to +180 degrees. Passed values outside this range are
+- * converted before doing the actual calculation.
+- */
+-struct cordic_iq cordic_calc_iq(s32 theta);
+-
+-#endif /* __CORDIC_H_ */
+--- a/include/linux/crc8.h
++++ /dev/null
+@@ -1,101 +0,0 @@
+-/*
+- * Copyright (c) 2011 Broadcom Corporation
+- *
+- * Permission to use, copy, modify, and/or distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+- */
+-#ifndef __CRC8_H_
+-#define __CRC8_H_
+-
+-#include <linux/types.h>
+-
+-/* see usage of this value in crc8() description */
+-#define CRC8_INIT_VALUE 0xFF
+-
+-/*
+- * Return value of crc8() indicating valid message+crc. This is true
+- * if a CRC is inverted before transmission. The CRC computed over the
+- * whole received bitstream is _table[x], where x is the bit pattern
+- * of the modification (almost always 0xff).
+- */
+-#define CRC8_GOOD_VALUE(_table) (_table[0xFF])
+-
+-/* required table size for crc8 algorithm */
+-#define CRC8_TABLE_SIZE 256
+-
+-/* helper macro assuring right table size is used */
+-#define DECLARE_CRC8_TABLE(_table) \
+- static u8 _table[CRC8_TABLE_SIZE]
+-
+-/**
+- * crc8_populate_lsb - fill crc table for given polynomial in regular bit order.
+- *
+- * @table: table to be filled.
+- * @polynomial: polynomial for which table is to be filled.
+- *
+- * This function fills the provided table according the polynomial provided for
+- * regular bit order (lsb first). Polynomials in CRC algorithms are typically
+- * represented as shown below.
+- *
+- * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1
+- *
+- * For lsb first direction x^7 maps to the lsb. So the polynomial is as below.
+- *
+- * - lsb first: poly = 10101011(1) = 0xAB
+- */
+-void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial);
+-
+-/**
+- * crc8_populate_msb - fill crc table for given polynomial in reverse bit order.
+- *
+- * @table: table to be filled.
+- * @polynomial: polynomial for which table is to be filled.
+- *
+- * This function fills the provided table according the polynomial provided for
+- * reverse bit order (msb first). Polynomials in CRC algorithms are typically
+- * represented as shown below.
+- *
+- * poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1
+- *
+- * For msb first direction x^7 maps to the msb. So the polynomial is as below.
+- *
+- * - msb first: poly = (1)11010101 = 0xD5
+- */
+-void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial);
+-
+-/**
+- * crc8() - calculate a crc8 over the given input data.
+- *
+- * @table: crc table used for calculation.
+- * @pdata: pointer to data buffer.
+- * @nbytes: number of bytes in data buffer.
+- * @crc: previous returned crc8 value.
+- *
+- * The CRC8 is calculated using the polynomial given in crc8_populate_msb()
+- * or crc8_populate_lsb().
+- *
+- * The caller provides the initial value (either %CRC8_INIT_VALUE
+- * or the previous returned value) to allow for processing of
+- * discontiguous blocks of data. When generating the CRC the
+- * caller is responsible for complementing the final return value
+- * and inserting it into the byte stream. When validating a byte
+- * stream (including CRC8), a final return value of %CRC8_GOOD_VALUE
+- * indicates the byte stream data can be considered valid.
+- *
+- * Reference:
+- * "A Painless Guide to CRC Error Detection Algorithms", ver 3, Aug 1993
+- * Williams, Ross N., ross<at>ross.net
+- * (see URL http://www.ross.net/crc/download/crc_v3.txt).
+- */
+-u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc);
+-
+-#endif /* __CRC8_H_ */
diff --git a/package/mac80211/patches/023-ath9k_disable_btcoex.patch b/package/mac80211/patches/023-ath9k_disable_btcoex.patch
new file mode 100644
index 000000000..37ae2d5d7
--- /dev/null
+++ b/package/mac80211/patches/023-ath9k_disable_btcoex.patch
@@ -0,0 +1,11 @@
+--- a/config.mk
++++ b/config.mk
+@@ -267,7 +267,7 @@ export CONFIG_ATH9K_COMMON=m
+ # for long range considerations.
+ # export CONFIG_COMPAT_ATH9K_RATE_CONTROL=y
+
+-export CONFIG_ATH9K_BTCOEX_SUPPORT=y
++# export CONFIG_ATH9K_BTCOEX_SUPPORT=y
+
+ # WIL6210 requires MSI only available >= 2.6.30
+ ifndef CONFIG_COMPAT_KERNEL_2_6_30
diff --git a/package/mac80211/patches/030-disable_tty_set_termios.patch b/package/mac80211/patches/030-disable_tty_set_termios.patch
new file mode 100644
index 000000000..fc5d4d63f
--- /dev/null
+++ b/package/mac80211/patches/030-disable_tty_set_termios.patch
@@ -0,0 +1,16 @@
+--- a/compat/compat-2.6.39.c
++++ b/compat/compat-2.6.39.c
+@@ -12,6 +12,7 @@
+ #include <linux/tty.h>
+ #include <linux/sched.h>
+
++#ifdef CONFIG_COMPAT_BLUETOOTH
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+ /*
+ * Termios Helper Methods
+@@ -111,4 +112,4 @@ int tty_set_termios(struct tty_struct *t
+ }
+ EXPORT_SYMBOL_GPL(tty_set_termios);
+ #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) */
+-
++#endif
diff --git a/package/mac80211/patches/050-compat_firmware.patch b/package/mac80211/patches/050-compat_firmware.patch
new file mode 100644
index 000000000..e4b91a316
--- /dev/null
+++ b/package/mac80211/patches/050-compat_firmware.patch
@@ -0,0 +1,78 @@
+--- a/compat/Makefile
++++ b/compat/Makefile
+@@ -1,7 +1,10 @@
+ obj-m += compat.o
+ #compat-objs :=
+
+-obj-$(CONFIG_COMPAT_FIRMWARE_CLASS) += compat_firmware_class.o
++ifdef CONFIG_COMPAT_FIRMWARE_CLASS
++ compat-y += compat_firmware_class.o
++endif
++
+ obj-$(CONFIG_COMPAT_NET_SCH_CODEL) += sch_codel.o
+
+ sch_fq_codel-y = sch_fq_codel_core.o flow_dissector.o
+--- a/compat/compat_firmware_class.c
++++ b/compat/compat_firmware_class.c
+@@ -741,19 +741,16 @@ compat_request_firmware_nowait(
+ return 0;
+ }
+
+-static int __init firmware_class_init(void)
++int __init firmware_class_init(void)
+ {
+ return class_register(&firmware_class);
+ }
+
+-static void __exit firmware_class_exit(void)
++void __exit firmware_class_exit(void)
+ {
+ class_unregister(&firmware_class);
+ }
+
+-fs_initcall(firmware_class_init);
+-module_exit(firmware_class_exit);
+-
+ EXPORT_SYMBOL_GPL(release_firmware);
+ EXPORT_SYMBOL_GPL(request_firmware);
+ EXPORT_SYMBOL_GPL(request_firmware_nowait);
+--- a/compat/main.c
++++ b/compat/main.c
+@@ -47,6 +47,17 @@ void compat_dependency_symbol(void)
+ EXPORT_SYMBOL_GPL(compat_dependency_symbol);
+
+
++#if defined(CONFIG_FW_LOADER) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
++int __init firmware_class_init(void);
++void __exit firmware_class_exit(void);
++#else
++static inline int firmware_class_init(void)
++{
++ return 0;
++}
++static inline void firmware_class_exit(void) {}
++#endif
++
+ static int __init compat_init(void)
+ {
+ compat_pm_qos_power_init();
+@@ -63,7 +74,8 @@ static int __init compat_init(void)
+ printk(KERN_INFO "compat.git: "
+ COMPAT_BASE_TREE "\n");
+
+- return 0;
++ firmware_class_init();
++ return 0;
+ }
+ module_init(compat_init);
+
+@@ -72,7 +84,8 @@ static void __exit compat_exit(void)
+ compat_pm_qos_power_deinit();
+ compat_system_workqueue_destroy();
+
+- return;
++ firmware_class_exit();
++ return;
+ }
+ module_exit(compat_exit);
+
diff --git a/package/mac80211/patches/060-compat_add_module_pci_driver.patch b/package/mac80211/patches/060-compat_add_module_pci_driver.patch
new file mode 100644
index 000000000..277ca3d37
--- /dev/null
+++ b/package/mac80211/patches/060-compat_add_module_pci_driver.patch
@@ -0,0 +1,22 @@
+--- a/include/linux/compat-3.4.h
++++ b/include/linux/compat-3.4.h
+@@ -112,6 +112,19 @@ static inline void eth_hw_addr_random(st
+ module_driver(__pci_driver, pci_register_driver, \
+ pci_unregister_driver)
+
++/* source include/linux/pci.h */
++/**
++ * module_pci_driver() - Helper macro for registering a PCI driver
++ * @__pci_driver: pci_driver struct
++ *
++ * Helper macro for PCI drivers which do not do anything special in module
++ * init/exit. This eliminates a lot of boilerplate. Each module may only
++ * use this macro once, and calling it replaces module_init() and module_exit()
++ */
++#define module_pci_driver(__pci_driver) \
++ module_driver(__pci_driver, pci_register_driver, \
++ pci_unregister_driver)
++
+ #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) */
+
+ #endif /* LINUX_5_4_COMPAT_H */
diff --git a/package/mac80211/patches/070-disable_codel.patch b/package/mac80211/patches/070-disable_codel.patch
new file mode 100644
index 000000000..0d6d74911
--- /dev/null
+++ b/package/mac80211/patches/070-disable_codel.patch
@@ -0,0 +1,19 @@
+--- a/compat/scripts/gen-compat-config.sh
++++ b/compat/scripts/gen-compat-config.sh
+@@ -66,16 +66,3 @@ if [[ ${CONFIG_COMPAT_KERNEL_2_6_36} = "
+ echo "export CONFIG_COMPAT_KFIFO=y"
+ fi
+ fi
+-
+-if [[ ${CONFIG_COMPAT_KERNEL_3_5} = "y" ]]; then
+- # We don't have 2.6.24 backport support yet for Codel / FQ CoDel
+- # For those who want to try this is what is required that I can tell
+- # so far:
+- # * struct Qdisc_ops
+- # - init and change callback ops use a different argument dataype
+- # - you need to parse data received from userspace differently
+- if [[ ${CONFIG_COMPAT_KERNEL_2_6_25} != "y" ]]; then
+- echo "export CONFIG_COMPAT_NET_SCH_CODEL=m"
+- echo "export CONFIG_COMPAT_NET_SCH_FQ_CODEL=m"
+- fi
+-fi
diff --git a/package/mac80211/patches/071-add_codel_ifdef.patch b/package/mac80211/patches/071-add_codel_ifdef.patch
new file mode 100644
index 000000000..86b415170
--- /dev/null
+++ b/package/mac80211/patches/071-add_codel_ifdef.patch
@@ -0,0 +1,19 @@
+--- a/include/linux/compat-3.5.h
++++ b/include/linux/compat-3.5.h
+@@ -8,6 +8,8 @@
+
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0))
+
++#ifndef TCA_CODEL_MAX
++
+ /*
+ * This backports:
+ *
+@@ -135,6 +137,7 @@ static inline int compat_vga_switcheroo_
+
+ #define SIZE_MAX (~(size_t)0)
+
++#endif /* TCA_CODEL_MAX */
+
+ #include <linux/pkt_sched.h>
+
diff --git a/package/mac80211/patches/100-disable_pcmcia_compat.patch b/package/mac80211/patches/100-disable_pcmcia_compat.patch
new file mode 100644
index 000000000..60927555b
--- /dev/null
+++ b/package/mac80211/patches/100-disable_pcmcia_compat.patch
@@ -0,0 +1,65 @@
+--- a/compat/compat-2.6.28.c
++++ b/compat/compat-2.6.28.c
+@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(usb_poison_urb);
+ #endif
+ #endif /* CONFIG_USB */
+
+-#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
++#if 0
+
+ #include <pcmcia/ds.h>
+ struct pcmcia_cfg_mem {
+--- a/compat/compat-2.6.33.c
++++ b/compat/compat-2.6.33.c
+@@ -10,7 +10,7 @@
+
+ #include <linux/compat.h>
+
+-#if defined(CONFIG_PCCARD) || defined(CONFIG_PCCARD_MODULE)
++#if 0
+
+ /**
+ * pccard_loop_tuple() - loop over tuples in the CIS
+@@ -72,7 +72,7 @@ next_entry:
+ EXPORT_SYMBOL_GPL(pccard_loop_tuple);
+ /* Source: drivers/pcmcia/cistpl.c */
+
+-#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
++#if 0
+
+ struct pcmcia_loop_mem {
+ struct pcmcia_device *p_dev;
+--- a/include/linux/compat-2.6.28.h
++++ b/include/linux/compat-2.6.28.h
+@@ -49,7 +49,7 @@ typedef u32 phys_addr_t;
+ })
+ #endif /* From include/asm-generic/bug.h */
+
+-#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
++#if 0
+
+ #include <pcmcia/cs_types.h>
+ #include <pcmcia/cs.h>
+--- a/include/linux/compat-2.6.33.h
++++ b/include/linux/compat-2.6.33.h
+@@ -7,7 +7,7 @@
+
+ #include <linux/skbuff.h>
+ #include <linux/pci.h>
+-#if defined(CONFIG_PCCARD) || defined(CONFIG_PCCARD_MODULE)
++#if 0
+ #include <pcmcia/cs_types.h>
+ #include <pcmcia/cistpl.h>
+ #include <pcmcia/ds.h>
+@@ -82,9 +82,9 @@ static inline struct sk_buff *netdev_all
+ return skb;
+ }
+
+-#if defined(CONFIG_PCCARD) || defined(CONFIG_PCCARD_MODULE)
++#if 0
+
+-#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
++#if 0
+
+ #define pcmcia_request_window(a, b, c) pcmcia_request_window(&a, b, c)
+
diff --git a/package/mac80211/patches/110-disable_usb_compat.patch b/package/mac80211/patches/110-disable_usb_compat.patch
new file mode 100644
index 000000000..d6287fd04
--- /dev/null
+++ b/package/mac80211/patches/110-disable_usb_compat.patch
@@ -0,0 +1,44 @@
+--- a/compat/compat-2.6.28.c
++++ b/compat/compat-2.6.28.c
+@@ -165,7 +165,7 @@ EXPORT_SYMBOL_GPL(pcmcia_loop_config);
+
+ #endif /* CONFIG_PCMCIA */
+
+-#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
++#if 0
+
+ void usb_unpoison_urb(struct urb *urb)
+ {
+--- a/compat/compat-2.6.29.c
++++ b/compat/compat-2.6.29.c
+@@ -49,7 +49,7 @@ void netdev_attach_ops(struct net_device
+ EXPORT_SYMBOL_GPL(netdev_attach_ops);
+
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))
+-#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
++#if 0
+ /**
+ * usb_unpoison_anchored_urbs - let an anchor be used successfully again
+ * @anchor: anchor the requests are bound to
+--- a/include/linux/compat-2.6.28.h
++++ b/include/linux/compat-2.6.28.h
+@@ -74,7 +74,7 @@ int pcmcia_loop_config(struct pcmcia_dev
+ /* USB anchors were added as of 2.6.23 */
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))
+
+-#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
++#if 0
+ #if 0
+ extern void usb_poison_urb(struct urb *urb);
+ #endif
+--- a/config.mk
++++ b/config.mk
+@@ -510,7 +510,7 @@ endif #CONFIG_COMPAT_KERNEL_2_6_29
+ # This activates a threading fix for usb urb.
+ # this is mainline commit: b3e670443b7fb8a2d29831b62b44a039c283e351
+ # This fix will be included in some stable releases.
+-export CONFIG_COMPAT_USB_URB_THREAD_FIX=y
++# export CONFIG_COMPAT_USB_URB_THREAD_FIX=y
+
+ export CONFIG_ATH9K_HTC=m
+ # export CONFIG_ATH9K_HTC_DEBUGFS=y
diff --git a/package/mac80211/patches/130-mesh_pathtbl_backport.patch b/package/mac80211/patches/130-mesh_pathtbl_backport.patch
new file mode 100644
index 000000000..15ad03ced
--- /dev/null
+++ b/package/mac80211/patches/130-mesh_pathtbl_backport.patch
@@ -0,0 +1,10 @@
+--- a/net/mac80211/mesh_pathtbl.c
++++ b/net/mac80211/mesh_pathtbl.c
+@@ -813,7 +813,6 @@ static void table_flush_by_iface(struct
+ struct hlist_node *p;
+ int i;
+
+- WARN_ON(!rcu_read_lock_held());
+ for_each_mesh_entry(tbl, p, node, i) {
+ mpath = node->mpath;
+ if (mpath->sdata != sdata)
diff --git a/package/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch b/package/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch
new file mode 100644
index 000000000..9e08a0897
--- /dev/null
+++ b/package/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch
@@ -0,0 +1,38 @@
+--- a/drivers/net/wireless/ath/ath5k/initvals.c
++++ b/drivers/net/wireless/ath/ath5k/initvals.c
+@@ -65,8 +65,14 @@ static const struct ath5k_ini ar5210_ini
+ { AR5K_IMR, 0 },
+ { AR5K_IER, AR5K_IER_DISABLE },
+ { AR5K_BSR, 0, AR5K_INI_READ },
++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
+ { AR5K_TXCFG, AR5K_DMASIZE_128B },
+ { AR5K_RXCFG, AR5K_DMASIZE_128B },
++#else
++ /* WAR for AR71xx PCI bug */
++ { AR5K_TXCFG, AR5K_DMASIZE_128B },
++ { AR5K_RXCFG, AR5K_DMASIZE_4B },
++#endif
+ { AR5K_CFG, AR5K_INIT_CFG },
+ { AR5K_TOPS, 8 },
+ { AR5K_RXNOFRM, 8 },
+--- a/drivers/net/wireless/ath/ath5k/dma.c
++++ b/drivers/net/wireless/ath/ath5k/dma.c
+@@ -863,10 +863,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) {
++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
+ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
++#else
++ /* WAR for AR71xx PCI bug */
++ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
++ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
++ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
++ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_4B);
++#endif
+ }
+
+ /* Pre-enable interrupts on 5211/5212*/
diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch
new file mode 100644
index 000000000..f7a0aede5
--- /dev/null
+++ b/package/mac80211/patches/300-pending_work.patch
@@ -0,0 +1,592 @@
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -325,6 +325,8 @@ ath5k_setup_channels(struct ath5k_hw *ah
+ if (!ath5k_is_standard_channel(ch, band))
+ continue;
+
++ channels[count].max_power = AR5K_TUNE_MAX_TXPOWER/2;
++
+ count++;
+ }
+
+--- a/net/mac80211/agg-rx.c
++++ b/net/mac80211/agg-rx.c
+@@ -203,6 +203,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);
+--- 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);
+@@ -460,6 +461,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;
+
+@@ -869,7 +871,7 @@ void ieee80211_process_addba_resp(struct
+
+ } else {
+ ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
+- true);
++ false);
+ }
+
+ out:
+--- a/net/mac80211/debugfs_sta.c
++++ b/net/mac80211/debugfs_sta.c
+@@ -63,11 +63,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",
+ 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
+@@ -420,7 +420,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;
+@@ -575,30 +574,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;
+- }
+-
+- 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);
+-
+- res = sta_info_insert(sta);
+- if (res) {
+- /* STA has been freed */
+- goto err_del_interface;
+- }
+-
+- 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);
+- }
+
+ /*
+ * set_multicast_list will be invoked by the networking core
+@@ -997,6 +974,72 @@ static void ieee80211_if_setup(struct ne
+ dev->destructor = free_netdev;
+ }
+
++static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
++ struct sk_buff *skb)
++{
++ 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 = local->hw.conf.channel->band;
++ struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
++
++ rx_status = IEEE80211_SKB_RXCB(skb);
++ mgmt = (struct ieee80211_mgmt *) skb->data;
++ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
++
++ if (stype != IEEE80211_STYPE_BEACON)
++ return;
++
++ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
++ if (baselen > skb->len)
++ return;
++
++ ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
++ skb->len - baselen, &elems);
++
++ rates = ieee80211_sta_get_rates(local, &elems, band, NULL);
++
++ rcu_read_lock();
++
++ sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
++
++ if (!sta) {
++ rcu_read_unlock();
++ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
++ GFP_KERNEL);
++ if (!sta)
++ return;
++
++ new = true;
++ }
++
++ sta->last_rx = jiffies;
++ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
++
++ if (elems.ht_cap_elem)
++ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
++ elems.ht_cap_elem, &sta->sta.ht_cap);
++
++ if (elems.wmm_param)
++ set_sta_flag(sta, WLAN_STA_WME);
++
++ 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);
++ }
++
++ rcu_read_unlock();
++}
++
+ static void ieee80211_iface_work(struct work_struct *work)
+ {
+ struct ieee80211_sub_if_data *sdata =
+@@ -1101,6 +1144,9 @@ static void ieee80211_iface_work(struct
+ break;
+ ieee80211_mesh_rx_queued_mgmt(sdata, skb);
+ break;
++ case NL80211_IFTYPE_WDS:
++ ieee80211_wds_rx_queued_mgmt(sdata, skb);
++ break;
+ default:
+ WARN(1, "frame for unexpected interface type");
+ break;
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2279,6 +2279,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)
+ break;
+
+@@ -2496,14 +2497,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):
+@@ -2827,10 +2829,16 @@ static int prepare_for_handlers(struct 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;
++
+ 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.
+@@ -64,7 +63,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/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -517,29 +517,41 @@ void ieee80211_tx_status(struct ieee8021
+
+ if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
+ u64 cookie = (unsigned long)skb;
++ bool found = false;
++
+ acked = info->flags & IEEE80211_TX_STAT_ACK;
+
+- if (ieee80211_is_nullfunc(hdr->frame_control) ||
+- ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+- cfg80211_probe_status(skb->dev, hdr->addr1,
+- cookie, acked, GFP_ATOMIC);
+- } else if (skb->dev) {
+- cfg80211_mgmt_tx_status(
+- skb->dev->ieee80211_ptr, cookie, skb->data,
+- skb->len, acked, GFP_ATOMIC);
+- } else {
+- struct ieee80211_sub_if_data *p2p_sdata;
++ rcu_read_lock();
+
+- rcu_read_lock();
++ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
++ if (!sdata->dev)
++ continue;
+
+- p2p_sdata = rcu_dereference(local->p2p_sdata);
+- if (p2p_sdata) {
+- cfg80211_mgmt_tx_status(
+- &p2p_sdata->wdev, cookie, skb->data,
+- skb->len, acked, GFP_ATOMIC);
+- }
+- rcu_read_unlock();
++ if (skb->dev != sdata->dev)
++ continue;
++
++ found = true;
++ break;
+ }
++
++ if (!skb->dev) {
++ sdata = rcu_dereference(local->p2p_sdata);
++ if (sdata)
++ found = true;
++ }
++
++ if (!found)
++ skb->dev = NULL;
++ else if (ieee80211_is_nullfunc(hdr->frame_control) ||
++ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
++ cfg80211_probe_status(sdata->dev, hdr->addr1,
++ cookie, acked, GFP_ATOMIC);
++ } else {
++ cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
++ skb->len, acked, GFP_ATOMIC);
++ }
++
++ rcu_read_unlock();
+ }
+
+ if (unlikely(info->ack_frame_id)) {
+--- a/drivers/net/wireless/p54/main.c
++++ b/drivers/net/wireless/p54/main.c
+@@ -139,6 +139,7 @@ static int p54_beacon_format_ie_tim(stru
+ static int p54_beacon_update(struct p54_common *priv,
+ struct ieee80211_vif *vif)
+ {
++ struct ieee80211_tx_control control = { };
+ struct sk_buff *beacon;
+ int ret;
+
+@@ -158,7 +159,7 @@ static int p54_beacon_update(struct p54_
+ * to cancel the old beacon template by hand, instead the firmware
+ * will release the previous one through the feedback mechanism.
+ */
+- p54_tx_80211(priv->hw, NULL, beacon);
++ p54_tx_80211(priv->hw, &control, beacon);
+ priv->tsf_high32 = 0;
+ priv->tsf_low32 = 0;
+
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -352,6 +352,9 @@ static void reg_regdb_search(struct work
+ struct reg_regdb_search_request *request;
+ const struct ieee80211_regdomain *curdom, *regdom;
+ int i, r;
++ bool set_reg = false;
++
++ mutex_lock(&cfg80211_mutex);
+
+ mutex_lock(&reg_regdb_search_mutex);
+ while (!list_empty(&reg_regdb_search_list)) {
+@@ -367,9 +370,7 @@ static void reg_regdb_search(struct work
+ r = reg_copy_regd(&regdom, curdom);
+ if (r)
+ break;
+- mutex_lock(&cfg80211_mutex);
+- set_regdom(regdom);
+- mutex_unlock(&cfg80211_mutex);
++ set_reg = true;
+ break;
+ }
+ }
+@@ -377,6 +378,11 @@ static void reg_regdb_search(struct work
+ kfree(request);
+ }
+ mutex_unlock(&reg_regdb_search_mutex);
++
++ if (set_reg)
++ set_regdom(regdom);
++
++ mutex_unlock(&cfg80211_mutex);
+ }
+
+ static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -424,8 +424,8 @@ u32 ath_calcrxfilter(struct ath_softc *s
+ rfilt |= ATH9K_RX_FILTER_COMP_BAR;
+
+ if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
+- /* The following may also be needed for other older chips */
+- if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
++ /* This is needed for older chips */
++ if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
+ rfilt |= ATH9K_RX_FILTER_PROM;
+ rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
+ }
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -818,23 +818,71 @@ void ieee80211_sta_process_chanswitch(st
+ }
+
+ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+- u16 capab_info, u8 *pwr_constr_elem,
+- u8 pwr_constr_elem_len)
++ struct ieee80211_channel *channel,
++ const u8 *country_ie, u8 country_ie_len,
++ const u8 *pwr_constr_elem)
+ {
+- struct ieee80211_conf *conf = &sdata->local->hw.conf;
++ struct ieee80211_country_ie_triplet *triplet;
++ int chan = ieee80211_frequency_to_channel(channel->center_freq);
++ int i, chan_pwr, chan_increment, new_ap_level;
++ bool have_chan_pwr = false;
+
+- if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
++ /* Invalid IE */
++ if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
+ return;
+
+- /* Power constraint IE length should be 1 octet */
+- if (pwr_constr_elem_len != 1)
+- return;
++ triplet = (void *)(country_ie + 3);
++ country_ie_len -= 3;
+
+- if ((*pwr_constr_elem <= conf->channel->max_reg_power) &&
+- (*pwr_constr_elem != sdata->local->power_constr_level)) {
+- sdata->local->power_constr_level = *pwr_constr_elem;
+- ieee80211_hw_config(sdata->local, 0);
++ switch (channel->band) {
++ default:
++ WARN_ON_ONCE(1);
++ /* fall through */
++ case IEEE80211_BAND_2GHZ:
++ case IEEE80211_BAND_60GHZ:
++ chan_increment = 1;
++ break;
++ case IEEE80211_BAND_5GHZ:
++ chan_increment = 4;
++ break;
+ }
++
++ /* find channel */
++ while (country_ie_len >= 3) {
++ u8 first_channel = triplet->chans.first_channel;
++
++ if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID)
++ goto next;
++
++ for (i = 0; i < triplet->chans.num_channels; i++) {
++ if (first_channel + i * chan_increment == chan) {
++ have_chan_pwr = true;
++ chan_pwr = triplet->chans.max_power;
++ break;
++ }
++ }
++ if (have_chan_pwr)
++ break;
++
++ next:
++ triplet++;
++ country_ie_len -= 3;
++ }
++
++ if (!have_chan_pwr)
++ return;
++
++ new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
++
++ if (sdata->local->ap_power_level == new_ap_level)
++ return;
++
++ sdata_info(sdata,
++ "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
++ new_ap_level, chan_pwr, *pwr_constr_elem,
++ sdata->u.mgd.bssid);
++ sdata->local->ap_power_level = new_ap_level;
++ ieee80211_hw_config(sdata->local, 0);
+ }
+
+ void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
+@@ -1390,7 +1438,7 @@ static void ieee80211_set_disassoc(struc
+ sta = sta_info_get(sdata, ifmgd->bssid);
+ if (sta) {
+ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+- ieee80211_sta_tear_down_BA_sessions(sta, tx);
++ ieee80211_sta_tear_down_BA_sessions(sta, false);
+ }
+ mutex_unlock(&local->sta_mtx);
+
+@@ -1438,7 +1486,7 @@ static void ieee80211_set_disassoc(struc
+ memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
+ memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
+
+- local->power_constr_level = 0;
++ local->ap_power_level = 0;
+
+ del_timer_sync(&local->dynamic_ps_timer);
+ cancel_work_sync(&local->dynamic_ps_enable_work);
+@@ -2530,15 +2578,13 @@ static void ieee80211_rx_mgmt_beacon(str
+ bssid, true);
+ }
+
+- /* Note: country IE parsing is done for us by cfg80211 */
+- if (elems.country_elem) {
+- /* TODO: IBSS also needs this */
+- if (elems.pwr_constr_elem)
+- ieee80211_handle_pwr_constr(sdata,
+- le16_to_cpu(mgmt->u.probe_resp.capab_info),
+- elems.pwr_constr_elem,
+- elems.pwr_constr_elem_len);
+- }
++ if (elems.country_elem && elems.pwr_constr_elem &&
++ mgmt->u.probe_resp.capab_info &
++ cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
++ ieee80211_handle_pwr_constr(sdata, local->oper_channel,
++ elems.country_elem,
++ elems.country_elem_len,
++ elems.pwr_constr_elem);
+
+ ieee80211_bss_info_change_notify(sdata, changed);
+ }
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -674,7 +674,7 @@ int __must_check __sta_info_destroy(stru
+ * will be sufficient.
+ */
+ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+- ieee80211_sta_tear_down_BA_sessions(sta, true);
++ ieee80211_sta_tear_down_BA_sessions(sta, false);
+
+ ret = sta_info_hash_del(local, sta);
+ if (ret)
+--- a/drivers/net/wireless/ath/ath5k/phy.c
++++ b/drivers/net/wireless/ath/ath5k/phy.c
+@@ -1977,11 +1977,13 @@ ath5k_hw_set_spur_mitigation_filter(stru
+ spur_delta_phase = (spur_offset << 18) / 25;
+ spur_freq_sigma_delta = (spur_delta_phase >> 10);
+ symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2;
++ break;
+ case AR5K_BWMODE_5MHZ:
+ /* Both sample_freq and chip_freq are 10MHz (?) */
+ spur_delta_phase = (spur_offset << 19) / 25;
+ spur_freq_sigma_delta = (spur_delta_phase >> 10);
+ symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
++ break;
+ default:
+ if (channel->band == IEEE80211_BAND_5GHZ) {
+ /* Both sample_freq and chip_freq are 40MHz */
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1062,7 +1062,7 @@ struct ieee80211_local {
+ bool disable_dynamic_ps;
+
+ int user_power_level; /* in dBm */
+- int power_constr_level; /* in dBm */
++ int ap_power_level; /* in dBm */
+
+ enum ieee80211_smps_mode smps_mode;
+
+@@ -1170,7 +1170,6 @@ struct ieee802_11_elems {
+ u8 prep_len;
+ u8 perr_len;
+ u8 country_elem_len;
+- u8 pwr_constr_elem_len;
+ u8 quiet_elem_len;
+ u8 num_of_quiet_elem; /* can be more the one */
+ u8 timeout_int_len;
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -792,8 +792,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start
+ elems->country_elem_len = elen;
+ break;
+ case WLAN_EID_PWR_CONSTRAINT:
++ if (elen != 1) {
++ elem_parse_failed = true;
++ break;
++ }
+ elems->pwr_constr_elem = pos;
+- elems->pwr_constr_elem_len = elen;
+ break;
+ case WLAN_EID_TIMEOUT_INTERVAL:
+ elems->timeout_int = pos;
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -154,13 +154,11 @@ int ieee80211_hw_config(struct ieee80211
+
+ if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+ test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
+- test_bit(SCAN_HW_SCANNING, &local->scanning))
++ test_bit(SCAN_HW_SCANNING, &local->scanning) ||
++ !local->ap_power_level)
+ power = chan->max_power;
+ else
+- power = local->power_constr_level ?
+- min(chan->max_power,
+- (chan->max_reg_power - local->power_constr_level)) :
+- chan->max_power;
++ power = min(chan->max_power, local->ap_power_level);
+
+ if (local->user_power_level >= 0)
+ power = min(power, local->user_power_level);
diff --git a/package/mac80211/patches/310-ap_scan.patch b/package/mac80211/patches/310-ap_scan.patch
new file mode 100644
index 000000000..67a9dcaba
--- /dev/null
+++ b/package/mac80211/patches/310-ap_scan.patch
@@ -0,0 +1,11 @@
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -1796,8 +1796,6 @@ static int ieee80211_scan(struct wiphy *
+ * beaconing hasn't been configured yet
+ */
+ case NL80211_IFTYPE_AP:
+- if (sdata->u.ap.beacon)
+- return -EOPNOTSUPP;
+ break;
+ default:
+ return -EOPNOTSUPP;
diff --git a/package/mac80211/patches/400-ath_move_debug_code.patch b/package/mac80211/patches/400-ath_move_debug_code.patch
new file mode 100644
index 000000000..256da42de
--- /dev/null
+++ b/package/mac80211/patches/400-ath_move_debug_code.patch
@@ -0,0 +1,28 @@
+--- a/drivers/net/wireless/ath/Makefile
++++ b/drivers/net/wireless/ath/Makefile
+@@ -8,7 +8,7 @@ obj-$(CONFIG_ATH_COMMON) += ath.o
+ ath-objs := main.o \
+ regd.o \
+ hw.o \
+- key.o
++ key.o \
++ debug.o
+
+-ath-$(CONFIG_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,
+ #endif /* CONFIG_ATH_DEBUG */
+
+ /** Returns string describing opmode, or NULL if unknown mode. */
+-#ifdef CONFIG_ATH_DEBUG
+ const char *ath_opmode_to_string(enum nl80211_iftype opmode);
+-#else
+-static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode)
+-{
+- return "UNKNOWN";
+-}
+-#endif
+
+ #endif /* ATH_H */
diff --git a/package/mac80211/patches/401-ath9k_blink_default.patch b/package/mac80211/patches/401-ath9k_blink_default.patch
new file mode 100644
index 000000000..10c763696
--- /dev/null
+++ b/package/mac80211/patches/401-ath9k_blink_default.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -40,7 +40,7 @@ int ath9k_modparam_nohwcrypt;
+ module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444);
+ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+
+-int led_blink;
++int led_blink = 1;
+ module_param_named(blink, led_blink, int, 0444);
+ MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+
diff --git a/package/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch b/package/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch
new file mode 100644
index 000000000..7c59e1f10
--- /dev/null
+++ b/package/mac80211/patches/402-ath9k-fix-invalid-mac-address-handling.patch
@@ -0,0 +1,29 @@
+--- 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>
+ #include <linux/module.h>
++#include <linux/etherdevice.h>
+ #include <asm/unaligned.h>
+
+ #include "hw.h"
+@@ -523,8 +524,16 @@ static int ath9k_hw_init_macaddr(struct
+ common->macaddr[2 * i] = eeval >> 8;
+ common->macaddr[2 * i + 1] = eeval & 0xff;
+ }
+- if (sum == 0 || sum == 0xffff * 3)
+- return -EADDRNOTAVAIL;
++ if (!is_valid_ether_addr(common->macaddr)) {
++ ath_err(common,
++ "eeprom contains invalid mac address: %pM\n",
++ common->macaddr);
++
++ random_ether_addr(common->macaddr);
++ ath_err(common,
++ "random mac address will be used: %pM\n",
++ common->macaddr);
++ }
+
+ return 0;
+ }
diff --git a/package/mac80211/patches/403-ath_regd_optional.patch b/package/mac80211/patches/403-ath_regd_optional.patch
new file mode 100644
index 000000000..1854c271e
--- /dev/null
+++ b/package/mac80211/patches/403-ath_regd_optional.patch
@@ -0,0 +1,46 @@
+--- a/drivers/net/wireless/ath/regd.c
++++ b/drivers/net/wireless/ath/regd.c
+@@ -200,6 +200,10 @@ ath_reg_apply_beaconing_flags(struct wip
+ u32 bandwidth = 0;
+ int r;
+
++#ifdef ATH_USER_REGD
++ return;
++#endif
++
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+
+ if (!wiphy->bands[band])
+@@ -259,6 +263,10 @@ ath_reg_apply_active_scan_flags(struct w
+ u32 bandwidth = 0;
+ int r;
+
++#ifdef ATH_USER_REGD
++ return;
++#endif
++
+ sband = wiphy->bands[IEEE80211_BAND_2GHZ];
+ if (!sband)
+ return;
+@@ -308,6 +316,10 @@ static void ath_reg_apply_radar_flags(st
+ struct ieee80211_channel *ch;
+ unsigned int i;
+
++#ifdef ATH_USER_REGD
++ return;
++#endif
++
+ if (!wiphy->bands[IEEE80211_BAND_5GHZ])
+ return;
+
+@@ -514,6 +526,10 @@ ath_regd_init_wiphy(struct ath_regulator
+ {
+ const struct ieee80211_regdomain *regd;
+
++#ifdef ATH_USER_REGD
++ return 0;
++#endif
++
+ wiphy->reg_notifier = reg_notifier;
+ wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+
diff --git a/package/mac80211/patches/404-world_regd_fixup.patch b/package/mac80211/patches/404-world_regd_fixup.patch
new file mode 100644
index 000000000..d609b55e0
--- /dev/null
+++ b/package/mac80211/patches/404-world_regd_fixup.patch
@@ -0,0 +1,84 @@
+--- a/drivers/net/wireless/ath/regd.c
++++ b/drivers/net/wireless/ath/regd.c
+@@ -44,7 +44,8 @@ static int __ath_regd_init(struct ath_re
+ NL80211_RRF_PASSIVE_SCAN | 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, 40, 0, 30,\
++#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5250, 40, 0, 30, 0), \
++ REG_RULE(5250, 5350+10, 40, 0, 30,\
+ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+ #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 40, 0, 30,\
+ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+@@ -62,57 +63,56 @@ static int __ath_regd_init(struct ath_re
+ #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
+ ATH9K_5GHZ_5725_5850
+
++#define REGD_RULES(...) \
++ .reg_rules = { __VA_ARGS__ }, \
++ .n_reg_rules = ARRAY_SIZE(((struct ieee80211_reg_rule[]) { __VA_ARGS__ }))
++
+ /* Can be used for:
+ * 0x60, 0x61, 0x62 */
+ static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
+- .n_reg_rules = 5,
+ .alpha2 = "99",
+- .reg_rules = {
++ REGD_RULES(
+ ATH9K_2GHZ_ALL,
+ ATH9K_5GHZ_ALL,
+- }
++ )
+ };
+
+ /* Can be used by 0x63 and 0x65 */
+ static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
+- .n_reg_rules = 4,
+ .alpha2 = "99",
+- .reg_rules = {
++ REGD_RULES(
+ ATH9K_2GHZ_CH01_11,
+ ATH9K_2GHZ_CH12_13,
+ ATH9K_5GHZ_NO_MIDBAND,
+- }
++ )
+ };
+
+ /* Can be used by 0x64 only */
+ static const struct ieee80211_regdomain ath_world_regdom_64 = {
+- .n_reg_rules = 3,
+ .alpha2 = "99",
+- .reg_rules = {
++ REGD_RULES(
+ ATH9K_2GHZ_CH01_11,
+ ATH9K_5GHZ_NO_MIDBAND,
+- }
++ )
+ };
+
+ /* Can be used by 0x66 and 0x69 */
+ static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
+- .n_reg_rules = 3,
+ .alpha2 = "99",
+- .reg_rules = {
++ REGD_RULES(
+ ATH9K_2GHZ_CH01_11,
+ ATH9K_5GHZ_ALL,
+- }
++ )
+ };
+
+ /* Can be used by 0x67, 0x68, 0x6A and 0x6C */
+ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
+- .n_reg_rules = 4,
+ .alpha2 = "99",
+- .reg_rules = {
++ REGD_RULES(
+ ATH9K_2GHZ_CH01_11,
+ ATH9K_2GHZ_CH12_13,
+ ATH9K_5GHZ_ALL,
+- }
++ )
+ };
+
+ static inline bool is_wwr_sku(u16 regd)
diff --git a/package/mac80211/patches/405-regd_no_assoc_hints.patch b/package/mac80211/patches/405-regd_no_assoc_hints.patch
new file mode 100644
index 000000000..8a5c2a2e3
--- /dev/null
+++ b/package/mac80211/patches/405-regd_no_assoc_hints.patch
@@ -0,0 +1,20 @@
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -1796,6 +1796,8 @@ void regulatory_hint_11d(struct wiphy *w
+ enum environment_cap env = ENVIRON_ANY;
+ struct regulatory_request *request;
+
++ return;
++
+ mutex_lock(&reg_mutex);
+
+ if (unlikely(!last_request))
+@@ -2030,6 +2032,8 @@ static void restore_regulatory_settings(
+
+ void regulatory_hint_disconnect(void)
+ {
++ return;
++
+ REG_DBG_PRINT("All devices are disconnected, going to "
+ "restore regulatory settings\n");
+ restore_regulatory_settings(false);
diff --git a/package/mac80211/patches/406-ath_regd_us.patch b/package/mac80211/patches/406-ath_regd_us.patch
new file mode 100644
index 000000000..cc5587780
--- /dev/null
+++ b/package/mac80211/patches/406-ath_regd_us.patch
@@ -0,0 +1,26 @@
+--- a/drivers/net/wireless/ath/regd_common.h
++++ b/drivers/net/wireless/ath/regd_common.h
+@@ -32,6 +32,7 @@ enum EnumRd {
+ FCC2_WORLD = 0x21,
+ FCC2_ETSIC = 0x22,
+ FCC6_WORLD = 0x23,
++ FCC3_FCCA_2 = 0x2A,
+ FRANCE_RES = 0x31,
+ FCC3_FCCA = 0x3A,
+ FCC3_WORLD = 0x3B,
+@@ -167,6 +168,7 @@ static struct reg_dmn_pair_mapping regDo
+ {FCC2_WORLD, CTL_FCC, CTL_ETSI},
+ {FCC2_ETSIC, CTL_FCC, CTL_ETSI},
+ {FCC3_FCCA, CTL_FCC, CTL_FCC},
++ {FCC3_FCCA_2, CTL_FCC, CTL_FCC},
+ {FCC3_WORLD, CTL_FCC, CTL_ETSI},
+ {FCC4_FCCA, CTL_FCC, CTL_FCC},
+ {FCC5_FCCA, CTL_FCC, CTL_FCC},
+@@ -463,6 +465,7 @@ static struct country_code_to_enum_rd al
+ {CTRY_UAE, NULL1_WORLD, "AE"},
+ {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"},
+ {CTRY_UNITED_STATES, FCC3_FCCA, "US"},
++ {CTRY_UNITED_STATES, FCC3_FCCA_2, "US"},
+ /* This "PS" is for US public safety actually... to support this we
+ * would need to assign new special alpha2 to CRDA db as with the world
+ * regdomain and use another alpha2 */
diff --git a/package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
new file mode 100644
index 000000000..aabf3c3f4
--- /dev/null
+++ b/package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
@@ -0,0 +1,10 @@
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -667,6 +667,7 @@ static const struct ieee80211_iface_limi
+ #ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ #endif
++ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) },
+ };
diff --git a/package/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch b/package/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch
new file mode 100644
index 000000000..8e02950e4
--- /dev/null
+++ b/package/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch
@@ -0,0 +1,46 @@
+--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+@@ -89,13 +89,8 @@ ath5k_add_interface(struct ieee80211_hw
+ goto end;
+ }
+
+- /* Don't allow other interfaces if one ad-hoc is configured.
+- * TODO: Fix the problems with ad-hoc and multiple other interfaces.
+- * We would need to operate the HW in ad-hoc mode to allow TSF updates
+- * for the IBSS, but this breaks with additional AP or STA interfaces
+- * at the moment. */
+- if (ah->num_adhoc_vifs ||
+- (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
++ /* Don't allow more than one ad-hoc interface */
++ if (ah->num_adhoc_vifs && vif->type == NL80211_IFTYPE_ADHOC) {
+ ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n");
+ ret = -ELNRNG;
+ goto end;
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -1878,7 +1878,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
+ }
+
+ if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +
+- ah->num_mesh_vifs > 1) ||
++ ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) ||
+ ah->opmode == NL80211_IFTYPE_MESH_POINT) {
+ u64 tsf = ath5k_hw_get_tsf64(ah);
+ u32 tsftu = TSF_TO_TU(tsf);
+@@ -1964,7 +1964,7 @@ ath5k_beacon_update_timers(struct ath5k_
+
+ intval = ah->bintval & AR5K_BEACON_PERIOD;
+ if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs
+- + ah->num_mesh_vifs > 1) {
++ + ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) {
+ intval /= ATH_BCBUF; /* staggered multi-bss beacons */
+ if (intval < 15)
+ ATH5K_WARN(ah, "intval %u is too low, min 15\n",
+@@ -2427,6 +2427,7 @@ static const struct ieee80211_iface_limi
+ #ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ #endif
++ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) },
+ };
+
diff --git a/package/mac80211/patches/412-mac80211_allow_adhoc_and_ap.patch b/package/mac80211/patches/412-mac80211_allow_adhoc_and_ap.patch
new file mode 100644
index 000000000..93f35567e
--- /dev/null
+++ b/package/mac80211/patches/412-mac80211_allow_adhoc_and_ap.patch
@@ -0,0 +1,20 @@
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -792,17 +792,11 @@ int ieee80211_register_hw(struct ieee802
+ */
+ for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
+ const struct ieee80211_iface_combination *c;
+- int j;
+
+ c = &hw->wiphy->iface_combinations[i];
+
+ if (c->num_different_channels > 1)
+ return -EINVAL;
+-
+- for (j = 0; j < c->n_limits; j++)
+- if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
+- c->limits[j].max > 1)
+- return -EINVAL;
+ }
+
+ #ifndef CONFIG_MAC80211_MESH
diff --git a/package/mac80211/patches/420-ath5k_disable_fast_cc.patch b/package/mac80211/patches/420-ath5k_disable_fast_cc.patch
new file mode 100644
index 000000000..bd661c6fb
--- /dev/null
+++ b/package/mac80211/patches/420-ath5k_disable_fast_cc.patch
@@ -0,0 +1,18 @@
+--- a/drivers/net/wireless/ath/ath5k/reset.c
++++ b/drivers/net/wireless/ath/ath5k/reset.c
+@@ -1156,6 +1156,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum
+ tsf_lo = 0;
+ mode = 0;
+
++#if 0
+ /*
+ * Sanity check for fast flag
+ * Fast channel change only available
+@@ -1163,6 +1164,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum
+ */
+ if (fast && (ah->ah_radio != AR5K_RF2413) &&
+ (ah->ah_radio != AR5K_RF5413))
++#endif
+ fast = false;
+
+ /* Disable sleep clock operation
diff --git a/package/mac80211/patches/430-add_ath5k_platform.patch b/package/mac80211/patches/430-add_ath5k_platform.patch
new file mode 100644
index 000000000..b213e2a81
--- /dev/null
+++ b/package/mac80211/patches/430-add_ath5k_platform.patch
@@ -0,0 +1,33 @@
+--- /dev/null
++++ b/include/linux/ath5k_platform.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (c) 2008 Atheros Communications Inc.
++ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (c) 2010 Daniel Golle <daniel.golle@gmail.com>
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef _LINUX_ATH5K_PLATFORM_H
++#define _LINUX_ATH5K_PLATFORM_H
++
++#define ATH5K_PLAT_EEP_MAX_WORDS 2048
++
++struct ath5k_platform_data {
++ u16 *eeprom_data;
++ u8 *macaddr;
++};
++
++#endif /* _LINUX_ATH5K_PLATFORM_H */
diff --git a/package/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch b/package/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch
new file mode 100644
index 000000000..6cafa236a
--- /dev/null
+++ b/package/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch
@@ -0,0 +1,56 @@
+--- a/drivers/net/wireless/ath/ath5k/pci.c
++++ b/drivers/net/wireless/ath/ath5k/pci.c
+@@ -23,6 +23,7 @@
+ #include <linux/pci-aspm.h>
+ #include <linux/etherdevice.h>
+ #include <linux/module.h>
++#include <linux/ath5k_platform.h>
+ #include "../ath.h"
+ #include "ath5k.h"
+ #include "debug.h"
+@@ -74,7 +75,7 @@ static void ath5k_pci_read_cachesize(str
+ }
+
+ /*
+- * Read from eeprom
++ * Read from eeprom or platform_data
+ */
+ static bool
+ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
+@@ -82,6 +83,19 @@ ath5k_pci_eeprom_read(struct ath_common
+ struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
+ u32 status, timeout;
+
++ struct ath5k_platform_data *pdata = NULL;
++
++ if (ah->pdev)
++ pdata = ah->pdev->dev.platform_data;
++
++ if (pdata && pdata->eeprom_data && pdata->eeprom_data[61] == AR5K_EEPROM_MAGIC_VALUE) {
++ if (offset >= ATH5K_PLAT_EEP_MAX_WORDS)
++ return false;
++
++ *data = pdata->eeprom_data[offset];
++ return true;
++ }
++
+ /*
+ * Initialize EEPROM access
+ */
+@@ -125,6 +139,16 @@ static int ath5k_pci_eeprom_read_mac(str
+ u16 data;
+ int octet;
+
++ struct ath5k_platform_data *pdata = NULL;
++
++ if (ah->pdev)
++ pdata = ah->pdev->dev.platform_data;
++
++ if (pdata && pdata->macaddr) {
++ memcpy(mac, pdata->macaddr, ETH_ALEN);
++ return 0;
++ }
++
+ AR5K_EEPROM_READ(0x20, data);
+
+ for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
diff --git a/package/mac80211/patches/432-ath5k_add_pciids.patch b/package/mac80211/patches/432-ath5k_add_pciids.patch
new file mode 100644
index 000000000..8db5e1b3f
--- /dev/null
+++ b/package/mac80211/patches/432-ath5k_add_pciids.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath5k/pci.c
++++ b/drivers/net/wireless/ath/ath5k/pci.c
+@@ -50,6 +50,8 @@ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci
+ { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
+ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
+ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
++ { PCI_VDEVICE(ATHEROS, 0xff16) }, /* 2413,2414 sx76x on lantiq_danube */
++ { PCI_VDEVICE(ATHEROS, 0xff1a) }, /* 2417 arv45xx on lantiq_danube */
+ { PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */
+ { 0 }
+ };
diff --git a/package/mac80211/patches/440-ath5k_channel_bw_debugfs.patch b/package/mac80211/patches/440-ath5k_channel_bw_debugfs.patch
new file mode 100644
index 000000000..a2141ab24
--- /dev/null
+++ b/package/mac80211/patches/440-ath5k_channel_bw_debugfs.patch
@@ -0,0 +1,113 @@
+This adds a bwmode debugfs file which can be used to set alternate
+channel operating bandwidths. Only tested with AR5413 and only at
+5 and 20 mhz channels.
+
+Signed-off-by: Pat Erley <pat-lkml at erley.org>
+---
+Other devices will need to be added to the switch in write_file_bwmode
+
+drivers/net/wireless/ath/ath5k/debug.c | 86 ++++++++++++++++++++++++++++++++
+ 1 files changed, 86 insertions(+), 0 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath5k/debug.c
++++ b/drivers/net/wireless/ath/ath5k/debug.c
+@@ -813,6 +813,89 @@ static const struct file_operations fops
+ .llseek = default_llseek,
+ };
+
++/* debugfs: bwmode */
++
++static ssize_t read_file_bwmode(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath5k_hw *ah = file->private_data;
++ char buf[15];
++ unsigned int len = 0;
++
++ int cur_ah_bwmode = ah->ah_bwmode;
++
++#define print_selected(MODE, LABEL) \
++ if (cur_ah_bwmode == MODE) \
++ len += snprintf(buf+len, sizeof(buf)-len, "[%s]", LABEL); \
++ else \
++ len += snprintf(buf+len, sizeof(buf)-len, "%s", LABEL); \
++ len += snprintf(buf+len, sizeof(buf)-len, " ");
++
++ print_selected(AR5K_BWMODE_5MHZ, "5");
++ print_selected(AR5K_BWMODE_10MHZ, "10");
++ print_selected(AR5K_BWMODE_DEFAULT, "20");
++ print_selected(AR5K_BWMODE_40MHZ, "40");
++#undef print_selected
++
++ len += snprintf(buf+len, sizeof(buf)-len, "\n");
++
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_bwmode(struct file *file,
++ const char __user *userbuf,
++ size_t count, loff_t *ppos)
++{
++ struct ath5k_hw *ah = file->private_data;
++ char buf[3];
++ int bw = 20;
++ int tobwmode = AR5K_BWMODE_DEFAULT;
++
++ if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
++ return -EFAULT;
++
++ /* TODO: Add check for active interface */
++
++ if(strncmp(buf, "5", 1) == 0 ) {
++ tobwmode = AR5K_BWMODE_5MHZ;
++ bw = 5;
++ } else if ( strncmp(buf, "10", 2) == 0 ) {
++ tobwmode = AR5K_BWMODE_10MHZ;
++ bw = 10;
++ } else if ( strncmp(buf, "20", 2) == 0 ) {
++ tobwmode = AR5K_BWMODE_DEFAULT;
++ bw = 20;
++ } else if ( strncmp(buf, "40", 2) == 0 ) {
++ tobwmode = AR5K_BWMODE_40MHZ;
++ bw = 40;
++ } else
++ return -EINVAL;
++
++ ATH5K_INFO(ah, "Changing to %imhz channel width[%i]\n",
++ 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;
++ }
++ return count;
++}
++
++static const struct file_operations fops_bwmode = {
++ .read = read_file_bwmode,
++ .write = write_file_bwmode,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
+
+ /* debugfs: queues etc */
+
+@@ -904,6 +987,9 @@ ath5k_debug_init_device(struct ath5k_hw
+ debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
+ &fops_beacon);
+
++ debugfs_create_file("bwmode", S_IWUSR | S_IRUSR, phydir, ah,
++ &fops_bwmode);
++
+ debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset);
+
+ debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah,
diff --git a/package/mac80211/patches/500-ath9k_eeprom_debugfs.patch b/package/mac80211/patches/500-ath9k_eeprom_debugfs.patch
new file mode 100644
index 000000000..11272b96e
--- /dev/null
+++ b/package/mac80211/patches/500-ath9k_eeprom_debugfs.patch
@@ -0,0 +1,65 @@
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1532,6 +1532,53 @@ static const struct file_operations fops
+
+ #endif
+
++static ssize_t read_file_eeprom(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;
++ struct ath_common *common = ath9k_hw_common(ah);
++ int bytes = 0;
++ int pos = *ppos;
++ int size = 4096;
++ u16 val;
++ int i;
++
++ if (AR_SREV_9300_20_OR_LATER(ah))
++ size = 16384;
++
++ if (*ppos < 0)
++ return -EINVAL;
++
++ if (count > size - *ppos)
++ count = size - *ppos;
++
++ for (i = *ppos / 2; count > 0; count -= bytes, *ppos += bytes, i++) {
++ void *from = &val;
++
++ if (!common->bus_ops->eeprom_read(common, i, &val))
++ val = 0xffff;
++
++ if (*ppos % 2) {
++ from++;
++ bytes = 1;
++ } else if (count == 1) {
++ bytes = 1;
++ } else {
++ bytes = 2;
++ }
++ copy_to_user(user_buf, from, bytes);
++ user_buf += bytes;
++ }
++ return *ppos - pos;
++}
++
++static const struct file_operations fops_eeprom = {
++ .read = read_file_eeprom,
++ .open = simple_open,
++ .owner = THIS_MODULE
++};
++
+ int ath9k_init_debug(struct ath_hw *ah)
+ {
+ struct ath_common *common = ath9k_hw_common(ah);
+@@ -1603,5 +1650,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
+
++ debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
++ &fops_eeprom);
++
+ return 0;
+ }
diff --git a/package/mac80211/patches/501-ath9k-eeprom_endianess.patch b/package/mac80211/patches/501-ath9k-eeprom_endianess.patch
new file mode 100644
index 000000000..52ae70fc6
--- /dev/null
+++ b/package/mac80211/patches/501-ath9k-eeprom_endianess.patch
@@ -0,0 +1,102 @@
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -266,7 +266,7 @@ static int ath9k_hw_def_check_eeprom(str
+ {
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ struct ath_common *common = ath9k_hw_common(ah);
+- u16 *eepdata, temp, magic, magic2;
++ u16 *eepdata, temp, magic;
+ u32 sum = 0, el;
+ bool need_swap = false;
+ int i, addr, size;
+@@ -276,27 +276,16 @@ static int ath9k_hw_def_check_eeprom(str
+ return false;
+ }
+
+- if (!ath9k_hw_use_flash(ah)) {
+- ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
+-
+- if (magic != AR5416_EEPROM_MAGIC) {
+- magic2 = swab16(magic);
+-
+- if (magic2 == AR5416_EEPROM_MAGIC) {
+- size = sizeof(struct ar5416_eeprom_def);
+- need_swap = true;
+- eepdata = (u16 *) (&ah->eeprom);
+-
+- for (addr = 0; addr < size / sizeof(u16); addr++) {
+- temp = swab16(*eepdata);
+- *eepdata = temp;
+- eepdata++;
+- }
+- } else {
+- ath_err(common,
+- "Invalid EEPROM Magic. Endianness mismatch.\n");
+- return -EINVAL;
+- }
++ if (swab16(magic) == AR5416_EEPROM_MAGIC &&
++ !(ah->ah_flags & AH_NO_EEP_SWAP)) {
++ size = sizeof(struct ar5416_eeprom_def);
++ need_swap = true;
++ eepdata = (u16 *) (&ah->eeprom);
++
++ for (addr = 0; addr < size / sizeof(u16); addr++) {
++ temp = swab16(*eepdata);
++ *eepdata = temp;
++ eepdata++;
+ }
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -195,7 +195,7 @@ static int ath9k_hw_4k_check_eeprom(stru
+ int i, addr;
+
+
+- if (!ath9k_hw_use_flash(ah)) {
++ if (!(ah->ah_flags & AH_NO_EEP_SWAP)) {
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
+ ath_err(common, "Reading Magic # failed\n");
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -189,7 +189,7 @@ static int ath9k_hw_ar9287_check_eeprom(
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+- if (!ath9k_hw_use_flash(ah)) {
++ if (!(ah->ah_flags & AH_NO_EEP_SWAP)) {
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
+ ath_err(common, "Reading Magic # failed\n");
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -705,6 +705,7 @@ enum ath_cal_list {
+ #define AH_USE_EEPROM 0x1
+ #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
+ #define AH_FASTCC 0x4
++#define AH_NO_EEP_SWAP 0x8 /* Do not swap EEPROM data */
+
+ struct ath_hw {
+ struct ath_ops reg_ops;
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -537,6 +537,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;
++ if (!pdata->endian_check)
++ ah->ah_flags |= AH_NO_EEP_SWAP;
+ }
+
+ common = ath9k_hw_common(ah);
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -29,6 +29,7 @@ struct ath9k_platform_data {
+ u32 gpio_mask;
+ u32 gpio_val;
+
++ bool endian_check;
+ bool is_clk_25mhz;
+ int (*get_mac_revision)(void);
+ int (*external_reset)(void);
diff --git a/package/mac80211/patches/502-ath9k_ahb_init.patch b/package/mac80211/patches/502-ath9k_ahb_init.patch
new file mode 100644
index 000000000..7d3df6b20
--- /dev/null
+++ b/package/mac80211/patches/502-ath9k_ahb_init.patch
@@ -0,0 +1,32 @@
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -926,23 +926,23 @@ static int __init ath9k_init(void)
+ goto err_out;
+ }
+
+- error = ath_pci_init();
++ error = ath_ahb_init();
+ if (error < 0) {
+- pr_err("No PCI devices found, driver not installed\n");
+ error = -ENODEV;
+ goto err_rate_unregister;
+ }
+
+- error = ath_ahb_init();
++ error = ath_pci_init();
+ if (error < 0) {
++ pr_err("No PCI devices found, driver not installed\n");
+ error = -ENODEV;
+- goto err_pci_exit;
++ goto err_ahb_exit;
+ }
+
+ return 0;
+
+- err_pci_exit:
+- ath_pci_exit();
++ err_ahb_exit:
++ ath_ahb_exit();
+
+ err_rate_unregister:
+ ath_rate_control_unregister();
diff --git a/package/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch b/package/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
new file mode 100644
index 000000000..3b78afae3
--- /dev/null
+++ b/package/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
@@ -0,0 +1,13 @@
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1949,8 +1949,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ REG_WRITE(ah, AR_OBS, 8);
+
+ 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);
+ }
+
+ if (ah->config.tx_intr_mitigation) {
diff --git a/package/mac80211/patches/511-ath9k_reduce_rxbuf.patch b/package/mac80211/patches/511-ath9k_reduce_rxbuf.patch
new file mode 100644
index 000000000..db13fea1b
--- /dev/null
+++ b/package/mac80211/patches/511-ath9k_reduce_rxbuf.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -122,7 +122,7 @@ void ath_descdma_cleanup(struct ath_soft
+ /* RX / TX */
+ /***********/
+
+-#define ATH_RXBUF 512
++#define ATH_RXBUF 256
+ #define ATH_TXBUF 512
+ #define ATH_TXBUF_RESERVE 5
+ #define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
diff --git a/package/mac80211/patches/512-ath9k_channelbw_debugfs.patch b/package/mac80211/patches/512-ath9k_channelbw_debugfs.patch
new file mode 100644
index 000000000..d4087a0b2
--- /dev/null
+++ b/package/mac80211/patches/512-ath9k_channelbw_debugfs.patch
@@ -0,0 +1,128 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -659,6 +659,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];
+
+@@ -734,6 +735,7 @@ struct ath_softc {
+ #endif
+ };
+
++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
+@@ -1579,6 +1579,50 @@ static const struct file_operations fops
+ .owner = THIS_MODULE
+ };
+
++
++static ssize_t read_file_chan_bw(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char buf[32];
++ unsigned int len;
++
++ len = sprintf(buf, "0x%08x\n", sc->chan_bw);
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_chan_bw(struct file *file, const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ unsigned long chan_bw;
++ 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 (strict_strtoul(buf, 0, &chan_bw))
++ return -EINVAL;
++
++ sc->chan_bw = chan_bw;
++ if (!(sc->sc_flags & SC_OP_INVALID))
++ ath9k_config(sc->hw, IEEE80211_CONF_CHANGE_CHANNEL);
++
++ return count;
++}
++
++static const struct file_operations fops_chanbw = {
++ .read = read_file_chan_bw,
++ .write = write_file_chan_bw,
++ .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);
+@@ -1653,5 +1697,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("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
++ sc, &fops_chanbw);
++
+ return 0;
+ }
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1127,7 +1127,7 @@ static void ath9k_disable_ps(struct ath_
+ ath_dbg(common, PS, "PowerSave disabled\n");
+ }
+
+-static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
++int ath9k_config(struct ieee80211_hw *hw, u32 changed)
+ {
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+@@ -1181,9 +1181,11 @@ static int ath9k_config(struct ieee80211
+
+ if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
+ struct ieee80211_channel *curchan = hw->conf.channel;
++ struct ath9k_channel *hchan;
+ int pos = curchan->hw_value;
+ int old_pos = -1;
+ unsigned long flags;
++ u32 oldflags;
+
+ if (ah->curchan)
+ old_pos = ah->curchan - &ah->channels[0];
+@@ -1226,7 +1228,23 @@ static int ath9k_config(struct ieee80211
+ memset(&sc->survey[pos], 0, sizeof(struct survey_info));
+ }
+
+- 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;
++ }
++
++ if (ath_set_channel(sc, hw, hchan) < 0) {
+ ath_err(common, "Unable to set channel\n");
+ mutex_unlock(&sc->mutex);
+ ath9k_ps_restore(sc);
diff --git a/package/mac80211/patches/513-mac80211_reduce_txqueuelen.patch b/package/mac80211/patches/513-mac80211_reduce_txqueuelen.patch
new file mode 100644
index 000000000..25f4fdd40
--- /dev/null
+++ b/package/mac80211/patches/513-mac80211_reduce_txqueuelen.patch
@@ -0,0 +1,10 @@
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -964,6 +964,7 @@ static const struct net_device_ops ieee8
+ static void ieee80211_if_setup(struct net_device *dev)
+ {
+ ether_setup(dev);
++ dev->tx_queue_len = 32;
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ netdev_attach_ops(dev, &ieee80211_dataif_ops);
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
diff --git a/package/mac80211/patches/520-mac80211_cur_txpower.patch b/package/mac80211/patches/520-mac80211_cur_txpower.patch
new file mode 100644
index 000000000..54f2e5040
--- /dev/null
+++ b/package/mac80211/patches/520-mac80211_cur_txpower.patch
@@ -0,0 +1,31 @@
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1372,6 +1372,7 @@ struct ieee80211_hw {
+ u8 max_tx_aggregation_subframes;
+ u8 offchannel_tx_hw_queue;
+ u8 radiotap_mcs_details;
++ s8 cur_power_level;
+ netdev_features_t netdev_features;
+ };
+
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -1967,7 +1967,7 @@ static int ieee80211_get_tx_power(struct
+ {
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+- *dbm = local->hw.conf.power_level;
++ *dbm = local->hw.cur_power_level;
+
+ return 0;
+ }
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -165,6 +165,7 @@ int ieee80211_hw_config(struct ieee80211
+
+ if (local->hw.conf.power_level != power) {
+ changed |= IEEE80211_CONF_CHANGE_POWER;
++ local->hw.cur_power_level = power;
+ local->hw.conf.power_level = power;
+ }
+
diff --git a/package/mac80211/patches/521-ath9k_cur_txpower.patch b/package/mac80211/patches/521-ath9k_cur_txpower.patch
new file mode 100644
index 000000000..1133cfa6b
--- /dev/null
+++ b/package/mac80211/patches/521-ath9k_cur_txpower.patch
@@ -0,0 +1,19 @@
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1251,6 +1251,8 @@ int ath9k_config(struct ieee80211_hw *hw
+ return -EINVAL;
+ }
+
++ hw->cur_power_level = sc->curtxpow / 2;
++
+ /*
+ * The most recent snapshot of channel->noisefloor for the old
+ * channel is only available after the hardware reset. Copy it to
+@@ -1265,6 +1267,7 @@ int ath9k_config(struct ieee80211_hw *hw
+ sc->config.txpowlimit = 2 * conf->power_level;
+ ath9k_cmn_update_txpow(ah, sc->curtxpow,
+ sc->config.txpowlimit, &sc->curtxpow);
++ hw->cur_power_level = sc->curtxpow / 2;
+ }
+
+ mutex_unlock(&sc->mutex);
diff --git a/package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch b/package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
new file mode 100644
index 000000000..8b26a50b3
--- /dev/null
+++ b/package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
@@ -0,0 +1,384 @@
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -729,6 +729,9 @@ enum mac80211_rx_flags {
+ * @signal: signal strength when receiving this frame, either in dBm, in dB or
+ * unspecified depending on the hardware capabilities flags
+ * @IEEE80211_HW_SIGNAL_*
++ * @chains: bitmask of receive chains for which separate signal strength
++ * values were filled.
++ * @chain_signal: per-chain signal strength, same format as @signal
+ * @antenna: antenna used
+ * @rate_idx: index of data rate into band's supported rates or MCS index if
+ * HT rates are use (RX_FLAG_HT)
+@@ -749,6 +752,8 @@ struct ieee80211_rx_status {
+ u8 band;
+ u8 antenna;
+ s8 signal;
++ u8 chains;
++ s8 chain_signal[4];
+ u8 ampdu_delimiter_crc;
+ };
+
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -325,6 +325,11 @@ struct sta_info {
+ unsigned long rx_dropped;
+ int last_signal;
+ struct ewma avg_signal;
++
++ u8 chains;
++ s8 chain_signal_last[4];
++ struct ewma chain_signal_avg[4];
++
+ /* Plus 1 for non-QoS frames */
+ __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1];
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1271,6 +1271,7 @@ ieee80211_rx_h_sta_process(struct ieee80
+ struct sk_buff *skb = rx->skb;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
++ int i;
+
+ if (!sta)
+ return RX_CONTINUE;
+@@ -1315,6 +1316,19 @@ ieee80211_rx_h_sta_process(struct ieee80
+ ewma_add(&sta->avg_signal, -status->signal);
+ }
+
++ if (status->chains) {
++ sta->chains = status->chains;
++ for (i = 0; i < 4; i++) {
++ int signal = status->chain_signal[i];
++
++ if (!(status->chains & BIT(i)))
++ continue;
++
++ sta->chain_signal_last[i] = signal;
++ ewma_add(&sta->chain_signal_avg[i], -signal);
++ }
++ }
++
+ /*
+ * Change STA power saving mode only at the end of a frame
+ * exchange sequence.
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -254,6 +254,8 @@ struct sta_info *sta_info_alloc(struct i
+ do_posix_clock_monotonic_gettime(&uptime);
+ sta->last_connected = uptime.tv_sec;
+ ewma_init(&sta->avg_signal, 1024, 8);
++ for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
++ ewma_init(&sta->chain_signal_avg[i], 1024, 8);
+
+ if (sta_prepare_rate_control(local, sta, gfp)) {
+ kfree(sta);
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -549,6 +549,8 @@ struct station_parameters {
+ * @STATION_INFO_STA_FLAGS: @sta_flags filled
+ * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled
+ * @STATION_INFO_T_OFFSET: @t_offset filled
++ * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled
++ * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled
+ */
+ enum station_info_flags {
+ STATION_INFO_INACTIVE_TIME = 1<<0,
+@@ -572,6 +574,8 @@ enum station_info_flags {
+ STATION_INFO_STA_FLAGS = 1<<18,
+ STATION_INFO_BEACON_LOSS_COUNT = 1<<19,
+ STATION_INFO_T_OFFSET = 1<<20,
++ STATION_INFO_CHAIN_SIGNAL = 1<<21,
++ STATION_INFO_CHAIN_SIGNAL_AVG = 1<<22,
+ };
+
+ /**
+@@ -655,6 +659,9 @@ struct sta_bss_parameters {
+ * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @signal_avg: Average signal strength, type depends on the wiphy's signal_type.
+ * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
++ * @chains: bitmask for filled values in @chain_signal, @chain_signal_avg
++ * @chain_signal: per-chain signal strength of last received packet in dBm
++ * @chain_signal_avg: per-chain signal strength average in dBm
+ * @txrate: current unicast bitrate from this station
+ * @rxrate: current unicast bitrate to this station
+ * @rx_packets: packets received from this station
+@@ -687,6 +694,11 @@ struct station_info {
+ u8 plink_state;
+ s8 signal;
+ s8 signal_avg;
++
++ u8 chains;
++ s8 chain_signal[4];
++ s8 chain_signal_avg[4];
++
+ struct rate_info txrate;
+ struct rate_info rxrate;
+ u32 rx_packets;
+--- 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
+@@ -955,6 +955,7 @@ static int ath9k_rx_skb_preprocess(struc
+ bool *decrypt_error)
+ {
+ struct ath_hw *ah = common->ah;
++ int i, j;
+
+ /*
+ * everything but the rate is checked here, the rate check is done
+@@ -980,6 +981,20 @@ 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++;
++ }
++
+ return 0;
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -458,12 +458,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
+@@ -553,25 +553,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/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -997,12 +997,12 @@ void ath_debug_stat_rx(struct ath_softc
+ #ifdef CONFIG_ATH9K_MAC_DEBUG
+ spin_lock(&sc->debug.samp_lock);
+ RX_SAMP_DBG(jiffies) = jiffies;
+- RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0;
+- RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1;
+- RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2;
+- RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0;
+- RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1;
+- RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2;
++ RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl[0];
++ RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl[1];
++ RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl[2];
++ RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext[0];
++ RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext[1];
++ RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext[2];
+ RX_SAMP_DBG(antenna) = rs->rs_antenna;
+ RX_SAMP_DBG(rssi) = rs->rs_rssi;
+ RX_SAMP_DBG(rate) = rs->rs_rate;
+--- a/include/linux/nl80211.h
++++ b/include/linux/nl80211.h
+@@ -1760,6 +1760,8 @@ enum nl80211_sta_bss_param {
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
+ * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
++ * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU
++ * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ */
+@@ -1784,6 +1786,8 @@ enum nl80211_sta_info {
+ NL80211_STA_INFO_STA_FLAGS,
+ NL80211_STA_INFO_BEACON_LOSS,
+ NL80211_STA_INFO_T_OFFSET,
++ NL80211_STA_INFO_CHAIN_SIGNAL,
++ NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -2769,6 +2769,32 @@ nla_put_failure:
+ return false;
+ }
+
++static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
++ int id)
++{
++ void *attr;
++ int i = 0;
++
++ if (!mask)
++ return true;
++
++ attr = nla_nest_start(msg, id);
++ if (!attr)
++ return false;
++
++ for (i = 0; i < 4; i++) {
++ if (!(mask & BIT(i)))
++ continue;
++
++ if (nla_put_u8(msg, i, signal[i]))
++ return false;
++ }
++
++ nla_nest_end(msg, attr);
++
++ return true;
++}
++
+ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
+ int flags,
+ struct cfg80211_registered_device *rdev,
+@@ -2830,6 +2856,18 @@ static int nl80211_send_station(struct s
+ default:
+ break;
+ }
++ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) {
++ if (!nl80211_put_signal(msg, sinfo->chains,
++ sinfo->chain_signal,
++ NL80211_STA_INFO_CHAIN_SIGNAL))
++ goto nla_put_failure;
++ }
++ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) {
++ if (!nl80211_put_signal(msg, sinfo->chains,
++ sinfo->chain_signal_avg,
++ NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
++ goto nla_put_failure;
++ }
+ if (sinfo->filled & STATION_INFO_TX_BITRATE) {
+ if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
+ NL80211_STA_INFO_TX_BITRATE))
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -367,6 +367,7 @@ static void sta_set_sinfo(struct sta_inf
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
+ struct timespec uptime;
++ int i;
+
+ sinfo->generation = sdata->local->sta_generation;
+
+@@ -406,6 +407,17 @@ static void sta_set_sinfo(struct sta_inf
+ sinfo->signal = (s8)sta->last_signal;
+ sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
+ }
++ if (sta->chains) {
++ sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
++ STATION_INFO_CHAIN_SIGNAL_AVG;
++
++ sinfo->chains = sta->chains;
++ for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
++ sinfo->chain_signal[i] = sta->chain_signal_last[i];
++ sinfo->chain_signal_avg[i] =
++ (s8) -ewma_read(&sta->chain_signal_avg[i]);
++ }
++ }
+
+ sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
+
+--- a/drivers/net/wireless/ath/ath9k/dfs.c
++++ b/drivers/net/wireless/ath/ath9k/dfs.c
+@@ -164,8 +164,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
+@@ -529,14 +529,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 */
diff --git a/package/mac80211/patches/523-cfg80211_fix_antenna_gain.patch b/package/mac80211/patches/523-cfg80211_fix_antenna_gain.patch
new file mode 100644
index 000000000..98f3d9675
--- /dev/null
+++ b/package/mac80211/patches/523-cfg80211_fix_antenna_gain.patch
@@ -0,0 +1,12 @@
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -908,8 +908,7 @@ static void handle_channel(struct wiphy
+
+ chan->beacon_found = false;
+ chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
+- chan->max_antenna_gain = min(chan->orig_mag,
+- (int) MBI_TO_DBI(power_rule->max_antenna_gain));
++ chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
+ chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
+ if (chan->orig_mpwr) {
+ /*
diff --git a/package/mac80211/patches/524-mac80211_configure_antenna_gain.patch b/package/mac80211/patches/524-mac80211_configure_antenna_gain.patch
new file mode 100644
index 000000000..b2870a8aa
--- /dev/null
+++ b/package/mac80211/patches/524-mac80211_configure_antenna_gain.patch
@@ -0,0 +1,179 @@
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -851,6 +851,7 @@ enum ieee80211_smps_mode {
+ * the CONF_PS flag is set.
+ *
+ * @power_level: requested transmit power (in dBm)
++ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
+ *
+ * @channel: the channel to tune to
+ * @channel_type: the channel (HT) type
+@@ -870,6 +871,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/main.c
++++ b/net/mac80211/main.c
+@@ -101,7 +101,7 @@ int ieee80211_hw_config(struct ieee80211
+ {
+ struct ieee80211_channel *chan;
+ int ret = 0;
+- int power;
++ int power, ant_gain, max_power;
+ enum nl80211_channel_type channel_type;
+ u32 offchannel_flag;
+
+@@ -152,19 +152,31 @@ int ieee80211_hw_config(struct ieee80211
+ changed |= IEEE80211_CONF_CHANGE_SMPS;
+ }
+
+- if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+- test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
+- test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+- !local->ap_power_level)
+- power = chan->max_power;
+- else
+- power = min(chan->max_power, local->ap_power_level);
++ max_power = chan->max_reg_power;
++ if (!test_bit(SCAN_SW_SCANNING, &local->scanning) &&
++ !test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) &&
++ !test_bit(SCAN_HW_SCANNING, &local->scanning) &&
++ local->ap_power_level)
++ max_power = min(max_power, local->ap_power_level);
++
++ ant_gain = 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(chan->max_power, max_power);
+
+ if (local->user_power_level >= 0)
+ power = min(power, local->user_power_level);
+
+- if (local->hw.conf.power_level != 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;
+ }
+@@ -620,6 +632,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+ IEEE80211_RADIOTAP_MCS_HAVE_GI |
+ IEEE80211_RADIOTAP_MCS_HAVE_BW;
+ local->user_power_level = -1;
++ local->user_antenna_gain = -1;
+ wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
+
+ INIT_LIST_HEAD(&local->interfaces);
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1063,6 +1063,7 @@ struct ieee80211_local {
+
+ int user_power_level; /* in dBm */
+ int ap_power_level; /* in dBm */
++ int user_antenna_gain; /* in dBi */
+
+ enum ieee80211_smps_mode smps_mode;
+
+--- a/include/linux/nl80211.h
++++ b/include/linux/nl80211.h
+@@ -1517,6 +1517,8 @@ enum nl80211_attrs {
+
+ NL80211_ATTR_USER_REG_HINT_TYPE,
+
++ 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
+@@ -355,6 +355,7 @@ static const struct nla_policy nl80211_p
+ [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
+ [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
+ [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
++ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
+ };
+
+ /* policy for the key attributes */
+@@ -1604,6 +1605,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
+@@ -1984,6 +1984,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)
+ {
+@@ -3082,6 +3095,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
+@@ -1551,6 +1551,7 @@ struct cfg80211_gtk_rekey_data {
+ * the power passed is in mBm, to get dBm use MBM_TO_DBM().
+ * @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
+ *
+@@ -1750,6 +1751,7 @@ struct cfg80211_ops {
+ int (*set_tx_power)(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type, int mbm);
+ int (*get_tx_power)(struct wiphy *wiphy, 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);
diff --git a/package/mac80211/patches/525-ath9k_use_configured_antenna_gain.patch b/package/mac80211/patches/525-ath9k_use_configured_antenna_gain.patch
new file mode 100644
index 000000000..35096b255
--- /dev/null
+++ b/package/mac80211/patches/525-ath9k_use_configured_antenna_gain.patch
@@ -0,0 +1,34 @@
+--- 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
+@@ -2828,7 +2828,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
+@@ -1263,7 +1263,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);
diff --git a/package/mac80211/patches/526-cfg80211_fix_max_reg_power.patch b/package/mac80211/patches/526-cfg80211_fix_max_reg_power.patch
new file mode 100644
index 000000000..6f8d53f95
--- /dev/null
+++ b/package/mac80211/patches/526-cfg80211_fix_max_reg_power.patch
@@ -0,0 +1,21 @@
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -901,7 +901,7 @@ static void handle_channel(struct wiphy
+ map_regdom_flags(reg_rule->flags) | bw_flags;
+ chan->max_antenna_gain = chan->orig_mag =
+ (int) MBI_TO_DBI(power_rule->max_antenna_gain);
+- chan->max_power = chan->orig_mpwr =
++ chan->max_reg_power = chan->max_power = chan->orig_mpwr =
+ (int) MBM_TO_DBM(power_rule->max_eirp);
+ return;
+ }
+@@ -1323,7 +1323,8 @@ static void handle_channel_custom(struct
+
+ chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
+ chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
+- chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
++ chan->max_reg_power = chan->max_power =
++ (int) MBM_TO_DBM(power_rule->max_eirp);
+ }
+
+ static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band,
diff --git a/package/mac80211/patches/530-ath9k_fix_initvals.patch b/package/mac80211/patches/530-ath9k_fix_initvals.patch
new file mode 100644
index 000000000..d86e718f0
--- /dev/null
+++ b/package/mac80211/patches/530-ath9k_fix_initvals.patch
@@ -0,0 +1,208 @@
+--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+@@ -534,108 +534,108 @@ static const u32 ar9300_2p2_baseband_cor
+
+ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+- {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+- {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+- {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
++ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
++ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
++ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+- {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+- {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+- {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+- {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+- {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+- {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+- {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+- {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+- {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+- {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+- {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+- {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+- {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+- {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+- {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+- {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+- {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+- {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+- {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+- {0x0000a54c, 0x5a08442e, 0x5a08442e, 0x47001a83, 0x47001a83},
+- {0x0000a550, 0x5e0a4431, 0x5e0a4431, 0x4a001c84, 0x4a001c84},
+- {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+- {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+- {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+- {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+- {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+- {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+- {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+- {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+- {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+- {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+- {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+- {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+- {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+- {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+- {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+- {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202},
+- {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400},
+- {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402},
+- {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404},
+- {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603},
+- {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02},
+- {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04},
+- {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20},
+- {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20},
+- {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22},
+- {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24},
+- {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640},
+- {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660},
+- {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861},
+- {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81},
+- {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83},
+- {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84},
+- {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3},
+- {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5},
+- {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9},
+- {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb},
+- {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+- {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+- {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+- {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+- {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+- {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+- {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
++ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
++ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
++ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
++ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
++ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
++ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
++ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
++ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
++ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
++ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
++ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
++ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
++ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
++ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
++ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
++ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
++ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
++ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
++ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
++ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
++ {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
++ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
++ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
++ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
++ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
++ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
++ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
++ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
++ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
++ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
++ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
++ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
++ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
++ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
++ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
++ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
++ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
++ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
++ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
++ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
++ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
++ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
++ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
++ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
++ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
++ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
++ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
++ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
++ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
++ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
++ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
++ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
++ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
++ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+- {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+- {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+- {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+- {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+- {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+- {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+- {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+- {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+- {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+- {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+- {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+- {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+- {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+- {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+- {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+- {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
++ {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
++ {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
++ {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
++ {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
++ {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
++ {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
++ {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
++ {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
++ {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
++ {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
++ {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
++ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
++ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+- {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+- {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+- {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
++ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
++ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
++ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+- {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+- {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+- {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+- {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+- {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+- {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+- {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+- {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+- {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
++ {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
++ {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
++ {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
++ {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
++ {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
++ {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
++ {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
++ {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
++ {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+ };
+
+ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
diff --git a/package/mac80211/patches/540-ath9k_extra_leds.patch b/package/mac80211/patches/540-ath9k_extra_leds.patch
new file mode 100644
index 000000000..86dc51856
--- /dev/null
+++ b/package/mac80211/patches/540-ath9k_extra_leds.patch
@@ -0,0 +1,258 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -538,6 +538,9 @@ struct ath9k_wow_pattern {
+ #ifdef CONFIG_MAC80211_LEDS
+ void ath_init_leds(struct ath_softc *sc);
+ void ath_deinit_leds(struct ath_softc *sc);
++int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
++ const char *trigger, bool active_low);
++
+ #else
+ static inline void ath_init_leds(struct ath_softc *sc)
+ {
+@@ -655,6 +658,13 @@ struct ath9k_vif_iter_data {
+ int nadhocs; /* number of adhoc vifs */
+ };
+
++struct ath_led {
++ struct list_head list;
++ struct ath_softc *sc;
++ const struct gpio_led *gpio;
++ struct led_classdev cdev;
++};
++
+ struct ath_softc {
+ struct ieee80211_hw *hw;
+ struct device *dev;
+@@ -696,9 +706,8 @@ struct ath_softc {
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
+
+ #ifdef CONFIG_MAC80211_LEDS
+- bool led_registered;
+- char led_name[32];
+- struct led_classdev led_cdev;
++ const char *led_default_trigger;
++ struct list_head leds;
+ #endif
+
+ struct ath9k_hw_cal_data caldata;
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -24,22 +24,89 @@
+ static void ath_led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+ {
+- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
+- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF));
++ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
++ struct ath_softc *sc = led->sc;
++
++ ath9k_ps_wakeup(sc);
++ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
++ (brightness != LED_OFF) ^ led->gpio->active_low);
++ ath9k_ps_restore(sc);
++}
++
++static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
++{
++ const struct gpio_led *gpio = led->gpio;
++ int ret;
++
++ led->cdev.name = gpio->name;
++ led->cdev.default_trigger = gpio->default_trigger;
++ led->cdev.brightness_set = ath_led_brightness;
++
++ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
++ if (ret < 0)
++ return ret;
++
++ led->sc = sc;
++ list_add(&led->list, &sc->leds);
++
++ /* Configure gpio for output */
++ ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++
++ /* LED off */
++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
++
++ return 0;
++}
++
++int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
++ const char *trigger, bool active_low)
++{
++ struct ath_led *led;
++ struct gpio_led *gpio;
++ char *_name;
++ int ret;
++
++ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
++ GFP_KERNEL);
++ if (!led)
++ return -ENOMEM;
++
++ led->gpio = gpio = (struct gpio_led *) (led + 1);
++ _name = (char *) (led->gpio + 1);
++
++ strcpy(_name, name);
++ gpio->name = _name;
++ gpio->gpio = gpio_num;
++ gpio->active_low = active_low;
++ gpio->default_trigger = trigger;
++
++ ret = ath_add_led(sc, led);
++ if (unlikely(ret < 0))
++ kfree(led);
++
++ return ret;
+ }
+
+ void ath_deinit_leds(struct ath_softc *sc)
+ {
+- if (!sc->led_registered)
+- return;
++ struct ath_led *led;
+
+- ath_led_brightness(&sc->led_cdev, LED_OFF);
+- led_classdev_unregister(&sc->led_cdev);
++ while (!list_empty(&sc->leds)) {
++ led = list_first_entry(&sc->leds, struct ath_led, list);
++ list_del(&led->list);
++ ath_led_brightness(&led->cdev, LED_OFF);
++ led_classdev_unregister(&led->cdev);
++ kfree(led);
++ }
+ }
+
+ void ath_init_leds(struct ath_softc *sc)
+ {
+- int ret;
++ char led_name[32];
++ const char *trigger;
++
++ INIT_LIST_HEAD(&sc->leds);
+
+ if (AR_SREV_9100(sc->sc_ah))
+ return;
+@@ -57,26 +124,15 @@ void ath_init_leds(struct ath_softc *sc)
+ sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+ }
+
+- /* Configure gpio 1 for output */
+- ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
+- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+- /* LED off, active low */
+- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+-
+- if (!led_blink)
+- sc->led_cdev.default_trigger =
+- ieee80211_get_radio_led_name(sc->hw);
+-
+- snprintf(sc->led_name, sizeof(sc->led_name),
+- "ath9k-%s", wiphy_name(sc->hw->wiphy));
+- sc->led_cdev.name = sc->led_name;
+- sc->led_cdev.brightness_set = ath_led_brightness;
++ snprintf(led_name, sizeof(led_name), "ath9k-%s",
++ wiphy_name(sc->hw->wiphy));
+
+- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
+- if (ret < 0)
+- return;
++ if (led_blink)
++ trigger = sc->led_default_trigger;
++ else
++ trigger = ieee80211_get_radio_led_name(sc->hw);
+
+- sc->led_registered = true;
++ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
+ }
+ #endif
+
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -811,7 +811,7 @@ int ath9k_init_device(u16 devid, struct
+
+ #ifdef CONFIG_MAC80211_LEDS
+ /* must be initialized before ieee80211_register_hw */
+- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
++ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
+ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
+ ARRAY_SIZE(ath9k_tpt_blink));
+ #endif
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1255,6 +1255,61 @@ static const struct file_operations fops
+ .llseek = default_llseek,
+ };
+
++#ifdef CONFIG_MAC80211_LEDS
++
++static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ struct ath_softc *sc = file->private_data;
++ char buf[32], *str, *name, *c;
++ ssize_t len;
++ unsigned int gpio;
++ bool active_low = false;
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, ubuf, len))
++ return -EFAULT;
++
++ buf[len] = '\0';
++ name = strchr(buf, ',');
++ if (!name)
++ return -EINVAL;
++
++ *(name++) = 0;
++ if (!*name)
++ return -EINVAL;
++
++ c = strchr(name, '\n');
++ if (c)
++ *c = 0;
++
++ str = buf;
++ if (*str == '!') {
++ str++;
++ active_low = true;
++ }
++
++ if (kstrtouint(str, 0, &gpio) < 0)
++ return -EINVAL;
++
++ if (gpio >= sc->sc_ah->caps.num_gpio_pins)
++ return -EINVAL;
++
++ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0)
++ return -EINVAL;
++
++ return count;
++}
++
++static const struct file_operations fops_gpio_led = {
++ .write = write_file_gpio_led,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++#endif
++
+ #ifdef CONFIG_ATH9K_MAC_DEBUG
+
+ void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
+@@ -1688,6 +1743,11 @@ int ath9k_init_debug(struct ath_hw *ah)
+ &fops_samps);
+ #endif
+
++#ifdef CONFIG_MAC80211_LEDS
++ debugfs_create_file("gpio_led", S_IWUSR,
++ sc->debug.debugfs_phy, sc, &fops_gpio_led);
++#endif
++
+ debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
+
diff --git a/package/mac80211/patches/541-ath9k_extra_platform_leds.patch b/package/mac80211/patches/541-ath9k_extra_platform_leds.patch
new file mode 100644
index 000000000..ac8ee533d
--- /dev/null
+++ b/package/mac80211/patches/541-ath9k_extra_platform_leds.patch
@@ -0,0 +1,71 @@
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -33,6 +33,9 @@ struct ath9k_platform_data {
+ bool is_clk_25mhz;
+ int (*get_mac_revision)(void);
+ int (*external_reset)(void);
++
++ int num_leds;
++ const struct gpio_led *leds;
+ };
+
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -14,6 +14,7 @@
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
++#include <linux/ath9k_platform.h>
+ #include "ath9k.h"
+
+ /********************************/
+@@ -88,6 +89,24 @@ int ath_create_gpio_led(struct ath_softc
+ return ret;
+ }
+
++static int ath_create_platform_led(struct ath_softc *sc,
++ const struct gpio_led *gpio)
++{
++ struct ath_led *led;
++ int ret;
++
++ led = kzalloc(sizeof(*led), GFP_KERNEL);
++ if (!led)
++ return -ENOMEM;
++
++ led->gpio = gpio;
++ ret = ath_add_led(sc, led);
++ if (ret < 0)
++ kfree(led);
++
++ return ret;
++}
++
+ void ath_deinit_leds(struct ath_softc *sc)
+ {
+ struct ath_led *led;
+@@ -103,8 +122,10 @@ void ath_deinit_leds(struct ath_softc *s
+
+ void ath_init_leds(struct ath_softc *sc)
+ {
++ struct ath9k_platform_data *pdata = sc->dev->platform_data;
+ char led_name[32];
+ const char *trigger;
++ int i;
+
+ INIT_LIST_HEAD(&sc->leds);
+
+@@ -133,6 +154,12 @@ void ath_init_leds(struct ath_softc *sc)
+ trigger = ieee80211_get_radio_led_name(sc->hw);
+
+ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);
++
++ if (!pdata)
++ return;
++
++ for (i = 0; i < pdata->num_leds; i++)
++ ath_create_platform_led(sc, &pdata->leds[i]);
+ }
+ #endif
+
diff --git a/package/mac80211/patches/550-mac80211_optimize_mcs_rate_mask.patch b/package/mac80211/patches/550-mac80211_optimize_mcs_rate_mask.patch
new file mode 100644
index 000000000..53889d19c
--- /dev/null
+++ b/package/mac80211/patches/550-mac80211_optimize_mcs_rate_mask.patch
@@ -0,0 +1,98 @@
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -715,6 +715,8 @@ struct ieee80211_sub_if_data {
+
+ /* bitmap of allowed (non-MCS) rate indexes for rate control */
+ u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
++
++ bool rc_has_mcs_mask[IEEE80211_NUM_BANDS];
+ u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
+
+ union {
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2160,9 +2160,20 @@ static int ieee80211_set_bitrate_mask(st
+ }
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
++ struct ieee80211_supported_band *sband = wiphy->bands[i];
++
+ sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
+ memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
+ sizeof(mask->control[i].mcs));
++
++ sdata->rc_has_mcs_mask[i] = false;
++ if (!sband)
++ continue;
++
++ if (memcmp(sdata->rc_rateidx_mcs_mask[i],
++ sband->ht_cap.mcs.rx_mask,
++ sizeof(sband->ht_cap.mcs.rx_mask)) != 0)
++ sdata->rc_has_mcs_mask[i] = true;
+ }
+
+ return 0;
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -3721,7 +3721,7 @@ void ieee80211_send_bar(struct ieee80211
+ * (deprecated; this will be removed once drivers get updated to use
+ * rate_idx_mask)
+ * @rate_idx_mask: user-requested (legacy) rate mask
+- * @rate_idx_mcs_mask: user-requested MCS rate mask
++ * @rate_idx_mcs_mask: user-requested MCS rate mask (NULL if not in use)
+ * @bss: whether this frame is sent out in AP or IBSS mode
+ */
+ struct ieee80211_tx_rate_control {
+@@ -3733,7 +3733,7 @@ struct ieee80211_tx_rate_control {
+ bool rts, short_preamble;
+ u8 max_rate_idx;
+ u32 rate_idx_mask;
+- u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
++ u8 *rate_idx_mcs_mask;
+ bool bss;
+ };
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -631,9 +631,11 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
+ txrc.max_rate_idx = -1;
+ else
+ txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+- memcpy(txrc.rate_idx_mcs_mask,
+- tx->sdata->rc_rateidx_mcs_mask[info->band],
+- sizeof(txrc.rate_idx_mcs_mask));
++
++ if (tx->sdata->rc_has_mcs_mask[info->band])
++ txrc.rate_idx_mcs_mask =
++ tx->sdata->rc_rateidx_mcs_mask[info->band];
++
+ txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
+ tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+ tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
+@@ -2447,8 +2449,6 @@ struct sk_buff *ieee80211_beacon_get_tim
+ txrc.max_rate_idx = -1;
+ else
+ txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+- memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band],
+- sizeof(txrc.rate_idx_mcs_mask));
+ txrc.bss = true;
+ rate_control_get_rate(sdata, NULL, &txrc);
+
+--- a/net/mac80211/rate.c
++++ b/net/mac80211/rate.c
+@@ -461,9 +461,12 @@ void rate_control_get_rate(struct ieee80
+ * the common case.
+ */
+ mask = sdata->rc_rateidx_mask[info->band];
+- memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
+- sizeof(mcs_mask));
+- if (mask != (1 << txrc->sband->n_bitrates) - 1) {
++ if (mask != (1 << txrc->sband->n_bitrates) - 1 || txrc->rate_idx_mcs_mask) {
++ if (txrc->rate_idx_mcs_mask)
++ memcpy(mcs_mask, txrc->rate_idx_mcs_mask, sizeof(mcs_mask));
++ else
++ memset(mcs_mask, 0xff, sizeof(mcs_mask));
++
+ if (sta) {
+ /* Filter out rates that the STA does not support */
+ mask &= sta->sta.supp_rates[info->band];
diff --git a/package/mac80211/patches/551-ath9k_optimize_interrupt_mitigation.patch b/package/mac80211/patches/551-ath9k_optimize_interrupt_mitigation.patch
new file mode 100644
index 000000000..2afc4deb4
--- /dev/null
+++ b/package/mac80211/patches/551-ath9k_optimize_interrupt_mitigation.patch
@@ -0,0 +1,30 @@
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -240,21 +240,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)) {
diff --git a/package/mac80211/patches/560-ath9k_reduce_ani_interval.patch b/package/mac80211/patches/560-ath9k_reduce_ani_interval.patch
new file mode 100644
index 000000000..e2a0d124a
--- /dev/null
+++ b/package/mac80211/patches/560-ath9k_reduce_ani_interval.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath9k/ani.h
++++ b/drivers/net/wireless/ath/ath9k/ani.h
+@@ -51,7 +51,7 @@
+ #define ATH9K_ANI_PERIOD 300
+
+ /* in ms */
+-#define ATH9K_ANI_POLLINTERVAL 1000
++#define ATH9K_ANI_POLLINTERVAL 100
+
+ #define HAL_NOISE_IMMUNE_MAX 4
+ #define HAL_SPUR_IMMUNE_MAX 7
diff --git a/package/mac80211/patches/561-ath9k_revert_initval_change.patch b/package/mac80211/patches/561-ath9k_revert_initval_change.patch
new file mode 100644
index 000000000..49aea350c
--- /dev/null
+++ b/package/mac80211/patches/561-ath9k_revert_initval_change.patch
@@ -0,0 +1,19 @@
+--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+@@ -778,11 +778,11 @@ static const u32 ar9300Common_rx_gain_ta
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+- {0x0000a080, 0x1a1a1a1a},
+- {0x0000a084, 0x1a1a1a1a},
+- {0x0000a088, 0x1a1a1a1a},
+- {0x0000a08c, 0x1a1a1a1a},
+- {0x0000a090, 0x171a1a1a},
++ {0x0000a080, 0x22222229},
++ {0x0000a084, 0x1d1d1d1d},
++ {0x0000a088, 0x1d1d1d1d},
++ {0x0000a08c, 0x1d1d1d1d},
++ {0x0000a090, 0x171d1d1d},
+ {0x0000a094, 0x11111717},
+ {0x0000a098, 0x00030311},
+ {0x0000a09c, 0x00000000},
diff --git a/package/mac80211/patches/562-ath9k_add_idle_hack.patch b/package/mac80211/patches/562-ath9k_add_idle_hack.patch
new file mode 100644
index 000000000..10fac17bd
--- /dev/null
+++ b/package/mac80211/patches/562-ath9k_add_idle_hack.patch
@@ -0,0 +1,20 @@
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1087,6 +1087,7 @@ static void ath9k_remove_interface(struc
+ ath9k_calculate_summary_state(hw, NULL);
+
+ mutex_unlock(&sc->mutex);
++ ath9k_config(hw, IEEE80211_CONF_CHANGE_IDLE);
+ ath9k_ps_restore(sc);
+ }
+
+@@ -1139,7 +1140,8 @@ int ath9k_config(struct ieee80211_hw *hw
+ mutex_lock(&sc->mutex);
+
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+- sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
++ sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE) &&
++ !sc->nvifs;
+ if (sc->ps_idle) {
+ ath_cancel_work(sc);
+ ath9k_stop_btcoex(sc);
diff --git a/package/mac80211/patches/563-ath9k_rx_dma_stop_check.patch b/package/mac80211/patches/563-ath9k_rx_dma_stop_check.patch
new file mode 100644
index 000000000..606eb1c63
--- /dev/null
+++ b/package/mac80211/patches/563-ath9k_rx_dma_stop_check.patch
@@ -0,0 +1,28 @@
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -689,7 +689,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 */
+@@ -719,6 +719,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,
diff --git a/package/mac80211/patches/564-ath9k_debugfs_diag.patch b/package/mac80211/patches/564-ath9k_debugfs_diag.patch
new file mode 100644
index 000000000..2cf2a73e0
--- /dev/null
+++ b/package/mac80211/patches/564-ath9k_debugfs_diag.patch
@@ -0,0 +1,139 @@
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1678,6 +1678,50 @@ static const struct file_operations fops
+ };
+
+
++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 (strict_strtoul(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);
+@@ -1760,5 +1804,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_chanbw);
+
++ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
++ sc, &fops_diag);
++
+ return 0;
+ }
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -498,6 +498,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;
+@@ -741,6 +747,8 @@ struct ath_hw {
+ u32 rfkill_polarity;
+ u32 ah_flags;
+
++ unsigned long diag;
++
+ bool htc_reset_init;
+
+ enum nl80211_iftype opmode;
+@@ -1007,6 +1015,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 CONFIG_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
+@@ -1749,6 +1749,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)
+ {
+@@ -2026,6 +2040,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ }
+
+ ath9k_hw_apply_gpio_override(ah);
++ ath9k_hw_update_diag(ah);
+
+ return 0;
+ }
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -476,6 +476,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).
diff --git a/package/mac80211/patches/565-ath9k_disable_paprd.patch b/package/mac80211/patches/565-ath9k_disable_paprd.patch
new file mode 100644
index 000000000..079986d60
--- /dev/null
+++ b/package/mac80211/patches/565-ath9k_disable_paprd.patch
@@ -0,0 +1,72 @@
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1767,6 +1767,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
+ debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_disable_ani);
++ debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
++ &sc->sc_ah->config.enable_paprd);
+ debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_regidx);
+ debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2521,10 +2521,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw
+ pCap->rx_status_len = sizeof(struct ar9003_rxs);
+ pCap->tx_desc_len = sizeof(struct ar9003_txc);
+ pCap->txs_len = sizeof(struct ar9003_txs);
+- if (!ah->config.paprd_disable &&
+- ah->eep_ops->get_eeprom(ah, EEP_PAPRD) &&
+- !AR_SREV_9462(ah))
+- pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
+ } else {
+ pCap->tx_desc_len = sizeof(struct ath_desc);
+ if (AR_SREV_9280_20(ah))
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -236,7 +236,6 @@ enum ath9k_hw_caps {
+ ATH9K_HW_CAP_LDPC = BIT(6),
+ ATH9K_HW_CAP_FASTCLOCK = BIT(7),
+ ATH9K_HW_CAP_SGI_20 = BIT(8),
+- ATH9K_HW_CAP_PAPRD = BIT(9),
+ ATH9K_HW_CAP_ANT_DIV_COMB = BIT(10),
+ ATH9K_HW_CAP_2GHZ = BIT(11),
+ ATH9K_HW_CAP_5GHZ = BIT(12),
+@@ -287,12 +286,12 @@ struct ath9k_ops_config {
+ u8 pcie_clock_req;
+ u32 pcie_waen;
+ u8 analog_shiftreg;
+- u8 paprd_disable;
+ u32 ofdm_trig_low;
+ u32 ofdm_trig_high;
+ u32 cck_trig_high;
+ u32 cck_trig_low;
+ u32 enable_ani;
++ u32 enable_paprd;
+ int serialize_regmode;
+ bool rx_intr_mitigation;
+ bool tx_intr_mitigation;
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -2982,6 +2982,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(st
+ case EEP_RX_MASK:
+ return pBase->txrxMask & 0xf;
+ case EEP_PAPRD:
++ if (AR_SREV_9462(ah))
++ return false;
++ if (!ah->config.enable_paprd);
++ return false;
+ return !!(pBase->featureEnable & BIT(5));
+ case EEP_CHAIN_MASK_REDUCE:
+ return (pBase->miscConfiguration >> 0x3) & 0x1;
+--- a/drivers/net/wireless/ath/ath9k/link.c
++++ b/drivers/net/wireless/ath/ath9k/link.c
+@@ -423,7 +423,7 @@ set_timer:
+ cal_interval = min(cal_interval, (u32)short_cal_interval);
+
+ mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
++ if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD) && ah->caldata) {
+ if (!ah->caldata->paprd_done)
+ ieee80211_queue_work(sc->hw, &sc->paprd_work);
+ else if (!ah->paprd_table_write_done)
diff --git a/package/mac80211/patches/566-ath9k_use_ieee80211_free_txskb.patch b/package/mac80211/patches/566-ath9k_use_ieee80211_free_txskb.patch
new file mode 100644
index 000000000..dd484662b
--- /dev/null
+++ b/package/mac80211/patches/566-ath9k_use_ieee80211_free_txskb.patch
@@ -0,0 +1,149 @@
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -66,8 +66,7 @@ static void ath_tx_update_baw(struct ath
+ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+- struct sk_buff *skb,
+- bool dequeue);
++ struct sk_buff *skb);
+
+ enum {
+ MCS_HT20,
+@@ -176,7 +175,15 @@ static void ath_tx_flush_tid(struct ath_
+ fi = get_frame_info(skb);
+ bf = fi->bf;
+
+- if (bf && fi->retries) {
++ if (!bf) {
++ bf = ath_tx_setup_buffer(sc, txq, tid, skb);
++ if (!bf) {
++ ieee80211_free_txskb(sc->hw, skb);
++ continue;
++ }
++ }
++
++ if (fi->retries) {
+ 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);
+@@ -785,10 +792,13 @@ static enum ATH_AGGR_STATUS ath_tx_form_
+ fi = get_frame_info(skb);
+ bf = fi->bf;
+ if (!fi->bf)
+- bf = ath_tx_setup_buffer(sc, txq, tid, skb, true);
++ bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+
+- if (!bf)
++ if (!bf) {
++ __skb_unlink(skb, &tid->buf_q);
++ ieee80211_free_txskb(sc->hw, skb);
+ continue;
++ }
+
+ bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
+ seqno = bf->bf_state.seqno;
+@@ -1731,9 +1741,11 @@ static void ath_tx_send_ampdu(struct ath
+ return;
+ }
+
+- bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
+- if (!bf)
++ bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
++ if (!bf) {
++ ieee80211_free_txskb(sc->hw, skb);
+ return;
++ }
+
+ bf->bf_state.bf_type = BUF_AMPDU;
+ INIT_LIST_HEAD(&bf_head);
+@@ -1757,11 +1769,6 @@ static void ath_tx_send_normal(struct at
+ struct ath_buf *bf;
+
+ bf = fi->bf;
+- if (!bf)
+- bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);
+-
+- if (!bf)
+- return;
+
+ INIT_LIST_HEAD(&bf_head);
+ list_add_tail(&bf->list, &bf_head);
+@@ -1835,8 +1842,7 @@ u8 ath_txchainmask_reduction(struct ath_
+ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+- struct sk_buff *skb,
+- bool dequeue)
++ struct sk_buff *skb)
+ {
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_frame_info *fi = get_frame_info(skb);
+@@ -1848,7 +1854,7 @@ static struct ath_buf *ath_tx_setup_buff
+ bf = ath_tx_get_buffer(sc);
+ if (!bf) {
+ ath_dbg(common, XMIT, "TX buffers are full\n");
+- goto error;
++ return NULL;
+ }
+
+ ATH_TXBUF_RESET(bf);
+@@ -1877,18 +1883,12 @@ static struct ath_buf *ath_tx_setup_buff
+ ath_err(ath9k_hw_common(sc->sc_ah),
+ "dma_mapping_error() on TX\n");
+ ath_tx_return_buffer(sc, bf);
+- goto error;
++ return NULL;
+ }
+
+ fi->bf = bf;
+
+ return bf;
+-
+-error:
+- if (dequeue)
+- __skb_unlink(skb, &tid->buf_q);
+- dev_kfree_skb_any(skb);
+- return NULL;
+ }
+
+ /* FIXME: tx power */
+@@ -1917,9 +1917,14 @@ static void ath_tx_start_dma(struct ath_
+ */
+ ath_tx_send_ampdu(sc, tid, skb, txctl);
+ } else {
+- bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
+- if (!bf)
++ bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
++ if (!bf) {
++ if (txctl->paprd)
++ dev_kfree_skb_any(skb);
++ else
++ ieee80211_free_txskb(sc->hw, skb);
+ return;
++ }
+
+ bf->bf_state.bfs_paprd = txctl->paprd;
+
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -775,7 +775,7 @@ static void ath9k_tx(struct ieee80211_hw
+
+ return;
+ exit:
+- dev_kfree_skb_any(skb);
++ ieee80211_free_txskb(hw, skb);
+ }
+
+ static void ath9k_stop(struct ieee80211_hw *hw)
+--- a/drivers/net/wireless/ath/ath9k/beacon.c
++++ b/drivers/net/wireless/ath/ath9k/beacon.c
+@@ -120,7 +120,7 @@ static void ath9k_tx_cabq(struct ieee802
+
+ if (ath_tx_start(hw, skb, &txctl) != 0) {
+ ath_dbg(common, XMIT, "CABQ TX failed\n");
+- dev_kfree_skb_any(skb);
++ ieee80211_free_txskb(hw, skb);
+ }
+ }
+
diff --git a/package/mac80211/patches/600-rt2x00-disable-pci-code-if-CONFIG_PCI-not-defined.patch b/package/mac80211/patches/600-rt2x00-disable-pci-code-if-CONFIG_PCI-not-defined.patch
new file mode 100644
index 000000000..a7609ede4
--- /dev/null
+++ b/package/mac80211/patches/600-rt2x00-disable-pci-code-if-CONFIG_PCI-not-defined.patch
@@ -0,0 +1,18 @@
+--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
++++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
+@@ -208,6 +208,7 @@ void rt2x00pci_uninitialize(struct rt2x0
+ }
+ EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
+
++#ifdef CONFIG_PCI
+ /*
+ * PCI driver handlers.
+ */
+@@ -392,6 +393,7 @@ int rt2x00pci_resume(struct pci_dev *pci
+ }
+ EXPORT_SYMBOL_GPL(rt2x00pci_resume);
+ #endif /* CONFIG_PM */
++#endif /* CONFIG_PCI */
+
+ /*
+ * rt2x00pci module information.
diff --git a/package/mac80211/patches/601-rt2x00-set_pci_mwi.patch b/package/mac80211/patches/601-rt2x00-set_pci_mwi.patch
new file mode 100644
index 000000000..9ff50b7bf
--- /dev/null
+++ b/package/mac80211/patches/601-rt2x00-set_pci_mwi.patch
@@ -0,0 +1,13 @@
+--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
++++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
+@@ -273,8 +273,10 @@ int rt2x00pci_probe(struct pci_dev *pci_
+
+ pci_set_master(pci_dev);
+
++#ifdef CONFIG_PCI_SET_MWI
+ if (pci_set_mwi(pci_dev))
+ ERROR_PROBE("MWI not available.\n");
++#endif
+
+ if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
+ ERROR_PROBE("PCI DMA not supported.\n");
diff --git a/package/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch b/package/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch
new file mode 100644
index 000000000..6c80c3dfa
--- /dev/null
+++ b/package/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch
@@ -0,0 +1,32 @@
+--- /dev/null
++++ b/include/linux/rt2x00_platform.h
+@@ -0,0 +1,19 @@
++/*
++ * Platform data definition for the rt2x00 driver
++ *
++ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.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.
++ *
++ */
++
++#ifndef _RT2X00_PLATFORM_H
++#define _RT2X00_PLATFORM_H
++
++struct rt2x00_platform_data {
++ char *eeprom_file_name;
++};
++
++#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>
+ #include <linux/kfifo.h>
+ #include <linux/hrtimer.h>
++#include <linux/rt2x00_platform.h>
+
+ #include <net/mac80211.h>
+
diff --git a/package/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch b/package/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
new file mode 100644
index 000000000..4f35ae899
--- /dev/null
+++ b/package/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch
@@ -0,0 +1,274 @@
+--- /dev/null
++++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c
+@@ -0,0 +1,98 @@
++/*
++ Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
++ Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
++ <http://rt2x00.serialmonkey.com>
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the
++ Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++/*
++ Module: rt2x00lib
++ Abstract: rt2x00 eeprom file loading routines.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include "rt2x00.h"
++#include "rt2x00lib.h"
++
++static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++ const struct firmware *ee;
++ char *ee_name;
++ int retval;
++
++ ee_name = rt2x00dev->ops->lib->get_eeprom_file_name(rt2x00dev);
++ if (!ee_name) {
++ ERROR(rt2x00dev,
++ "Invalid EEPROM filename.\n"
++ "Please file bug report to %s.\n", DRV_PROJECT);
++ return -EINVAL;
++ }
++
++ INFO(rt2x00dev, "Loading EEPROM data from '%s'.\n", ee_name);
++
++ retval = request_firmware(&ee, ee_name, rt2x00dev->dev);
++ if (retval) {
++ ERROR(rt2x00dev, "Failed to request EEPROM.\n");
++ return retval;
++ }
++
++ if (!ee || !ee->size || !ee->data) {
++ ERROR(rt2x00dev, "Failed to read EEPROM file.\n");
++ retval = -ENOENT;
++ goto err_exit;
++ }
++
++ if (ee->size != rt2x00dev->ops->eeprom_size) {
++ ERROR(rt2x00dev,
++ "EEPROM file size is invalid, it should be %d bytes\n",
++ rt2x00dev->ops->eeprom_size);
++ retval = -EINVAL;
++ goto err_release_ee;
++ }
++
++ rt2x00dev->eeprom_file = ee;
++ return 0;
++
++err_release_ee:
++ release_firmware(ee);
++err_exit:
++ return retval;
++}
++
++int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++ int retval;
++
++ if (!test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags))
++ return 0;
++
++ if (!rt2x00dev->eeprom_file) {
++ retval = rt2x00lib_request_eeprom_file(rt2x00dev);
++ if (retval)
++ return retval;
++ }
++
++ return 0;
++}
++
++void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++ release_firmware(rt2x00dev->eeprom_file);
++ rt2x00dev->eeprom_file = NULL;
++}
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -560,6 +560,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.
+@@ -721,6 +722,7 @@ enum rt2x00_capability_flags {
+ REQUIRE_SW_SEQNO,
+ REQUIRE_HT_TX_DESC,
+ REQUIRE_PS_AUTOWAKE,
++ REQUIRE_EEPROM_FILE,
+
+ /*
+ * Capabilities
+@@ -976,6 +978,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
+ #endif /* CONFIG_RT2X00_LIB_FIRMWARE */
+
+ /*
++ * EEPROM file handlers.
++ */
++#ifdef CONFIG_RT2X00_LIB_EEPROM
++int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev);
++void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev);
++#else
++static inline int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++ return 0;
++}
++static inline void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++}
++#endif /* CONFIG_RT2X00_LIB_EEPROM_FILE */
++
++/*
+ * Debugfs handlers.
+ */
+ #ifdef CONFIG_RT2X00_LIB_DEBUGFS
+--- a/drivers/net/wireless/rt2x00/Kconfig
++++ b/drivers/net/wireless/rt2x00/Kconfig
+@@ -60,6 +60,7 @@ config RT2800PCI
+ select RT2X00_LIB_PCI if PCI
+ select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X
+ select RT2X00_LIB_FIRMWARE
++ select RT2X00_LIB_EEPROM
+ select RT2X00_LIB_CRYPTO
+ select CRC_CCITT
+ select EEPROM_93CX6
+@@ -212,6 +213,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-$(CONFIG_RT2X00_LIB_DEBUGFS) +
+ rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
+ rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
+ rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
++rt2x00lib-$(CONFIG_RT2X00_LIB_EEPROM) += rt2x00eeprom.o
+
+ obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
+ obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
+--- a/drivers/net/wireless/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/rt2x00/rt2800pci.c
+@@ -89,20 +89,10 @@ static void rt2800pci_mcu_status(struct
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+ }
+
+-#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
+ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+ {
+- void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
+-
+- memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
+-
+- iounmap(base_addr);
++ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, EEPROM_SIZE);
+ }
+-#else
+-static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+-{
+-}
+-#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
+
+ #ifdef CONFIG_PCI
+ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+@@ -322,6 +312,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)
+@@ -1033,6 +1037,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 = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .get_entry_state = rt2800pci_get_entry_state,
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -1163,6 +1163,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
+
+ rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
++ retval = rt2x00lib_load_eeprom_file(rt2x00dev);
++ if (retval)
++ goto exit;
++
+ /*
+ * Initialize work.
+ */
+@@ -1287,6 +1291,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
+ rt2x00dev->hw = hw;
+ rt2x00dev->irq = platform_get_irq(pdev, 0);
+ rt2x00dev->name = pdev->dev.driver->name;
++ set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags);
+
+ rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
+
diff --git a/package/mac80211/patches/604-rt2x00-add-CONFIG_RT2X00_LIB_EEPROM-option.patch b/package/mac80211/patches/604-rt2x00-add-CONFIG_RT2X00_LIB_EEPROM-option.patch
new file mode 100644
index 000000000..5331b2678
--- /dev/null
+++ b/package/mac80211/patches/604-rt2x00-add-CONFIG_RT2X00_LIB_EEPROM-option.patch
@@ -0,0 +1,10 @@
+--- a/config.mk
++++ b/config.mk
+@@ -624,6 +624,7 @@ export CONFIG_RT2X00=y
+ export CONFIG_RT2X00_LIB=m
+ export CONFIG_RT2800_LIB=m
+ export CONFIG_RT2X00_LIB_FIRMWARE=y
++export CONFIG_RT2X00_LIB_EEPROM=y
+ export CONFIG_RT2X00_LIB_CRYPTO=y
+ # export CONFIG_RT2X00_LIB_SOC=y
+ ifdef CONFIG_COMPAT_KERNEL_2_6_25
diff --git a/package/mac80211/patches/605-rt2x00-pci-eeprom.patch b/package/mac80211/patches/605-rt2x00-pci-eeprom.patch
new file mode 100644
index 000000000..fbc86199a
--- /dev/null
+++ b/package/mac80211/patches/605-rt2x00-pci-eeprom.patch
@@ -0,0 +1,46 @@
+--- a/drivers/net/wireless/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/rt2x00/rt2800pci.c
+@@ -89,7 +89,7 @@ static void rt2800pci_mcu_status(struct
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+ }
+
+-static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
++static void rt2800pci_read_eeprom_file(struct rt2x00_dev *rt2x00dev)
+ {
+ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, EEPROM_SIZE);
+ }
+@@ -976,8 +976,9 @@ static irqreturn_t rt2800pci_interrupt(i
+ */
+ static void rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
+ {
+- if (rt2x00_is_soc(rt2x00dev))
+- rt2800pci_read_eeprom_soc(rt2x00dev);
++ if (rt2x00_is_soc(rt2x00dev) ||
++ test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags))
++ rt2800pci_read_eeprom_file(rt2x00dev);
+ else if (rt2800pci_efuse_detect(rt2x00dev))
+ rt2800pci_read_eeprom_efuse(rt2x00dev);
+ else
+--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
++++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
+@@ -255,6 +255,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;
+@@ -300,6 +301,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
diff --git a/package/mac80211/patches/606-rt2x00_no_realign.patch b/package/mac80211/patches/606-rt2x00_no_realign.patch
new file mode 100644
index 000000000..e0a920a58
--- /dev/null
+++ b/package/mac80211/patches/606-rt2x00_no_realign.patch
@@ -0,0 +1,67 @@
+[RFC] rt2x00: For drivers that only need L2 padding don't realign frames
+
+Signed-off-by: Helmut Schaa <helmut.schaa@...>
+---
+
+Ivo, Gertjan, do you remeber by any chance why this alignment stuff was added
+in the first place? Was it because of DMA restrictions?
+
+While doing some profiling on the rt3052 SoC I noticed that 30-40% time was
+spent in memmove calls. And the culprit is the memmove aligning the payload
+to a 4byte boundary since that has to move a whole bunch of data.
+
+Interesstingly the legacy drivers insert an l2pad between the header and the
+payload but doesn't realign the payload itself to a 4-byte boundary. Hence,
+I came up with this patch and indeed CPU usage improves impressively.
+
+Only tested on rt2800pci!
+
+Thanks,
+Helmut
+
+ drivers/net/wireless/rt2x00/rt2x00queue.c | 30 +++-------------------------
+ 1 files changed, 4 insertions(+), 26 deletions(-)
+
+--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
+@@ -151,36 +151,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;
+- unsigned int header_align = ALIGN_SIZE(skb, 0);
+- unsigned int payload_align = ALIGN_SIZE(skb, header_length);
+ unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
+
+- /*
+- * Adjust the header alignment if the payload needs to be moved more
+- * than the header.
+- */
+- if (payload_align > header_align)
+- header_align += 4;
+-
+- /* There is nothing to do if no alignment is needed */
+- if (!header_align)
++ if (!l2pad)
+ return;
+
+- /* Reserve the amount of space needed in front of the frame */
+- skb_push(skb, header_align);
+-
+- /*
+- * Move the header.
+- */
+- memmove(skb->data, skb->data + header_align, header_length);
+-
+- /* Move the payload, if present and if required */
+- if (payload_length && payload_align)
+- memmove(skb->data + header_length + l2pad,
+- skb->data + header_length + l2pad + payload_align,
+- payload_length);
+-
+- /* Trim the skb to the correct size */
++ /* insert l2pad -> Move header */
++ skb_push(skb, l2pad);
++ memmove(skb->data, skb->data + l2pad, header_length);
+ skb_trim(skb, header_length + l2pad + payload_length);
+ }
+
diff --git a/package/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch b/package/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch
new file mode 100644
index 000000000..57abb07ab
--- /dev/null
+++ b/package/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch
@@ -0,0 +1,47 @@
+--- a/include/linux/rt2x00_platform.h
++++ b/include/linux/rt2x00_platform.h
+@@ -14,6 +14,9 @@
+
+ struct rt2x00_platform_data {
+ char *eeprom_file_name;
++
++ int disable_2ghz;
++ int disable_5ghz;
+ };
+
+ #endif /* _RT2X00_PLATFORM_H */
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -834,6 +834,22 @@ static int rt2x00lib_probe_hw_modes(stru
+ unsigned int num_rates;
+ unsigned int i;
+
++ if (rt2x00dev->dev->platform_data) {
++ struct rt2x00_platform_data *pdata;
++
++ pdata = rt2x00dev->dev->platform_data;
++ if (pdata->disable_2ghz)
++ spec->supported_bands &= ~SUPPORT_BAND_2GHZ;
++ if (pdata->disable_5ghz)
++ spec->supported_bands &= ~SUPPORT_BAND_5GHZ;
++ }
++
++ if ((spec->supported_bands & SUPPORT_BAND_BOTH) == 0) {
++ ERROR(rt2x00dev, "No supported bands\n");
++ return -EINVAL;
++ }
++
++
+ num_rates = 0;
+ if (spec->supported_rates & SUPPORT_RATE_CCK)
+ num_rates += 4;
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -425,6 +425,7 @@ struct hw_mode_spec {
+ unsigned int supported_bands;
+ #define SUPPORT_BAND_2GHZ 0x00000001
+ #define SUPPORT_BAND_5GHZ 0x00000002
++#define SUPPORT_BAND_BOTH (SUPPORT_BAND_2GHZ | SUPPORT_BAND_5GHZ)
+
+ unsigned int supported_rates;
+ #define SUPPORT_RATE_CCK 0x00000001
diff --git a/package/mac80211/patches/608-add_platform_data_mac_addr.patch b/package/mac80211/patches/608-add_platform_data_mac_addr.patch
new file mode 100644
index 000000000..c1b22e7a2
--- /dev/null
+++ b/package/mac80211/patches/608-add_platform_data_mac_addr.patch
@@ -0,0 +1,63 @@
+--- a/include/linux/rt2x00_platform.h
++++ b/include/linux/rt2x00_platform.h
+@@ -14,6 +14,7 @@
+
+ struct rt2x00_platform_data {
+ char *eeprom_file_name;
++ const u8 *mac_address;
+
+ int disable_2ghz;
+ int disable_5ghz;
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -825,6 +825,18 @@ static void rt2x00lib_rate(struct ieee80
+ entry->flags |= IEEE80211_RATE_SHORT_PREAMBLE;
+ }
+
++const u8 *rt2x00lib_get_mac_address(struct rt2x00_dev *rt2x00dev)
++{
++ struct rt2x00_platform_data *pdata;
++
++ pdata = rt2x00dev->dev->platform_data;
++ if (!pdata)
++ return NULL;
++
++ return pdata->mac_address;
++}
++EXPORT_SYMBOL_GPL(rt2x00lib_get_mac_address);
++
+ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
+ struct hw_mode_spec *spec)
+ {
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -1280,6 +1280,7 @@ static inline void rt2x00debug_dump_fram
+ */
+ u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif);
++const u8 *rt2x00lib_get_mac_address(struct rt2x00_dev *rt2x00dev);
+
+ /*
+ * Interrupt context handlers.
+--- a/drivers/net/wireless/rt2x00/rt61pci.c
++++ b/drivers/net/wireless/rt2x00/rt61pci.c
+@@ -2392,6 +2392,7 @@ static int rt61pci_validate_eeprom(struc
+ u32 reg;
+ u16 word;
+ u8 *mac;
++ const u8 *pdata_mac;
+ s8 value;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+@@ -2412,7 +2413,11 @@ static int rt61pci_validate_eeprom(struc
+ /*
+ * Start validation of the data that has been read.
+ */
++ pdata_mac = rt2x00lib_get_mac_address(rt2x00dev);
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
++ if (pdata_mac)
++ memcpy(mac, pdata_mac, 6);
++
+ if (!is_valid_ether_addr(mac)) {
+ eth_random_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
diff --git a/package/mac80211/patches/620-rt2x00-support-rt3352.patch b/package/mac80211/patches/620-rt2x00-support-rt3352.patch
new file mode 100644
index 000000000..bb2086daa
--- /dev/null
+++ b/package/mac80211/patches/620-rt2x00-support-rt3352.patch
@@ -0,0 +1,464 @@
+From 03839951515b0ea2b21d649b1fe7b63f9817d0c8 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <dgolle@allnet.de>
+Date: Sun, 9 Sep 2012 14:24:39 +0300
+Subject: [PATCH] rt2x00: add MediaTek/RaLink Rt3352 WiSoC
+
+Support for the RT3352 WiSoC was developed for and tested with the ALL5002
+devboard running OpenWrt. For now, this supports only devices with internal
+TXALC. Corrections were made according to the remarks of Stanislaw Gruszka and
+Gertjan van Wingerde, thank you guys for reviewing!
+
+Signed-off-by: Daniel Golle <dgolle@allnet.de>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/rt2x00/rt2800.h | 5 +
+ drivers/net/wireless/rt2x00/rt2800lib.c | 211 +++++++++++++++++++++++++++++++-
+ drivers/net/wireless/rt2x00/rt2x00.h | 1 +
+ 3 files changed, 212 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
+index e13916f..6d67c3e 100644
+--- a/drivers/net/wireless/rt2x00/rt2800.h
++++ b/drivers/net/wireless/rt2x00/rt2800.h
+@@ -1943,6 +1943,11 @@ struct mac_iveiv_entry {
+ #define BBP47_TSSI_ADC6 FIELD8(0x80)
+
+ /*
++ * BBP 49
++ */
++#define BBP49_UPDATE_FLAG FIELD8(0x01)
++
++/*
+ * BBP 109
+ */
+ #define BBP109_TX0_POWER FIELD8(0x0f)
+diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
+index a04e222..9e09367 100644
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -1615,6 +1615,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
+ case 1:
+ if (rt2x00_rt(rt2x00dev, RT3070) ||
+ rt2x00_rt(rt2x00dev, RT3090) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT3390)) {
+ rt2x00_eeprom_read(rt2x00dev,
+ EEPROM_NIC_CONF1, &eeprom);
+@@ -2053,6 +2054,60 @@ static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev,
+ }
+ }
+
++static void rt2800_config_channel_rf3322(struct rt2x00_dev *rt2x00dev,
++ struct ieee80211_conf *conf,
++ struct rf_channel *rf,
++ struct channel_info *info)
++{
++ u8 rfcsr;
++
++ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
++ rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
++
++ rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
++ rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
++ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
++
++ if (info->default_power1 > POWER_BOUND)
++ rt2800_rfcsr_write(rt2x00dev, 47, POWER_BOUND);
++ else
++ rt2800_rfcsr_write(rt2x00dev, 47, info->default_power1);
++
++ if (info->default_power2 > POWER_BOUND)
++ rt2800_rfcsr_write(rt2x00dev, 48, POWER_BOUND);
++ else
++ rt2800_rfcsr_write(rt2x00dev, 48, info->default_power2);
++
++ rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
++ if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND)
++ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND);
++ else
++ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
++
++ rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
++
++ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
++ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
++ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
++
++ if ( rt2x00dev->default_ant.tx_chain_num == 2 )
++ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
++ else
++ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
++
++ if ( rt2x00dev->default_ant.rx_chain_num == 2 )
++ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
++ else
++ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
++
++ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
++ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
++
++ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
++
++ rt2800_rfcsr_write(rt2x00dev, 31, 80);
++}
++
+ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+@@ -2182,6 +2237,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
+ case RF3290:
+ rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info);
+ break;
++ case RF3322:
++ rt2800_config_channel_rf3322(rt2x00dev, conf, rf, info);
++ break;
+ case RF5360:
+ case RF5370:
+ case RF5372:
+@@ -2194,6 +2252,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
+ }
+
+ if (rt2x00_rf(rt2x00dev, RF3290) ||
++ rt2x00_rf(rt2x00dev, RF3322) ||
+ rt2x00_rf(rt2x00dev, RF5360) ||
+ rt2x00_rf(rt2x00dev, RF5370) ||
+ rt2x00_rf(rt2x00dev, RF5372) ||
+@@ -2212,10 +2271,17 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
+ /*
+ * Change BBP settings
+ */
+- 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, 86, 0);
++ if (rt2x00_rt(rt2x00dev, RT3352)) {
++ rt2800_bbp_write(rt2x00dev, 27, 0x0);
++ rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
++ rt2800_bbp_write(rt2x00dev, 27, 0x20);
++ rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
++ } else {
++ 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, 86, 0);
++ }
+
+ if (rf->channel <= 14) {
+ if (!rt2x00_rt(rt2x00dev, RT5390) &&
+@@ -2310,6 +2376,15 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
++
++ /*
++ * Clear update flag
++ */
++ if (rt2x00_rt(rt2x00dev, RT3352)) {
++ rt2800_bbp_read(rt2x00dev, 49, &bbp);
++ rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0);
++ rt2800_bbp_write(rt2x00dev, 49, bbp);
++ }
+ }
+
+ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
+@@ -2998,6 +3073,10 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030);
++ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402);
++ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
++ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+ } else if (rt2x00_rt(rt2x00dev, RT3572)) {
+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+@@ -3378,6 +3457,11 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2800_wait_bbp_ready(rt2x00dev)))
+ return -EACCES;
+
++ if (rt2x00_rt(rt2x00dev, RT3352)) {
++ rt2800_bbp_write(rt2x00dev, 3, 0x00);
++ rt2800_bbp_write(rt2x00dev, 4, 0x50);
++ }
++
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392)) {
+@@ -3388,15 +3472,20 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+
+ if (rt2800_is_305x_soc(rt2x00dev) ||
+ rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT3572) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
+
++ if (rt2x00_rt(rt2x00dev, RT3352))
++ rt2800_bbp_write(rt2x00dev, 47, 0x48);
++
+ rt2800_bbp_write(rt2x00dev, 65, 0x2c);
+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
+
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 68, 0x0b);
+@@ -3405,6 +3494,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2800_bbp_write(rt2x00dev, 69, 0x16);
+ rt2800_bbp_write(rt2x00dev, 73, 0x12);
+ } else if (rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392)) {
+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
+@@ -3436,6 +3526,10 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ } else if (rt2800_is_305x_soc(rt2x00dev)) {
+ rt2800_bbp_write(rt2x00dev, 78, 0x0e);
+ rt2800_bbp_write(rt2x00dev, 80, 0x08);
++ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
++ rt2800_bbp_write(rt2x00dev, 78, 0x0e);
++ rt2800_bbp_write(rt2x00dev, 80, 0x08);
++ rt2800_bbp_write(rt2x00dev, 81, 0x37);
+ } else {
+ rt2800_bbp_write(rt2x00dev, 81, 0x37);
+ }
+@@ -3465,18 +3559,21 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
+
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
+ else
+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
+
+- if (rt2x00_rt(rt2x00dev, RT5392))
++ if (rt2x00_rt(rt2x00dev, RT3352) ||
++ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 88, 0x90);
+
+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
+
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 92, 0x02);
+@@ -3493,6 +3590,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
+ rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
+ rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT3572) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392) ||
+@@ -3502,6 +3600,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2800_bbp_write(rt2x00dev, 103, 0x00);
+
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 104, 0x92);
+@@ -3510,6 +3609,8 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2800_bbp_write(rt2x00dev, 105, 0x01);
+ else if (rt2x00_rt(rt2x00dev, RT3290))
+ rt2800_bbp_write(rt2x00dev, 105, 0x1c);
++ else if (rt2x00_rt(rt2x00dev, RT3352))
++ rt2800_bbp_write(rt2x00dev, 105, 0x34);
+ else if (rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 105, 0x3c);
+@@ -3519,11 +3620,16 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
+ rt2x00_rt(rt2x00dev, RT5390))
+ rt2800_bbp_write(rt2x00dev, 106, 0x03);
++ else if (rt2x00_rt(rt2x00dev, RT3352))
++ rt2800_bbp_write(rt2x00dev, 106, 0x05);
+ else if (rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp_write(rt2x00dev, 106, 0x12);
+ else
+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
+
++ if (rt2x00_rt(rt2x00dev, RT3352))
++ rt2800_bbp_write(rt2x00dev, 120, 0x50);
++
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+@@ -3534,6 +3640,9 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2800_bbp_write(rt2x00dev, 135, 0xf6);
+ }
+
++ if (rt2x00_rt(rt2x00dev, RT3352))
++ rt2800_bbp_write(rt2x00dev, 137, 0x0f);
++
+ if (rt2x00_rt(rt2x00dev, RT3071) ||
+ rt2x00_rt(rt2x00dev, RT3090) ||
+ rt2x00_rt(rt2x00dev, RT3390) ||
+@@ -3574,6 +3683,28 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+ rt2800_bbp_write(rt2x00dev, 3, value);
+ }
+
++ if (rt2x00_rt(rt2x00dev, RT3352)) {
++ rt2800_bbp_write(rt2x00dev, 163, 0xbd);
++ /* Set ITxBF timeout to 0x9c40=1000msec */
++ rt2800_bbp_write(rt2x00dev, 179, 0x02);
++ rt2800_bbp_write(rt2x00dev, 180, 0x00);
++ rt2800_bbp_write(rt2x00dev, 182, 0x40);
++ rt2800_bbp_write(rt2x00dev, 180, 0x01);
++ rt2800_bbp_write(rt2x00dev, 182, 0x9c);
++ rt2800_bbp_write(rt2x00dev, 179, 0x00);
++ /* Reprogram the inband interface to put right values in RXWI */
++ rt2800_bbp_write(rt2x00dev, 142, 0x04);
++ rt2800_bbp_write(rt2x00dev, 143, 0x3b);
++ rt2800_bbp_write(rt2x00dev, 142, 0x06);
++ rt2800_bbp_write(rt2x00dev, 143, 0xa0);
++ rt2800_bbp_write(rt2x00dev, 142, 0x07);
++ rt2800_bbp_write(rt2x00dev, 143, 0xa1);
++ rt2800_bbp_write(rt2x00dev, 142, 0x08);
++ rt2800_bbp_write(rt2x00dev, 143, 0xa2);
++
++ rt2800_bbp_write(rt2x00dev, 148, 0xc8);
++ }
++
+ if (rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392)) {
+ int ant, div_mode;
+@@ -3707,6 +3838,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+ !rt2x00_rt(rt2x00dev, RT3071) &&
+ !rt2x00_rt(rt2x00dev, RT3090) &&
+ !rt2x00_rt(rt2x00dev, RT3290) &&
++ !rt2x00_rt(rt2x00dev, RT3352) &&
+ !rt2x00_rt(rt2x00dev, RT3390) &&
+ !rt2x00_rt(rt2x00dev, RT3572) &&
+ !rt2x00_rt(rt2x00dev, RT5390) &&
+@@ -3903,6 +4035,70 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+ return 0;
++ } else if (rt2x00_rt(rt2x00dev, RT3352)) {
++ rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
++ rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
++ rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
++ rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
++ rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
++ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
++ rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
++ rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
++ rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
++ rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
++ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
++ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
++ rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
++ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
++ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
++ rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
++ rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
++ rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
++ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
++ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
++ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
++ rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
++ rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
++ rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
++ rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
++ rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
++ rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
++ rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
++ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
++ rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
++ rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
++ rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
++ rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
++ rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
++ rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
++ rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
++ rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
++ rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
++ rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
++ rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
++ rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
++ rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
++ rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
++ rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+ } else if (rt2x00_rt(rt2x00dev, RT5390)) {
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+@@ -4104,6 +4300,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+ rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
+ } else if (rt2x00_rt(rt2x00dev, RT3071) ||
+ rt2x00_rt(rt2x00dev, RT3090) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT3390) ||
+ rt2x00_rt(rt2x00dev, RT3572)) {
+ drv_data->calibration_bw20 =
+@@ -4566,6 +4763,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
+ case RT3071:
+ case RT3090:
+ case RT3290:
++ case RT3352:
+ case RT3390:
+ case RT3572:
+ case RT5390:
+@@ -4588,6 +4786,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
+ case RF3052:
+ case RF3290:
+ case RF3320:
++ case RF3322:
+ case RF5360:
+ case RF5370:
+ case RF5372:
+@@ -4612,6 +4811,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
+
+ if (rt2x00_rt(rt2x00dev, RT3070) ||
+ rt2x00_rt(rt2x00dev, RT3090) ||
++ rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT3390)) {
+ value = rt2x00_get_field16(eeprom,
+ EEPROM_NIC_CONF1_ANT_DIVERSITY);
+@@ -4904,6 +5104,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+ 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) ||
+diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
+index f991e8b..49375c8 100644
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -188,6 +188,7 @@ struct rt2x00_chip {
+ #define RT3071 0x3071
+ #define RT3090 0x3090 /* 2.4GHz PCIe */
+ #define RT3290 0x3290
++#define RT3352 0x3352 /* WSOC */
+ #define RT3390 0x3390
+ #define RT3572 0x3572
+ #define RT3593 0x3593
+--
+1.7.12.2
+
diff --git a/package/mac80211/patches/621-rt2x00-fix-rt3352-lnagain.patch b/package/mac80211/patches/621-rt2x00-fix-rt3352-lnagain.patch
new file mode 100644
index 000000000..824c3810d
--- /dev/null
+++ b/package/mac80211/patches/621-rt2x00-fix-rt3352-lnagain.patch
@@ -0,0 +1,30 @@
+From d0ae5f33c0221339a50bd1005c569934417003a5 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <dgolle@allnet.de>
+Date: Thu, 4 Oct 2012 00:34:01 +0200
+Subject: [PATCH] rt2x00/rt3352: Fix lnagain assignment to use register 66.
+To: users@rt2x00.serialmonkey.com
+Cc: gwingerde@gmail.com
+
+---
+ drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
+index 540c94f..01dc889 100644
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -2252,9 +2252,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
+ */
+ if (rt2x00_rt(rt2x00dev, RT3352)) {
+ rt2800_bbp_write(rt2x00dev, 27, 0x0);
+- rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
++ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 27, 0x20);
+- rt2800_bbp_write(rt2x00dev, 62, 0x26 + rt2x00dev->lna_gain);
++ rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
+ } else {
+ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+--
+1.7.12.2
+
diff --git a/package/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch b/package/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch
new file mode 100644
index 000000000..7ebc4f12d
--- /dev/null
+++ b/package/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch
@@ -0,0 +1,10 @@
+--- a/drivers/net/wireless/mwl8k.c
++++ b/drivers/net/wireless/mwl8k.c
+@@ -5302,6 +5302,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) = {
++ { PCI_VDEVICE(MARVELL, 0x2a02), .driver_data = MWL8363, },
+ { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },
+ { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, },
+ { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, },
diff --git a/package/mac80211/patches/800-b43-gpio-mask-module-option.patch b/package/mac80211/patches/800-b43-gpio-mask-module-option.patch
new file mode 100644
index 000000000..55ab0aa3a
--- /dev/null
+++ b/package/mac80211/patches/800-b43-gpio-mask-module-option.patch
@@ -0,0 +1,37 @@
+--- a/drivers/net/wireless/b43/b43.h
++++ b/drivers/net/wireless/b43/b43.h
+@@ -807,6 +807,7 @@ struct b43_wldev {
+ bool qos_enabled; /* TRUE, if QoS is used. */
+ bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */
+ bool use_pio; /* TRUE if next init should use PIO */
++ int gpiomask; /* GPIO LED mask as a module parameter */
+
+ /* PHY/Radio device. */
+ struct b43_phy phy;
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -76,6 +76,11 @@ MODULE_FIRMWARE("b43/ucode16_mimo.fw");
+ MODULE_FIRMWARE("b43/ucode5.fw");
+ MODULE_FIRMWARE("b43/ucode9.fw");
+
++static int modparam_gpiomask = 0x000F;
++module_param_named(gpiomask, modparam_gpiomask, int, 0444);
++MODULE_PARM_DESC(gpiomask,
++ "GPIO mask for LED control (default 0x000F)");
++
+ static int modparam_bad_frames_preempt;
+ module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+ MODULE_PARM_DESC(bad_frames_preempt,
+@@ -2688,10 +2693,10 @@ static int b43_gpio_init(struct b43_wlde
+ u32 mask, set;
+
+ b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0);
+- b43_maskset16(dev, B43_MMIO_GPIO_MASK, ~0, 0xF);
++ b43_maskset16(dev, B43_MMIO_GPIO_MASK, ~0, modparam_gpiomask);
+
+ mask = 0x0000001F;
+- set = 0x0000000F;
++ set = modparam_gpiomask;
+ if (dev->dev->chip_id == 0x4301) {
+ mask |= 0x0060;
+ set |= 0x0060;
diff --git a/package/mac80211/patches/810-b43_no_pio.patch b/package/mac80211/patches/810-b43_no_pio.patch
new file mode 100644
index 000000000..f511795b1
--- /dev/null
+++ b/package/mac80211/patches/810-b43_no_pio.patch
@@ -0,0 +1,75 @@
+--- a/drivers/net/wireless/b43/Makefile
++++ b/drivers/net/wireless/b43/Makefile
+@@ -20,7 +20,7 @@ b43-y += xmit.o
+ b43-y += lo.o
+ b43-y += wa.o
+ b43-y += dma.o
+-b43-y += pio.o
++b43-$(CONFIG_B43_PIO) += pio.o
+ b43-y += rfkill.o
+ b43-$(CONFIG_B43_LEDS) += leds.o
+ b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -1885,10 +1885,12 @@ static void b43_do_interrupt_thread(stru
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
++#ifdef CONFIG_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! */
+ dev->use_pio = true;
++#endif
+ b43_controller_restart(dev, "DMA error");
+ return;
+ }
+--- a/drivers/net/wireless/b43/pio.h
++++ b/drivers/net/wireless/b43/pio.h
+@@ -150,7 +150,7 @@ static inline void b43_piorx_write32(str
+ b43_write32(q->dev, q->mmio_base + offset, value);
+ }
+
+-
++#ifdef CONFIG_B43_PIO
+ int b43_pio_init(struct b43_wldev *dev);
+ void b43_pio_free(struct b43_wldev *dev);
+
+@@ -161,5 +161,37 @@ void b43_pio_rx(struct b43_pio_rxqueue *
+
+ void b43_pio_tx_suspend(struct b43_wldev *dev);
+ void b43_pio_tx_resume(struct b43_wldev *dev);
++#else
++static inline int b43_pio_init(struct b43_wldev *dev)
++{
++ return 0;
++}
++
++static inline void b43_pio_free(struct b43_wldev *dev)
++{
++}
++
++static inline int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
++{
++ return 0;
++}
++
++static inline void b43_pio_handle_txstatus(struct b43_wldev *dev,
++ const struct b43_txstatus *status)
++{
++}
++
++static inline void b43_pio_rx(struct b43_pio_rxqueue *q)
++{
++}
++
++static inline void b43_pio_tx_suspend(struct b43_wldev *dev)
++{
++}
++
++static inline void b43_pio_tx_resume(struct b43_wldev *dev)
++{
++}
++#endif /* CONFIG_B43_PIO */
+
+ #endif /* B43_PIO_H_ */
diff --git a/package/mac80211/patches/820-b43-add-antenna-control.patch b/package/mac80211/patches/820-b43-add-antenna-control.patch
new file mode 100644
index 000000000..551213d5f
--- /dev/null
+++ b/package/mac80211/patches/820-b43-add-antenna-control.patch
@@ -0,0 +1,131 @@
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -1529,7 +1529,7 @@ static void b43_write_beacon_template(st
+ len, ram_offset, shm_size_offset, rate);
+
+ /* Write the PHY TX control parameters. */
+- antenna = B43_ANTENNA_DEFAULT;
++ antenna = dev->tx_antenna;
+ 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. */
+@@ -3049,8 +3049,8 @@ static int b43_chip_init(struct b43_wlde
+
+ /* Select the antennae */
+ if (phy->ops->set_rx_antenna)
+- phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
+- b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
++ phy->ops->set_rx_antenna(dev, dev->rx_antenna);
++ b43_mgmtframe_txantenna(dev, dev->tx_antenna);
+
+ if (phy->type == B43_PHYTYPE_B) {
+ value16 = b43_read16(dev, 0x005E);
+@@ -3794,7 +3794,6 @@ static int b43_op_config(struct ieee8021
+ struct b43_wldev *dev;
+ struct b43_phy *phy;
+ struct ieee80211_conf *conf = &hw->conf;
+- int antenna;
+ int err = 0;
+ bool reload_bss = false;
+
+@@ -3848,11 +3847,9 @@ static int b43_op_config(struct ieee8021
+ }
+
+ /* Antennas for RX and management frame TX. */
+- antenna = B43_ANTENNA_DEFAULT;
+- b43_mgmtframe_txantenna(dev, antenna);
+- antenna = B43_ANTENNA_DEFAULT;
++ b43_mgmtframe_txantenna(dev, dev->tx_antenna);
+ if (phy->ops->set_rx_antenna)
+- phy->ops->set_rx_antenna(dev, antenna);
++ phy->ops->set_rx_antenna(dev, dev->rx_antenna);
+
+ if (wl->radio_enabled != phy->radio_on) {
+ if (wl->radio_enabled) {
+@@ -4974,6 +4971,47 @@ static int b43_op_get_survey(struct ieee
+ return 0;
+ }
+
++static int b43_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
++{
++ struct b43_wl *wl = hw_to_b43_wl(hw);
++ struct b43_wldev *dev = wl->current_dev;
++
++ if (tx_ant == 1 && rx_ant == 1) {
++ dev->tx_antenna = B43_ANTENNA0;
++ dev->rx_antenna = B43_ANTENNA0;
++ }
++ else if (tx_ant == 2 && rx_ant == 2) {
++ dev->tx_antenna = B43_ANTENNA1;
++ dev->rx_antenna = B43_ANTENNA1;
++ }
++ else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3) {
++ dev->tx_antenna = B43_ANTENNA_DEFAULT;
++ dev->rx_antenna = B43_ANTENNA_DEFAULT;
++ }
++ else {
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++
++static int b43_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
++{
++ struct b43_wl *wl = hw_to_b43_wl(hw);
++ struct b43_wldev *dev = wl->current_dev;
++
++ switch (dev->tx_antenna) {
++ case B43_ANTENNA0:
++ *tx_ant = 1; *rx_ant = 1; break;
++ case B43_ANTENNA1:
++ *tx_ant = 2; *rx_ant = 2; break;
++ case B43_ANTENNA_DEFAULT:
++ *tx_ant = 3; *rx_ant = 3; break;
++ }
++ return 0;
++}
++
+ static const struct ieee80211_ops b43_hw_ops = {
+ .tx = b43_op_tx,
+ .conf_tx = b43_op_conf_tx,
+@@ -4995,6 +5033,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,
++ .set_antenna = b43_op_set_antenna,
++ .get_antenna = b43_op_get_antenna,
+ };
+
+ /* Hard-reset the chip. Do not call this directly.
+@@ -5241,6 +5281,8 @@ static int b43_one_core_attach(struct b4
+ if (!wldev)
+ goto out;
+
++ wldev->rx_antenna = B43_ANTENNA_DEFAULT;
++ wldev->tx_antenna = B43_ANTENNA_DEFAULT;
+ wldev->use_pio = b43_modparam_pio;
+ wldev->dev = dev;
+ wldev->wl = wl;
+@@ -5331,6 +5373,9 @@ static struct b43_wl *b43_wireless_init(
+
+ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
++ hw->wiphy->available_antennas_rx = 0x3;
++ hw->wiphy->available_antennas_tx = 0x3;
++
+ wl->hw_registred = false;
+ hw->max_rates = 2;
+ SET_IEEE80211_DEV(hw, dev->dev);
+--- a/drivers/net/wireless/b43/b43.h
++++ b/drivers/net/wireless/b43/b43.h
+@@ -808,6 +808,8 @@ struct b43_wldev {
+ bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */
+ bool use_pio; /* TRUE if next init should use PIO */
+ int gpiomask; /* GPIO LED mask as a module parameter */
++ int rx_antenna; /* Used RX antenna (B43_ANTENNAxxx) */
++ int tx_antenna; /* Used TX antenna (B43_ANTENNAxxx) */
+
+ /* PHY/Radio device. */
+ struct b43_phy phy;
diff --git a/package/mac80211/patches/830-b43-workaround-pcie-bcm4716.patch b/package/mac80211/patches/830-b43-workaround-pcie-bcm4716.patch
new file mode 100644
index 000000000..ce9ad7d5c
--- /dev/null
+++ b/package/mac80211/patches/830-b43-workaround-pcie-bcm4716.patch
@@ -0,0 +1,134 @@
+From 4f214b1ead0af7439921637645cb63f378516175 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 21 Jan 2012 18:48:38 +0100
+Subject: [PATCH 33/34] b43: add workaround for b43 on pcie bus of bcm4716.
+
+bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder
+transactions. As a fix, a read after write is performed on certain
+places in the code. Older chips and the newer 5357 family don't require
+this fix.
+This code is based on the brcmsmac driver.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/wireless/b43/b43.h | 26 ++++++++++++++++++++++++++
+ drivers/net/wireless/b43/bus.h | 10 ++++++++++
+ drivers/net/wireless/b43/phy_common.c | 6 ++++++
+ drivers/net/wireless/b43/phy_n.c | 10 +++++-----
+ 4 files changed, 47 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/wireless/b43/b43.h
++++ b/drivers/net/wireless/b43/b43.h
+@@ -1048,6 +1048,32 @@ static inline bool b43_using_pio_transfe
+ return dev->__using_pio_transfers;
+ }
+
++/*
++ * bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder
++ * transactions. As a fix, a read after write is performed on certain places
++ * in the code. Older chips and the newer 5357 family don't require this fix.
++ */
++#ifdef CONFIG_BCM47XX_BCMA
++#include <asm/mach-bcm47xx/bcm47xx.h>
++static inline void b43_wflush16(struct b43_wldev *dev, u16 offset, u16 value)
++{
++ 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)) {
++ b43_write16(dev, offset, value);
++ b43_read16(dev, offset);
++ } else {
++ b43_write16(dev, offset, value);
++ }
++}
++#else
++static inline void b43_wflush16(struct b43_wldev *dev, u16 offset, u16 value)
++{
++ b43_write16(dev, offset, value);
++}
++#endif
++
+ /* Message printing */
+ __printf(2, 3) void b43info(struct b43_wl *wl, const char *fmt, ...);
+ __printf(2, 3) void b43err(struct b43_wl *wl, const char *fmt, ...);
+--- a/drivers/net/wireless/b43/bus.h
++++ b/drivers/net/wireless/b43/bus.h
+@@ -60,6 +60,16 @@ static inline bool b43_bus_host_is_sdio(
+ return (dev->bus_type == B43_BUS_SSB &&
+ dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO);
+ }
++static inline bool b43_bus_host_is_pci(struct b43_bus_dev *dev)
++{
++ if (dev->bus_type == B43_BUS_SSB)
++ return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI);
++#ifdef CONFIG_B43_BCMA
++ if (dev->bus_type == B43_BUS_BCMA)
++ return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI);
++#endif
++ return false;
++}
+
+ 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/phy_common.c
++++ b/drivers/net/wireless/b43/phy_common.c
+@@ -266,6 +266,12 @@ void b43_phy_write(struct b43_wldev *dev
+ {
+ assert_mac_suspended(dev);
+ dev->phy.ops->phy_write(dev, reg, value);
++#ifdef CONFIG_BCM47XX
++ if (b43_bus_host_is_pci(dev->dev) && reg == 0x72) {
++ b43_read16(dev, B43_MMIO_PHY_VER);
++ return;
++ }
++#endif
+ 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_n.c
++++ b/drivers/net/wireless/b43/phy_n.c
+@@ -5423,14 +5423,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_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
+ }
+
+ static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+ {
+ check_phyreg(dev, reg);
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA, value);
+ }
+
+@@ -5438,7 +5438,7 @@ static void b43_nphy_op_maskset(struct b
+ u16 set)
+ {
+ check_phyreg(dev, reg);
+- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set);
+ }
+
+@@ -5449,7 +5449,7 @@ static u16 b43_nphy_op_radio_read(struct
+ /* N-PHY needs 0x100 for read access */
+ reg |= 0x100;
+
+- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+ }
+
+@@ -5458,7 +5458,7 @@ static void b43_nphy_op_radio_write(stru
+ /* Register 1 is a 32-bit register. */
+ B43_WARN_ON(reg == 1);
+
+- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
++ b43_wflush16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
+ }
+
diff --git a/package/mac80211/patches/849-brcmsmac-add-device-found-on-some-SoCs-like-the-bcm4.patch b/package/mac80211/patches/849-brcmsmac-add-device-found-on-some-SoCs-like-the-bcm4.patch
new file mode 100644
index 000000000..f70a261f0
--- /dev/null
+++ b/package/mac80211/patches/849-brcmsmac-add-device-found-on-some-SoCs-like-the-bcm4.patch
@@ -0,0 +1,39 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -94,6 +94,7 @@ MODULE_FIRMWARE("brcm/bcm43xx_hdr-0.fw")
+
+ /* recognized BCMA Core IDs */
+ static struct bcma_device_id brcms_coreid_table[] = {
++// BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -734,7 +734,7 @@ static void brcms_c_ucode_bsinit(struct
+ brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
+
+ /* do band-specific ucode IHR, SHM, and SCR inits */
+- if (D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
+ else
+@@ -2259,7 +2259,7 @@ static void brcms_ucode_download(struct
+ if (wlc_hw->ucode_loaded)
+ return;
+
+- if (D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
+ ucode->bcm43xx_16_mimosz);
+@@ -3221,7 +3221,7 @@ static void brcms_b_coreinit(struct brcm
+
+ sflags = bcma_aread32(core, BCMA_IOST);
+
+- if (D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
+ else
diff --git a/package/mac80211/patches/850-brcmsmac-add-support-for-BCM43224.patch b/package/mac80211/patches/850-brcmsmac-add-support-for-BCM43224.patch
new file mode 100644
index 000000000..b135c7d3f
--- /dev/null
+++ b/package/mac80211/patches/850-brcmsmac-add-support-for-BCM43224.patch
@@ -0,0 +1,29 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -4135,6 +4135,7 @@ void brcms_c_wme_setparams(struct brcms_
+ M_EDCF_QINFO +
+ wme_ac2fifo[aci] * M_EDCF_QLEN + i,
+ *shm_entry++);
++ printk("dummy\n");
+ }
+
+ if (suspend) {
+@@ -4537,7 +4538,8 @@ static int brcms_b_attach(struct brcms_c
+
+ /* check device id(srom, nvram etc.) to set bands */
+ if (wlc_hw->deviceid == BCM43224_D11N_ID ||
+- wlc_hw->deviceid == BCM43224_D11N_ID_VEN1)
++ wlc_hw->deviceid == BCM43224_D11N_ID_VEN1 ||
++ wlc_hw->deviceid == BCM43224_CHIP_ID)
+ /* Dualband boards */
+ wlc_hw->_nbands = 2;
+ else
+@@ -5797,7 +5799,7 @@ static bool brcms_c_chipmatch_pci(struct
+ return false;
+ }
+
+- if (device == BCM43224_D11N_ID_VEN1)
++ if (device == BCM43224_D11N_ID_VEN1 || device == BCM43224_CHIP_ID)
+ return true;
+ if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
+ return true;
diff --git a/package/mac80211/patches/851-brcmsmac-start-adding-support-for-core-rev-28.patch b/package/mac80211/patches/851-brcmsmac-start-adding-support-for-core-rev-28.patch
new file mode 100644
index 000000000..198af613c
--- /dev/null
+++ b/package/mac80211/patches/851-brcmsmac-start-adding-support-for-core-rev-28.patch
@@ -0,0 +1,75 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -97,6 +97,7 @@ static struct bcma_device_id brcms_corei
+ // BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
++// BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 28, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+ };
+ MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -734,7 +734,7 @@ static void brcms_c_ucode_bsinit(struct
+ brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
+
+ /* do band-specific ucode IHR, SHM, and SCR inits */
+- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
+ else
+@@ -2259,7 +2259,7 @@ static void brcms_ucode_download(struct
+ if (wlc_hw->ucode_loaded)
+ return;
+
+- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
+ ucode->bcm43xx_16_mimosz);
+@@ -3221,7 +3221,7 @@ static void brcms_b_coreinit(struct brcm
+
+ sflags = bcma_aread32(core, BCMA_IOST);
+
+- if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {
++ if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23) || D11REV_IS(wlc_hw->corerev, 28)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
+ else
+@@ -5818,6 +5818,8 @@ static bool brcms_c_chipmatch_soc(struct
+
+ if (chipinfo->id == BCMA_CHIP_ID_BCM4716)
+ return true;
++ if (chipinfo->id == BCMA_CHIP_ID_BCM5357)
++ return true;
+
+ pr_err("unknown chip id %04x\n", chipinfo->id);
+ return false;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -65,7 +65,7 @@
+ #define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */
+
+ /* max # supported core revisions (0 .. MAXCOREREV - 1) */
+-#define MAXCOREREV 28
++#define MAXCOREREV 29
+
+ /* Double check that unsupported cores are not enabled */
+ #if CONF_MSK(D11CONF, 0x4f) || CONF_GE(D11CONF, MAXCOREREV)
+--- a/drivers/net/wireless/brcm80211/brcmsmac/types.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/types.h
+@@ -93,11 +93,11 @@
+ #define BOARD_GPIO_13 0x2000
+
+ /* **** Core type/rev defaults **** */
+-#define D11CONF 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27
++#define D11CONF 0x1fffffb0 /* Supported D11 revs: 4, 5, 7-27
+ * also need to update wlc.h MAXCOREREV
+ */
+
+-#define NCONF 0x000001ff /* Supported nphy revs:
++#define NCONF 0x000002ff /* Supported nphy revs:
+ * 0 4321a0
+ * 1 4321a1
+ * 2 4321b0/b1/c0/c1