diff options
Diffstat (limited to 'package/kernel/mac80211/patches')
152 files changed, 12073 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/000-fix_kconfig.patch b/package/kernel/mac80211/patches/000-fix_kconfig.patch new file mode 100644 index 0000000..3987aae --- /dev/null +++ b/package/kernel/mac80211/patches/000-fix_kconfig.patch @@ -0,0 +1,14 @@ +--- a/kconf/Makefile ++++ b/kconf/Makefile +@@ -1,9 +1,9 @@ +-CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer ++CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -DKBUILD_NO_NLS + + LXDIALOG := lxdialog/checklist.o lxdialog/inputbox.o lxdialog/menubox.o lxdialog/textbox.o lxdialog/util.o lxdialog/yesno.o + + conf: conf.o zconf.tab.o +-mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags) -DLOCALE ++mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags) + mconf_LDFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ldflags $(CC)) + mconf: CFLAGS += $(mconf_CFLAGS) + diff --git a/package/kernel/mac80211/patches/001-fix_build.patch b/package/kernel/mac80211/patches/001-fix_build.patch new file mode 100644 index 0000000..402649d --- /dev/null +++ b/package/kernel/mac80211/patches/001-fix_build.patch @@ -0,0 +1,167 @@ +--- a/Makefile ++++ b/Makefile +@@ -5,7 +5,7 @@ + ifeq ($(KERNELRELEASE),) + + MAKEFLAGS += --no-print-directory +-SHELL := /bin/bash ++SHELL := /usr/bin/env bash + BACKPORT_DIR := $(shell pwd) + + KMODDIR ?= updates +@@ -19,6 +19,7 @@ KLIB_BUILD ?= $(KLIB)/build/ + KERNEL_CONFIG := $(KLIB_BUILD)/.config + KERNEL_MAKEFILE := $(KLIB_BUILD)/Makefile + CONFIG_MD5 := $(shell md5sum $(KERNEL_CONFIG) 2>/dev/null | sed 's/\s.*//') ++STAMP_KERNEL_CONFIG := .kernel_config_md5_$(CONFIG_MD5) + + export KLIB KLIB_BUILD BACKPORT_DIR KMODDIR KMODPATH_ARG + +@@ -36,7 +37,8 @@ mrproper: + @rm -f .kernel_config_md5 Kconfig.versions Kconfig.kernel + @rm -f backport-include/backport/autoconf.h + +-.DEFAULT: ++.SILENT: $(STAMP_KERNEL_CONFIG) ++$(STAMP_KERNEL_CONFIG): + @set -e ; test -f .local-symbols || ( \ + echo "/--------------" ;\ + echo "| You shouldn't run make in the backports tree, but only in" ;\ +@@ -60,57 +62,61 @@ mrproper: + echo "| (that isn't currently running.)" ;\ + echo "\\--" ;\ + false) +- @set -e ; if [ "$$(cat .kernel_config_md5 2>/dev/null)" != "$(CONFIG_MD5)" ] ;\ +- then \ +- echo -n "Generating local configuration database from kernel ..." ;\ +- grep -v -f .local-symbols $(KERNEL_CONFIG) | grep = | ( \ +- while read l ; do \ +- if [ "$${l:0:7}" != "CONFIG_" ] ; then \ +- continue ;\ +- fi ;\ +- l=$${l:7} ;\ +- n=$${l%%=*} ;\ +- v=$${l#*=} ;\ +- if [ "$$v" = "m" ] ; then \ +- echo config $$n ;\ +- echo ' tristate' ;\ +- elif [ "$$v" = "y" ] ; then \ +- echo config $$n ;\ +- echo ' bool' ;\ +- else \ +- continue ;\ +- fi ;\ +- echo " default $$v" ;\ +- echo "" ;\ +- done \ +- ) > Kconfig.kernel ;\ +- kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion | \ +- sed 's/^\(\([3-4]\|2\.6\)\.[0-9]\+\).*/\1/;t;d') ;\ +- test "$$kver" != "" || echo "Kernel version parse failed!" ;\ +- test "$$kver" != "" ;\ +- kvers="$$(seq 14 39 | sed 's/^/2.6./')" ;\ +- kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')" ;\ +- kvers="$$kvers $$(seq 0 99 | sed 's/^/4./')" ;\ +- print=0 ;\ +- for v in $$kvers ; do \ +- if [ "$$print" = "1" ] ; then \ +- echo config KERNEL_$$(echo $$v | tr . _) ;\ +- echo " def_bool y" ;\ +- fi ;\ +- if [ "$$v" = "$$kver" ] ; then print=1 ; fi ;\ +- done > Kconfig.versions ;\ +- # RHEL as well, sadly we need to grep for it ;\ +- RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | \ +- sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ +- RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | \ +- sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ +- for v in $$(seq 0 $$RHEL_MINOR) ; do \ +- echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v ;\ +- echo " def_bool y" ;\ +- done >> Kconfig.versions ;\ +- echo " done." ;\ +- fi ;\ +- echo "$(CONFIG_MD5)" > .kernel_config_md5 ++ @rm -f .kernel_config_md5_* ++ @touch $@ ++ ++Kconfig.kernel: $(STAMP_KERNEL_CONFIG) .local-symbols ++ @printf "Generating local configuration database from kernel ..." ++ @grep -v -f .local-symbols $(KERNEL_CONFIG) | grep = | ( \ ++ while read l ; do \ ++ if [ "$${l:0:7}" != "CONFIG_" ] ; then \ ++ continue ;\ ++ fi ;\ ++ l=$${l:7} ;\ ++ n=$${l%%=*} ;\ ++ v=$${l#*=} ;\ ++ if [ "$$v" = "m" ] ; then \ ++ echo config $$n ;\ ++ echo ' tristate' ;\ ++ elif [ "$$v" = "y" ] ; then \ ++ echo config $$n ;\ ++ echo ' bool' ;\ ++ else \ ++ continue ;\ ++ fi ;\ ++ echo " default $$v" ;\ ++ echo "" ;\ ++ done \ ++ ) > $@ ++ @echo " done." ++ ++Kconfig.versions: Kconfig.kernel ++ @kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion | \ ++ sed 's/^\(\([3-4]\|2\.6\)\.[0-9]\+\).*/\1/;t;d') ;\ ++ test "$$kver" != "" || echo "Kernel version parse failed!" ;\ ++ test "$$kver" != "" ;\ ++ kvers="$$(seq 14 39 | sed 's/^/2.6./')" ;\ ++ kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')" ;\ ++ kvers="$$kvers $$(seq 0 99 | sed 's/^/4./')" ;\ ++ print=0 ;\ ++ for v in $$kvers ; do \ ++ if [ "$$print" = "1" ] ; then \ ++ echo config KERNEL_$$(echo $$v | tr . _) ;\ ++ echo " def_bool y" ;\ ++ fi ;\ ++ if [ "$$v" = "$$kver" ] ; then print=1 ; fi ;\ ++ done > $@ ++ @RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | \ ++ sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ ++ RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | \ ++ sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ ++ for v in $$(seq 0 $$RHEL_MINOR) ; do \ ++ echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v ;\ ++ echo " def_bool y" ;\ ++ done >> $@ ++ ++.DEFAULT: ++ @$(MAKE) Kconfig.versions + @$(MAKE) -f Makefile.real "$@" + + .PHONY: defconfig-help +--- a/Makefile.real ++++ b/Makefile.real +@@ -59,7 +59,7 @@ defconfig-%:: + + backport-include/backport/autoconf.h: .config Kconfig.versions Kconfig.kernel + @$(MAKE) oldconfig +- @echo -n "Building backport-include/backport/autoconf.h ..." ++ @printf "Building backport-include/backport/autoconf.h ..." + @grep -f .local-symbols .config | ( \ + echo "#ifndef COMPAT_AUTOCONF_INCLUDED" ;\ + echo "#define COMPAT_AUTOCONF_INCLUDED" ;\ +@@ -80,7 +80,12 @@ backport-include/backport/autoconf.h: .c + esac ;\ + done ;\ + echo "#endif /* COMPAT_AUTOCONF_INCLUDED */" ;\ +- ) > backport-include/backport/autoconf.h ++ ) > $@.new ++ @if cmp -s $@ $@.new; then \ ++ rm -f $@.new; \ ++ else \ ++ mv $@.new $@; \ ++ fi + @echo " done." + + .PHONY: modules diff --git a/package/kernel/mac80211/patches/002-change_allconfig.patch b/package/kernel/mac80211/patches/002-change_allconfig.patch new file mode 100644 index 0000000..91ad20f --- /dev/null +++ b/package/kernel/mac80211/patches/002-change_allconfig.patch @@ -0,0 +1,44 @@ +--- a/kconf/conf.c ++++ b/kconf/conf.c +@@ -578,40 +578,12 @@ int main(int ac, char **av) + case oldconfig: + case listnewconfig: + case olddefconfig: +- conf_read(NULL); +- break; + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case randconfig: +- name = getenv("KCONFIG_ALLCONFIG"); +- if (!name) +- break; +- if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { +- if (conf_read_simple(name, S_DEF_USER)) { +- fprintf(stderr, +- _("*** Can't read seed configuration \"%s\"!\n"), +- name); +- exit(1); +- } +- break; +- } +- switch (input_mode) { +- case allnoconfig: name = "allno.config"; break; +- case allyesconfig: name = "allyes.config"; break; +- case allmodconfig: name = "allmod.config"; break; +- case alldefconfig: name = "alldef.config"; break; +- case randconfig: name = "allrandom.config"; break; +- default: break; +- } +- if (conf_read_simple(name, S_DEF_USER) && +- conf_read_simple("all.config", S_DEF_USER)) { +- fprintf(stderr, +- _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), +- name); +- exit(1); +- } ++ conf_read(NULL); + break; + default: + break; diff --git a/package/kernel/mac80211/patches/003-remove_bogus_modparams.patch b/package/kernel/mac80211/patches/003-remove_bogus_modparams.patch new file mode 100644 index 0000000..8fa465a --- /dev/null +++ b/package/kernel/mac80211/patches/003-remove_bogus_modparams.patch @@ -0,0 +1,34 @@ +--- a/compat/main.c ++++ b/compat/main.c +@@ -20,31 +20,6 @@ MODULE_LICENSE("GPL"); + #error "You need a CPTCFG_VERSION" + #endif + +-static char *backported_kernel_name = CPTCFG_KERNEL_NAME; +- +-module_param(backported_kernel_name, charp, 0400); +-MODULE_PARM_DESC(backported_kernel_name, +- "The kernel tree name that was used for this backport (" CPTCFG_KERNEL_NAME ")"); +- +-#ifdef BACKPORTS_GIT_TRACKED +-static char *backports_tracker_id = BACKPORTS_GIT_TRACKED; +-module_param(backports_tracker_id, charp, 0400); +-MODULE_PARM_DESC(backports_tracker_id, +- "The version of the tree containing this backport (" BACKPORTS_GIT_TRACKED ")"); +-#else +-static char *backported_kernel_version = CPTCFG_KERNEL_VERSION; +-static char *backports_version = CPTCFG_VERSION; +- +-module_param(backported_kernel_version, charp, 0400); +-MODULE_PARM_DESC(backported_kernel_version, +- "The kernel version that was used for this backport (" CPTCFG_KERNEL_VERSION ")"); +- +-module_param(backports_version, charp, 0400); +-MODULE_PARM_DESC(backports_version, +- "The git version of the backports tree used to generate this backport (" CPTCFG_VERSION ")"); +- +-#endif +- + void backport_dependency_symbol(void) + { + } diff --git a/package/kernel/mac80211/patches/010-disable_rfkill.patch b/package/kernel/mac80211/patches/010-disable_rfkill.patch new file mode 100644 index 0000000..c5a92d6 --- /dev/null +++ b/package/kernel/mac80211/patches/010-disable_rfkill.patch @@ -0,0 +1,13 @@ +--- a/backport-include/linux/rfkill.h ++++ b/backport-include/linux/rfkill.h +@@ -2,6 +2,10 @@ + #define __COMPAT_RFKILL_H + #include <linux/version.h> + ++#undef CONFIG_RFKILL ++#undef CONFIG_RFKILL_LEDS ++#undef CONFIG_RFKILL_MODULE ++ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + #include_next <linux/rfkill.h> + #else diff --git a/package/kernel/mac80211/patches/020-backports-do-not-add-debugfs_create_devm_seqfile-on-.patch b/package/kernel/mac80211/patches/020-backports-do-not-add-debugfs_create_devm_seqfile-on-.patch new file mode 100644 index 0000000..97f678c --- /dev/null +++ b/package/kernel/mac80211/patches/020-backports-do-not-add-debugfs_create_devm_seqfile-on-.patch @@ -0,0 +1,33 @@ +From e15e9231e7a9f81f5264d294fd3fd96a20d92516 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens <hauke@hauke-m.de> +Date: Sat, 25 Jul 2015 15:19:17 +0200 +Subject: [PATCH 3/3] backports: do not add debugfs_create_devm_seqfile() on + recent kernel versions + +An #ifdef for the kernel version was missing around the header of +debugfs_create_devm_seqfile() and the LINUX_BACKPORT() was also not +done. + +Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> +--- + backport/backport-include/linux/debugfs.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/backport-include/linux/debugfs.h ++++ b/backport-include/linux/debugfs.h +@@ -5,6 +5,8 @@ + #include <linux/device.h> + #include <generated/utsrelease.h> + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) ++#define debugfs_create_devm_seqfile LINUX_BACKPORT(debugfs_create_devm_seqfile) + #if defined(CONFIG_DEBUG_FS) + struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name, + struct dentry *parent, +@@ -20,5 +22,6 @@ static inline struct dentry *debugfs_cre + return ERR_PTR(-ENODEV); + } + #endif /* CONFIG_DEBUG_FS */ ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) */ + + #endif /* __BACKPORT_DEBUGFS_H_ */ diff --git a/package/kernel/mac80211/patches/030-rt2x00_options.patch b/package/kernel/mac80211/patches/030-rt2x00_options.patch new file mode 100644 index 0000000..35b5b5d --- /dev/null +++ b/package/kernel/mac80211/patches/030-rt2x00_options.patch @@ -0,0 +1,47 @@ +--- a/drivers/net/wireless/rt2x00/Kconfig ++++ b/drivers/net/wireless/rt2x00/Kconfig +@@ -225,36 +225,37 @@ config RT2800SOC + + + config RT2800_LIB +- tristate ++ tristate "RT2800 USB/PCI support" + depends on m + + config RT2800_LIB_MMIO +- tristate ++ tristate "RT2800 MMIO support" + depends on m + select RT2X00_LIB_MMIO + select RT2800_LIB + + config RT2X00_LIB_MMIO +- tristate ++ tristate "RT2x00 MMIO support" + depends on m + + config RT2X00_LIB_PCI +- tristate ++ tristate "RT2x00 PCI support" + depends on m + select RT2X00_LIB + + config RT2X00_LIB_SOC +- tristate ++ tristate "RT2x00 SoC support" ++ depends on SOC_RT288X || SOC_RT305X + depends on m + select RT2X00_LIB + + config RT2X00_LIB_USB +- tristate ++ tristate "RT2x00 USB support" + depends on m + select RT2X00_LIB + + config RT2X00_LIB +- tristate ++ tristate "RT2x00 support" + depends on m + select BPAUTO_AVERAGE + diff --git a/package/kernel/mac80211/patches/040-brcmutil_option.patch b/package/kernel/mac80211/patches/040-brcmutil_option.patch new file mode 100644 index 0000000..8a6cae6 --- /dev/null +++ b/package/kernel/mac80211/patches/040-brcmutil_option.patch @@ -0,0 +1,9 @@ +--- a/drivers/net/wireless/brcm80211/Kconfig ++++ b/drivers/net/wireless/brcm80211/Kconfig +@@ -1,5 +1,5 @@ + config BRCMUTIL +- tristate ++ tristate "Broadcom 802.11 driver utility functions" + depends on m + + config BRCMSMAC diff --git a/package/kernel/mac80211/patches/050-lib80211_option.patch b/package/kernel/mac80211/patches/050-lib80211_option.patch new file mode 100644 index 0000000..5fe5558 --- /dev/null +++ b/package/kernel/mac80211/patches/050-lib80211_option.patch @@ -0,0 +1,30 @@ +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -174,7 +174,7 @@ config CFG80211_WEXT_EXPORT + wext compatibility symbols to be exported. + + config LIB80211 +- tristate ++ tristate "lib80211" + depends on m + default n + help +@@ -184,15 +184,15 @@ config LIB80211 + Drivers should select this themselves if needed. + + config LIB80211_CRYPT_WEP +- tristate ++ tristate "lib80211 WEP support" + depends on m + + config LIB80211_CRYPT_CCMP +- tristate ++ tristate "lib80211 CCMP support" + depends on m + + config LIB80211_CRYPT_TKIP +- tristate ++ tristate "lib80211 TKIP support" + depends on m + + config LIB80211_DEBUG diff --git a/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch b/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch new file mode 100644 index 0000000..4fbab23 --- /dev/null +++ b/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch @@ -0,0 +1,130 @@ +--- a/.local-symbols ++++ b/.local-symbols +@@ -449,43 +449,6 @@ USB_CDC_PHONET= + USB_IPHETH= + USB_SIERRA_NET= + USB_VL600= +-SSB_POSSIBLE= +-SSB= +-SSB_SPROM= +-SSB_BLOCKIO= +-SSB_PCIHOST_POSSIBLE= +-SSB_PCIHOST= +-SSB_B43_PCI_BRIDGE= +-SSB_PCMCIAHOST_POSSIBLE= +-SSB_PCMCIAHOST= +-SSB_SDIOHOST_POSSIBLE= +-SSB_SDIOHOST= +-SSB_SILENT= +-SSB_DEBUG= +-SSB_SERIAL= +-SSB_DRIVER_PCICORE_POSSIBLE= +-SSB_DRIVER_PCICORE= +-SSB_PCICORE_HOSTMODE= +-SSB_DRIVER_MIPS= +-SSB_SFLASH= +-SSB_EMBEDDED= +-SSB_DRIVER_EXTIF= +-SSB_DRIVER_GIGE= +-SSB_DRIVER_GPIO= +-BCMA_POSSIBLE= +-BCMA= +-BCMA_BLOCKIO= +-BCMA_HOST_PCI_POSSIBLE= +-BCMA_HOST_PCI= +-BCMA_HOST_SOC= +-BCMA_DRIVER_PCI= +-BCMA_DRIVER_PCI_HOSTMODE= +-BCMA_DRIVER_MIPS= +-BCMA_SFLASH= +-BCMA_NFLASH= +-BCMA_DRIVER_GMAC_CMN= +-BCMA_DRIVER_GPIO= +-BCMA_DEBUG= + NFC= + NFC_DIGITAL= + NFC_NCI= +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -2866,7 +2866,7 @@ static struct ssb_device *b43_ssb_gpio_d + { + struct ssb_bus *bus = dev->dev->sdev->bus; + +-#ifdef CPTCFG_SSB_DRIVER_PCICORE ++#ifdef CONFIG_SSB_DRIVER_PCICORE + return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev); + #else + return bus->chipco.dev; +@@ -4903,7 +4903,7 @@ static int b43_wireless_core_init(struct + } + if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW) + hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */ +-#if defined(CPTCFG_B43_SSB) && defined(CPTCFG_SSB_DRIVER_PCICORE) ++#if defined(CPTCFG_B43_SSB) && defined(CONFIG_SSB_DRIVER_PCICORE) + if (dev->dev->bus_type == B43_BUS_SSB && + dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && + dev->dev->sdev->bus->pcicore.dev->id.revision <= 10) +--- a/drivers/net/wireless/b43legacy/main.c ++++ b/drivers/net/wireless/b43legacy/main.c +@@ -1937,7 +1937,7 @@ static int b43legacy_gpio_init(struct b4 + if (dev->dev->id.revision >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + +-#ifdef CPTCFG_SSB_DRIVER_PCICORE ++#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; + #endif + gpiodev = bus->chipco.dev ? : pcidev; +@@ -1956,7 +1956,7 @@ static void b43legacy_gpio_cleanup(struc + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + +-#ifdef CPTCFG_SSB_DRIVER_PCICORE ++#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; + #endif + gpiodev = bus->chipco.dev ? : pcidev; +--- a/drivers/net/wireless/brcm80211/brcmsmac/Makefile ++++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile +@@ -43,6 +43,6 @@ brcmsmac-y := \ + brcms_trace_events.o \ + debug.o + +-brcmsmac-$(CPTCFG_BCMA_DRIVER_GPIO) += led.o ++brcmsmac-$(CONFIG_BCMA_DRIVER_GPIO) += led.o + + obj-$(CPTCFG_BRCMSMAC) += brcmsmac.o +--- a/drivers/net/wireless/brcm80211/brcmsmac/led.h ++++ b/drivers/net/wireless/brcm80211/brcmsmac/led.h +@@ -22,7 +22,7 @@ struct brcms_led { + bool active_low; + }; + +-#ifdef CPTCFG_BCMA_DRIVER_GPIO ++#ifdef CONFIG_BCMA_DRIVER_GPIO + void brcms_led_unregister(struct brcms_info *wl); + int brcms_led_register(struct brcms_info *wl); + #else +--- a/Kconfig.sources ++++ b/Kconfig.sources +@@ -9,9 +9,6 @@ source "$BACKPORT_DIR/drivers/net/wirele + source "$BACKPORT_DIR/drivers/net/ethernet/Kconfig" + source "$BACKPORT_DIR/drivers/net/usb/Kconfig" + +-source "$BACKPORT_DIR/drivers/ssb/Kconfig" +-source "$BACKPORT_DIR/drivers/bcma/Kconfig" +- + source "$BACKPORT_DIR/net/nfc/Kconfig" + + source "$BACKPORT_DIR/drivers/media/Kconfig" +--- a/Makefile.kernel ++++ b/Makefile.kernel +@@ -38,8 +38,6 @@ obj-$(CPTCFG_MAC80211) += net/mac80211/ + obj-$(CPTCFG_WLAN) += drivers/net/wireless/ + obj-$(CPTCFG_BT) += net/bluetooth/ + obj-$(CPTCFG_BT) += drivers/bluetooth/ +-obj-$(CPTCFG_SSB) += drivers/ssb/ +-obj-$(CPTCFG_BCMA) += drivers/bcma/ + obj-$(CPTCFG_ETHERNET) += drivers/net/ethernet/ + obj-$(CPTCFG_USB_NET_RNDIS_WLAN) += drivers/net/usb/ + obj-$(CPTCFG_NFC) += net/nfc/ diff --git a/package/kernel/mac80211/patches/070-ath_common_config.patch b/package/kernel/mac80211/patches/070-ath_common_config.patch new file mode 100644 index 0000000..c6e9cd8 --- /dev/null +++ b/package/kernel/mac80211/patches/070-ath_common_config.patch @@ -0,0 +1,10 @@ +--- a/drivers/net/wireless/ath/Kconfig ++++ b/drivers/net/wireless/ath/Kconfig +@@ -6,6 +6,7 @@ menuconfig ATH_CARDS + tristate "Atheros Wireless Cards" + depends on m + depends on CFG80211 && (!UML || BROKEN) ++ select ATH_COMMON + ---help--- + This will enable the support for the Atheros wireless drivers. + ath5k, ath9k, ath9k_htc and ar9170 drivers share some common code, this option diff --git a/package/kernel/mac80211/patches/080-disable_clk_backport.patch b/package/kernel/mac80211/patches/080-disable_clk_backport.patch new file mode 100644 index 0000000..3765591 --- /dev/null +++ b/package/kernel/mac80211/patches/080-disable_clk_backport.patch @@ -0,0 +1,20 @@ +--- a/compat/compat-3.6.c ++++ b/compat/compat-3.6.c +@@ -147,17 +147,3 @@ int sg_alloc_table_from_pages(struct sg_ + return 0; + } + EXPORT_SYMBOL_GPL(sg_alloc_table_from_pages); +- +-/* whoopsie ! */ +-#ifndef CONFIG_COMMON_CLK +-int clk_enable(struct clk *clk) +-{ +- return 0; +-} +-EXPORT_SYMBOL_GPL(clk_enable); +- +-void clk_disable(struct clk *clk) +-{ +-} +-EXPORT_SYMBOL_GPL(clk_disable); +-#endif diff --git a/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch b/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch new file mode 100644 index 0000000..07dde54 --- /dev/null +++ b/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch @@ -0,0 +1,376 @@ +--- a/net/mac80211/Kconfig ++++ b/net/mac80211/Kconfig +@@ -5,8 +5,6 @@ config MAC80211 + depends on CRYPTO + depends on CRYPTO_ARC4 + depends on CRYPTO_AES +- select BPAUTO_CRYPTO_CCM +- depends on CRYPTO_GCM + depends on CRC32 + select BPAUTO_AVERAGE + ---help--- +--- a/net/mac80211/Makefile ++++ b/net/mac80211/Makefile +@@ -15,9 +15,7 @@ mac80211-y := \ + michael.o \ + tkip.o \ + aes_ccm.o \ +- aes_gcm.o \ + aes_cmac.o \ +- aes_gmac.o \ + cfg.o \ + ethtool.o \ + rx.o \ +--- a/net/mac80211/aes_ccm.c ++++ b/net/mac80211/aes_ccm.c +@@ -13,89 +13,132 @@ + #include <linux/types.h> + #include <linux/err.h> + #include <crypto/aead.h> ++#include <crypto/aes.h> + + #include <net/mac80211.h> + #include "key.h" + #include "aes_ccm.h" + +-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, +- u8 *data, size_t data_len, u8 *mic, +- size_t mic_len) ++static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0, ++ u8 *a, u8 *b) + { +- struct scatterlist sg[3]; ++ int i; ++ ++ crypto_cipher_encrypt_one(tfm, b, b_0); ++ ++ /* Extra Authenticate-only data (always two AES blocks) */ ++ for (i = 0; i < AES_BLOCK_SIZE; i++) ++ aad[i] ^= b[i]; ++ crypto_cipher_encrypt_one(tfm, b, aad); ++ ++ aad += AES_BLOCK_SIZE; ++ ++ for (i = 0; i < AES_BLOCK_SIZE; i++) ++ aad[i] ^= b[i]; ++ crypto_cipher_encrypt_one(tfm, a, aad); + +- char aead_req_data[sizeof(struct aead_request) + +- crypto_aead_reqsize(tfm)] +- __aligned(__alignof__(struct aead_request)); +- struct aead_request *aead_req = (void *) aead_req_data; ++ /* Mask out bits from auth-only-b_0 */ ++ b_0[0] &= 0x07; + +- memset(aead_req, 0, sizeof(aead_req_data)); ++ /* S_0 is used to encrypt T (= MIC) */ ++ b_0[14] = 0; ++ b_0[15] = 0; ++ crypto_cipher_encrypt_one(tfm, s_0, b_0); ++} + +- sg_init_table(sg, 3); +- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); +- sg_set_buf(&sg[1], data, data_len); +- sg_set_buf(&sg[2], mic, mic_len); + +- aead_request_set_tfm(aead_req, tfm); +- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0); +- aead_request_set_ad(aead_req, sg[0].length); ++void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, ++ u8 *data, size_t data_len, u8 *mic, ++ size_t mic_len) ++{ ++ int i, j, last_len, num_blocks; ++ u8 b[AES_BLOCK_SIZE]; ++ u8 s_0[AES_BLOCK_SIZE]; ++ u8 e[AES_BLOCK_SIZE]; ++ u8 *pos, *cpos; ++ ++ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); ++ last_len = data_len % AES_BLOCK_SIZE; ++ aes_ccm_prepare(tfm, b_0, aad, s_0, b, b); ++ ++ /* Process payload blocks */ ++ pos = data; ++ cpos = data; ++ for (j = 1; j <= num_blocks; j++) { ++ int blen = (j == num_blocks && last_len) ? ++ last_len : AES_BLOCK_SIZE; ++ ++ /* Authentication followed by encryption */ ++ for (i = 0; i < blen; i++) ++ b[i] ^= pos[i]; ++ crypto_cipher_encrypt_one(tfm, b, b); ++ ++ b_0[14] = (j >> 8) & 0xff; ++ b_0[15] = j & 0xff; ++ crypto_cipher_encrypt_one(tfm, e, b_0); ++ for (i = 0; i < blen; i++) ++ *cpos++ = *pos++ ^ e[i]; ++ } + +- crypto_aead_encrypt(aead_req); ++ for (i = 0; i < mic_len; i++) ++ mic[i] = b[i] ^ s_0[i]; + } + +-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, ++int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic, + size_t mic_len) + { +- struct scatterlist sg[3]; +- char aead_req_data[sizeof(struct aead_request) + +- crypto_aead_reqsize(tfm)] +- __aligned(__alignof__(struct aead_request)); +- struct aead_request *aead_req = (void *) aead_req_data; +- +- if (data_len == 0) +- return -EINVAL; +- +- memset(aead_req, 0, sizeof(aead_req_data)); +- +- sg_init_table(sg, 3); +- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); +- sg_set_buf(&sg[1], data, data_len); +- sg_set_buf(&sg[2], mic, mic_len); +- +- aead_request_set_tfm(aead_req, tfm); +- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0); +- aead_request_set_ad(aead_req, sg[0].length); ++ int i, j, last_len, num_blocks; ++ u8 *pos, *cpos; ++ u8 a[AES_BLOCK_SIZE]; ++ u8 b[AES_BLOCK_SIZE]; ++ u8 s_0[AES_BLOCK_SIZE]; ++ ++ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); ++ last_len = data_len % AES_BLOCK_SIZE; ++ aes_ccm_prepare(tfm, b_0, aad, s_0, a, b); ++ ++ /* Process payload blocks */ ++ cpos = data; ++ pos = data; ++ for (j = 1; j <= num_blocks; j++) { ++ int blen = (j == num_blocks && last_len) ? ++ last_len : AES_BLOCK_SIZE; ++ ++ /* Decryption followed by authentication */ ++ b_0[14] = (j >> 8) & 0xff; ++ b_0[15] = j & 0xff; ++ crypto_cipher_encrypt_one(tfm, b, b_0); ++ for (i = 0; i < blen; i++) { ++ *pos = *cpos++ ^ b[i]; ++ a[i] ^= *pos++; ++ } ++ crypto_cipher_encrypt_one(tfm, a, a); ++ } ++ ++ for (i = 0; i < mic_len; i++) { ++ if ((mic[i] ^ s_0[i]) != a[i]) ++ return -1; ++ } + +- return crypto_aead_decrypt(aead_req); ++ return 0; + } + +-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], +- size_t key_len, +- size_t mic_len) ++struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[], ++ size_t key_len, ++ size_t mic_len) + { +- struct crypto_aead *tfm; +- int err; ++ struct crypto_cipher *tfm; + +- tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return tfm; +- +- err = crypto_aead_setkey(tfm, key, key_len); +- if (err) +- goto free_aead; +- err = crypto_aead_setauthsize(tfm, mic_len); +- if (err) +- goto free_aead; ++ tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); ++ if (!IS_ERR(tfm)) ++ crypto_cipher_setkey(tfm, key, key_len); + + return tfm; +- +-free_aead: +- crypto_free_aead(tfm); +- return ERR_PTR(err); + } + +-void ieee80211_aes_key_free(struct crypto_aead *tfm) ++ ++void ieee80211_aes_key_free(struct crypto_cipher *tfm) + { +- crypto_free_aead(tfm); ++ crypto_free_cipher(tfm); + } +--- a/net/mac80211/aes_ccm.h ++++ b/net/mac80211/aes_ccm.h +@@ -12,15 +12,15 @@ + + #include <linux/crypto.h> + +-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], +- size_t key_len, +- size_t mic_len); +-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, ++struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[], ++ size_t key_len, ++ size_t mic_len); ++void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic, + size_t mic_len); +-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, ++int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic, + size_t mic_len); +-void ieee80211_aes_key_free(struct crypto_aead *tfm); ++void ieee80211_aes_key_free(struct crypto_cipher *tfm); + + #endif /* AES_CCM_H */ +--- a/net/mac80211/aes_gcm.h ++++ b/net/mac80211/aes_gcm.h +@@ -11,12 +11,28 @@ + + #include <linux/crypto.h> + +-void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, +- u8 *data, size_t data_len, u8 *mic); +-int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, +- u8 *data, size_t data_len, u8 *mic); +-struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], +- size_t key_len); +-void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm); ++static inline void ++ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, ++ u8 *data, size_t data_len, u8 *mic) ++{ ++} ++ ++static inline int ++ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, ++ u8 *data, size_t data_len, u8 *mic) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline struct crypto_aead * ++ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], size_t key_len) ++{ ++ return NULL; ++} ++ ++static inline void ++ieee80211_aes_gcm_key_free(struct crypto_aead *tfm) ++{ ++} + + #endif /* AES_GCM_H */ +--- a/net/mac80211/aes_gmac.h ++++ b/net/mac80211/aes_gmac.h +@@ -11,10 +11,22 @@ + + #include <linux/crypto.h> + +-struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[], +- size_t key_len); +-int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, +- const u8 *data, size_t data_len, u8 *mic); +-void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm); ++static inline struct crypto_aead * ++ieee80211_aes_gmac_key_setup(const u8 key[], size_t key_len) ++{ ++ return NULL; ++} ++ ++static inline int ++ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, ++ const u8 *data, size_t data_len, u8 *mic) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline void ++ieee80211_aes_gmac_key_free(struct crypto_aead *tfm) ++{ ++} + + #endif /* AES_GMAC_H */ +--- a/net/mac80211/key.h ++++ b/net/mac80211/key.h +@@ -84,7 +84,7 @@ struct ieee80211_key { + * Management frames. + */ + u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN]; +- struct crypto_aead *tfm; ++ struct crypto_cipher *tfm; + u32 replays; /* dot11RSNAStatsCCMPReplays */ + } ccmp; + struct { +--- a/net/mac80211/wpa.c ++++ b/net/mac80211/wpa.c +@@ -304,7 +304,8 @@ ieee80211_crypto_tkip_decrypt(struct iee + } + + +-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) ++static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad, ++ u16 data_len) + { + __le16 mask_fc; + int a4_included, mgmt; +@@ -334,14 +335,8 @@ static void ccmp_special_blocks(struct s + else + qos_tid = 0; + +- /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC +- * mode authentication are not allowed to collide, yet both are derived +- * from this vector b_0. We only set L := 1 here to indicate that the +- * data size can be represented in (L+1) bytes. The CCM layer will take +- * care of storing the data length in the top (L+1) bytes and setting +- * and clearing the other bits as is required to derive the two IVs. +- */ +- b_0[0] = 0x1; ++ /* First block, b_0 */ ++ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ + + /* Nonce: Nonce Flags | A2 | PN + * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) +@@ -349,6 +344,8 @@ static void ccmp_special_blocks(struct s + b_0[1] = qos_tid | (mgmt << 4); + memcpy(&b_0[2], hdr->addr2, ETH_ALEN); + memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN); ++ /* l(m) */ ++ put_unaligned_be16(data_len, &b_0[14]); + + /* AAD (extra authenticate-only data) / masked 802.11 header + * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ +@@ -460,7 +457,7 @@ static int ccmp_encrypt_skb(struct ieee8 + return 0; + + pos += IEEE80211_CCMP_HDR_LEN; +- ccmp_special_blocks(skb, pn, b_0, aad); ++ ccmp_special_blocks(skb, pn, b_0, aad, len); + ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, + skb_put(skb, mic_len), mic_len); + +@@ -531,7 +528,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee + u8 aad[2 * AES_BLOCK_SIZE]; + u8 b_0[AES_BLOCK_SIZE]; + /* hardware didn't decrypt/verify MIC */ +- ccmp_special_blocks(skb, pn, b_0, aad); ++ ccmp_special_blocks(skb, pn, b_0, aad, data_len); + + if (ieee80211_aes_ccm_decrypt( + key->u.ccmp.tfm, b_0, aad, diff --git a/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch b/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch new file mode 100644 index 0000000..cff6d89 --- /dev/null +++ b/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch @@ -0,0 +1,12 @@ +Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -886,7 +886,6 @@ static int ieee80211_stop_ap(struct wiph + sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF; + + __sta_info_flush(sdata, true); +- ieee80211_free_keys(sdata, true); + + sdata->vif.bss_conf.enable_beacon = false; + sdata->vif.bss_conf.ssid_len = 0; diff --git a/package/kernel/mac80211/patches/120-cfg80211_allow_perm_addr_change.patch b/package/kernel/mac80211/patches/120-cfg80211_allow_perm_addr_change.patch new file mode 100644 index 0000000..ffd8807 --- /dev/null +++ b/package/kernel/mac80211/patches/120-cfg80211_allow_perm_addr_change.patch @@ -0,0 +1,43 @@ +--- a/net/wireless/sysfs.c ++++ b/net/wireless/sysfs.c +@@ -24,18 +24,35 @@ static inline struct cfg80211_registered + return container_of(dev, struct cfg80211_registered_device, wiphy.dev); + } + +-#define SHOW_FMT(name, fmt, member) \ ++#define SHOW_FMT(name, fmt, member, mode) \ + static ssize_t name ## _show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ + } \ +-static DEVICE_ATTR_RO(name) ++static DEVICE_ATTR_##mode(name) + +-SHOW_FMT(index, "%d", wiphy_idx); +-SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); +-SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); ++static ssize_t macaddress_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') ++ return -EINVAL; ++ ++ memcpy(dev_to_rdev(dev)->wiphy.perm_addr, mac, ETH_ALEN); ++ ++ return strnlen(buf, len); ++} ++ ++SHOW_FMT(index, "%d", wiphy_idx, RO); ++SHOW_FMT(macaddress, "%pM", wiphy.perm_addr, RW); ++SHOW_FMT(address_mask, "%pM", wiphy.addr_mask, RO); + + static ssize_t name_show(struct device *dev, + struct device_attribute *attr, diff --git a/package/kernel/mac80211/patches/150-disable_addr_notifier.patch b/package/kernel/mac80211/patches/150-disable_addr_notifier.patch new file mode 100644 index 0000000..5fc9454 --- /dev/null +++ b/package/kernel/mac80211/patches/150-disable_addr_notifier.patch @@ -0,0 +1,67 @@ +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -287,7 +287,7 @@ void ieee80211_restart_hw(struct ieee802 + } + EXPORT_SYMBOL(ieee80211_restart_hw); + +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + static int ieee80211_ifa_changed(struct notifier_block *nb, + unsigned long data, void *arg) + { +@@ -346,7 +346,7 @@ static int ieee80211_ifa_changed(struct + } + #endif + +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + static int ieee80211_ifa6_changed(struct notifier_block *nb, + unsigned long data, void *arg) + { +@@ -1086,14 +1086,14 @@ int ieee80211_register_hw(struct ieee802 + if (result) + goto fail_pm_qos; + +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + local->ifa_notifier.notifier_call = ieee80211_ifa_changed; + result = register_inetaddr_notifier(&local->ifa_notifier); + if (result) + goto fail_ifa; + #endif + +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; + result = register_inet6addr_notifier(&local->ifa6_notifier); + if (result) +@@ -1102,13 +1102,13 @@ int ieee80211_register_hw(struct ieee802 + + return 0; + +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + fail_ifa6: +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + unregister_inetaddr_notifier(&local->ifa_notifier); + #endif + #endif +-#if defined(CONFIG_INET) || defined(CONFIG_IPV6) ++#if defined(__disabled__CONFIG_INET) || defined(__disabled__CONFIG_IPV6) + fail_ifa: + pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, + &local->network_latency_notifier); +@@ -1141,10 +1141,10 @@ void ieee80211_unregister_hw(struct ieee + + pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, + &local->network_latency_notifier); +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + unregister_inetaddr_notifier(&local->ifa_notifier); + #endif +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + unregister_inet6addr_notifier(&local->ifa6_notifier); + #endif + diff --git a/package/kernel/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch b/package/kernel/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch new file mode 100644 index 0000000..21516ff --- /dev/null +++ b/package/kernel/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 +@@ -62,8 +62,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 +@@ -869,10 +869,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) + * guess we can tweak it and see how it goes ;-) + */ + if (ah->ah_version != AR5K_AR5210) { ++#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/kernel/mac80211/patches/210-ap_scan.patch b/package/kernel/mac80211/patches/210-ap_scan.patch new file mode 100644 index 0000000..29f05c4 --- /dev/null +++ b/package/kernel/mac80211/patches/210-ap_scan.patch @@ -0,0 +1,11 @@ +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -2008,7 +2008,7 @@ static int ieee80211_scan(struct wiphy * + * the frames sent while scanning on other channel will be + * lost) + */ +- if (sdata->u.ap.beacon && ++ if (0 && sdata->u.ap.beacon && + (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || + !(req->flags & NL80211_SCAN_FLAG_AP))) + return -EOPNOTSUPP; diff --git a/package/kernel/mac80211/patches/300-ath9k-force-rx_clear-when-disabling-rx.patch b/package/kernel/mac80211/patches/300-ath9k-force-rx_clear-when-disabling-rx.patch new file mode 100644 index 0000000..bddb15a --- /dev/null +++ b/package/kernel/mac80211/patches/300-ath9k-force-rx_clear-when-disabling-rx.patch @@ -0,0 +1,31 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Sun, 7 Jun 2015 13:53:35 +0200 +Subject: [PATCH] ath9k: force rx_clear when disabling rx + +This makes stopping Rx more reliable and should reduce the frequency of +Rx related DMA stop warnings + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/wireless/ath/ath9k/mac.c ++++ b/drivers/net/wireless/ath/ath9k/mac.c +@@ -677,13 +677,15 @@ void ath9k_hw_startpcureceive(struct ath + + ath9k_ani_reset(ah, is_scanning); + +- REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); ++ REG_CLR_BIT(ah, AR_DIAG_SW, ++ AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); + } + EXPORT_SYMBOL(ath9k_hw_startpcureceive); + + void ath9k_hw_abortpcurecv(struct ath_hw *ah) + { +- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS); ++ REG_SET_BIT(ah, AR_DIAG_SW, ++ AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); + + ath9k_hw_disable_mib_counters(ah); + } diff --git a/package/kernel/mac80211/patches/301-ath9k-limit-retries-for-powersave-response-frames.patch b/package/kernel/mac80211/patches/301-ath9k-limit-retries-for-powersave-response-frames.patch new file mode 100644 index 0000000..4faac0d --- /dev/null +++ b/package/kernel/mac80211/patches/301-ath9k-limit-retries-for-powersave-response-frames.patch @@ -0,0 +1,121 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Thu, 2 Jul 2015 15:20:56 +0200 +Subject: [PATCH] ath9k: limit retries for powersave response frames + +In some cases, the channel might be busy enough that an ath9k AP's +response to PS-Poll frames might be too slow and the station has already +gone to sleep. To avoid wasting too much airtime on this, limit the +number of retries on such frames and ensure that no sample rate gets +used. + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -147,10 +147,25 @@ static void ath_send_bar(struct ath_atx_ + } + + static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, +- struct ath_buf *bf) ++ struct ath_buf *bf, bool ps) + { ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu); ++ ++ if (ps) { ++ /* Clear the first rate to avoid using a sample rate for PS frames */ ++ info->control.rates[0].idx = -1; ++ info->control.rates[0].count = 0; ++ } ++ + ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, + ARRAY_SIZE(bf->rates)); ++ if (!ps) ++ return; ++ ++ if (bf->rates[0].count > 2) ++ bf->rates[0].count = 2; ++ ++ bf->rates[1].idx = -1; + } + + static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, +@@ -1430,7 +1445,7 @@ ath_tx_form_burst(struct ath_softc *sc, + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + break; + +- ath_set_rates(tid->an->vif, tid->an->sta, bf); ++ ath_set_rates(tid->an->vif, tid->an->sta, bf, false); + } while (1); + } + +@@ -1461,7 +1476,7 @@ static bool ath_tx_sched_aggr(struct ath + return false; + } + +- ath_set_rates(tid->an->vif, tid->an->sta, bf); ++ ath_set_rates(tid->an->vif, tid->an->sta, bf, false); + if (aggr) + last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, + tid_q, &aggr_len); +@@ -1653,7 +1668,7 @@ void ath9k_release_buffered_frames(struc + + __skb_unlink(bf->bf_mpdu, tid_q); + list_add_tail(&bf->list, &bf_q); +- ath_set_rates(tid->an->vif, tid->an->sta, bf); ++ ath_set_rates(tid->an->vif, tid->an->sta, bf, true); + if (bf_isampdu(bf)) { + ath_tx_addto_baw(sc, tid, bf); + bf->bf_state.bf_type &= ~BUF_AGGR; +@@ -2318,7 +2333,7 @@ int ath_tx_start(struct ieee80211_hw *hw + struct ath_txq *txq = txctl->txq; + struct ath_atx_tid *tid = NULL; + struct ath_buf *bf; +- bool queue, skip_uapsd = false, ps_resp; ++ bool queue, ps_resp; + int q, ret; + + if (vif) +@@ -2365,13 +2380,13 @@ int ath_tx_start(struct ieee80211_hw *hw + if (!txctl->an) + txctl->an = &avp->mcast_node; + queue = true; +- skip_uapsd = true; ++ ps_resp = false; + } + + if (txctl->an && queue) + tid = ath_get_skb_tid(sc, txctl->an, skb); + +- if (!skip_uapsd && ps_resp) { ++ if (ps_resp) { + ath_txq_unlock(sc, txq); + txq = sc->tx.uapsdq; + ath_txq_lock(sc, txq); +@@ -2409,7 +2424,7 @@ int ath_tx_start(struct ieee80211_hw *hw + if (txctl->paprd) + bf->bf_state.bfs_paprd_timestamp = jiffies; + +- ath_set_rates(vif, sta, bf); ++ ath_set_rates(vif, sta, bf, ps_resp); + ath_tx_send_normal(sc, txq, tid, skb); + + out: +@@ -2448,7 +2463,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw + break; + + bf->bf_lastbf = bf; +- ath_set_rates(vif, NULL, bf); ++ ath_set_rates(vif, NULL, bf, false); + ath_buf_set_rate(sc, bf, &info, fi->framelen, false); + duration += info.rates[0].PktDuration; + if (bf_tail) +@@ -2968,7 +2983,7 @@ int ath9k_tx99_send(struct ath_softc *sc + return -EINVAL; + } + +- ath_set_rates(sc->tx99_vif, NULL, bf); ++ ath_set_rates(sc->tx99_vif, NULL, bf, false); + + ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); + ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); diff --git a/package/kernel/mac80211/patches/302-ath10k-Delay-device-access-after-cold-reset.patch b/package/kernel/mac80211/patches/302-ath10k-Delay-device-access-after-cold-reset.patch new file mode 100644 index 0000000..820aa9a --- /dev/null +++ b/package/kernel/mac80211/patches/302-ath10k-Delay-device-access-after-cold-reset.patch @@ -0,0 +1,56 @@ +From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com> +Date: Fri, 3 Jul 2015 11:45:42 +0530 +Subject: [PATCH] ath10k: Delay device access after cold reset + +It is observed that during cold reset pcie access right +after a write operation to SOC_GLOBAL_RESET_ADDRESS causes +Data Bus Error and system hard lockup. The reason +for bus error is that pcie needs some time to get +back to stable state for any transaction during cold reset. Add +delay of 20 msecs after write of SOC_GLOBAL_RESET_ADDRESS +to fix this issue. + +Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com> +--- + +--- a/drivers/net/wireless/ath/ath10k/pci.c ++++ b/drivers/net/wireless/ath/ath10k/pci.c +@@ -2761,7 +2761,6 @@ static int ath10k_pci_wait_for_target_in + + static int ath10k_pci_cold_reset(struct ath10k *ar) + { +- int i; + u32 val; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); +@@ -2777,23 +2776,18 @@ static int ath10k_pci_cold_reset(struct + val |= 1; + ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); + +- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { +- if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & +- RTC_STATE_COLD_RESET_MASK) +- break; +- msleep(1); +- } ++ /* After writing into SOC_GLOBAL_RESET to put device into ++ * reset and pulling out of reset pcie may not be stable ++ * for any immediate pcie register access and cause bus error, ++ * add delay before any pcie access request to fix this issue. ++ */ ++ msleep(20); + + /* Pull Target, including PCIe, out of RESET. */ + val &= ~1; + ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); + +- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { +- if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & +- RTC_STATE_COLD_RESET_MASK)) +- break; +- msleep(1); +- } ++ msleep(20); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); + diff --git a/package/kernel/mac80211/patches/303-ath9k-add-fast-xmit-support.patch b/package/kernel/mac80211/patches/303-ath9k-add-fast-xmit-support.patch new file mode 100644 index 0000000..139015c --- /dev/null +++ b/package/kernel/mac80211/patches/303-ath9k-add-fast-xmit-support.patch @@ -0,0 +1,17 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Mon, 11 May 2015 18:35:20 +0200 +Subject: [PATCH] ath9k: add fast-xmit support + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -826,6 +826,7 @@ static void ath9k_set_hw_capab(struct at + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, RX_INCLUDES_FCS); + ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ++ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + + if (ath9k_ps_enable) + ieee80211_hw_set(hw, SUPPORTS_PS); diff --git a/package/kernel/mac80211/patches/304-ath9k-remove-struct-ath_atx_ac.patch b/package/kernel/mac80211/patches/304-ath9k-remove-struct-ath_atx_ac.patch new file mode 100644 index 0000000..9f04276 --- /dev/null +++ b/package/kernel/mac80211/patches/304-ath9k-remove-struct-ath_atx_ac.patch @@ -0,0 +1,385 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Sat, 4 Apr 2015 18:39:06 +0200 +Subject: [PATCH] ath9k: remove struct ath_atx_ac + +struct ath_atx_ac contains a list of active TIDs belonging to one WMM AC. +This patch changes the code to track active station TIDs in the txq directly. + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -173,14 +173,6 @@ struct ath_txq { + struct sk_buff_head complete_q; + }; + +-struct ath_atx_ac { +- struct ath_txq *txq; +- struct list_head list; +- struct list_head tid_q; +- bool clear_ps_filter; +- bool sched; +-}; +- + struct ath_frame_info { + struct ath_buf *bf; + u16 framelen; +@@ -243,7 +235,7 @@ struct ath_atx_tid { + struct sk_buff_head buf_q; + struct sk_buff_head retry_q; + struct ath_node *an; +- struct ath_atx_ac *ac; ++ struct ath_txq *txq; + unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; + u16 seq_start; + u16 seq_next; +@@ -255,6 +247,7 @@ struct ath_atx_tid { + s8 bar_index; + bool sched; + bool active; ++ bool clear_ps_filter; + }; + + struct ath_node { +@@ -262,7 +255,6 @@ struct ath_node { + struct ieee80211_sta *sta; /* station struct we're part of */ + struct ieee80211_vif *vif; /* interface with which we're associated */ + struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; +- struct ath_atx_ac ac[IEEE80211_NUM_ACS]; + + u16 maxampdu; + u8 mpdudensity; +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -106,7 +106,6 @@ void ath_txq_unlock_complete(struct ath_ + static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid) + { +- struct ath_atx_ac *ac = tid->ac; + struct list_head *list; + struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv; + struct ath_chanctx *ctx = avp->chanctx; +@@ -118,15 +117,8 @@ static void ath_tx_queue_tid(struct ath_ + return; + + tid->sched = true; +- list_add_tail(&tid->list, &ac->tid_q); +- +- if (ac->sched) +- return; +- +- ac->sched = true; +- + list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; +- list_add_tail(&ac->list, list); ++ list_add_tail(&tid->list, list); + } + + static struct ath_frame_info *get_frame_info(struct sk_buff *skb) +@@ -223,7 +215,7 @@ static struct sk_buff *ath_tid_dequeue(s + static void + ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) + { +- struct ath_txq *txq = tid->ac->txq; ++ struct ath_txq *txq = tid->txq; + struct ieee80211_tx_info *tx_info; + struct sk_buff *skb, *tskb; + struct ath_buf *bf; +@@ -252,7 +244,7 @@ ath_tx_tid_change_state(struct ath_softc + + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) + { +- struct ath_txq *txq = tid->ac->txq; ++ struct ath_txq *txq = tid->txq; + struct sk_buff *skb; + struct ath_buf *bf; + struct list_head bf_head; +@@ -659,7 +651,7 @@ static void ath_tx_complete_aggr(struct + ath_tx_queue_tid(sc, txq, tid); + + if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) +- tid->ac->clear_ps_filter = true; ++ tid->clear_ps_filter = true; + } + } + +@@ -749,7 +741,7 @@ static u32 ath_lookup_rate(struct ath_so + struct ieee80211_tx_rate *rates; + u32 max_4ms_framelen, frmlen; + u16 aggr_limit, bt_aggr_limit, legacy = 0; +- int q = tid->ac->txq->mac80211_qnum; ++ int q = tid->txq->mac80211_qnum; + int i; + + skb = bf->bf_mpdu; +@@ -1486,8 +1478,8 @@ static bool ath_tx_sched_aggr(struct ath + if (list_empty(&bf_q)) + return false; + +- if (tid->ac->clear_ps_filter || tid->an->no_ps_filter) { +- tid->ac->clear_ps_filter = false; ++ if (tid->clear_ps_filter || tid->an->no_ps_filter) { ++ tid->clear_ps_filter = false; + tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + } + +@@ -1506,7 +1498,7 @@ int ath_tx_aggr_start(struct ath_softc * + + an = (struct ath_node *)sta->drv_priv; + txtid = ATH_AN_2_TID(an, tid); +- txq = txtid->ac->txq; ++ txq = txtid->txq; + + ath_txq_lock(sc, txq); + +@@ -1540,7 +1532,7 @@ void ath_tx_aggr_stop(struct ath_softc * + { + struct ath_node *an = (struct ath_node *)sta->drv_priv; + struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); +- struct ath_txq *txq = txtid->ac->txq; ++ struct ath_txq *txq = txtid->txq; + + ath_txq_lock(sc, txq); + txtid->active = false; +@@ -1553,7 +1545,6 @@ void ath_tx_aggr_sleep(struct ieee80211_ + struct ath_node *an) + { + struct ath_atx_tid *tid; +- struct ath_atx_ac *ac; + struct ath_txq *txq; + bool buffered; + int tidno; +@@ -1561,8 +1552,7 @@ void ath_tx_aggr_sleep(struct ieee80211_ + for (tidno = 0, tid = &an->tid[tidno]; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + +- ac = tid->ac; +- txq = ac->txq; ++ txq = tid->txq; + + ath_txq_lock(sc, txq); + +@@ -1576,11 +1566,6 @@ void ath_tx_aggr_sleep(struct ieee80211_ + tid->sched = false; + list_del(&tid->list); + +- if (ac->sched) { +- ac->sched = false; +- list_del(&ac->list); +- } +- + ath_txq_unlock(sc, txq); + + ieee80211_sta_set_buffered(sta, tidno, buffered); +@@ -1590,18 +1575,16 @@ void ath_tx_aggr_sleep(struct ieee80211_ + void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) + { + struct ath_atx_tid *tid; +- struct ath_atx_ac *ac; + struct ath_txq *txq; + int tidno; + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + +- ac = tid->ac; +- txq = ac->txq; ++ txq = tid->txq; + + ath_txq_lock(sc, txq); +- ac->clear_ps_filter = true; ++ tid->clear_ps_filter = true; + + if (ath_tid_has_buffered(tid)) { + ath_tx_queue_tid(sc, txq, tid); +@@ -1621,7 +1604,7 @@ void ath_tx_aggr_resume(struct ath_softc + + an = (struct ath_node *)sta->drv_priv; + tid = ATH_AN_2_TID(an, tidno); +- txq = tid->ac->txq; ++ txq = tid->txq; + + ath_txq_lock(sc, txq); + +@@ -1660,7 +1643,7 @@ void ath9k_release_buffered_frames(struc + + tid = ATH_AN_2_TID(an, i); + +- ath_txq_lock(sc, tid->ac->txq); ++ ath_txq_lock(sc, tid->txq); + while (nframes > 0) { + bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q); + if (!bf) +@@ -1684,7 +1667,7 @@ void ath9k_release_buffered_frames(struc + if (an->sta && !ath_tid_has_buffered(tid)) + ieee80211_sta_set_buffered(an->sta, i, false); + } +- ath_txq_unlock_complete(sc, tid->ac->txq); ++ ath_txq_unlock_complete(sc, tid->txq); + } + + if (list_empty(&bf_q)) +@@ -1933,9 +1916,8 @@ void ath_tx_cleanupq(struct ath_softc *s + void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) + { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); +- struct ath_atx_ac *ac, *last_ac; + struct ath_atx_tid *tid, *last_tid; +- struct list_head *ac_list; ++ struct list_head *tid_list; + bool sent = false; + + if (txq->mac80211_qnum < 0) +@@ -1945,63 +1927,46 @@ void ath_txq_schedule(struct ath_softc * + return; + + spin_lock_bh(&sc->chan_lock); +- ac_list = &sc->cur_chan->acq[txq->mac80211_qnum]; ++ tid_list = &sc->cur_chan->acq[txq->mac80211_qnum]; + +- if (list_empty(ac_list)) { ++ if (list_empty(tid_list)) { + spin_unlock_bh(&sc->chan_lock); + return; + } + + rcu_read_lock(); + +- last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); +- while (!list_empty(ac_list)) { ++ last_tid = list_entry(tid_list->prev, struct ath_atx_tid, list); ++ while (!list_empty(tid_list)) { + bool stop = false; + + if (sc->cur_chan->stopped) + break; + +- ac = list_first_entry(ac_list, struct ath_atx_ac, list); +- last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); +- list_del(&ac->list); +- ac->sched = false; +- +- while (!list_empty(&ac->tid_q)) { +- +- tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, +- list); +- list_del(&tid->list); +- tid->sched = false; +- +- if (ath_tx_sched_aggr(sc, txq, tid, &stop)) +- sent = true; +- +- /* +- * add tid to round-robin queue if more frames +- * are pending for the tid +- */ +- if (ath_tid_has_buffered(tid)) +- ath_tx_queue_tid(sc, txq, tid); ++ tid = list_first_entry(tid_list, struct ath_atx_tid, list); ++ list_del(&tid->list); ++ tid->sched = false; + +- if (stop || tid == last_tid) +- break; +- } ++ if (ath_tx_sched_aggr(sc, txq, tid, &stop)) ++ sent = true; + +- if (!list_empty(&ac->tid_q) && !ac->sched) { +- ac->sched = true; +- list_add_tail(&ac->list, ac_list); +- } ++ /* ++ * add tid to round-robin queue if more frames ++ * are pending for the tid ++ */ ++ if (ath_tid_has_buffered(tid)) ++ ath_tx_queue_tid(sc, txq, tid); + + if (stop) + break; + +- if (ac == last_ac) { ++ if (tid == last_tid) { + if (!sent) + break; + + sent = false; +- last_ac = list_entry(ac_list->prev, +- struct ath_atx_ac, list); ++ last_tid = list_entry(tid_list->prev, ++ struct ath_atx_tid, list); + } + } + +@@ -2391,10 +2356,10 @@ int ath_tx_start(struct ieee80211_hw *hw + txq = sc->tx.uapsdq; + ath_txq_lock(sc, txq); + } else if (txctl->an && queue) { +- WARN_ON(tid->ac->txq != txctl->txq); ++ WARN_ON(tid->txq != txctl->txq); + + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) +- tid->ac->clear_ps_filter = true; ++ tid->clear_ps_filter = true; + + /* + * Add this frame to software queue for scheduling later +@@ -2888,7 +2853,6 @@ int ath_tx_init(struct ath_softc *sc, in + void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) + { + struct ath_atx_tid *tid; +- struct ath_atx_ac *ac; + int tidno, acno; + + for (tidno = 0, tid = &an->tid[tidno]; +@@ -2901,24 +2865,16 @@ void ath_tx_node_init(struct ath_softc * + tid->baw_head = tid->baw_tail = 0; + tid->sched = false; + tid->active = false; ++ tid->clear_ps_filter = true; + __skb_queue_head_init(&tid->buf_q); + __skb_queue_head_init(&tid->retry_q); + acno = TID_TO_WME_AC(tidno); +- tid->ac = &an->ac[acno]; +- } +- +- for (acno = 0, ac = &an->ac[acno]; +- acno < IEEE80211_NUM_ACS; acno++, ac++) { +- ac->sched = false; +- ac->clear_ps_filter = true; +- ac->txq = sc->tx.txq_map[acno]; +- INIT_LIST_HEAD(&ac->tid_q); ++ tid->txq = sc->tx.txq_map[acno]; + } + } + + void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) + { +- struct ath_atx_ac *ac; + struct ath_atx_tid *tid; + struct ath_txq *txq; + int tidno; +@@ -2926,8 +2882,7 @@ void ath_tx_node_cleanup(struct ath_soft + for (tidno = 0, tid = &an->tid[tidno]; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + +- ac = tid->ac; +- txq = ac->txq; ++ txq = tid->txq; + + ath_txq_lock(sc, txq); + +@@ -2936,11 +2891,6 @@ void ath_tx_node_cleanup(struct ath_soft + tid->sched = false; + } + +- if (ac->sched) { +- list_del(&ac->list); +- tid->ac->sched = false; +- } +- + ath_tid_drain(sc, txq, tid); + tid->active = false; + diff --git a/package/kernel/mac80211/patches/305-ath9k-remove-the-sched-field-in-struct-ath_atx_tid.patch b/package/kernel/mac80211/patches/305-ath9k-remove-the-sched-field-in-struct-ath_atx_tid.patch new file mode 100644 index 0000000..ec860dc --- /dev/null +++ b/package/kernel/mac80211/patches/305-ath9k-remove-the-sched-field-in-struct-ath_atx_tid.patch @@ -0,0 +1,90 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Sat, 4 Apr 2015 18:42:33 +0200 +Subject: [PATCH] ath9k: remove the sched field in struct ath_atx_tid + +Use list_empty(&tid->list) instead + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -245,7 +245,6 @@ struct ath_atx_tid { + int baw_tail; /* next unused tx buffer slot */ + + s8 bar_index; +- bool sched; + bool active; + bool clear_ps_filter; + }; +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -113,12 +113,9 @@ static void ath_tx_queue_tid(struct ath_ + if (!ctx) + return; + +- if (tid->sched) +- return; +- +- tid->sched = true; + list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; +- list_add_tail(&tid->list, list); ++ if (list_empty(&tid->list)) ++ list_add_tail(&tid->list, list); + } + + static struct ath_frame_info *get_frame_info(struct sk_buff *skb) +@@ -1556,15 +1553,14 @@ void ath_tx_aggr_sleep(struct ieee80211_ + + ath_txq_lock(sc, txq); + +- if (!tid->sched) { ++ if (list_empty(&tid->list)) { + ath_txq_unlock(sc, txq); + continue; + } + + buffered = ath_tid_has_buffered(tid); + +- tid->sched = false; +- list_del(&tid->list); ++ list_del_init(&tid->list); + + ath_txq_unlock(sc, txq); + +@@ -1944,8 +1940,7 @@ void ath_txq_schedule(struct ath_softc * + break; + + tid = list_first_entry(tid_list, struct ath_atx_tid, list); +- list_del(&tid->list); +- tid->sched = false; ++ list_del_init(&tid->list); + + if (ath_tx_sched_aggr(sc, txq, tid, &stop)) + sent = true; +@@ -2863,11 +2858,11 @@ void ath_tx_node_init(struct ath_softc * + tid->seq_start = tid->seq_next = 0; + tid->baw_size = WME_MAX_BA; + tid->baw_head = tid->baw_tail = 0; +- tid->sched = false; + tid->active = false; + tid->clear_ps_filter = true; + __skb_queue_head_init(&tid->buf_q); + __skb_queue_head_init(&tid->retry_q); ++ INIT_LIST_HEAD(&tid->list); + acno = TID_TO_WME_AC(tidno); + tid->txq = sc->tx.txq_map[acno]; + } +@@ -2886,10 +2881,8 @@ void ath_tx_node_cleanup(struct ath_soft + + ath_txq_lock(sc, txq); + +- if (tid->sched) { +- list_del(&tid->list); +- tid->sched = false; +- } ++ if (!list_empty(&tid->list)) ++ list_del_init(&tid->list); + + ath_tid_drain(sc, txq, tid); + tid->active = false; diff --git a/package/kernel/mac80211/patches/306-mac80211-Deinline-rate_control_rate_init-rate_contro.patch b/package/kernel/mac80211/patches/306-mac80211-Deinline-rate_control_rate_init-rate_contro.patch new file mode 100644 index 0000000..928c93b --- /dev/null +++ b/package/kernel/mac80211/patches/306-mac80211-Deinline-rate_control_rate_init-rate_contro.patch @@ -0,0 +1,161 @@ +From: Denys Vlasenko <dvlasenk@redhat.com> +Date: Wed, 15 Jul 2015 14:56:06 +0200 +Subject: [PATCH] mac80211: Deinline rate_control_rate_init, + rate_control_rate_update + +With this .config: http://busybox.net/~vda/kernel_config, +after deinlining these functions have sizes and callsite counts +as follows: + +rate_control_rate_init: 554 bytes, 8 calls +rate_control_rate_update: 1596 bytes, 5 calls + +Total size reduction: about 11 kbytes. + +Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com> +CC: John Linville <linville@tuxdriver.com> +CC: Michal Kazior <michal.kazior@tieto.com> +CC: Johannes Berg <johannes.berg@intel.com> +Cc: linux-wireless@vger.kernel.org +Cc: netdev@vger.kernel.org +CC: linux-kernel@vger.kernel.org +--- + +--- a/net/mac80211/rate.c ++++ b/net/mac80211/rate.c +@@ -29,6 +29,65 @@ module_param(ieee80211_default_rc_algo, + MODULE_PARM_DESC(ieee80211_default_rc_algo, + "Default rate control algorithm for mac80211 to use"); + ++void rate_control_rate_init(struct sta_info *sta) ++{ ++ struct ieee80211_local *local = sta->sdata->local; ++ struct rate_control_ref *ref = sta->rate_ctrl; ++ struct ieee80211_sta *ista = &sta->sta; ++ void *priv_sta = sta->rate_ctrl_priv; ++ struct ieee80211_supported_band *sband; ++ struct ieee80211_chanctx_conf *chanctx_conf; ++ ++ ieee80211_sta_set_rx_nss(sta); ++ ++ if (!ref) ++ return; ++ ++ rcu_read_lock(); ++ ++ chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); ++ if (WARN_ON(!chanctx_conf)) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; ++ ++ spin_lock_bh(&sta->rate_ctrl_lock); ++ ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, ++ priv_sta); ++ spin_unlock_bh(&sta->rate_ctrl_lock); ++ rcu_read_unlock(); ++ set_sta_flag(sta, WLAN_STA_RATE_CONTROL); ++} ++ ++void rate_control_rate_update(struct ieee80211_local *local, ++ struct ieee80211_supported_band *sband, ++ struct sta_info *sta, u32 changed) ++{ ++ struct rate_control_ref *ref = local->rate_ctrl; ++ struct ieee80211_sta *ista = &sta->sta; ++ void *priv_sta = sta->rate_ctrl_priv; ++ struct ieee80211_chanctx_conf *chanctx_conf; ++ ++ if (ref && ref->ops->rate_update) { ++ rcu_read_lock(); ++ ++ chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); ++ if (WARN_ON(!chanctx_conf)) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ spin_lock_bh(&sta->rate_ctrl_lock); ++ ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def, ++ ista, priv_sta, changed); ++ spin_unlock_bh(&sta->rate_ctrl_lock); ++ rcu_read_unlock(); ++ } ++ drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); ++} ++ + int ieee80211_rate_control_register(const struct rate_control_ops *ops) + { + struct rate_control_alg *alg; +--- a/net/mac80211/rate.h ++++ b/net/mac80211/rate.h +@@ -71,64 +71,10 @@ rate_control_tx_status_noskb(struct ieee + spin_unlock_bh(&sta->rate_ctrl_lock); + } + +-static inline void rate_control_rate_init(struct sta_info *sta) +-{ +- struct ieee80211_local *local = sta->sdata->local; +- struct rate_control_ref *ref = sta->rate_ctrl; +- struct ieee80211_sta *ista = &sta->sta; +- void *priv_sta = sta->rate_ctrl_priv; +- struct ieee80211_supported_band *sband; +- struct ieee80211_chanctx_conf *chanctx_conf; +- +- ieee80211_sta_set_rx_nss(sta); +- +- if (!ref) +- return; +- +- rcu_read_lock(); +- +- chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); +- if (WARN_ON(!chanctx_conf)) { +- rcu_read_unlock(); +- return; +- } +- +- sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; +- +- spin_lock_bh(&sta->rate_ctrl_lock); +- ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, +- priv_sta); +- spin_unlock_bh(&sta->rate_ctrl_lock); +- rcu_read_unlock(); +- set_sta_flag(sta, WLAN_STA_RATE_CONTROL); +-} +- +-static inline void rate_control_rate_update(struct ieee80211_local *local, ++void rate_control_rate_init(struct sta_info *sta); ++void rate_control_rate_update(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, +- struct sta_info *sta, u32 changed) +-{ +- struct rate_control_ref *ref = local->rate_ctrl; +- struct ieee80211_sta *ista = &sta->sta; +- void *priv_sta = sta->rate_ctrl_priv; +- struct ieee80211_chanctx_conf *chanctx_conf; +- +- if (ref && ref->ops->rate_update) { +- rcu_read_lock(); +- +- chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); +- if (WARN_ON(!chanctx_conf)) { +- rcu_read_unlock(); +- return; +- } +- +- spin_lock_bh(&sta->rate_ctrl_lock); +- ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def, +- ista, priv_sta, changed); +- spin_unlock_bh(&sta->rate_ctrl_lock); +- rcu_read_unlock(); +- } +- drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); +-} ++ struct sta_info *sta, u32 changed); + + static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, + struct sta_info *sta, gfp_t gfp) diff --git a/package/kernel/mac80211/patches/307-mac80211-Deinline-drv_sta_state.patch b/package/kernel/mac80211/patches/307-mac80211-Deinline-drv_sta_state.patch new file mode 100644 index 0000000..474c409 --- /dev/null +++ b/package/kernel/mac80211/patches/307-mac80211-Deinline-drv_sta_state.patch @@ -0,0 +1,116 @@ +From: Denys Vlasenko <dvlasenk@redhat.com> +Date: Wed, 15 Jul 2015 14:56:05 +0200 +Subject: [PATCH] mac80211: Deinline drv_sta_state + +With this .config: http://busybox.net/~vda/kernel_config, +after deinlining the function size is 3132 bytes and there are +7 callsites. + +Total size reduction: about 20 kbytes. + +Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com> +CC: John Linville <linville@tuxdriver.com> +CC: Michal Kazior <michal.kazior@tieto.com> +Cc: Johannes Berg <johannes.berg@intel.com> +Cc: linux-wireless@vger.kernel.org +Cc: netdev@vger.kernel.org +CC: linux-kernel@vger.kernel.org +--- + create mode 100644 net/mac80211/driver-ops.c + +--- a/net/mac80211/Makefile ++++ b/net/mac80211/Makefile +@@ -3,6 +3,7 @@ obj-$(CPTCFG_MAC80211) += mac80211.o + # mac80211 objects + mac80211-y := \ + main.o status.o \ ++ driver-ops.o \ + sta_info.o \ + wep.o \ + wpa.o \ +--- /dev/null ++++ b/net/mac80211/driver-ops.c +@@ -0,0 +1,41 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <net/mac80211.h> ++#include "ieee80211_i.h" ++#include "trace.h" ++#include "driver-ops.h" ++ ++__must_check ++int drv_sta_state(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta, ++ enum ieee80211_sta_state old_state, ++ enum ieee80211_sta_state new_state) ++{ ++ int ret = 0; ++ ++ might_sleep(); ++ ++ sdata = get_bss_sdata(sdata); ++ if (!check_sdata_in_driver(sdata)) ++ return -EIO; ++ ++ trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); ++ if (local->ops->sta_state) { ++ ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, ++ old_state, new_state); ++ } else if (old_state == IEEE80211_STA_AUTH && ++ new_state == IEEE80211_STA_ASSOC) { ++ ret = drv_sta_add(local, sdata, &sta->sta); ++ if (ret == 0) ++ sta->uploaded = true; ++ } else if (old_state == IEEE80211_STA_ASSOC && ++ new_state == IEEE80211_STA_AUTH) { ++ drv_sta_remove(local, sdata, &sta->sta); ++ } ++ trace_drv_return_int(local, ret); ++ return ret; ++} +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -573,37 +573,12 @@ static inline void drv_sta_pre_rcu_remov + trace_drv_return_void(local); + } + +-static inline __must_check ++__must_check + int drv_sta_state(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + enum ieee80211_sta_state old_state, +- enum ieee80211_sta_state new_state) +-{ +- int ret = 0; +- +- might_sleep(); +- +- sdata = get_bss_sdata(sdata); +- if (!check_sdata_in_driver(sdata)) +- return -EIO; +- +- trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); +- if (local->ops->sta_state) { +- ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, +- old_state, new_state); +- } else if (old_state == IEEE80211_STA_AUTH && +- new_state == IEEE80211_STA_ASSOC) { +- ret = drv_sta_add(local, sdata, &sta->sta); +- if (ret == 0) +- sta->uploaded = true; +- } else if (old_state == IEEE80211_STA_ASSOC && +- new_state == IEEE80211_STA_AUTH) { +- drv_sta_remove(local, sdata, &sta->sta); +- } +- trace_drv_return_int(local, ret); +- return ret; +-} ++ enum ieee80211_sta_state new_state); + + static inline void drv_sta_rc_update(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, diff --git a/package/kernel/mac80211/patches/308-ath9k-Fix-NF-CCA-limits-for-AR9287-and-AR9227.patch b/package/kernel/mac80211/patches/308-ath9k-Fix-NF-CCA-limits-for-AR9287-and-AR9227.patch new file mode 100644 index 0000000..1a3a9d4 --- /dev/null +++ b/package/kernel/mac80211/patches/308-ath9k-Fix-NF-CCA-limits-for-AR9287-and-AR9227.patch @@ -0,0 +1,30 @@ +From: Martin Blumenstingl <martin.blumenstingl@googlemail.com> +Date: Wed, 22 Jul 2015 10:42:43 +0200 +Subject: [PATCH] ath9k: Fix NF CCA limits for AR9287 and AR9227 + +The FreeBSD driver [0] uses the same 2G values as for the AR9280 chips. +Using the same values in ath9k results in much better throughput for me. + +Before this patch I had a huge amount of packet loss (sometimes up to +40%) and the max transfer speed was somewhere around 5Mbit/s. With this +patch applied I have zero packet loss and ten times the throughput. +My device uses a AR9227 which is the PCI variant of the AR9287. + +[0] http://bxr.su/FreeBSD/sys/dev/ath/ath_hal/ar9002/ar9287.h + +Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> +--- + +--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h ++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h +@@ -610,8 +610,8 @@ + #define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ -127 + #define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ -116 + +-#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -120 ++#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -112 + #define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ -127 +-#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -110 ++#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -97 + + #endif diff --git a/package/kernel/mac80211/patches/309-mac80211-make-local-tx_headroom-a-multiple-of-4.patch b/package/kernel/mac80211/patches/309-mac80211-make-local-tx_headroom-a-multiple-of-4.patch new file mode 100644 index 0000000..e8e9617 --- /dev/null +++ b/package/kernel/mac80211/patches/309-mac80211-make-local-tx_headroom-a-multiple-of-4.patch @@ -0,0 +1,20 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Thu, 30 Jul 2015 14:12:25 +0200 +Subject: [PATCH] mac80211: make local->tx_headroom a multiple of 4 + +This ensures that mac80211 generated management frames and beacons are +aligned before being passed to the driver + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1031,6 +1031,7 @@ int ieee80211_register_hw(struct ieee802 + */ + local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, + IEEE80211_TX_STATUS_HEADROOM); ++ local->tx_headroom = ALIGN(local->tx_headroom, 4); + + debugfs_hw_add(local); + diff --git a/package/kernel/mac80211/patches/310-mac80211-fix-invalid-read-in-minstrel_sort_best_tp_r.patch b/package/kernel/mac80211/patches/310-mac80211-fix-invalid-read-in-minstrel_sort_best_tp_r.patch new file mode 100644 index 0000000..51a315c --- /dev/null +++ b/package/kernel/mac80211/patches/310-mac80211-fix-invalid-read-in-minstrel_sort_best_tp_r.patch @@ -0,0 +1,34 @@ +From: Adrien Schildknecht <adrien+dev@schischi.me> +Date: Tue, 28 Jul 2015 10:30:16 +0200 +Subject: [PATCH] mac80211: fix invalid read in minstrel_sort_best_tp_rates() + +At the last iteration of the loop, j may equal zero and thus +tp_list[j - 1] causes an invalid read. +Changed the logic of the loop so that j - 1 is always >= 0. + +Signed-off-by: Adrien Schildknecht <adrien+dev@schischi.me> +--- + +--- a/net/mac80211/rc80211_minstrel.c ++++ b/net/mac80211/rc80211_minstrel.c +@@ -92,14 +92,15 @@ int minstrel_get_tp_avg(struct minstrel_ + static inline void + minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) + { +- int j = MAX_THR_RATES; +- struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats; ++ int j; ++ struct minstrel_rate_stats *tmp_mrs; + struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats; + +- while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) > +- minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) { +- j--; ++ for (j = MAX_THR_RATES; j > 0; --j) { + tmp_mrs = &mi->r[tp_list[j - 1]].stats; ++ if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <= ++ minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma)) ++ break; + } + + if (j < MAX_THR_RATES - 1) diff --git a/package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch b/package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch new file mode 100644 index 0000000..e44f121 --- /dev/null +++ b/package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch @@ -0,0 +1,45 @@ +From: Vineet Gupta <Vineet.Gupta1@synopsys.com> +Date: Thu, 9 Jul 2015 13:43:18 +0530 +Subject: [PATCH] brcmfmac: dhd_sdio.c: use existing atomic_or primitive + +There's already a generic implementation so use that instead. + +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -2564,15 +2564,6 @@ static inline void brcmf_sdio_clrintr(st + } + } + +-static void atomic_orr(int val, atomic_t *v) +-{ +- int old_val; +- +- old_val = atomic_read(v); +- while (atomic_cmpxchg(v, old_val, val | old_val) != old_val) +- old_val = atomic_read(v); +-} +- + static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) + { + struct brcmf_core *buscore; +@@ -2595,7 +2586,7 @@ static int brcmf_sdio_intr_rstatus(struc + if (val) { + brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); + bus->sdcnt.f1regdata++; +- atomic_orr(val, &bus->intstatus); ++ atomic_or(val, &bus->intstatus); + } + + return ret; +@@ -2712,7 +2703,7 @@ static void brcmf_sdio_dpc(struct brcmf_ + + /* Keep still-pending events for next scheduling */ + if (intstatus) +- atomic_orr(intstatus, &bus->intstatus); ++ atomic_or(intstatus, &bus->intstatus); + + brcmf_sdio_clrintr(bus); + diff --git a/package/kernel/mac80211/patches/312-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch b/package/kernel/mac80211/patches/312-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch new file mode 100644 index 0000000..bb27115 --- /dev/null +++ b/package/kernel/mac80211/patches/312-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch @@ -0,0 +1,46 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Thu, 20 Aug 2015 00:16:42 +0200 +Subject: [PATCH] brcmfmac: check all combinations when setting wiphy's + addresses +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Broadcom is working on better reflection of interface combinations. With +upcoming patches we may have 1st combination supporting less interfaces +than others. +To don't run out of addresses check all combinations to find the one +with the greatest max_interfaces value. + +Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -5786,7 +5786,9 @@ static void brcmf_wiphy_wowl_params(stru + static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) + { + struct brcmf_pub *drvr = ifp->drvr; ++ const struct ieee80211_iface_combination *combo; + struct ieee80211_supported_band *band; ++ u16 max_interfaces = 0; + __le32 bandlist[3]; + u32 n_bands; + int err, i; +@@ -5799,8 +5801,13 @@ static int brcmf_setup_wiphy(struct wiph + if (err) + return err; + +- for (i = 0; i < wiphy->iface_combinations->max_interfaces && +- i < ARRAY_SIZE(drvr->addresses); i++) { ++ for (i = 0, combo = wiphy->iface_combinations; ++ i < wiphy->n_iface_combinations; i++, combo++) { ++ max_interfaces = max(max_interfaces, combo->max_interfaces); ++ } ++ ++ for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses); ++ i++) { + u8 *addr = drvr->addresses[i].addr; + + memcpy(addr, drvr->mac, ETH_ALEN); diff --git a/package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch b/package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch new file mode 100644 index 0000000..baee295 --- /dev/null +++ b/package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch @@ -0,0 +1,204 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Thu, 20 Aug 2015 22:06:03 +0200 +Subject: [PATCH] brcmfmac: correct interface combination info + +The interface combination provided by brcmfmac did not truly reflect +the combinations supported by driver and/or firmware. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Reviewed-by: Pontus Fuchs <pontusf@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -5695,63 +5695,132 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = + } + }; + ++/** ++ * brcmf_setup_ifmodes() - determine interface modes and combinations. ++ * ++ * @wiphy: wiphy object. ++ * @ifp: interface object needed for feat module api. ++ * ++ * The interface modes and combinations are determined dynamically here ++ * based on firmware functionality. ++ * ++ * no p2p and no mbss: ++ * ++ * #STA <= 1, #AP <= 1, channels = 1, 2 total ++ * ++ * no p2p and mbss: ++ * ++ * #STA <= 1, #AP <= 1, channels = 1, 2 total ++ * #AP <= 4, matching BI, channels = 1, 4 total ++ * ++ * p2p, no mchan, and mbss: ++ * ++ * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total ++ * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total ++ * #AP <= 4, matching BI, channels = 1, 4 total ++ * ++ * p2p, mchan, and mbss: ++ * ++ * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total ++ * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total ++ * #AP <= 4, matching BI, channels = 1, 4 total ++ */ + static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) + { + struct ieee80211_iface_combination *combo = NULL; +- struct ieee80211_iface_limit *limits = NULL; +- int i = 0, max_iface_cnt; ++ struct ieee80211_iface_limit *c0_limits = NULL; ++ struct ieee80211_iface_limit *p2p_limits = NULL; ++ struct ieee80211_iface_limit *mbss_limits = NULL; ++ bool mbss, p2p; ++ int i, c, n_combos; + +- combo = kzalloc(sizeof(*combo), GFP_KERNEL); ++ mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS); ++ p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P); ++ ++ n_combos = 1 + !!p2p + !!mbss; ++ combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL); + if (!combo) + goto err; + +- limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL); +- if (!limits) ++ c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); ++ if (!c0_limits) + goto err; + ++ if (p2p) { ++ p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); ++ if (!p2p_limits) ++ goto err; ++ } ++ ++ if (mbss) { ++ mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); ++ if (!mbss_limits) ++ goto err; ++ } ++ + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + +- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) +- combo->num_different_channels = 2; +- else +- combo->num_different_channels = 1; +- +- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { +- limits[i].max = 1; +- limits[i++].types = BIT(NL80211_IFTYPE_STATION); +- limits[i].max = 4; +- limits[i++].types = BIT(NL80211_IFTYPE_AP); +- max_iface_cnt = 5; +- } else { +- limits[i].max = 2; +- limits[i++].types = BIT(NL80211_IFTYPE_STATION) | +- BIT(NL80211_IFTYPE_AP); +- max_iface_cnt = 2; +- } +- +- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) { ++ c = 0; ++ i = 0; ++ combo[c].num_different_channels = 1; ++ c0_limits[i].max = 1; ++ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); ++ if (p2p) { ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) ++ combo[c].num_different_channels = 2; + wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_DEVICE); +- limits[i].max = 1; +- limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | +- BIT(NL80211_IFTYPE_P2P_GO); +- limits[i].max = 1; +- limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); +- max_iface_cnt += 2; +- } +- combo->max_interfaces = max_iface_cnt; +- combo->limits = limits; +- combo->n_limits = i; ++ c0_limits[i].max = 1; ++ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); ++ c0_limits[i].max = 1; ++ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | ++ BIT(NL80211_IFTYPE_P2P_GO); ++ } else { ++ c0_limits[i].max = 1; ++ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); ++ } ++ combo[c].max_interfaces = i; ++ combo[c].n_limits = i; ++ combo[c].limits = c0_limits; ++ ++ if (p2p) { ++ c++; ++ i = 0; ++ combo[c].num_different_channels = 1; ++ p2p_limits[i].max = 1; ++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION); ++ p2p_limits[i].max = 1; ++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP); ++ p2p_limits[i].max = 1; ++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT); ++ p2p_limits[i].max = 1; ++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); ++ combo[c].max_interfaces = i; ++ combo[c].n_limits = i; ++ combo[c].limits = p2p_limits; ++ } + ++ if (mbss) { ++ c++; ++ combo[c].beacon_int_infra_match = true; ++ combo[c].num_different_channels = 1; ++ mbss_limits[0].max = 4; ++ mbss_limits[0].types = BIT(NL80211_IFTYPE_AP); ++ combo[c].max_interfaces = 4; ++ combo[c].n_limits = 1; ++ combo[c].limits = mbss_limits; ++ } ++ wiphy->n_iface_combinations = n_combos; + wiphy->iface_combinations = combo; +- wiphy->n_iface_combinations = 1; + return 0; + + err: +- kfree(limits); ++ kfree(c0_limits); ++ kfree(p2p_limits); ++ kfree(mbss_limits); + kfree(combo); + return -ENOMEM; + } +@@ -6080,11 +6149,15 @@ static void brcmf_cfg80211_reg_notifier( + + static void brcmf_free_wiphy(struct wiphy *wiphy) + { ++ int i; ++ + if (!wiphy) + return; + +- if (wiphy->iface_combinations) +- kfree(wiphy->iface_combinations->limits); ++ if (wiphy->iface_combinations) { ++ for (i = 0; i < wiphy->n_iface_combinations; i++) ++ kfree(wiphy->iface_combinations[i].limits); ++ } + kfree(wiphy->iface_combinations); + if (wiphy->bands[IEEE80211_BAND_2GHZ]) { + kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); diff --git a/package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch b/package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch new file mode 100644 index 0000000..9768ef2 --- /dev/null +++ b/package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch @@ -0,0 +1,87 @@ +From: Franky Lin <frankyl@broadcom.com> +Date: Thu, 20 Aug 2015 22:06:04 +0200 +Subject: [PATCH] brcmfmac: add debugfs entry for msgbuf statistics + +Expose ring buffer read/write pointers and other useful statistics +through debugfs. + +Reviewed-by: Arend Van Spriel <arend@broadcom.com> +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Franky Lin <frankyl@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -1360,6 +1360,60 @@ void brcmf_msgbuf_delete_flowring(struct + } + } + ++#ifdef DEBUG ++static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); ++ struct brcmf_pub *drvr = bus_if->drvr; ++ struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; ++ struct brcmf_commonring *commonring; ++ u16 i; ++ struct brcmf_flowring_ring *ring; ++ struct brcmf_flowring_hash *hash; ++ ++ commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; ++ seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n", ++ commonring->r_ptr, commonring->w_ptr, commonring->depth); ++ commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT]; ++ seq_printf(seq, "h2d_rx_submit: rp %4u, wp %4u, depth %4u\n", ++ commonring->r_ptr, commonring->w_ptr, commonring->depth); ++ commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE]; ++ seq_printf(seq, "d2h_ctl_cmplt: rp %4u, wp %4u, depth %4u\n", ++ commonring->r_ptr, commonring->w_ptr, commonring->depth); ++ commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE]; ++ seq_printf(seq, "d2h_tx_cmplt: rp %4u, wp %4u, depth %4u\n", ++ commonring->r_ptr, commonring->w_ptr, commonring->depth); ++ commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE]; ++ seq_printf(seq, "d2h_rx_cmplt: rp %4u, wp %4u, depth %4u\n", ++ commonring->r_ptr, commonring->w_ptr, commonring->depth); ++ ++ seq_printf(seq, "\nh2d_flowrings: depth %u\n", ++ BRCMF_H2D_TXFLOWRING_MAX_ITEM); ++ seq_puts(seq, "Active flowrings:\n"); ++ hash = msgbuf->flow->hash; ++ for (i = 0; i < msgbuf->flow->nrofrings; i++) { ++ if (!msgbuf->flow->rings[i]) ++ continue; ++ ring = msgbuf->flow->rings[i]; ++ if (ring->status != RING_OPEN) ++ continue; ++ commonring = msgbuf->flowrings[i]; ++ hash = &msgbuf->flow->hash[ring->hash_id]; ++ seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n" ++ " ifidx %u, fifo %u, da %pM\n", ++ i, commonring->r_ptr, commonring->w_ptr, ++ skb_queue_len(&ring->skblist), ring->blocked, ++ hash->ifidx, hash->fifo, hash->mac); ++ } ++ ++ return 0; ++} ++#else ++static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) ++{ ++ return 0; ++} ++#endif + + int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) + { +@@ -1460,6 +1514,8 @@ int brcmf_proto_msgbuf_attach(struct brc + spin_lock_init(&msgbuf->flowring_work_lock); + INIT_LIST_HEAD(&msgbuf->work_queue); + ++ brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read); ++ + return 0; + + fail: diff --git a/package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch b/package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch new file mode 100644 index 0000000..281f02b --- /dev/null +++ b/package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch @@ -0,0 +1,83 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Thu, 20 Aug 2015 22:06:05 +0200 +Subject: [PATCH] brcmfmac: make use of cfg80211_check_combinations() + +Use cfg80211_check_combinations() so we can bail out early when an +interface add or change results in an invalid combination. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -469,6 +469,36 @@ brcmf_find_wpsie(const u8 *parse, u32 le + return NULL; + } + ++static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg, ++ struct brcmf_cfg80211_vif *vif, ++ enum nl80211_iftype new_type) ++{ ++ int iftype_num[NUM_NL80211_IFTYPES]; ++ struct brcmf_cfg80211_vif *pos; ++ ++ memset(&iftype_num[0], 0, sizeof(iftype_num)); ++ list_for_each_entry(pos, &cfg->vif_list, list) ++ if (pos == vif) ++ iftype_num[new_type]++; ++ else ++ iftype_num[pos->wdev.iftype]++; ++ ++ return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); ++} ++ ++static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg, ++ enum nl80211_iftype new_type) ++{ ++ int iftype_num[NUM_NL80211_IFTYPES]; ++ struct brcmf_cfg80211_vif *pos; ++ ++ memset(&iftype_num[0], 0, sizeof(iftype_num)); ++ list_for_each_entry(pos, &cfg->vif_list, list) ++ iftype_num[pos->wdev.iftype]++; ++ ++ iftype_num[new_type]++; ++ return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); ++} + + static void convert_key_from_CPU(struct brcmf_wsec_key *key, + struct brcmf_wsec_key_le *key_le) +@@ -663,8 +693,14 @@ static struct wireless_dev *brcmf_cfg802 + struct vif_params *params) + { + struct wireless_dev *wdev; ++ int err; + + brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); ++ err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); ++ if (err) { ++ brcmf_err("iface validation failed: err=%d\n", err); ++ return ERR_PTR(err); ++ } + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: +@@ -823,8 +859,12 @@ brcmf_cfg80211_change_iface(struct wiphy + s32 ap = 0; + s32 err = 0; + +- brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type); +- ++ brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type); ++ err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type); ++ if (err) { ++ brcmf_err("iface validation failed: err=%d\n", err); ++ return err; ++ } + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: diff --git a/package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch b/package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch new file mode 100644 index 0000000..2d5f7b9 --- /dev/null +++ b/package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch @@ -0,0 +1,48 @@ +From: Franky Lin <frankyl@broadcom.com> +Date: Thu, 20 Aug 2015 22:06:06 +0200 +Subject: [PATCH] brcmfmac: block the correct flowring when backup queue + overflow + +brcmf_flowring_block blocks the last active flowring under the same +interface instead of the one provided by caller. This could lead to a +dead lock of netif stop if there are more than one flowring under the +interface and the traffic is high enough so brcmf_flowring_enqueue can +not unblock the ring right away. + +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Signed-off-by: Franky Lin <frankyl@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +@@ -194,11 +194,15 @@ static void brcmf_flowring_block(struct + spin_lock_irqsave(&flow->block_lock, flags); + + ring = flow->rings[flowid]; ++ if (ring->blocked == blocked) { ++ spin_unlock_irqrestore(&flow->block_lock, flags); ++ return; ++ } + ifidx = brcmf_flowring_ifidx_get(flow, flowid); + + currently_blocked = false; + for (i = 0; i < flow->nrofrings; i++) { +- if (flow->rings[i]) { ++ if ((flow->rings[i]) && (i != flowid)) { + ring = flow->rings[i]; + if ((ring->status == RING_OPEN) && + (brcmf_flowring_ifidx_get(flow, i) == ifidx)) { +@@ -209,8 +213,8 @@ static void brcmf_flowring_block(struct + } + } + } +- ring->blocked = blocked; +- if (currently_blocked == blocked) { ++ flow->rings[flowid]->blocked = blocked; ++ if (currently_blocked) { + spin_unlock_irqrestore(&flow->block_lock, flags); + return; + } diff --git a/package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch b/package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch new file mode 100644 index 0000000..7378401 --- /dev/null +++ b/package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch @@ -0,0 +1,52 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Thu, 20 Aug 2015 22:06:07 +0200 +Subject: [PATCH] brcmfmac: bump highest event number for 4339 firmware + +The event mask length is determined by the highest event number +that is specified in the driver. When this length is shorter than +firmware expects setting event mask will fail and device becomes +pretty useless. This issue was reported with bcm4339 firmware that +was recently released. + +Reported-by: Pontus Fuchs <pontusf@broadcom.com> +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Reviewed-by: Pontus Fuchs <pontusf@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +@@ -85,7 +85,6 @@ struct brcmf_event; + BRCMF_ENUM_DEF(IF, 54) \ + BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ + BRCMF_ENUM_DEF(RSSI, 56) \ +- BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ + BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ + BRCMF_ENUM_DEF(ACTION_FRAME, 59) \ + BRCMF_ENUM_DEF(ACTION_FRAME_COMPLETE, 60) \ +@@ -103,8 +102,7 @@ struct brcmf_event; + BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ + BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \ + BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \ +- BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ +- BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128) ++ BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) + + #define BRCMF_ENUM_DEF(id, val) \ + BRCMF_E_##id = (val), +@@ -112,7 +110,11 @@ struct brcmf_event; + /* firmware event codes sent by the dongle */ + enum brcmf_fweh_event_code { + BRCMF_FWEH_EVENT_ENUM_DEFLIST +- BRCMF_E_LAST ++ /* this determines event mask length which must match ++ * minimum length check in device firmware so it is ++ * hard-coded here. ++ */ ++ BRCMF_E_LAST = 139 + }; + #undef BRCMF_ENUM_DEF + diff --git a/package/kernel/mac80211/patches/319-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch b/package/kernel/mac80211/patches/319-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch new file mode 100644 index 0000000..97444b3 --- /dev/null +++ b/package/kernel/mac80211/patches/319-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch @@ -0,0 +1,138 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:14:53 +0200 +Subject: [PATCH] brcmfmac: consolidate ifp lookup in driver core + +In rx path the firmware provide an interface index which is used to +map to a struct brcmf_if instance. However, this involves some trick +that is done in two places. This is changed by having driver core +providing brcmf_get_ifp() function. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +@@ -276,6 +276,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + struct sk_buff *pktbuf) + { + struct brcmf_proto_bcdc_header *h; ++ struct brcmf_if *ifp; + + brcmf_dbg(BCDC, "Enter\n"); + +@@ -289,30 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + trace_brcmf_bcdchdr(pktbuf->data); + h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); + +- *ifidx = BCDC_GET_IF_IDX(h); +- if (*ifidx >= BRCMF_MAX_IFS) { +- brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); ++ ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); ++ if (IS_ERR_OR_NULL(ifp)) { ++ brcmf_dbg(INFO, "no matching ifp found\n"); + return -EBADE; + } +- /* The ifidx is the idx to map to matching netdev/ifp. When receiving +- * events this is easy because it contains the bssidx which maps +- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. +- * bssidx 1 is used for p2p0 and no data can be received or +- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 +- */ +- if (*ifidx) +- (*ifidx)++; +- + if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != + BCDC_PROTO_VER) { + brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", +- brcmf_ifname(drvr, *ifidx), h->flags); ++ brcmf_ifname(drvr, ifp->ifidx), h->flags); + return -EBADE; + } + + if (h->flags & BCDC_FLAG_SUM_GOOD) { + brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", +- brcmf_ifname(drvr, *ifidx), h->flags); ++ brcmf_ifname(drvr, ifp->ifidx), h->flags); + pktbuf->ip_summed = CHECKSUM_UNNECESSARY; + } + +@@ -320,12 +312,15 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + + skb_pull(pktbuf, BCDC_HEADER_LEN); + if (do_fws) +- brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); ++ brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2, ++ pktbuf); + else + skb_pull(pktbuf, h->data_offset << 2); + + if (pktbuf->len == 0) + return -ENODATA; ++ ++ *ifidx = ifp->ifidx; + return 0; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -83,6 +83,25 @@ char *brcmf_ifname(struct brcmf_pub *drv + return "<if_none>"; + } + ++struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx) ++{ ++ if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { ++ brcmf_err("ifidx %d out of range\n", ifidx); ++ return ERR_PTR(-ERANGE); ++ } ++ ++ /* The ifidx is the idx to map to matching netdev/ifp. When receiving ++ * events this is easy because it contains the bssidx which maps ++ * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. ++ * bssidx 1 is used for p2p0 and no data can be received or ++ * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 ++ */ ++ if (ifidx) ++ ifidx++; ++ ++ return drvr->iflist[ifidx]; ++} ++ + static void _brcmf_set_multicast_list(struct work_struct *work) + { + struct brcmf_if *ifp; +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -202,7 +202,7 @@ int brcmf_netdev_wait_pend8021x(struct b + + /* Return pointer to interface name */ + char *brcmf_ifname(struct brcmf_pub *drvr, int idx); +- ++struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); + int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, + char *name, u8 *mac_addr); +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -1081,16 +1081,8 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf + { + struct brcmf_if *ifp; + +- /* The ifidx is the idx to map to matching netdev/ifp. When receiving +- * events this is easy because it contains the bssidx which maps +- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. +- * bssidx 1 is used for p2p0 and no data can be received or +- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 +- */ +- if (ifidx) +- (ifidx)++; +- ifp = msgbuf->drvr->iflist[ifidx]; +- if (!ifp || !ifp->ndev) { ++ ifp = brcmf_get_ifp(msgbuf->drvr, ifidx); ++ if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) { + brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); + brcmu_pkt_buf_free_skb(skb); + return; diff --git a/package/kernel/mac80211/patches/320-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch b/package/kernel/mac80211/patches/320-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch new file mode 100644 index 0000000..632714c --- /dev/null +++ b/package/kernel/mac80211/patches/320-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch @@ -0,0 +1,222 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:14:54 +0200 +Subject: [PATCH] brcmfmac: make brcmf_proto_hdrpull() return struct + brcmf_if instance + +Avoid spreading the ifidx in the driver, but have it return the +struct brcmf_if instance. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +@@ -272,11 +272,11 @@ brcmf_proto_bcdc_hdrpush(struct brcmf_pu + } + + static int +-brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, +- struct sk_buff *pktbuf) ++brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, ++ struct sk_buff *pktbuf, struct brcmf_if **ifp) + { + struct brcmf_proto_bcdc_header *h; +- struct brcmf_if *ifp; ++ struct brcmf_if *tmp_if; + + brcmf_dbg(BCDC, "Enter\n"); + +@@ -290,21 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + trace_brcmf_bcdchdr(pktbuf->data); + h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); + +- ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); +- if (IS_ERR_OR_NULL(ifp)) { ++ tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); ++ if (!tmp_if) { + brcmf_dbg(INFO, "no matching ifp found\n"); + return -EBADE; + } + if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != + BCDC_PROTO_VER) { + brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", +- brcmf_ifname(drvr, ifp->ifidx), h->flags); ++ brcmf_ifname(drvr, tmp_if->ifidx), h->flags); + return -EBADE; + } + + if (h->flags & BCDC_FLAG_SUM_GOOD) { + brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", +- brcmf_ifname(drvr, ifp->ifidx), h->flags); ++ brcmf_ifname(drvr, tmp_if->ifidx), h->flags); + pktbuf->ip_summed = CHECKSUM_UNNECESSARY; + } + +@@ -312,7 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + + skb_pull(pktbuf, BCDC_HEADER_LEN); + if (do_fws) +- brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2, ++ brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2, + pktbuf); + else + skb_pull(pktbuf, h->data_offset << 2); +@@ -320,7 +320,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + if (pktbuf->len == 0) + return -ENODATA; + +- *ifidx = ifp->ifidx; ++ *ifp = tmp_if; + return 0; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -87,7 +87,7 @@ struct brcmf_if *brcmf_get_ifp(struct br + { + if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { + brcmf_err("ifidx %d out of range\n", ifidx); +- return ERR_PTR(-ERANGE); ++ return NULL; + } + + /* The ifidx is the idx to map to matching netdev/ifp. When receiving +@@ -539,17 +539,15 @@ void brcmf_rx_frame(struct device *dev, + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_skb_reorder_data *rd; +- u8 ifidx; + int ret; + + brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb); + + /* process and remove protocol-specific header */ +- ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb); +- ifp = drvr->iflist[ifidx]; ++ ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp); + + if (ret || !ifp || !ifp->ndev) { +- if ((ret != -ENODATA) && ifp) ++ if (ret != -ENODATA && ifp) + ifp->stats.rx_errors++; + brcmu_pkt_buf_free_skb(skb); + return; +@@ -592,17 +590,17 @@ void brcmf_txcomplete(struct device *dev + { + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; +- u8 ifidx; ++ struct brcmf_if *ifp; + + /* await txstatus signal for firmware if active */ + if (brcmf_fws_fc_active(drvr->fws)) { + if (!success) + brcmf_fws_bustxfail(drvr->fws, txp); + } else { +- if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp)) ++ if (brcmf_proto_hdrpull(drvr, false, txp, &ifp)) + brcmu_pkt_buf_free_skb(txp); + else +- brcmf_txfinalize(drvr, txp, ifidx, success); ++ brcmf_txfinalize(drvr, txp, ifp->ifidx, success); + } + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1448,7 +1448,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i + struct sk_buff *skb; + struct brcmf_skbuff_cb *skcb; + struct brcmf_fws_mac_descriptor *entry = NULL; +- u8 ifidx; ++ struct brcmf_if *ifp; + + brcmf_dbg(DATA, "flags %d\n", flags); + +@@ -1497,15 +1497,16 @@ brcmf_fws_txs_process(struct brcmf_fws_i + } + brcmf_fws_macdesc_return_req_credit(skb); + +- if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) { ++ ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp); ++ if (ret) { + brcmu_pkt_buf_free_skb(skb); + return -EINVAL; + } + if (!remove_from_hanger) +- ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx, ++ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx, + genbit, seq); + if (remove_from_hanger || ret) +- brcmf_txfinalize(fws->drvr, skb, ifidx, true); ++ brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true); + + return 0; + } +@@ -1848,7 +1849,7 @@ static int brcmf_fws_commit_skb(struct b + entry->transit_count--; + if (entry->suppressed) + entry->suppr_transit_count--; +- brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); ++ (void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL); + goto rollback; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -522,7 +522,7 @@ static int brcmf_msgbuf_set_dcmd(struct + + + static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws, +- u8 *ifidx, struct sk_buff *skb) ++ struct sk_buff *skb, struct brcmf_if **ifp) + { + return -ENODEV; + } +@@ -1082,7 +1082,7 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf + struct brcmf_if *ifp; + + ifp = brcmf_get_ifp(msgbuf->drvr, ifidx); +- if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) { ++ if (!ifp || !ifp->ndev) { + brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); + brcmu_pkt_buf_free_skb(skb); + return; +--- a/drivers/net/wireless/brcm80211/brcmfmac/proto.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h +@@ -24,8 +24,8 @@ enum proto_addr_mode { + + + struct brcmf_proto { +- int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, +- struct sk_buff *skb); ++ int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, ++ struct sk_buff *skb, struct brcmf_if **ifp); + int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len); + int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, +@@ -46,9 +46,19 @@ int brcmf_proto_attach(struct brcmf_pub + void brcmf_proto_detach(struct brcmf_pub *drvr); + + static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, +- u8 *ifidx, struct sk_buff *skb) ++ struct sk_buff *skb, ++ struct brcmf_if **ifp) + { +- return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb); ++ struct brcmf_if *tmp = NULL; ++ ++ /* assure protocol is always called with ++ * non-null initialized pointer. ++ */ ++ if (ifp) ++ *ifp = NULL; ++ else ++ ifp = &tmp; ++ return drvr->proto->hdrpull(drvr, do_fws, skb, ifp); + } + static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len) diff --git a/package/kernel/mac80211/patches/321-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch b/package/kernel/mac80211/patches/321-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch new file mode 100644 index 0000000..3360cbc --- /dev/null +++ b/package/kernel/mac80211/patches/321-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch @@ -0,0 +1,87 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:14:55 +0200 +Subject: [PATCH] brcmfmac: change parameters for + brcmf_remove_interface() + +Just pass the interface to be removed, ie. the struct brcmf_if instance. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -4983,7 +4983,7 @@ brcmf_notify_connect_status_ap(struct br + brcmf_dbg(CONN, "AP mode link down\n"); + complete(&cfg->vif_disabled); + if (ifp->vif->mbss) +- brcmf_remove_interface(ifp->drvr, ifp->bssidx); ++ brcmf_remove_interface(ifp); + return 0; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -887,12 +887,13 @@ static void brcmf_del_if(struct brcmf_pu + } + } + +-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx) ++void brcmf_remove_interface(struct brcmf_if *ifp) + { +- if (drvr->iflist[bssidx]) { +- brcmf_fws_del_interface(drvr->iflist[bssidx]); +- brcmf_del_if(drvr, bssidx); +- } ++ if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bssidx] != ifp)) ++ return; ++ ++ brcmf_fws_del_interface(ifp); ++ brcmf_del_if(ifp->drvr, ifp->bssidx); + } + + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) +@@ -1122,7 +1123,7 @@ void brcmf_detach(struct device *dev) + + /* make sure primary interface removed last */ + for (i = BRCMF_MAX_IFS-1; i > -1; i--) +- brcmf_remove_interface(drvr, i); ++ brcmf_remove_interface(drvr->iflist[i]); + + brcmf_cfg80211_detach(drvr->config); + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -206,7 +206,7 @@ struct brcmf_if *brcmf_get_ifp(struct br + int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, + char *name, u8 *mac_addr); +-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx); ++void brcmf_remove_interface(struct brcmf_if *ifp); + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + void brcmf_txflowblock_if(struct brcmf_if *ifp, + enum brcmf_netif_stop_reason reason, bool state); +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -222,7 +222,7 @@ static void brcmf_fweh_handle_if_event(s + err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); + + if (ifp && ifevent->action == BRCMF_E_IF_DEL) +- brcmf_remove_interface(drvr, ifevent->bssidx); ++ brcmf_remove_interface(ifp); + } + + /** +--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +@@ -2140,7 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(stru + { + cfg80211_unregister_wdev(&vif->wdev); + p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; +- brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx); ++ brcmf_remove_interface(vif->ifp); + brcmf_free_vif(vif); + } + diff --git a/package/kernel/mac80211/patches/322-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch b/package/kernel/mac80211/patches/322-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch new file mode 100644 index 0000000..2b61f4e --- /dev/null +++ b/package/kernel/mac80211/patches/322-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch @@ -0,0 +1,92 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:14:56 +0200 +Subject: [PATCH] brcmfmac: only call brcmf_cfg80211_detach() when attach + was successful + +In brcmf_bus_start() the function brcmf_cfg80211_attach() is called which +may fail. If this happens we should not call brcmf_cfg80211_detach() in +the failure path as it will result in NULL pointer dereference: + + brcmf_fweh_activate_events: Set event_msgs error (-5) + brcmf_bus_start: failed: -5 + brcmf_sdio_firmware_callback: dongle is not responding + BUG: unable to handle kernel NULL pointer dereference at 0000000000000068 + IP: [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0 + PGD 0 + Oops: 0000 [#1] SMP + Modules linked in: brcmfmac(O) brcmutil(O) cfg80211 auth_rpcgss + CPU: 1 PID: 45 Comm: kworker/1:1 Tainted: G O + Hardware name: Dell Inc. Latitude E6410/07XJP9, BIOS A07 02/15/2011 + Workqueue: events request_firmware_work_func + task: ffff880036c09ac0 ti: ffff880036dd4000 task.ti: ffff880036dd4000 + RIP: 0010:[<ffffffff811e8f08>] [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0 + RSP: 0018:ffff880036dd7a28 EFLAGS: 00010246 + RAX: ffff880036c09ac0 RBX: 0000000000000000 RCX: 000000007fffffff + RDX: 0000000000000000 RSI: ffffffff816578b9 RDI: 0000000000000000 + RBP: ffff880036dd7a48 R08: 0000000000000000 R09: ffff880036c0b340 + R10: 00000000000002ec R11: ffff880036dd7b08 R12: ffffffff816578b9 + R13: 0000000000000000 R14: ffffffff816578b9 R15: ffff8800c6c87000 + FS: 0000000000000000(0000) GS:ffff88012bc40000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b + CR2: 0000000000000068 CR3: 0000000001a0b000 CR4: 00000000000006e0 + Stack: + 0000000000000000 ffffffff816578b9 0000000000000000 ffff8800c0d003c8 + ffff880036dd7a78 ffffffff811e8ff5 0000000ffffffff1 ffffffff81a9b060 + ffff8800c789f880 ffff8800c0d00000 ffff880036dd7a98 ffffffff811ebe0d + Call Trace: + [<ffffffff811e8ff5>] kernfs_find_and_get_ns+0x35/0x60 + [<ffffffff811ebe0d>] sysfs_unmerge_group+0x1d/0x60 + [<ffffffff81404ef2>] dpm_sysfs_remove+0x22/0x60 + [<ffffffff813f9db9>] device_del+0x49/0x240 + [<ffffffff815da768>] rfkill_unregister+0x58/0xc0 + [<ffffffffa06bd91b>] wiphy_unregister+0xab/0x2f0 [cfg80211] + [<ffffffffa0742fe3>] brcmf_cfg80211_detach+0x23/0x50 [brcmfmac] + [<ffffffffa074d986>] brcmf_detach+0x86/0xe0 [brcmfmac] + [<ffffffffa0757de8>] brcmf_sdio_remove+0x48/0x120 [brcmfmac] + [<ffffffffa0758ed9>] brcmf_sdiod_remove+0x29/0xd0 [brcmfmac] + [<ffffffffa0759031>] brcmf_ops_sdio_remove+0xb1/0x110 [brcmfmac] + [<ffffffffa001c267>] sdio_bus_remove+0x37/0x100 [mmc_core] + [<ffffffff813fe026>] __device_release_driver+0x96/0x130 + [<ffffffff813fe0e3>] device_release_driver+0x23/0x30 + [<ffffffffa0754bc8>] brcmf_sdio_firmware_callback+0x2a8/0x5d0 [brcmfmac] + [<ffffffffa074deaf>] brcmf_fw_request_nvram_done+0x15f/0x5e0 [brcmfmac] + [<ffffffff8140142f>] ? devres_add+0x3f/0x50 + [<ffffffff810642b5>] ? usermodehelper_read_unlock+0x15/0x20 + [<ffffffff81400000>] ? platform_match+0x70/0xa0 + [<ffffffff8140f400>] request_firmware_work_func+0x30/0x60 + [<ffffffff8106828c>] process_one_work+0x14c/0x3d0 + [<ffffffff8106862a>] worker_thread+0x11a/0x450 + [<ffffffff81068510>] ? process_one_work+0x3d0/0x3d0 + [<ffffffff8106d692>] kthread+0xd2/0xf0 + [<ffffffff8106d5c0>] ? kthread_create_on_node+0x180/0x180 + [<ffffffff815ed35f>] ret_from_fork+0x3f/0x70 + [<ffffffff8106d5c0>] ? kthread_create_on_node+0x180/0x180 + Code: e9 40 fe ff ff 48 89 d8 eb 87 66 0f 1f 84 00 00 00 00 00 66 66 66 66 + 90 55 48 89 e5 41 56 49 89 f6 41 55 49 89 d5 31 d2 41 54 53 <0f> b7 + 47 68 48 8b 5f 48 66 c1 e8 05 83 e0 01 4d 85 ed 0f b6 c8 + RIP [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0 + RSP <ffff880036dd7a28> + CR2: 0000000000000068 + ---[ end trace 87d6ec0d3fe46740 ]--- + +Reported-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -1049,7 +1049,10 @@ int brcmf_bus_start(struct device *dev) + fail: + if (ret < 0) { + brcmf_err("failed: %d\n", ret); +- brcmf_cfg80211_detach(drvr->config); ++ if (drvr->config) { ++ brcmf_cfg80211_detach(drvr->config); ++ drvr->config = NULL; ++ } + if (drvr->fws) { + brcmf_fws_del_interface(ifp); + brcmf_fws_deinit(drvr); diff --git a/package/kernel/mac80211/patches/323-brcmfmac-correct-detection-of-p2pdev-interface-event.patch b/package/kernel/mac80211/patches/323-brcmfmac-correct-detection-of-p2pdev-interface-event.patch new file mode 100644 index 0000000..868b0a8 --- /dev/null +++ b/package/kernel/mac80211/patches/323-brcmfmac-correct-detection-of-p2pdev-interface-event.patch @@ -0,0 +1,105 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:14:57 +0200 +Subject: [PATCH] brcmfmac: correct detection of p2pdev interface event + +The p2pdev interface is setup in firmware resulting in a interface +event. This event has role and no-if flag. When role is p2p client +and no-if flag is set it indicates that this is the p2pdev interface. +This info is used in handling the event and adding interface in the +driver. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -795,7 +795,7 @@ fail: + } + + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, +- char *name, u8 *mac_addr) ++ bool is_p2pdev, char *name, u8 *mac_addr) + { + struct brcmf_if *ifp; + struct net_device *ndev; +@@ -821,7 +821,7 @@ struct brcmf_if *brcmf_add_if(struct brc + } + } + +- if (!brcmf_p2p_enable && bssidx == 1) { ++ if (!brcmf_p2p_enable && is_p2pdev) { + /* this is P2P_DEVICE interface */ + brcmf_dbg(INFO, "allocate non-netdev interface\n"); + ifp = kzalloc(sizeof(*ifp), GFP_KERNEL); +@@ -999,12 +999,12 @@ int brcmf_bus_start(struct device *dev) + brcmf_dbg(TRACE, "\n"); + + /* add primary networking interface */ +- ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL); ++ ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL); + if (IS_ERR(ifp)) + return PTR_ERR(ifp); + + if (brcmf_p2p_enable) +- p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL); ++ p2p_ifp = brcmf_add_if(drvr, 1, 0, false, "p2p%d", NULL); + else + p2p_ifp = NULL; + if (IS_ERR(p2p_ifp)) +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -205,7 +205,7 @@ char *brcmf_ifname(struct brcmf_pub *drv + struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); + int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, +- char *name, u8 *mac_addr); ++ bool is_p2pdev, char *name, u8 *mac_addr); + void brcmf_remove_interface(struct brcmf_if *ifp); + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + void brcmf_txflowblock_if(struct brcmf_if *ifp, +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -179,6 +179,7 @@ static void brcmf_fweh_handle_if_event(s + { + struct brcmf_if_event *ifevent = data; + struct brcmf_if *ifp; ++ bool is_p2pdev; + int err = 0; + + brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n", +@@ -186,18 +187,16 @@ static void brcmf_fweh_handle_if_event(s + ifevent->flags, ifevent->role); + + /* The P2P Device interface event must not be ignored +- * contrary to what firmware tells us. The only way to +- * distinguish the P2P Device is by looking at the ifidx +- * and bssidx received. ++ * contrary to what firmware tells us. + */ +- if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) && +- (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { ++ is_p2pdev = (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) && ++ ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT; ++ if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { + brcmf_dbg(EVENT, "event can be ignored\n"); + return; + } + if (ifevent->ifidx >= BRCMF_MAX_IFS) { +- brcmf_err("invalid interface index: %u\n", +- ifevent->ifidx); ++ brcmf_err("invalid interface index: %u\n", ifevent->ifidx); + return; + } + +@@ -207,7 +206,7 @@ static void brcmf_fweh_handle_if_event(s + brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, + emsg->addr); + ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, +- emsg->ifname, emsg->addr); ++ is_p2pdev, emsg->ifname, emsg->addr); + if (IS_ERR(ifp)) + return; + brcmf_fws_add_interface(ifp); diff --git a/package/kernel/mac80211/patches/324-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch b/package/kernel/mac80211/patches/324-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch new file mode 100644 index 0000000..abd6681 --- /dev/null +++ b/package/kernel/mac80211/patches/324-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch @@ -0,0 +1,126 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:14:58 +0200 +Subject: [PATCH] brcmfmac: use brcmf_get_ifp() to map ifidx to struct + brcmf_if instance + +The knowledge on how to map the interface index to a struct brcmf_if +instance is in brcmf_get_ifp() so use that function when only the +interface index is known instead of accessing brcmf_pub::iflist +directly. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c +@@ -149,7 +149,7 @@ static s32 brcmf_btcoex_params_read(stru + static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci, + bool trump_sco) + { +- struct brcmf_if *ifp = btci->cfg->pub->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(btci->cfg->pub, 0); + + if (trump_sco && !btci->saved_regs_part2) { + /* this should reduce eSCO agressive +@@ -468,7 +468,7 @@ int brcmf_btcoex_set_mode(struct brcmf_c + { + struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy); + struct brcmf_btcoex_info *btci = cfg->btcoex; +- struct brcmf_if *ifp = cfg->pub->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); + + switch (mode) { + case BRCMF_BTCOEX_DISABLED: +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -6213,7 +6213,7 @@ static void brcmf_free_wiphy(struct wiph + struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, + struct device *busdev) + { +- struct net_device *ndev = drvr->iflist[0]->ndev; ++ struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev; + struct brcmf_cfg80211_info *cfg; + struct wiphy *wiphy; + struct brcmf_cfg80211_vif *vif; +--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c +@@ -121,7 +121,7 @@ static void brcmf_feat_iovar_int_set(str + + void brcmf_feat_attach(struct brcmf_pub *drvr) + { +- struct brcmf_if *ifp = drvr->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); + + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); +--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +@@ -221,7 +221,7 @@ static void brcmf_flowring_block(struct + + bus_if = dev_get_drvdata(flow->dev); + drvr = bus_if->drvr; +- ifp = drvr->iflist[ifidx]; ++ ifp = brcmf_get_ifp(drvr, ifidx); + brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked); + + spin_unlock_irqrestore(&flow->block_lock, flags); +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -334,7 +334,7 @@ void brcmf_fweh_attach(struct brcmf_pub + void brcmf_fweh_detach(struct brcmf_pub *drvr) + { + struct brcmf_fweh_info *fweh = &drvr->fweh; +- struct brcmf_if *ifp = drvr->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + + if (ifp) { +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -972,7 +972,7 @@ static void + brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq, + u8 if_id) + { +- struct brcmf_if *ifp = fws->drvr->iflist[!if_id ? 0 : if_id + 1]; ++ struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id); + + if (WARN_ON(!ifp)) + return; +@@ -2118,6 +2118,7 @@ static int brcmf_debugfs_fws_stats_read( + int brcmf_fws_init(struct brcmf_pub *drvr) + { + struct brcmf_fws_info *fws; ++ struct brcmf_if *ifp; + u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS; + int rc; + u32 mode; +@@ -2177,21 +2178,22 @@ int brcmf_fws_init(struct brcmf_pub *drv + * continue. Set mode back to none indicating not enabled. + */ + fws->fw_signals = true; +- if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) { ++ ifp = brcmf_get_ifp(drvr, 0); ++ if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) { + brcmf_err("failed to set bdcv2 tlv signaling\n"); + fws->fcmode = BRCMF_FWS_FCMODE_NONE; + fws->fw_signals = false; + } + +- if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1)) ++ if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1)) + brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n"); + + /* Enable seq number reuse, if supported */ +- if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) { ++ if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) { + if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) { + mode = 0; + BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1); +- if (brcmf_fil_iovar_int_set(drvr->iflist[0], ++ if (brcmf_fil_iovar_int_set(ifp, + "wlfc_mode", mode) == 0) { + BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1); + } diff --git a/package/kernel/mac80211/patches/325-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch b/package/kernel/mac80211/patches/325-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch new file mode 100644 index 0000000..23a7b6f --- /dev/null +++ b/package/kernel/mac80211/patches/325-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch @@ -0,0 +1,122 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:14:59 +0200 +Subject: [PATCH] brcmfmac: pass struct brcmf_if instance in + brcmf_txfinalize() + +Most call sites of brcmf_txfinalize already have struct brcmf_if +instance so pass that to brcmf_txfinalize() as the function +needs it anyway. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -560,17 +560,11 @@ void brcmf_rx_frame(struct device *dev, + brcmf_netif_rx(ifp, skb); + } + +-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, +- bool success) ++void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) + { +- struct brcmf_if *ifp; + struct ethhdr *eh; + u16 type; + +- ifp = drvr->iflist[ifidx]; +- if (!ifp) +- goto done; +- + eh = (struct ethhdr *)(txp->data); + type = ntohs(eh->h_proto); + +@@ -582,7 +576,7 @@ void brcmf_txfinalize(struct brcmf_pub * + + if (!success) + ifp->stats.tx_errors++; +-done: ++ + brcmu_pkt_buf_free_skb(txp); + } + +@@ -600,7 +594,7 @@ void brcmf_txcomplete(struct device *dev + if (brcmf_proto_hdrpull(drvr, false, txp, &ifp)) + brcmu_pkt_buf_free_skb(txp); + else +- brcmf_txfinalize(drvr, txp, ifp->ifidx, success); ++ brcmf_txfinalize(ifp, txp, success); + } + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -210,8 +210,7 @@ void brcmf_remove_interface(struct brcmf + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + void brcmf_txflowblock_if(struct brcmf_if *ifp, + enum brcmf_netif_stop_reason reason, bool state); +-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, +- bool success); ++void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); + void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); + + /* Sets dongle media info (drv_version, mac address). */ +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1506,7 +1506,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i + ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx, + genbit, seq); + if (remove_from_hanger || ret) +- brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true); ++ brcmf_txfinalize(ifp, skb, true); + + return 0; + } +@@ -1905,7 +1905,7 @@ int brcmf_fws_process_skb(struct brcmf_i + if (fws->avoid_queueing) { + rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb); + if (rc < 0) +- brcmf_txfinalize(drvr, skb, ifp->ifidx, false); ++ brcmf_txfinalize(ifp, skb, false); + return rc; + } + +@@ -1929,7 +1929,7 @@ int brcmf_fws_process_skb(struct brcmf_i + brcmf_fws_schedule_deq(fws); + } else { + brcmf_err("drop skb: no hanger slot\n"); +- brcmf_txfinalize(drvr, skb, ifp->ifidx, false); ++ brcmf_txfinalize(ifp, skb, false); + rc = -ENOMEM; + } + brcmf_fws_unlock(fws); +@@ -2009,8 +2009,9 @@ static void brcmf_fws_dequeue_worker(str + ret = brcmf_proto_txdata(drvr, ifidx, 0, skb); + brcmf_fws_lock(fws); + if (ret < 0) +- brcmf_txfinalize(drvr, skb, ifidx, +- false); ++ brcmf_txfinalize(brcmf_get_ifp(drvr, ++ ifidx), ++ skb, false); + if (fws->bus_flow_blocked) + break; + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -873,7 +873,11 @@ brcmf_msgbuf_process_txstatus(struct brc + commonring = msgbuf->flowrings[flowid]; + atomic_dec(&commonring->outstanding_tx); + +- brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true); ++ /* Hante: i believe this was a bug as tx_status->msg.ifidx was used ++ * in brcmf_txfinalize as index in drvr->iflist. Can you confirm/deny? ++ */ ++ brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx), ++ skb, true); + } + + diff --git a/package/kernel/mac80211/patches/326-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch b/package/kernel/mac80211/patches/326-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch new file mode 100644 index 0000000..8ddc0a6 --- /dev/null +++ b/package/kernel/mac80211/patches/326-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch @@ -0,0 +1,92 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:15:00 +0200 +Subject: [PATCH] brcmfmac: add mapping for interface index to bsscfg + index + +Because the P2P Device interface in firmware uses the same interface +index as the primary interface we use the bsscfg index as index in the +struct brcmf_pub::iflist. However, in the data path we get the interface +index and not the bsscfg index. So we need a mapping of interface index +to bsscfg index, which can be determined upon handle adding the interface. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -85,21 +85,20 @@ char *brcmf_ifname(struct brcmf_pub *drv + + struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx) + { ++ struct brcmf_if *ifp; ++ s32 bssidx; ++ + if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { + brcmf_err("ifidx %d out of range\n", ifidx); + return NULL; + } + +- /* The ifidx is the idx to map to matching netdev/ifp. When receiving +- * events this is easy because it contains the bssidx which maps +- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. +- * bssidx 1 is used for p2p0 and no data can be received or +- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 +- */ +- if (ifidx) +- ifidx++; ++ ifp = NULL; ++ bssidx = drvr->if2bss[ifidx]; ++ if (bssidx >= 0) ++ ifp = drvr->iflist[bssidx]; + +- return drvr->iflist[ifidx]; ++ return ifp; + } + + static void _brcmf_set_multicast_list(struct work_struct *work) +@@ -831,6 +830,8 @@ struct brcmf_if *brcmf_add_if(struct brc + + ifp = netdev_priv(ndev); + ifp->ndev = ndev; ++ /* store mapping ifidx to bssidx */ ++ drvr->if2bss[ifidx] = bssidx; + } + + ifp->drvr = drvr; +@@ -855,6 +856,7 @@ static void brcmf_del_if(struct brcmf_pu + struct brcmf_if *ifp; + + ifp = drvr->iflist[bssidx]; ++ drvr->if2bss[ifp->ifidx] = -1; + drvr->iflist[bssidx] = NULL; + if (!ifp) { + brcmf_err("Null interface, idx=%d\n", bssidx); +@@ -862,6 +864,7 @@ static void brcmf_del_if(struct brcmf_pu + } + brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx); + if (ifp->ndev) { ++ drvr->if2bss[ifp->ifidx] = -1; + if (bssidx == 0) { + if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { + rtnl_lock(); +@@ -926,6 +929,7 @@ int brcmf_attach(struct device *dev) + if (!drvr) + return -ENOMEM; + ++ memset(drvr->if2bss, 0xFF, sizeof(drvr->if2bss)); + mutex_init(&drvr->proto_block); + + /* Link to bus module */ +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -122,6 +122,7 @@ struct brcmf_pub { + struct mac_address addresses[BRCMF_MAX_IFS]; + + struct brcmf_if *iflist[BRCMF_MAX_IFS]; ++ s32 if2bss[BRCMF_MAX_IFS]; + + struct mutex proto_block; + unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; diff --git a/package/kernel/mac80211/patches/327-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch b/package/kernel/mac80211/patches/327-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch new file mode 100644 index 0000000..a0a798b --- /dev/null +++ b/package/kernel/mac80211/patches/327-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch @@ -0,0 +1,103 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:15:01 +0200 +Subject: [PATCH] brcmfmac: add dedicated debug level for firmware + console logging + +Both PCIe and SDIO devices have the possibility to log the firmware +console output in kernel log. For PCIe it is logged when PCIE debug +level is enabled. For SDIO it is logged when user specifies a non-zero +console interval through debugfs. This patch tries to make it a +bit more consistent. The firmware console output is only logged when +FWCON debug level is enabled. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Reviewed-by: Pontus Fuchs <pontusf@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h +@@ -37,6 +37,7 @@ + #define BRCMF_SDIO_VAL 0x00020000 + #define BRCMF_MSGBUF_VAL 0x00040000 + #define BRCMF_PCIE_VAL 0x00080000 ++#define BRCMF_FWCON_VAL 0x00100000 + + /* set default print format */ + #undef pr_fmt +@@ -78,6 +79,7 @@ do { \ + #define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) + #define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL) + #define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL) ++#define BRCMF_FWCON_ON() (brcmf_msg_level & BRCMF_FWCON_VAL) + + #else /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */ + +@@ -90,6 +92,7 @@ do { \ + #define BRCMF_GLOM_ON() 0 + #define BRCMF_EVENT_ON() 0 + #define BRCMF_FIL_ON() 0 ++#define BRCMF_FWCON_ON() 0 + + #endif /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */ + +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -644,7 +644,7 @@ static void brcmf_pcie_bus_console_init( + addr = console->base_addr + BRCMF_CONSOLE_BUFSIZE_OFFSET; + console->bufsize = brcmf_pcie_read_tcm32(devinfo, addr); + +- brcmf_dbg(PCIE, "Console: base %x, buf %x, size %d\n", ++ brcmf_dbg(FWCON, "Console: base %x, buf %x, size %d\n", + console->base_addr, console->buf_addr, console->bufsize); + } + +@@ -656,6 +656,9 @@ static void brcmf_pcie_bus_console_read( + u8 ch; + u32 newidx; + ++ if (!BRCMF_FWCON_ON()) ++ return; ++ + console = &devinfo->shared.console; + addr = console->base_addr + BRCMF_CONSOLE_WRITEIDX_OFFSET; + newidx = brcmf_pcie_read_tcm32(devinfo, addr); +@@ -677,7 +680,7 @@ static void brcmf_pcie_bus_console_read( + } + if (ch == '\n') { + console->log_str[console->log_idx] = 0; +- brcmf_dbg(PCIE, "CONSOLE: %s", console->log_str); ++ pr_debug("CONSOLE: %s", console->log_str); + console->log_idx = 0; + } + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -123,6 +123,7 @@ struct rte_console { + + #define BRCMF_FIRSTREAD (1 << 6) + ++#define BRCMF_CONSOLE 10 /* watchdog interval to poll console */ + + /* SBSDIO_DEVICE_CTL */ + +@@ -3204,6 +3205,8 @@ static void brcmf_sdio_debugfs_create(st + if (IS_ERR_OR_NULL(dentry)) + return; + ++ bus->console_interval = BRCMF_CONSOLE; ++ + brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read); + brcmf_debugfs_add_entry(drvr, "counters", + brcmf_debugfs_sdio_count_read); +@@ -3613,7 +3616,7 @@ static void brcmf_sdio_bus_watchdog(stru + } + #ifdef DEBUG + /* Poll for console output periodically */ +- if (bus->sdiodev->state == BRCMF_SDIOD_DATA && ++ if (bus->sdiodev->state == BRCMF_SDIOD_DATA && BRCMF_FWCON_ON() && + bus->console_interval != 0) { + bus->console.count += BRCMF_WD_POLL_MS; + if (bus->console.count >= bus->console_interval) { diff --git a/package/kernel/mac80211/patches/328-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch b/package/kernel/mac80211/patches/328-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch new file mode 100644 index 0000000..53e7ede --- /dev/null +++ b/package/kernel/mac80211/patches/328-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch @@ -0,0 +1,34 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:15:02 +0200 +Subject: [PATCH] brcmfmac: remove ifidx parameter from + brcmf_fws_txstatus_suppressed() + +The brcmf_fws_txstatus_suppressed() function prototype specifies an +ifidx parameter which is not used within the function implementation. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1398,7 +1398,7 @@ done: + } + + static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, +- struct sk_buff *skb, u8 ifidx, ++ struct sk_buff *skb, + u32 genbit, u16 seq) + { + struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; +@@ -1503,7 +1503,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i + return -EINVAL; + } + if (!remove_from_hanger) +- ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx, ++ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, + genbit, seq); + if (remove_from_hanger || ret) + brcmf_txfinalize(ifp, skb, true); diff --git a/package/kernel/mac80211/patches/329-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch b/package/kernel/mac80211/patches/329-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch new file mode 100644 index 0000000..bb05235 --- /dev/null +++ b/package/kernel/mac80211/patches/329-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch @@ -0,0 +1,97 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:15:03 +0200 +Subject: [PATCH] brcmfmac: change prototype for brcmf_fws_hdrpull() + +Instead of passing ifidx and drvr just pass struct brcmf_if pointer +which holds both parameters. + +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +@@ -312,8 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + + skb_pull(pktbuf, BCDC_HEADER_LEN); + if (do_fws) +- brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2, +- pktbuf); ++ brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf); + else + skb_pull(pktbuf, h->data_offset << 2); + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1616,11 +1616,10 @@ static int brcmf_fws_notify_bcmc_credit_ + return 0; + } + +-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, +- struct sk_buff *skb) ++void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb) + { + struct brcmf_skb_reorder_data *rd; +- struct brcmf_fws_info *fws = drvr->fws; ++ struct brcmf_fws_info *fws = ifp->drvr->fws; + u8 *signal_data; + s16 data_len; + u8 type; +@@ -1630,20 +1629,20 @@ int brcmf_fws_hdrpull(struct brcmf_pub * + s32 err; + + brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n", +- ifidx, skb->len, signal_len); ++ ifp->ifidx, skb->len, siglen); + +- WARN_ON(signal_len > skb->len); ++ WARN_ON(siglen > skb->len); + +- if (!signal_len) +- return 0; ++ if (!siglen) ++ return; + /* if flow control disabled, skip to packet data and leave */ + if ((!fws) || (!fws->fw_signals)) { +- skb_pull(skb, signal_len); +- return 0; ++ skb_pull(skb, siglen); ++ return; + } + + fws->stats.header_pulls++; +- data_len = signal_len; ++ data_len = siglen; + signal_data = skb->data; + + status = BRCMF_FWS_RET_OK_NOSCHEDULE; +@@ -1731,14 +1730,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub * + /* signalling processing result does + * not affect the actual ethernet packet. + */ +- skb_pull(skb, signal_len); ++ skb_pull(skb, siglen); + + /* this may be a signal-only packet + */ + if (skb->len == 0) + fws->stats.header_only_pkt++; +- +- return 0; + } + + static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h +@@ -21,8 +21,7 @@ + int brcmf_fws_init(struct brcmf_pub *drvr); + void brcmf_fws_deinit(struct brcmf_pub *drvr); + bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); +-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, +- struct sk_buff *skb); ++void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb); + int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb); + + void brcmf_fws_reset_interface(struct brcmf_if *ifp); diff --git a/package/kernel/mac80211/patches/330-brcmfmac-introduce-brcmf_net_detach-function.patch b/package/kernel/mac80211/patches/330-brcmfmac-introduce-brcmf_net_detach-function.patch new file mode 100644 index 0000000..0651a2f --- /dev/null +++ b/package/kernel/mac80211/patches/330-brcmfmac-introduce-brcmf_net_detach-function.patch @@ -0,0 +1,99 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Wed, 26 Aug 2015 22:15:04 +0200 +Subject: [PATCH] brcmfmac: introduce brcmf_net_detach() function + +In case of error during brcmf_bus_start() the network interfaces were +freed using free_netdev(). However, the interfaces may have additional +memory allocated which is not freed. The netdev has destructor set to +brcmf_cfg80211_free_netdev() which frees the additional memory if +allocated and call free_netdev(). The brcmf_net_detach() either calls +brcmf_cfg80211_free_netdev() directly or uses unregister_netdev() when +struct net_device::reg_state indicates the netdev was registered. + +Reported-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> +Reviewed-by: Hante Meuleman <meuleman@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -4747,7 +4747,8 @@ void brcmf_cfg80211_free_netdev(struct n + ifp = netdev_priv(ndev); + vif = ifp->vif; + +- brcmf_free_vif(vif); ++ if (vif) ++ brcmf_free_vif(vif); + free_netdev(ndev); + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -718,8 +718,6 @@ int brcmf_net_attach(struct brcmf_if *if + } + + brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); +- +- ndev->destructor = brcmf_cfg80211_free_netdev; + return 0; + + fail: +@@ -729,6 +727,14 @@ fail: + return -EBADE; + } + ++static void brcmf_net_detach(struct net_device *ndev) ++{ ++ if (ndev->reg_state == NETREG_REGISTERED) ++ unregister_netdev(ndev); ++ else ++ brcmf_cfg80211_free_netdev(ndev); ++} ++ + static int brcmf_net_p2p_open(struct net_device *ndev) + { + brcmf_dbg(TRACE, "Enter\n"); +@@ -805,8 +811,7 @@ struct brcmf_if *brcmf_add_if(struct brc + ifp->ndev->name); + if (ifidx) { + netif_stop_queue(ifp->ndev); +- unregister_netdev(ifp->ndev); +- free_netdev(ifp->ndev); ++ brcmf_net_detach(ifp->ndev); + drvr->iflist[bssidx] = NULL; + } else { + brcmf_err("ignore IF event\n"); +@@ -828,6 +833,7 @@ struct brcmf_if *brcmf_add_if(struct brc + if (!ndev) + return ERR_PTR(-ENOMEM); + ++ ndev->destructor = brcmf_cfg80211_free_netdev; + ifp = netdev_priv(ndev); + ifp->ndev = ndev; + /* store mapping ifidx to bssidx */ +@@ -879,8 +885,7 @@ static void brcmf_del_if(struct brcmf_pu + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); + } +- /* unregister will take care of freeing it */ +- unregister_netdev(ifp->ndev); ++ brcmf_net_detach(ifp->ndev); + } + } + +@@ -1056,11 +1061,11 @@ fail: + brcmf_fws_deinit(drvr); + } + if (drvr->iflist[0]) { +- free_netdev(ifp->ndev); ++ brcmf_net_detach(ifp->ndev); + drvr->iflist[0] = NULL; + } + if (p2p_ifp) { +- free_netdev(p2p_ifp->ndev); ++ brcmf_net_detach(p2p_ifp->ndev); + drvr->iflist[1] = NULL; + } + return ret; diff --git a/package/kernel/mac80211/patches/331-brcmfmac-Reset-PCIE-devices-after-recognition.patch b/package/kernel/mac80211/patches/331-brcmfmac-Reset-PCIE-devices-after-recognition.patch new file mode 100644 index 0000000..5a7e447 --- /dev/null +++ b/package/kernel/mac80211/patches/331-brcmfmac-Reset-PCIE-devices-after-recognition.patch @@ -0,0 +1,193 @@ +From: Hante Meuleman <meuleman@broadcom.com> +Date: Thu, 27 Aug 2015 16:14:06 +0200 +Subject: [PATCH] brcmfmac: Reset PCIE devices after recognition. + +When PCIE type devices are being FW reloaded without being properly +reset then the device ends up in a locked state, requiring the +device to be completely powered down. This patch adds a reset +through watchdog at the moment the device (cores) has been +recognized. This will solve warm reboot issues. + +Cc: Rafal Milecki <zajec5@gmail.com> +Reviewed-by: Arend Van Spriel <arend@broadcom.com> +Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +Signed-off-by: Hante Meuleman <meuleman@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c +@@ -101,6 +101,9 @@ + /* ARM Cortex M3 core, ID 0x82a */ + #define BCM4329_CORE_ARM_BASE 0x18002000 + ++/* Max possibly supported memory size (limited by IO mapped memory) */ ++#define BRCMF_CHIP_MAX_MEMSIZE (4 * 1024 * 1024) ++ + #define CORE_SB(base, field) \ + (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) + #define SBCOREREV(sbidh) \ +@@ -687,6 +690,12 @@ static int brcmf_chip_get_raminfo(struct + brcmf_err("RAM size is undetermined\n"); + return -ENOMEM; + } ++ ++ if (ci->pub.ramsize > BRCMF_CHIP_MAX_MEMSIZE) { ++ brcmf_err("RAM size is incorrect\n"); ++ return -ENOMEM; ++ } ++ + return 0; + } + +@@ -899,6 +908,15 @@ static int brcmf_chip_recognition(struct + + /* assure chip is passive for core access */ + brcmf_chip_set_passive(&ci->pub); ++ ++ /* Call bus specific reset function now. Cores have been determined ++ * but further access may require a chip specific reset at this point. ++ */ ++ if (ci->ops->reset) { ++ ci->ops->reset(ci->ctx, &ci->pub); ++ brcmf_chip_set_passive(&ci->pub); ++ } ++ + return brcmf_chip_get_raminfo(ci); + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h +@@ -73,6 +73,7 @@ struct brcmf_buscore_ops { + u32 (*read32)(void *ctx, u32 addr); + void (*write32)(void *ctx, u32 addr, u32 value); + int (*prepare)(void *ctx); ++ int (*reset)(void *ctx, struct brcmf_chip *chip); + int (*setup)(void *ctx, struct brcmf_chip *chip); + void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec); + }; +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -74,6 +74,8 @@ enum brcmf_pcie_state { + #define BRCMF_PCIE_REG_INTMASK 0x94 + #define BRCMF_PCIE_REG_SBMBX 0x98 + ++#define BRCMF_PCIE_REG_LINK_STATUS_CTRL 0xBC ++ + #define BRCMF_PCIE_PCIE2REG_INTMASK 0x24 + #define BRCMF_PCIE_PCIE2REG_MAILBOXINT 0x48 + #define BRCMF_PCIE_PCIE2REG_MAILBOXMASK 0x4C +@@ -466,6 +468,7 @@ brcmf_pcie_select_core(struct brcmf_pcie + + static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo) + { ++ struct brcmf_core *core; + u16 cfg_offset[] = { BRCMF_PCIE_CFGREG_STATUS_CMD, + BRCMF_PCIE_CFGREG_PM_CSR, + BRCMF_PCIE_CFGREG_MSI_CAP, +@@ -484,32 +487,38 @@ static void brcmf_pcie_reset_device(stru + if (!devinfo->ci) + return; + ++ /* Disable ASPM */ + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, +- BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL); +- lsc = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA); ++ pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_LINK_STATUS_CTRL, ++ &lsc); + val = lsc & (~BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB); +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, val); ++ pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_LINK_STATUS_CTRL, ++ val); + ++ /* Watchdog reset */ + brcmf_pcie_select_core(devinfo, BCMA_CORE_CHIPCOMMON); + WRITECC32(devinfo, watchdog, 4); + msleep(100); + ++ /* Restore ASPM */ + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, +- BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL); +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, lsc); ++ pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_LINK_STATUS_CTRL, ++ lsc); + +- brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); +- for (i = 0; i < ARRAY_SIZE(cfg_offset); i++) { +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, +- cfg_offset[i]); +- val = brcmf_pcie_read_reg32(devinfo, +- BRCMF_PCIE_PCIE2REG_CONFIGDATA); +- brcmf_dbg(PCIE, "config offset 0x%04x, value 0x%04x\n", +- cfg_offset[i], val); +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, +- val); ++ core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_PCIE2); ++ if (core->rev <= 13) { ++ for (i = 0; i < ARRAY_SIZE(cfg_offset); i++) { ++ brcmf_pcie_write_reg32(devinfo, ++ BRCMF_PCIE_PCIE2REG_CONFIGADDR, ++ cfg_offset[i]); ++ val = brcmf_pcie_read_reg32(devinfo, ++ BRCMF_PCIE_PCIE2REG_CONFIGDATA); ++ brcmf_dbg(PCIE, "config offset 0x%04x, value 0x%04x\n", ++ cfg_offset[i], val); ++ brcmf_pcie_write_reg32(devinfo, ++ BRCMF_PCIE_PCIE2REG_CONFIGDATA, ++ val); ++ } + } + } + +@@ -519,8 +528,6 @@ static void brcmf_pcie_attach(struct brc + u32 config; + + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); +- if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0) +- brcmf_pcie_reset_device(devinfo); + /* BAR1 window may not be sized properly */ + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0); +@@ -1636,6 +1643,23 @@ static int brcmf_pcie_buscoreprep(void * + } + + ++static int brcmf_pcie_buscore_reset(void *ctx, struct brcmf_chip *chip) ++{ ++ struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; ++ u32 val; ++ ++ devinfo->ci = chip; ++ brcmf_pcie_reset_device(devinfo); ++ ++ val = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); ++ if (val != 0xffffffff) ++ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, ++ val); ++ ++ return 0; ++} ++ ++ + static void brcmf_pcie_buscore_activate(void *ctx, struct brcmf_chip *chip, + u32 rstvec) + { +@@ -1647,6 +1671,7 @@ static void brcmf_pcie_buscore_activate( + + static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { + .prepare = brcmf_pcie_buscoreprep, ++ .reset = brcmf_pcie_buscore_reset, + .activate = brcmf_pcie_buscore_activate, + .read32 = brcmf_pcie_buscore_read32, + .write32 = brcmf_pcie_buscore_write32, +@@ -1814,7 +1839,6 @@ brcmf_pcie_remove(struct pci_dev *pdev) + brcmf_pcie_intr_disable(devinfo); + + brcmf_detach(&pdev->dev); +- brcmf_pcie_reset_device(devinfo); + + kfree(bus->bus_priv.pcie); + kfree(bus->msgbuf->flowrings); diff --git a/package/kernel/mac80211/patches/332-ath10k-fix-DMA-related-firmware-crashes-on-multiple-.patch b/package/kernel/mac80211/patches/332-ath10k-fix-DMA-related-firmware-crashes-on-multiple-.patch new file mode 100644 index 0000000..52b7fa9 --- /dev/null +++ b/package/kernel/mac80211/patches/332-ath10k-fix-DMA-related-firmware-crashes-on-multiple-.patch @@ -0,0 +1,33 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Sun, 13 Sep 2015 22:26:10 +0200 +Subject: [PATCH] ath10k: fix DMA related firmware crashes on multiple devices + +Some platforms really don't like DMA bursts of 256 bytes, and this +causes the firmware to crash when sending beacons. +Also, changing this based on the firmware version does not seem to make +much sense, so use 128 bytes for all versions. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/wireless/ath/ath10k/hw.h ++++ b/drivers/net/wireless/ath/ath10k/hw.h +@@ -340,7 +340,7 @@ enum ath10k_hw_rate_cck { + #define TARGET_10X_MAX_FRAG_ENTRIES 0 + + /* 10.2 parameters */ +-#define TARGET_10_2_DMA_BURST_SIZE 1 ++#define TARGET_10_2_DMA_BURST_SIZE 0 + + /* Target specific defines for WMI-TLV firmware */ + #define TARGET_TLV_NUM_VDEVS 4 +@@ -397,7 +397,7 @@ enum ath10k_hw_rate_cck { + + #define TARGET_10_4_TX_DBG_LOG_SIZE 1024 + #define TARGET_10_4_NUM_WDS_ENTRIES 32 +-#define TARGET_10_4_DMA_BURST_SIZE 1 ++#define TARGET_10_4_DMA_BURST_SIZE 0 + #define TARGET_10_4_MAC_AGGR_DELIM 0 + #define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 + #define TARGET_10_4_VOW_CONFIG 0 diff --git a/package/kernel/mac80211/patches/333-ath9k-enable-hw-manual-peak-calibration-for-QCA9561.patch b/package/kernel/mac80211/patches/333-ath9k-enable-hw-manual-peak-calibration-for-QCA9561.patch new file mode 100644 index 0000000..faf6cdc --- /dev/null +++ b/package/kernel/mac80211/patches/333-ath9k-enable-hw-manual-peak-calibration-for-QCA9561.patch @@ -0,0 +1,33 @@ +From: Miaoqing Pan <miaoqing@qca.qualcomm.com> +Date: Tue, 1 Sep 2015 10:56:09 +0800 +Subject: [PATCH] ath9k: enable hw manual peak calibration for QCA9561 + +This patch fix https://lists.openwrt.org/pipermail/openwrt-devel/ +2015-August/034979.html. As the peak detect calibration is set +incorrectly. + +Signed-off-by: Miaoqing Pan <miaoqing@qca.qualcomm.com> +--- + +--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c +@@ -1249,7 +1249,8 @@ static void ar9003_hw_manual_peak_cal(st + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0); + +- if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) { ++ if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || ++ AR_SREV_9561(ah)) { + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, +@@ -1640,7 +1641,8 @@ static bool ar9003_hw_init_cal_soc(struc + + skip_tx_iqcal: + if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { +- if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) { ++ if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) || ++ AR_SREV_9561(ah)) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; diff --git a/package/kernel/mac80211/patches/334-mac80211-fix-tx-sequence-number-assignment-with-soft.patch b/package/kernel/mac80211/patches/334-mac80211-fix-tx-sequence-number-assignment-with-soft.patch new file mode 100644 index 0000000..b19e7ee --- /dev/null +++ b/package/kernel/mac80211/patches/334-mac80211-fix-tx-sequence-number-assignment-with-soft.patch @@ -0,0 +1,23 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Thu, 24 Sep 2015 14:10:07 +0200 +Subject: [PATCH] mac80211: fix tx sequence number assignment with software + queue + fast-xmit + +When using software queueing, tx sequence number assignment happens at +ieee80211_tx_dequeue time, so the fast-xmit codepath must not do that. + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -2766,7 +2766,8 @@ static bool ieee80211_xmit_fast(struct i + + if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { + *ieee80211_get_qos_ctl(hdr) = tid; +- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); ++ if (!sta->sta.txq[0]) ++ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); + } else { + info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); diff --git a/package/kernel/mac80211/patches/335-mac80211-fix-handling-of-PS-filtering-with-fast-xmit.patch b/package/kernel/mac80211/patches/335-mac80211-fix-handling-of-PS-filtering-with-fast-xmit.patch new file mode 100644 index 0000000..7aef205 --- /dev/null +++ b/package/kernel/mac80211/patches/335-mac80211-fix-handling-of-PS-filtering-with-fast-xmit.patch @@ -0,0 +1,45 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Thu, 24 Sep 2015 14:11:40 +0200 +Subject: [PATCH] mac80211: fix handling of PS filtering with fast-xmit + +Fixes dropped packets in the tx path in case a non-PS station triggers +the tx filter. + +Cc: stable@vger.kernel.org # 4.2 +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -101,6 +101,7 @@ static void ieee80211_handle_filtered_fr + * when it wakes up for the next time. + */ + set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT); ++ ieee80211_clear_fast_xmit(sta); + + /* + * This code races in the following way: +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1217,8 +1217,10 @@ ieee80211_tx_prepare(struct ieee80211_su + + if (!tx->sta) + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; +- else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT)) ++ else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT)) { + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; ++ ieee80211_check_fast_xmit(tx->sta); ++ } + + info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT; + +@@ -2450,7 +2452,8 @@ void ieee80211_check_fast_xmit(struct st + + if (test_sta_flag(sta, WLAN_STA_PS_STA) || + test_sta_flag(sta, WLAN_STA_PS_DRIVER) || +- test_sta_flag(sta, WLAN_STA_PS_DELIVER)) ++ test_sta_flag(sta, WLAN_STA_PS_DELIVER) || ++ test_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT)) + goto out; + + if (sdata->noack_map) diff --git a/package/kernel/mac80211/patches/336-ath9k-declare-required-extra-tx-headroom.patch b/package/kernel/mac80211/patches/336-ath9k-declare-required-extra-tx-headroom.patch new file mode 100644 index 0000000..4d88591 --- /dev/null +++ b/package/kernel/mac80211/patches/336-ath9k-declare-required-extra-tx-headroom.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Thu, 24 Sep 2015 16:57:37 +0200 +Subject: [PATCH] ath9k: declare required extra tx headroom + +ath9k inserts padding between the 802.11 header and the data area (to +align it). Since it didn't declare this extra required headroom, this +led to some nasty issues like randomly dropped packets in some setups. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -875,6 +875,7 @@ static void ath9k_set_hw_capab(struct at + hw->max_rate_tries = 10; + hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vif); ++ hw->extra_tx_headroom = 4; + + hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; + hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; diff --git a/package/kernel/mac80211/patches/400-ath_move_debug_code.patch b/package/kernel/mac80211/patches/400-ath_move_debug_code.patch new file mode 100644 index 0000000..72e9a41 --- /dev/null +++ b/package/kernel/mac80211/patches/400-ath_move_debug_code.patch @@ -0,0 +1,30 @@ +--- a/drivers/net/wireless/ath/Makefile ++++ b/drivers/net/wireless/ath/Makefile +@@ -13,10 +13,10 @@ ath-objs := main.o \ + regd.o \ + hw.o \ + key.o \ ++ debug.o \ + dfs_pattern_detector.o \ + dfs_pri_detector.o + +-ath-$(CPTCFG_ATH_DEBUG) += debug.o + ath-$(CPTCFG_ATH_TRACEPOINTS) += trace.o + + ccflags-y += -D__CHECK_ENDIAN__ +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -318,13 +318,6 @@ void _ath_dbg(struct ath_common *common, + #endif /* CPTCFG_ATH_DEBUG */ + + /** Returns string describing opmode, or NULL if unknown mode. */ +-#ifdef CPTCFG_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/kernel/mac80211/patches/401-ath9k_blink_default.patch b/package/kernel/mac80211/patches/401-ath9k_blink_default.patch new file mode 100644 index 0000000..4a997f1 --- /dev/null +++ b/package/kernel/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 +@@ -45,7 +45,7 @@ int ath9k_modparam_nohwcrypt; + module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); + MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +-int ath9k_led_blink; ++int ath9k_led_blink = 1; + module_param_named(blink, ath9k_led_blink, int, 0444); + MODULE_PARM_DESC(blink, "Enable LED blink on activity"); + diff --git a/package/kernel/mac80211/patches/402-ath_regd_optional.patch b/package/kernel/mac80211/patches/402-ath_regd_optional.patch new file mode 100644 index 0000000..f918c18 --- /dev/null +++ b/package/kernel/mac80211/patches/402-ath_regd_optional.patch @@ -0,0 +1,69 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -341,6 +341,10 @@ ath_reg_apply_beaconing_flags(struct wip + struct ieee80211_channel *ch; + unsigned int i; + ++#ifdef CPTCFG_ATH_USER_REGD ++ return; ++#endif ++ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wiphy->bands[band]) + continue; +@@ -374,6 +378,10 @@ ath_reg_apply_ir_flags(struct wiphy *wip + { + struct ieee80211_supported_band *sband; + ++#ifdef CPTCFG_ATH_USER_REGD ++ return; ++#endif ++ + sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + if (!sband) + return; +@@ -402,6 +410,10 @@ static void ath_reg_apply_radar_flags(st + struct ieee80211_channel *ch; + unsigned int i; + ++#ifdef CPTCFG_ATH_USER_REGD ++ return; ++#endif ++ + if (!wiphy->bands[IEEE80211_BAND_5GHZ]) + return; + +@@ -633,6 +645,11 @@ ath_regd_init_wiphy(struct ath_regulator + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; ++ ++#ifdef CPTCFG_ATH_USER_REGD ++ return 0; ++#endif ++ + wiphy->regulatory_flags |= REGULATORY_STRICT_REG | + REGULATORY_CUSTOM_REG; + +--- a/drivers/net/wireless/ath/Kconfig ++++ b/drivers/net/wireless/ath/Kconfig +@@ -22,6 +22,9 @@ menuconfig ATH_CARDS + + if ATH_CARDS + ++config ATH_USER_REGD ++ bool "Do not enforce EEPROM regulatory restrictions" ++ + config ATH_DEBUG + bool "Atheros wireless debugging" + ---help--- +--- a/.local-symbols ++++ b/.local-symbols +@@ -137,6 +137,7 @@ RTL8187_LEDS= + ATH_COMMON= + ATH_CARDS= + ATH_DEBUG= ++ATH_USER_REGD= + ATH_TRACEPOINTS= + ATH_REG_DYNAMIC_USER_REG_HINTS= + ATH_REG_DYNAMIC_USER_CERT_TESTING= diff --git a/package/kernel/mac80211/patches/403-world_regd_fixup.patch b/package/kernel/mac80211/patches/403-world_regd_fixup.patch new file mode 100644 index 0000000..2b04309 --- /dev/null +++ b/package/kernel/mac80211/patches/403-world_regd_fixup.patch @@ -0,0 +1,84 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -43,7 +43,8 @@ static int __ath_regd_init(struct ath_re + NL80211_RRF_NO_OFDM) + + /* We allow IBSS on these on a case by case basis by regulatory domain */ +-#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ ++#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\ ++ REG_RULE(5260-10, 5350+10, 80, 0, 30,\ + NL80211_RRF_NO_IR) + #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ + NL80211_RRF_NO_IR) +@@ -61,57 +62,56 @@ static int __ath_regd_init(struct ath_re + #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ + ATH9K_5GHZ_5725_5850 + ++#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 bool dynamic_country_user_possible(struct ath_regulatory *reg) diff --git a/package/kernel/mac80211/patches/404-regd_no_assoc_hints.patch b/package/kernel/mac80211/patches/404-regd_no_assoc_hints.patch new file mode 100644 index 0000000..8b52ac3 --- /dev/null +++ b/package/kernel/mac80211/patches/404-regd_no_assoc_hints.patch @@ -0,0 +1,19 @@ +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -2390,6 +2390,8 @@ void regulatory_hint_country_ie(struct w + enum environment_cap env = ENVIRON_ANY; + struct regulatory_request *request = NULL, *lr; + ++ return; ++ + /* IE len must be evenly divisible by 2 */ + if (country_ie_len & 0x01) + return; +@@ -2596,6 +2598,7 @@ 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/kernel/mac80211/patches/405-ath_regd_us.patch b/package/kernel/mac80211/patches/405-ath_regd_us.patch new file mode 100644 index 0000000..cc55877 --- /dev/null +++ b/package/kernel/mac80211/patches/405-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/kernel/mac80211/patches/406-ath_relax_default_regd.patch b/package/kernel/mac80211/patches/406-ath_relax_default_regd.patch new file mode 100644 index 0000000..6336f1f --- /dev/null +++ b/package/kernel/mac80211/patches/406-ath_relax_default_regd.patch @@ -0,0 +1,47 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -114,10 +114,22 @@ static const struct ieee80211_regdomain + ) + }; + ++static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) ++{ ++ return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; ++} ++ ++static bool is_default_regd(struct ath_regulatory *reg) ++{ ++ return ath_regd_get_eepromRD(reg) == CTRY_DEFAULT; ++} ++ + static bool dynamic_country_user_possible(struct ath_regulatory *reg) + { + if (config_enabled(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) + return true; ++ if (is_default_regd(reg)) ++ return true; + + switch (reg->country_code) { + case CTRY_UNITED_STATES: +@@ -202,11 +214,6 @@ static inline bool is_wwr_sku(u16 regd) + (regd == WORLD)); + } + +-static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) +-{ +- return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; +-} +- + bool ath_is_world_regd(struct ath_regulatory *reg) + { + return is_wwr_sku(ath_regd_get_eepromRD(reg)); +@@ -650,6 +657,9 @@ ath_regd_init_wiphy(struct ath_regulator + return 0; + #endif + ++ if (is_default_regd(reg)) ++ return 0; ++ + wiphy->regulatory_flags |= REGULATORY_STRICT_REG | + REGULATORY_CUSTOM_REG; + diff --git a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch new file mode 100644 index 0000000..1a62484 --- /dev/null +++ b/package/kernel/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 +@@ -722,6 +722,7 @@ static const struct ieee80211_iface_limi + BIT(NL80211_IFTYPE_AP) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + }; + + static const struct ieee80211_iface_limit wds_limits[] = { diff --git a/package/kernel/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch new file mode 100644 index 0000000..2a5ab3d --- /dev/null +++ b/package/kernel/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 +@@ -86,13 +86,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 +@@ -1965,7 +1965,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); +@@ -2051,7 +2051,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", +@@ -2518,6 +2518,7 @@ static const struct ieee80211_iface_limi + BIT(NL80211_IFTYPE_MESH_POINT) | + #endif + BIT(NL80211_IFTYPE_AP) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + }; + + static const struct ieee80211_iface_combination if_comb = { diff --git a/package/kernel/mac80211/patches/420-ath5k_disable_fast_cc.patch b/package/kernel/mac80211/patches/420-ath5k_disable_fast_cc.patch new file mode 100644 index 0000000..414f495 --- /dev/null +++ b/package/kernel/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 +@@ -1154,6 +1154,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 +@@ -1161,6 +1162,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/kernel/mac80211/patches/430-add_ath5k_platform.patch b/package/kernel/mac80211/patches/430-add_ath5k_platform.patch new file mode 100644 index 0000000..b213e2a --- /dev/null +++ b/package/kernel/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/kernel/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch b/package/kernel/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch new file mode 100644 index 0000000..cdc9315 --- /dev/null +++ b/package/kernel/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 +@@ -21,6 +21,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" +@@ -72,7 +73,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) +@@ -80,6 +81,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 + */ +@@ -123,6 +137,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/kernel/mac80211/patches/432-ath5k_add_pciids.patch b/package/kernel/mac80211/patches/432-ath5k_add_pciids.patch new file mode 100644 index 0000000..d82f800 --- /dev/null +++ b/package/kernel/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 +@@ -48,6 +48,8 @@ static const struct pci_device_id ath5k_ + { 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/kernel/mac80211/patches/440-ath5k_channel_bw_debugfs.patch b/package/kernel/mac80211/patches/440-ath5k_channel_bw_debugfs.patch new file mode 100644 index 0000000..42d43a4 --- /dev/null +++ b/package/kernel/mac80211/patches/440-ath5k_channel_bw_debugfs.patch @@ -0,0 +1,143 @@ +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 +@@ -823,6 +823,97 @@ 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_debug; ++ ++#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_debug != tobwmode) { ++ mutex_lock(&ah->lock); ++ ah->ah_bwmode = tobwmode; ++ ah->ah_bwmode_debug = tobwmode; ++ mutex_unlock(&ah->lock); ++ } ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return count; ++} ++ ++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 */ + +@@ -1010,6 +1101,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, +--- a/drivers/net/wireless/ath/ath5k/ath5k.h ++++ b/drivers/net/wireless/ath/ath5k/ath5k.h +@@ -1370,6 +1370,7 @@ struct ath5k_hw { + u8 ah_coverage_class; + bool ah_ack_bitrate_high; + u8 ah_bwmode; ++ u8 ah_bwmode_debug; + bool ah_short_slot; + + /* Antenna Control */ +--- a/drivers/net/wireless/ath/ath5k/base.c ++++ b/drivers/net/wireless/ath/ath5k/base.c +@@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru + return -EINVAL; + } + ++ if (ah->ah_bwmode_debug != AR5K_BWMODE_DEFAULT) ++ ah->ah_bwmode = ah->ah_bwmode_debug; ++ + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the diff --git a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch new file mode 100644 index 0000000..a7f9d9f --- /dev/null +++ b/package/kernel/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 +@@ -1301,6 +1301,53 @@ void ath9k_deinit_debug(struct ath_softc + ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); + } + ++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); +@@ -1320,6 +1367,8 @@ int ath9k_init_debug(struct ath_hw *ah) + ath9k_tx99_init_debug(sc); + ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); + ++ debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_eeprom); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, diff --git a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch new file mode 100644 index 0000000..5a3e37c --- /dev/null +++ b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch @@ -0,0 +1,32 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -1032,23 +1032,23 @@ static int __init ath9k_init(void) + { + int error; + +- 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_out; + } + +- 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_out: + return error; + } diff --git a/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch b/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch new file mode 100644 index 0000000..d2a3b96 --- /dev/null +++ b/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch @@ -0,0 +1,18 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -390,13 +390,8 @@ static void ath9k_hw_init_config(struct + + ah->config.rx_intr_mitigation = true; + +- if (AR_SREV_9300_20_OR_LATER(ah)) { +- ah->config.rimt_last = 500; +- ah->config.rimt_first = 2000; +- } else { +- ah->config.rimt_last = 250; +- ah->config.rimt_first = 700; +- } ++ ah->config.rimt_last = 250; ++ ah->config.rimt_first = 500; + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + ah->config.pll_pwrsave = 7; diff --git a/package/kernel/mac80211/patches/511-ath9k_reduce_rxbuf.patch b/package/kernel/mac80211/patches/511-ath9k_reduce_rxbuf.patch new file mode 100644 index 0000000..6766111 --- /dev/null +++ b/package/kernel/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 +@@ -88,7 +88,7 @@ int ath_descdma_setup(struct ath_softc * + (_l) &= ((_sz) - 1); \ + } while (0) + +-#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/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch new file mode 100644 index 0000000..5ecf528 --- /dev/null +++ b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch @@ -0,0 +1,125 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1348,6 +1348,52 @@ 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; ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ char buf[32]; ++ unsigned int len; ++ ++ len = sprintf(buf, "0x%08x\n", common->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; ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ 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 (kstrtoul(buf, 0, &chan_bw)) ++ return -EINVAL; ++ ++ common->chan_bw = chan_bw; ++ if (!test_bit(ATH_OP_INVALID, &common->op_flags)) ++ ath9k_ops.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); +@@ -1369,6 +1415,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); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -151,6 +151,7 @@ struct ath_common { + int debug_mask; + enum ath_device_state state; + unsigned long op_flags; ++ u32 chan_bw; + + struct ath_ani ani; + +--- a/drivers/net/wireless/ath/ath9k/common.c ++++ b/drivers/net/wireless/ath/ath9k/common.c +@@ -296,11 +296,13 @@ EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_ke + /* + * Update internal channel flags. + */ +-static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, ++static void ath9k_cmn_update_ichannel(struct ath_common *common, ++ struct ath9k_channel *ichan, + struct cfg80211_chan_def *chandef) + { + struct ieee80211_channel *chan = chandef->chan; + u16 flags = 0; ++ int width; + + ichan->channel = chan->center_freq; + ichan->chan = chan; +@@ -308,7 +310,19 @@ static void ath9k_cmn_update_ichannel(st + if (chan->band == IEEE80211_BAND_5GHZ) + flags |= CHANNEL_5GHZ; + +- switch (chandef->width) { ++ switch (common->chan_bw) { ++ case 5: ++ width = NL80211_CHAN_WIDTH_5; ++ break; ++ case 10: ++ width = NL80211_CHAN_WIDTH_10; ++ break; ++ default: ++ width = chandef->width; ++ break; ++ } ++ ++ switch (width) { + case NL80211_CHAN_WIDTH_5: + flags |= CHANNEL_QUARTER; + break; +@@ -341,10 +355,11 @@ struct ath9k_channel *ath9k_cmn_get_chan + struct cfg80211_chan_def *chandef) + { + struct ieee80211_channel *curchan = chandef->chan; ++ struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *channel; + + channel = &ah->channels[curchan->hw_value]; +- ath9k_cmn_update_ichannel(channel, chandef); ++ ath9k_cmn_update_ichannel(common, channel, chandef); + + return channel; + } diff --git a/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch new file mode 100644 index 0000000..c84d1bc --- /dev/null +++ b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch @@ -0,0 +1,30 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -651,6 +651,7 @@ int ath9k_hw_init(struct ath_hw *ah) + + /* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */ + switch (ah->hw_version.devid) { ++ case AR9300_DEVID_INVALID: + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -36,6 +36,7 @@ + + #define ATHEROS_VENDOR_ID 0x168c + ++#define AR9300_DEVID_INVALID 0xabcd + #define AR5416_DEVID_PCI 0x0023 + #define AR5416_DEVID_PCIE 0x0024 + #define AR9160_DEVID_PCI 0x0027 +--- a/drivers/net/wireless/ath/ath9k/pci.c ++++ b/drivers/net/wireless/ath/ath9k/pci.c +@@ -751,6 +751,7 @@ static const struct pci_device_id ath_pc + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + #endif + ++ { PCI_VDEVICE(ATHEROS, 0xabcd) }, /* PCI-E internal chip default ID */ + { 0 } + }; + diff --git a/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch new file mode 100644 index 0000000..99bf7e8 --- /dev/null +++ b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch @@ -0,0 +1,160 @@ +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -2320,6 +2320,7 @@ struct cfg80211_qos_map { + * (as advertised by the nl80211 feature flag.) + * @get_tx_power: store the current TX power into the dbm variable; + * return 0 if successful ++ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary + * + * @set_wds_peer: set the WDS peer for a WDS interface + * +@@ -2576,6 +2577,7 @@ struct cfg80211_ops { + enum nl80211_tx_power_setting type, int mbm); + int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, + int *dbm); ++ int (*set_antenna_gain)(struct wiphy *wiphy, int dbi); + + int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, + const u8 *addr); +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1252,6 +1252,7 @@ enum ieee80211_smps_mode { + * + * @power_level: requested transmit power (in dBm), backward compatibility + * value only that is set to the minimum of all interfaces ++ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi) + * + * @chandef: the channel definition to tune to + * @radar_enabled: whether radar detection is enabled +@@ -1273,6 +1274,7 @@ struct ieee80211_conf { + u32 flags; + int power_level, dynamic_ps_timeout; + int max_sleep_period; ++ int max_antenna_gain; + + u16 listen_interval; + u8 ps_dtim_period; +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -1761,6 +1761,9 @@ enum nl80211_commands { + * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device + * is operating in an indoor environment. + * ++ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce ++ * transmit power to stay within regulatory limits. u32, dBi. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -2130,6 +2133,8 @@ enum nl80211_attrs { + + NL80211_ATTR_REG_INDOOR, + ++ NL80211_ATTR_WIPHY_ANTENNA_GAIN, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -2233,6 +2233,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) + { +@@ -3845,6 +3858,7 @@ const struct cfg80211_ops mac80211_confi + .set_wiphy_params = ieee80211_set_wiphy_params, + .set_tx_power = ieee80211_set_tx_power, + .get_tx_power = ieee80211_get_tx_power, ++ .set_antenna_gain = ieee80211_set_antenna_gain, + .set_wds_peer = ieee80211_set_wds_peer, + .rfkill_poll = ieee80211_rfkill_poll, + CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1318,6 +1318,7 @@ struct ieee80211_local { + int dynamic_ps_forced_timeout; + + int user_power_level; /* in dBm, for all interfaces */ ++ int user_antenna_gain; /* in dBi */ + + enum ieee80211_smps_mode smps_mode; + +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -95,7 +95,7 @@ static u32 ieee80211_hw_conf_chan(struct + struct ieee80211_sub_if_data *sdata; + struct cfg80211_chan_def chandef = {}; + u32 changed = 0; +- int power; ++ int power, max_power; + u32 offchannel_flag; + + offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; +@@ -152,6 +152,12 @@ static u32 ieee80211_hw_conf_chan(struct + } + rcu_read_unlock(); + ++ max_power = chandef.chan->max_reg_power; ++ if (local->user_antenna_gain > 0) { ++ max_power -= local->user_antenna_gain; ++ power = min(power, max_power); ++ } ++ + if (local->hw.conf.power_level != power) { + changed |= IEEE80211_CONF_CHANGE_POWER; + local->hw.conf.power_level = power; +@@ -581,6 +587,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + IEEE80211_RADIOTAP_MCS_HAVE_BW; + local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | + IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; ++ local->user_antenna_gain = 0; + local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; + local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; + local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -402,6 +402,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, + [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, + [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, ++ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, + }; + + /* policy for the key attributes */ +@@ -2207,6 +2208,20 @@ static int nl80211_set_wiphy(struct sk_b + if (result) + return result; + } ++ ++ if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) { ++ int idx, dbi = 0; ++ ++ if (!rdev->ops->set_antenna_gain) ++ return -EOPNOTSUPP; ++ ++ idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN; ++ dbi = nla_get_u32(info->attrs[idx]); ++ ++ result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi); ++ if (result) ++ return result; ++ } + + if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && + info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { diff --git a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch new file mode 100644 index 0000000..3cfffa0 --- /dev/null +++ b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch @@ -0,0 +1,251 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -806,6 +806,9 @@ static inline int ath9k_dump_btcoex(stru + void ath_init_leds(struct ath_softc *sc); + void ath_deinit_leds(struct ath_softc *sc); + void ath_fill_led_pin(struct ath_softc *sc); ++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) + { +@@ -945,6 +948,13 @@ void ath_ant_comb_scan(struct ath_softc + + #define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */ + ++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; +@@ -996,9 +1006,8 @@ struct ath_softc { + spinlock_t chan_lock; + + #ifdef CPTCFG_MAC80211_LEDS +- bool led_registered; +- char led_name[32]; +- struct led_classdev led_cdev; ++ const char *led_default_trigger; ++ struct list_head leds; + #endif + + #ifdef CPTCFG_ATH9K_DEBUGFS +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -24,45 +24,102 @@ + 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); +- u32 val = (brightness == LED_OFF); ++ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev); ++ struct ath_softc *sc = led->sc; + +- if (sc->sc_ah->config.led_active_high) +- val = !val; ++ 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; + +- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val); ++ 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; + +- if (!ath9k_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 (ath9k_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); + } + + void ath_fill_led_pin(struct ath_softc *sc) +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -944,7 +944,7 @@ int ath9k_init_device(u16 devid, struct + + #ifdef CPTCFG_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 +@@ -1393,6 +1393,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 ++ + + int ath9k_init_debug(struct ath_hw *ah) + { +@@ -1417,6 +1472,10 @@ int ath9k_init_debug(struct ath_hw *ah) + &fops_eeprom); + debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_chanbw); ++#ifdef CONFIG_MAC80211_LEDS ++ debugfs_create_file("gpio_led", S_IWUSR, ++ sc->debug.debugfs_phy, sc, &fops_gpio_led); ++#endif + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, diff --git a/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch b/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch new file mode 100644 index 0000000..dc33cd0 --- /dev/null +++ b/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch @@ -0,0 +1,71 @@ +--- a/include/linux/ath9k_platform.h ++++ b/include/linux/ath9k_platform.h +@@ -41,6 +41,9 @@ struct ath9k_platform_data { + int (*external_reset)(void); + + bool use_eeprom; ++ ++ 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 +@@ -15,6 +15,7 @@ + */ + + #include "ath9k.h" ++#include <linux/ath9k_platform.h> + + /********************************/ + /* LED functions */ +@@ -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); + +@@ -120,6 +141,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]); + } + + void ath_fill_led_pin(struct ath_softc *sc) diff --git a/package/kernel/mac80211/patches/540-ath9k_reduce_ani_interval.patch b/package/kernel/mac80211/patches/540-ath9k_reduce_ani_interval.patch new file mode 100644 index 0000000..e899903 --- /dev/null +++ b/package/kernel/mac80211/patches/540-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 +@@ -42,7 +42,7 @@ + #define ATH9K_ANI_PERIOD 300 + + /* in ms */ +-#define ATH9K_ANI_POLLINTERVAL 1000 ++#define ATH9K_ANI_POLLINTERVAL 300 + + #define ATH9K_SIG_FIRSTEP_SETTING_MIN 0 + #define ATH9K_SIG_FIRSTEP_SETTING_MAX 20 diff --git a/package/kernel/mac80211/patches/541-ath9k_rx_dma_stop_check.patch b/package/kernel/mac80211/patches/541-ath9k_rx_dma_stop_check.patch new file mode 100644 index 0000000..3c5e9f5 --- /dev/null +++ b/package/kernel/mac80211/patches/541-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 +@@ -695,7 +695,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 */ +@@ -725,6 +725,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/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch new file mode 100644 index 0000000..2b2c763 --- /dev/null +++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch @@ -0,0 +1,139 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1449,6 +1449,50 @@ static const struct file_operations fops + #endif + + ++static ssize_t read_file_diag(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_hw *ah = sc->sc_ah; ++ char buf[32]; ++ unsigned int len; ++ ++ len = sprintf(buf, "0x%08lx\n", ah->diag); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_diag(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_hw *ah = sc->sc_ah; ++ unsigned long diag; ++ char buf[32]; ++ ssize_t len; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ if (kstrtoul(buf, 0, &diag)) ++ return -EINVAL; ++ ++ ah->diag = diag; ++ ath9k_hw_update_diag(ah); ++ ++ return count; ++} ++ ++static const struct file_operations fops_diag = { ++ .read = read_file_diag, ++ .write = write_file_diag, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++ + int ath9k_init_debug(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); +@@ -1476,6 +1520,8 @@ int ath9k_init_debug(struct ath_hw *ah) + debugfs_create_file("gpio_led", S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_gpio_led); + #endif ++ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_diag); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -519,6 +519,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; +@@ -804,6 +810,8 @@ struct ath_hw { + u32 rfkill_polarity; + u32 ah_flags; + ++ unsigned long diag; ++ + bool reset_power_on; + bool htc_reset_init; + +@@ -1066,6 +1074,7 @@ void ath9k_hw_check_nav(struct ath_hw *a + bool ath9k_hw_check_alive(struct ath_hw *ah); + + bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); ++void ath9k_hw_update_diag(struct ath_hw *ah); + + /* Generic hw timer primitives */ + struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1808,6 +1808,20 @@ u32 ath9k_hw_get_tsf_offset(struct times + } + EXPORT_SYMBOL(ath9k_hw_get_tsf_offset); + ++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) + { +@@ -2016,6 +2030,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st + ar9003_hw_disable_phy_restart(ah); + + ath9k_hw_apply_gpio_override(ah); ++ ath9k_hw_update_diag(ah); + + if (AR_SREV_9565(ah) && common->bt_ant_diversity) + REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -533,6 +533,11 @@ irqreturn_t ath_isr(int irq, void *dev) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) + return IRQ_HANDLED; + ++ 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/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch new file mode 100644 index 0000000..fddaf56 --- /dev/null +++ b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch @@ -0,0 +1,186 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -720,6 +720,7 @@ struct ath_spec_scan { + * @config_pci_powersave: + * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC + * ++ * @get_adc_entropy: get entropy from the raw ADC I/Q output + * @spectral_scan_config: set parameters for spectral scan and enable/disable it + * @spectral_scan_trigger: trigger a spectral scan run + * @spectral_scan_wait: wait for a spectral scan run to finish +@@ -742,6 +743,7 @@ struct ath_hw_ops { + struct ath_hw_antcomb_conf *antconf); + void (*antdiv_comb_conf_set)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); ++ void (*get_adc_entropy)(struct ath_hw *ah, u8 *buf, size_t len); + void (*spectral_scan_config)(struct ath_hw *ah, + struct ath_spec_scan *param); + void (*spectral_scan_trigger)(struct ath_hw *ah); +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -1999,6 +1999,26 @@ void ar9003_hw_init_rate_txpower(struct + } + } + ++static void ar9003_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len) ++{ ++ int i, j; ++ ++ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1); ++ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); ++ REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0); ++ ++ memset(buf, 0, len); ++ for (i = 0; i < len; i++) { ++ for (j = 0; j < 4; j++) { ++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC); ++ ++ buf[i] <<= 2; ++ buf[i] |= (regval & 1) | ((regval & BIT(10)) >> 9); ++ udelay(1); ++ } ++ } ++} ++ + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); +@@ -2035,6 +2055,7 @@ void ar9003_hw_attach_phy_ops(struct ath + priv_ops->set_radar_params = ar9003_hw_set_radar_params; + priv_ops->fast_chan_change = ar9003_hw_fast_chan_change; + ++ ops->get_adc_entropy = ar9003_hw_get_adc_entropy; + ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; + ops->spectral_scan_config = ar9003_hw_spectral_scan_config; +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -710,7 +710,8 @@ static void ath9k_init_txpower_limits(st + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ); + +- ah->curchan = curchan; ++ if (curchan) ++ ah->curchan = curchan; + } + + static const struct ieee80211_iface_limit if_limits[] = { +@@ -904,6 +905,18 @@ static void ath9k_set_hw_capab(struct at + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + } + ++static void ath_get_initial_entropy(struct ath_softc *sc) ++{ ++ struct ath_hw *ah = sc->sc_ah; ++ char buf[256]; ++ ++ /* reuse last channel initialized by the tx power test */ ++ ath9k_hw_reset(ah, ah->curchan, NULL, false); ++ ++ ath9k_hw_get_adc_entropy(ah, buf, sizeof(buf)); ++ add_device_randomness(buf, sizeof(buf)); ++} ++ + int ath9k_init_device(u16 devid, struct ath_softc *sc, + const struct ath_bus_ops *bus_ops) + { +@@ -949,6 +962,8 @@ int ath9k_init_device(u16 devid, struct + ARRAY_SIZE(ath9k_tpt_blink)); + #endif + ++ ath_get_initial_entropy(sc); ++ + /* Register with mac80211 */ + error = ieee80211_register_hw(hw); + if (error) +--- a/drivers/net/wireless/ath/ath9k/hw-ops.h ++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h +@@ -100,6 +100,12 @@ static inline void ath9k_hw_tx99_set_txp + ath9k_hw_ops(ah)->tx99_set_txpower(ah, power); + } + ++static inline void ath9k_hw_get_adc_entropy(struct ath_hw *ah, ++ u8 *buf, size_t len) ++{ ++ ath9k_hw_ops(ah)->get_adc_entropy(ah, buf, len); ++} ++ + #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT + + static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) +--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c +@@ -1327,9 +1327,30 @@ void ar5008_hw_init_rate_txpower(struct + } + } + ++static void ar5008_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len) ++{ ++ int i, j; ++ ++ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1); ++ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); ++ REG_RMW_FIELD(ah, AR_PHY_TEST2, AR_PHY_TEST2_RX_OBS_SEL, 0); ++ ++ memset(buf, 0, len); ++ for (i = 0; i < len; i++) { ++ for (j = 0; j < 4; j++) { ++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC); ++ ++ buf[i] <<= 2; ++ buf[i] |= (regval & 1) | ((regval & BIT(9)) >> 8); ++ udelay(1); ++ } ++ } ++} ++ + int ar5008_hw_attach_phy_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); ++ struct ath_hw_ops *ops = ath9k_hw_ops(ah); + static const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, +@@ -1344,6 +1365,8 @@ int ar5008_hw_attach_phy_ops(struct ath_ + if (ret) + return ret; + ++ ops->get_adc_entropy = ar5008_hw_get_adc_entropy; ++ + priv_ops->rf_set_freq = ar5008_hw_set_channel; + priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate; + +--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h ++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h +@@ -20,6 +20,12 @@ + #define PHY_AGC_CLR 0x10000000 + #define RFSILENT_BB 0x00002000 + ++#define AR_PHY_TEST_BBB_OBS_SEL 0x780000 ++#define AR_PHY_TEST_BBB_OBS_SEL_S 19 ++ ++#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23 ++#define AR_PHY_TEST_RX_OBS_SEL_BIT5 (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S) ++ + #define AR_PHY_TURBO 0x9804 + #define AR_PHY_FC_TURBO_MODE 0x00000001 + #define AR_PHY_FC_TURBO_SHORT 0x00000002 +@@ -36,6 +42,9 @@ + + #define AR_PHY_TEST2 0x9808 + ++#define AR_PHY_TEST2_RX_OBS_SEL 0x3C00 ++#define AR_PHY_TEST2_RX_OBS_SEL_S 10 ++ + #define AR_PHY_TIMING2 0x9810 + #define AR_PHY_TIMING3 0x9814 + #define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 +@@ -390,6 +399,8 @@ + #define AR_PHY_RFBUS_GRANT 0x9C20 + #define AR_PHY_RFBUS_GRANT_EN 0x00000001 + ++#define AR_PHY_TST_ADC 0x9C24 ++ + #define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 + #define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 + diff --git a/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch new file mode 100644 index 0000000..6ca642a --- /dev/null +++ b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch @@ -0,0 +1,79 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -246,6 +246,19 @@ void ath9k_hw_get_channel_centers(struct + centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT); + } + ++static inline void ath9k_hw_disable_pll_lock_detect(struct ath_hw *ah) ++{ ++ /* On AR9330 and AR9340 devices, some PHY registers must be ++ * tuned to gain better stability/performance. These registers ++ * might be changed while doing wlan reset so the registers must ++ * be reprogrammed after each reset. ++ */ ++ REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, BIT(20)); ++ REG_RMW(ah, AR_PHY_USB_CTRL2, ++ (1 << 21) | (0xf << 22), ++ (1 << 21) | (0x3 << 22)); ++} ++ + /******************/ + /* Chip Revisions */ + /******************/ +@@ -1386,6 +1399,9 @@ static bool ath9k_hw_set_reset(struct at + if (AR_SREV_9100(ah)) + udelay(50); + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return true; + } + +@@ -1485,6 +1501,9 @@ static bool ath9k_hw_chip_reset(struct a + ar9003_hw_internal_regulator_apply(ah); + ath9k_hw_init_pll(ah, chan); + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return true; + } + +@@ -1786,8 +1805,14 @@ static int ath9k_hw_do_fastcc(struct ath + if (AR_SREV_9271(ah)) + ar9002_hw_load_ani_reg(ah, chan); + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return 0; + fail: ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return -EINVAL; + } + +@@ -2041,6 +2066,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st + ath9k_hw_set_radar_params(ah); + } + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return 0; + } + EXPORT_SYMBOL(ath9k_hw_reset); +--- a/drivers/net/wireless/ath/ath9k/phy.h ++++ b/drivers/net/wireless/ath/ath9k/phy.h +@@ -48,6 +48,9 @@ + #define AR_PHY_PLL_CONTROL 0x16180 + #define AR_PHY_PLL_MODE 0x16184 + ++#define AR_PHY_USB_CTRL1 0x16c84 ++#define AR_PHY_USB_CTRL2 0x16c88 ++ + enum ath9k_ant_div_comb_lna_conf { + ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, + ATH_ANT_DIV_COMB_LNA2, diff --git a/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch b/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch new file mode 100644 index 0000000..bc0aca6 --- /dev/null +++ b/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch @@ -0,0 +1,155 @@ +--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c +@@ -956,55 +956,6 @@ static bool ar5008_hw_ani_control_new(st + * on == 0 means more noise imm + */ + u32 on = param ? 1 : 0; +- /* +- * make register setting for default +- * (weak sig detect ON) come from INI file +- */ +- int m1ThreshLow = on ? +- aniState->iniDef.m1ThreshLow : m1ThreshLow_off; +- int m2ThreshLow = on ? +- aniState->iniDef.m2ThreshLow : m2ThreshLow_off; +- int m1Thresh = on ? +- aniState->iniDef.m1Thresh : m1Thresh_off; +- int m2Thresh = on ? +- aniState->iniDef.m2Thresh : m2Thresh_off; +- int m2CountThr = on ? +- aniState->iniDef.m2CountThr : m2CountThr_off; +- int m2CountThrLow = on ? +- aniState->iniDef.m2CountThrLow : m2CountThrLow_off; +- int m1ThreshLowExt = on ? +- aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off; +- int m2ThreshLowExt = on ? +- aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off; +- int m1ThreshExt = on ? +- aniState->iniDef.m1ThreshExt : m1ThreshExt_off; +- int m2ThreshExt = on ? +- aniState->iniDef.m2ThreshExt : m2ThreshExt_off; +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M1_THRESH_LOW, +- m1ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2_THRESH_LOW, +- m2ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M1_THRESH, m1Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2_THRESH, m2Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2COUNT_THR, m2CountThr); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, +- m2CountThrLow); +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -41,20 +41,6 @@ static const int cycpwrThr1_table[] = + /* level: 0 1 2 3 4 5 6 7 8 */ + { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */ + +-/* +- * register values to turn OFDM weak signal detection OFF +- */ +-static const int m1ThreshLow_off = 127; +-static const int m2ThreshLow_off = 127; +-static const int m1Thresh_off = 127; +-static const int m2Thresh_off = 127; +-static const int m2CountThr_off = 31; +-static const int m2CountThrLow_off = 63; +-static const int m1ThreshLowExt_off = 127; +-static const int m2ThreshLowExt_off = 127; +-static const int m1ThreshExt_off = 127; +-static const int m2ThreshExt_off = 127; +- + static const u8 ofdm2pwr[] = { + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_6_24, +@@ -1090,11 +1076,6 @@ static bool ar9003_hw_ani_control(struct + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *chan = ah->curchan; + struct ar5416AniState *aniState = &ah->ani; +- int m1ThreshLow, m2ThreshLow; +- int m1Thresh, m2Thresh; +- int m2CountThr, m2CountThrLow; +- int m1ThreshLowExt, m2ThreshLowExt; +- int m1ThreshExt, m2ThreshExt; + s32 value, value2; + + switch (cmd & ah->ani_function) { +@@ -1108,61 +1089,6 @@ static bool ar9003_hw_ani_control(struct + */ + u32 on = param ? 1 : 0; + +- if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) +- goto skip_ws_det; +- +- m1ThreshLow = on ? +- aniState->iniDef.m1ThreshLow : m1ThreshLow_off; +- m2ThreshLow = on ? +- aniState->iniDef.m2ThreshLow : m2ThreshLow_off; +- m1Thresh = on ? +- aniState->iniDef.m1Thresh : m1Thresh_off; +- m2Thresh = on ? +- aniState->iniDef.m2Thresh : m2Thresh_off; +- m2CountThr = on ? +- aniState->iniDef.m2CountThr : m2CountThr_off; +- m2CountThrLow = on ? +- aniState->iniDef.m2CountThrLow : m2CountThrLow_off; +- m1ThreshLowExt = on ? +- aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off; +- m2ThreshLowExt = on ? +- aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off; +- m1ThreshExt = on ? +- aniState->iniDef.m1ThreshExt : m1ThreshExt_off; +- m2ThreshExt = on ? +- aniState->iniDef.m2ThreshExt : m2ThreshExt_off; +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M1_THRESH_LOW, +- m1ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2_THRESH_LOW, +- m2ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M1_THRESH, +- m1Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2_THRESH, +- m2Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2COUNT_THR, +- m2CountThr); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, +- m2CountThrLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH_LOW, +- m1ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH_LOW, +- m2ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH, +- m1ThreshExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH, +- m2ThreshExt); +-skip_ws_det: + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); diff --git a/package/kernel/mac80211/patches/600-0001-rt2x00-rt2800lib-move-rt2800_drv_data-declaration-in.patch b/package/kernel/mac80211/patches/600-0001-rt2x00-rt2800lib-move-rt2800_drv_data-declaration-in.patch new file mode 100644 index 0000000..15863a6 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0001-rt2x00-rt2800lib-move-rt2800_drv_data-declaration-in.patch @@ -0,0 +1,66 @@ +From 7a69da907de668fb22a30ae218062d6f081864ea Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sat, 17 Aug 2013 19:31:41 +0200 +Subject: [PATCH] rt2x00: rt2800lib: move rt2800_drv_data declaration into + rt2800lib.h + +The rt2800_drv_data structure contains driver specific +information. Move the declaration into the rt2800lib.h +header which is a more logical place for it. Also fix +the comment style to avoid checkpatch warning. + +The patch contains no functional changes, it is in +preparation for the next patch. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- +Changes since v1: --- +--- + drivers/net/wireless/rt2x00/rt2800.h | 13 ------------- + drivers/net/wireless/rt2x00/rt2800lib.h | 11 +++++++++++ + 2 files changed, 11 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/rt2x00/rt2800lib.h +@@ -20,6 +20,20 @@ + #ifndef RT2800LIB_H + #define RT2800LIB_H + ++#include "rt2800.h" ++ ++/* RT2800 driver data structure */ ++struct rt2800_drv_data { ++ u8 calibration_bw20; ++ u8 calibration_bw40; ++ u8 bbp25; ++ u8 bbp26; ++ u8 txmixer_gain_24g; ++ u8 txmixer_gain_5g; ++ unsigned int tbtt_tick; ++ DECLARE_BITMAP(sta_ids, STA_IDS_SIZE); ++}; ++ + struct rt2800_ops { + void (*register_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value); +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -2969,18 +2969,4 @@ enum rt2800_eeprom_word { + #define WCID_END 222 + #define STA_IDS_SIZE (WCID_END - WCID_START + 2) + +-/* +- * RT2800 driver data structure +- */ +-struct rt2800_drv_data { +- u8 calibration_bw20; +- u8 calibration_bw40; +- u8 bbp25; +- u8 bbp26; +- u8 txmixer_gain_24g; +- u8 txmixer_gain_5g; +- unsigned int tbtt_tick; +- DECLARE_BITMAP(sta_ids, STA_IDS_SIZE); +-}; +- + #endif /* RT2800_H */ diff --git a/package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch b/package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch new file mode 100644 index 0000000..9165eec --- /dev/null +++ b/package/kernel/mac80211/patches/600-0002-rt2x00-rt2800lib-introduce-RT2800_HAS_HIGH_SHARED_ME.patch @@ -0,0 +1,80 @@ +From a7f268af31dddf763fe3dbe9cbf96ea77e0540e0 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sat, 17 Aug 2013 19:31:41 +0200 +Subject: [PATCH] rt2x00: rt2800lib: introduce RT2800_HAS_HIGH_SHARED_MEM flag + +Some chipsets have more than 16KB of shared memory. +Introduce a new rt2800 specific flag to indicate that +and add a helper function which helps to check the +presence of the new flag. + +Also enable the new flag for the RT3593 chipset which +has 24KB of shared memory. The flag can also be used +for other chipsets, but none of those has been tested +yet. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- +Changes since v1: + - don't enable the new flag for RT3071 and RT5592 +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++++ + drivers/net/wireless/rt2x00/rt2800lib.h | 13 +++++++++++++ + 2 files changed, 17 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7721,6 +7721,7 @@ static int rt2800_probe_rt(struct rt2x00 + + int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) + { ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + int retval; + u32 reg; + +@@ -7728,6 +7729,9 @@ int rt2800_probe_hw(struct rt2x00_dev *r + if (retval) + return retval; + ++ if (rt2x00_rt(rt2x00dev, RT3593)) ++ __set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags); ++ + /* + * Allocate eeprom data. + */ +--- a/drivers/net/wireless/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/rt2x00/rt2800lib.h +@@ -22,6 +22,10 @@ + + #include "rt2800.h" + ++enum rt2800_flag { ++ RT2800_HAS_HIGH_SHARED_MEM, ++}; ++ + /* RT2800 driver data structure */ + struct rt2800_drv_data { + u8 calibration_bw20; +@@ -32,6 +36,8 @@ struct rt2800_drv_data { + u8 txmixer_gain_5g; + unsigned int tbtt_tick; + DECLARE_BITMAP(sta_ids, STA_IDS_SIZE); ++ ++ unsigned long rt2800_flags; + }; + + struct rt2800_ops { +@@ -64,6 +70,13 @@ struct rt2800_ops { + __le32 *(*drv_get_txwi)(struct queue_entry *entry); + }; + ++static inline bool rt2800_has_high_shared_mem(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ return test_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags); ++} ++ + static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) diff --git a/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch b/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch new file mode 100644 index 0000000..5671515 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0003-rt2x00-rt2800-serialize-shared-memory-access.patch @@ -0,0 +1,531 @@ +From 250a1b520cd7fdc0df4fc3fedea9066913f49ecf Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sat, 17 Aug 2013 19:31:42 +0200 +Subject: [PATCH] rt2x00: rt2800: serialize shared memory access + +The shared memory of the rt2800 devices is accessible +through the register offset range between 0x4000 and +0x8000. The size of this range is 16KB only and on +devices which have more than 16KB of shared memory either +the low or the high part of the memory is accessible at a +time. + +Serialize all accesses to the shared memory by a mutex, +in order to avoid concurrent use of that. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- +Changes since v1: --- +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 55 +++++++++++++++++++++++++++++- + drivers/net/wireless/rt2x00/rt2800lib.h | 32 +++++++++++++++++ + drivers/net/wireless/rt2x00/rt2800mmio.c | 26 ++++++++++++++ + drivers/net/wireless/rt2x00/rt2800mmio.h | 4 +++ + drivers/net/wireless/rt2x00/rt2800pci.c | 14 ++++++++ + drivers/net/wireless/rt2x00/rt2800soc.c | 3 ++ + drivers/net/wireless/rt2x00/rt2800usb.c | 31 +++++++++++++++++ + 7 files changed, 164 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -451,11 +451,13 @@ void rt2800_mcu_request(struct rt2x00_de + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); + + reg = 0; + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +@@ -674,7 +676,9 @@ int rt2800_load_firmware(struct rt2x00_d + * Wait for device to stabilize. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); ++ rt2800_shared_mem_unlock(rt2x00dev); + if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) + break; + msleep(1); +@@ -694,10 +698,16 @@ int rt2800_load_firmware(struct rt2x00_d + /* + * Initialize firmware. + */ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); ++ rt2800_shared_mem_unlock(rt2x00dev); ++ + if (rt2x00_is_usb(rt2x00dev)) { ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0); ++ rt2800_shared_mem_unlock(rt2x00dev); ++ + rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); + } + msleep(1); +@@ -1035,8 +1045,10 @@ void rt2800_write_beacon(struct queue_en + + beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx); + ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, + entry->skb->len + padding_len); ++ rt2800_shared_mem_unlock(rt2x00dev); + __set_bit(ENTRY_BCN_ENABLED, &entry->flags); + + /* +@@ -1066,6 +1078,8 @@ static inline void rt2800_clear_beacon_r + + beacon_base = rt2800_hw_beacon_base(rt2x00dev, index); + ++ rt2800_shared_mem_lock(rt2x00dev); ++ + /* + * For the Beacon base registers we only need to clear + * the whole TXWI which (when set to 0) will invalidate +@@ -1073,6 +1087,8 @@ static inline void rt2800_clear_beacon_r + */ + for (i = 0; i < txwi_desc_size; i += sizeof(__le32)) + rt2800_register_write(rt2x00dev, beacon_base + i, 0); ++ ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + void rt2800_clear_beacon(struct queue_entry *entry) +@@ -1261,7 +1277,9 @@ static void rt2800_delete_wcid_attr(stru + { + u32 offset; + offset = MAC_WCID_ATTR_ENTRY(wcid); ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write(rt2x00dev, offset, 0); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev, +@@ -1274,11 +1292,13 @@ static void rt2800_config_wcid_attr_bssi + * The BSS Idx numbers is split in a main value of 3 bits, + * and a extended field for adding one additional bit to the value. + */ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7)); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT, + (bssidx & 0x8) >> 3); + rt2800_register_write(rt2x00dev, offset, reg); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev, +@@ -1291,6 +1311,7 @@ static void rt2800_config_wcid_attr_ciph + + offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); + ++ rt2800_shared_mem_lock(rt2x00dev); + if (crypto->cmd == SET_KEY) { + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, +@@ -1315,6 +1336,7 @@ static void rt2800_config_wcid_attr_ciph + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0); + rt2800_register_write(rt2x00dev, offset, reg); + } ++ rt2800_shared_mem_unlock(rt2x00dev); + + offset = MAC_IVEIV_ENTRY(key->hw_key_idx); + +@@ -1324,8 +1346,11 @@ static void rt2800_config_wcid_attr_ciph + (crypto->cipher == CIPHER_AES)) + iveiv_entry.iv[3] |= 0x20; + iveiv_entry.iv[3] |= key->keyidx << 6; ++ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_multiwrite(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, +@@ -1348,8 +1373,11 @@ int rt2800_config_shared_key(struct rt2x + sizeof(key_entry.rx_mic)); + + offset = SHARED_KEY_ENTRY(key->hw_key_idx); ++ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + /* +@@ -1364,10 +1392,12 @@ int rt2800_config_shared_key(struct rt2x + + offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); + ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2800_register_write(rt2x00dev, offset, reg); ++ rt2800_shared_mem_unlock(rt2x00dev); + + /* + * Update WCID information +@@ -1405,8 +1435,11 @@ int rt2800_config_pairwise_key(struct rt + sizeof(key_entry.rx_mic)); + + offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); ++ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + /* +@@ -4884,14 +4917,19 @@ static int rt2800_init_registers(struct + /* + * ASIC will keep garbage value after boot, clear encryption keys. + */ ++ rt2800_shared_mem_lock(rt2x00dev); + for (i = 0; i < 4; i++) + rt2800_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); ++ rt2800_shared_mem_unlock(rt2x00dev); + + for (i = 0; i < 256; i++) { + rt2800_config_wcid(rt2x00dev, NULL, i); + rt2800_delete_wcid_attr(rt2x00dev, i); ++ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + /* +@@ -5017,8 +5055,10 @@ static int rt2800_wait_bbp_ready(struct + * BBP was enabled after firmware was loaded, + * but we need to reactivate it now. + */ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); ++ rt2800_shared_mem_unlock(rt2x00dev); + msleep(1); + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { +@@ -6714,11 +6754,19 @@ int rt2800_enable_radio(struct rt2x00_de + /* + * Send signal during boot time to initialize firmware. + */ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); +- if (rt2x00_is_usb(rt2x00dev)) ++ rt2800_shared_mem_unlock(rt2x00dev); ++ ++ if (rt2x00_is_usb(rt2x00dev)) { ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0); ++ rt2800_shared_mem_unlock(rt2x00dev); ++ } ++ + rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); ++ + msleep(1); + + /* +@@ -7725,6 +7773,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r + int retval; + u32 reg; + ++ rt2800_shared_mem_init_lock(rt2x00dev); ++ + retval = rt2800_probe_rt(rt2x00dev); + if (retval) + return retval; +@@ -7808,8 +7858,11 @@ void rt2800_get_key_seq(struct ieee80211 + return; + + offset = MAC_IVEIV_ENTRY(key->hw_key_idx); ++ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2800_register_multiread(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); ++ rt2800_shared_mem_unlock(rt2x00dev); + + memcpy(&seq->tkip.iv16, &iveiv_entry.iv[0], 2); + memcpy(&seq->tkip.iv32, &iveiv_entry.iv[4], 4); +--- a/drivers/net/wireless/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/rt2x00/rt2800lib.h +@@ -38,6 +38,11 @@ struct rt2800_drv_data { + DECLARE_BITMAP(sta_ids, STA_IDS_SIZE); + + unsigned long rt2800_flags; ++ ++ union { ++ spinlock_t spin; ++ struct mutex mutex; ++ } shmem_lock; + }; + + struct rt2800_ops { +@@ -68,6 +73,10 @@ struct rt2800_ops { + const u8 *data, const size_t len); + int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev); + __le32 *(*drv_get_txwi)(struct queue_entry *entry); ++ ++ void (*shmem_init_lock)(struct rt2x00_dev *rt2x00dev); ++ void (*shmem_lock)(struct rt2x00_dev *rt2x00dev); ++ void (*shmem_unlock)(struct rt2x00_dev *rt2x00dev); + }; + + static inline bool rt2800_has_high_shared_mem(struct rt2x00_dev *rt2x00dev) +@@ -77,6 +86,29 @@ static inline bool rt2800_has_high_share + return test_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags); + } + ++static inline void rt2800_shared_mem_init_lock(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ rt2800ops->shmem_init_lock(rt2x00dev); ++} ++ ++static inline void rt2800_shared_mem_lock(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ if (rt2800_has_high_shared_mem(rt2x00dev)) ++ rt2800ops->shmem_lock(rt2x00dev); ++} ++ ++static inline void rt2800_shared_mem_unlock(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ if (rt2800_has_high_shared_mem(rt2x00dev)) ++ rt2800ops->shmem_unlock(rt2x00dev); ++} ++ + static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +--- a/drivers/net/wireless/rt2x00/rt2800mmio.c ++++ b/drivers/net/wireless/rt2x00/rt2800mmio.c +@@ -820,8 +820,10 @@ int rt2800mmio_init_registers(struct rt2 + rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); + rt2x00mmio_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); + rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); ++ rt2800_shared_mem_unlock(rt2x00dev); + + if (rt2x00_is_pcie(rt2x00dev) && + (rt2x00_rt(rt2x00dev, RT3090) || +@@ -865,6 +867,30 @@ int rt2800mmio_enable_radio(struct rt2x0 + } + EXPORT_SYMBOL_GPL(rt2800mmio_enable_radio); + ++void rt2800mmio_shmem_init_lock(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ spin_lock_init(&drv_data->shmem_lock.spin); ++} ++EXPORT_SYMBOL_GPL(rt2800mmio_shmem_init_lock); ++ ++void rt2800mmio_shmem_lock(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ spin_lock_bh(&drv_data->shmem_lock.spin); ++} ++EXPORT_SYMBOL_GPL(rt2800mmio_shmem_lock); ++ ++void rt2800mmio_shmem_unlock(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ spin_unlock_bh(&drv_data->shmem_lock.spin); ++} ++EXPORT_SYMBOL_GPL(rt2800mmio_shmem_unlock); ++ + MODULE_AUTHOR(DRV_PROJECT); + MODULE_VERSION(DRV_VERSION); + MODULE_DESCRIPTION("rt2800 MMIO library"); +--- a/drivers/net/wireless/rt2x00/rt2800mmio.h ++++ b/drivers/net/wireless/rt2x00/rt2800mmio.h +@@ -160,4 +160,8 @@ int rt2800mmio_init_registers(struct rt2 + /* Device state switch handlers. */ + int rt2800mmio_enable_radio(struct rt2x00_dev *rt2x00dev); + ++void rt2800mmio_shmem_init_lock(struct rt2x00_dev *rt2x00dev); ++void rt2800mmio_shmem_lock(struct rt2x00_dev *rt2x00dev); ++void rt2800mmio_shmem_unlock(struct rt2x00_dev *rt2x00dev); ++ + #endif /* RT2800MMIO_H */ +--- a/drivers/net/wireless/rt2x00/rt2800pci.c ++++ b/drivers/net/wireless/rt2x00/rt2800pci.c +@@ -69,7 +69,9 @@ static void rt2800pci_mcu_status(struct + return; + + for (i = 0; i < 200; i++) { ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); ++ rt2800_shared_mem_unlock(rt2x00dev); + + if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || + (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || +@@ -83,8 +85,10 @@ static void rt2800pci_mcu_status(struct + if (i == 200) + rt2x00_err(rt2x00dev, "MCU request failed, no response from hardware\n"); + ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ rt2800_shared_mem_unlock(rt2x00dev); + } + + static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +@@ -184,6 +188,8 @@ static int rt2800pci_write_firmware(stru + */ + reg = 0; + rt2x00_set_field32(®, PBF_SYS_CTRL_HOST_RAM_WRITE, 1); ++ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, reg); + + /* +@@ -197,6 +203,7 @@ static int rt2800pci_write_firmware(stru + + rt2x00mmio_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); ++ rt2800_shared_mem_unlock(rt2x00dev); + + return 0; + } +@@ -213,8 +220,10 @@ static int rt2800pci_enable_radio(struct + return retval; + + /* After resume MCU_BOOT_SIGNAL will trash these. */ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ rt2800_shared_mem_unlock(rt2x00dev); + + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, 0xff, 0x02); + rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF); +@@ -233,10 +242,12 @@ static int rt2800pci_set_state(struct rt + 0, 0x02); + rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP); + } else if (state == STATE_SLEEP) { ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, + 0xffffffff); + rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, + 0xffffffff); ++ rt2800_shared_mem_unlock(rt2x00dev); + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP, + 0xff, 0x01); + } +@@ -337,6 +348,9 @@ static const struct rt2800_ops rt2800pci + .drv_write_firmware = rt2800pci_write_firmware, + .drv_init_registers = rt2800mmio_init_registers, + .drv_get_txwi = rt2800mmio_get_txwi, ++ .shmem_init_lock = rt2800mmio_shmem_init_lock, ++ .shmem_lock = rt2800mmio_shmem_lock, ++ .shmem_unlock = rt2800mmio_shmem_unlock, + }; + + static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { +--- a/drivers/net/wireless/rt2x00/rt2800soc.c ++++ b/drivers/net/wireless/rt2x00/rt2800soc.c +@@ -176,6 +176,9 @@ static const struct rt2800_ops rt2800soc + .drv_write_firmware = rt2800soc_write_firmware, + .drv_init_registers = rt2800mmio_init_registers, + .drv_get_txwi = rt2800mmio_get_txwi, ++ .shmem_init_lock = rt2800mmio_shmem_init_lock, ++ .shmem_lock = rt2800mmio_shmem_lock, ++ .shmem_unlock = rt2800mmio_shmem_unlock, + }; + + static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = { +--- a/drivers/net/wireless/rt2x00/rt2800usb.c ++++ b/drivers/net/wireless/rt2x00/rt2800usb.c +@@ -51,6 +51,27 @@ static bool rt2800usb_hwcrypt_disabled(s + return modparam_nohwcrypt; + } + ++static void rt2800usb_shmem_init_lock(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ mutex_init(&drv_data->shmem_lock.mutex); ++} ++ ++static void rt2800usb_shmem_lock(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ mutex_lock(&drv_data->shmem_lock.mutex); ++} ++ ++static void rt2800usb_shmem_unlock(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ mutex_unlock(&drv_data->shmem_lock.mutex); ++} ++ + /* + * Queue handlers. + */ +@@ -299,8 +320,10 @@ static int rt2800usb_write_firmware(stru + data + offset, length); + } + ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); ++ rt2800_shared_mem_unlock(rt2x00dev); + + /* + * Send firmware request to device to load firmware, +@@ -315,7 +338,10 @@ static int rt2800usb_write_firmware(stru + } + + msleep(10); ++ ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); ++ rt2800_shared_mem_unlock(rt2x00dev); + + return 0; + } +@@ -333,8 +359,10 @@ static int rt2800usb_init_registers(stru + if (rt2800_wait_csr_ready(rt2x00dev)) + return -EBUSY; + ++ rt2800_shared_mem_lock(rt2x00dev); + rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); ++ rt2800_shared_mem_unlock(rt2x00dev); + + reg = 0; + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); +@@ -863,6 +891,9 @@ static const struct rt2800_ops rt2800usb + .drv_write_firmware = rt2800usb_write_firmware, + .drv_init_registers = rt2800usb_init_registers, + .drv_get_txwi = rt2800usb_get_txwi, ++ .shmem_init_lock = rt2800usb_shmem_init_lock, ++ .shmem_lock = rt2800usb_shmem_lock, ++ .shmem_unlock = rt2800usb_shmem_unlock, + }; + + static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { diff --git a/package/kernel/mac80211/patches/600-0004-rt2x00-rt2800lib-fix-beacon-generation-on-RT3593.patch b/package/kernel/mac80211/patches/600-0004-rt2x00-rt2800lib-fix-beacon-generation-on-RT3593.patch new file mode 100644 index 0000000..b8c1914 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0004-rt2x00-rt2800lib-fix-beacon-generation-on-RT3593.patch @@ -0,0 +1,131 @@ +From dcfe3dd46242050f100162dce2bcad24d2c942c6 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sat, 17 Aug 2013 19:31:42 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix beacon generation on RT3593 + +On the RT3593 chipset, the beacon registers are located +in the high 8KB part of the shared memory. + +The high part of the shared memory is only accessible +if it is explicitly selected. Add a helper function +in order to be able to control the SHR_MSEL bit in +the PBF_SYS_CTRL register. Also add a few more helper +functions and use those to select the correct part of +the shared memory before and after accessing the beacon +registers. + +The base addresses of the beacon registers are also +different from the actually used values, so fix the +'rt2800_hw_beacon_base' function to return the correct +values. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- +Changes since v1: --- +--- + drivers/net/wireless/rt2x00/rt2800.h | 3 +++ + drivers/net/wireless/rt2x00/rt2800lib.c | 44 +++++++++++++++++++++++++++++++ + 2 files changed, 47 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -574,6 +574,7 @@ + #define PBF_SYS_CTRL 0x0400 + #define PBF_SYS_CTRL_READY FIELD32(0x00000080) + #define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) ++#define PBF_SYS_CTRL_SHR_MSEL FIELD32(0x00080000) + + /* + * HOST-MCU shared memory +@@ -2026,6 +2027,8 @@ struct mac_iveiv_entry { + (((__index) < 6) ? (HW_BEACON_BASE4 + ((__index - 4) * 0x0200)) : \ + (HW_BEACON_BASE6 - ((__index - 6) * 0x0200)))) + ++#define HW_BEACON_BASE_HIGH(__index) (0x4000 + (__index) * 512) ++ + #define BEACON_BASE_TO_OFFSET(_base) (((_base) - 0x4000) / 64) + + /* +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -82,6 +82,39 @@ static inline bool rt2800_is_305x_soc(st + return false; + } + ++static inline void rt2800_shared_mem_select(struct rt2x00_dev *rt2x00dev, ++ bool high) ++{ ++ u32 reg; ++ ++ if (WARN_ON_ONCE(!rt2800_has_high_shared_mem(rt2x00dev))) ++ return; ++ ++ rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); ++ rt2x00_set_field32(®, PBF_SYS_CTRL_SHR_MSEL, high); ++ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg); ++} ++ ++static inline bool rt2800_beacon_uses_high_mem(struct rt2x00_dev *rt2x00dev) ++{ ++ if (rt2x00_rt(rt2x00dev, RT3593)) ++ return true; ++ ++ return false; ++} ++ ++static inline void rt2800_select_beacon_mem(struct rt2x00_dev *rt2x00dev) ++{ ++ if (rt2800_beacon_uses_high_mem(rt2x00dev)) ++ rt2800_shared_mem_select(rt2x00dev, true); ++} ++ ++static inline void rt2800_deselect_beacon_mem(struct rt2x00_dev *rt2x00dev) ++{ ++ if (rt2800_beacon_uses_high_mem(rt2x00dev)) ++ rt2800_shared_mem_select(rt2x00dev, false); ++} ++ + static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) + { +@@ -948,6 +981,9 @@ EXPORT_SYMBOL_GPL(rt2800_txdone_entry); + static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, + unsigned int index) + { ++ if (rt2x00_rt(rt2x00dev, RT3593)) ++ return HW_BEACON_BASE_HIGH(index); ++ + return HW_BEACON_BASE(index); + } + +@@ -1046,8 +1082,12 @@ void rt2800_write_beacon(struct queue_en + beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx); + + rt2800_shared_mem_lock(rt2x00dev); ++ ++ rt2800_select_beacon_mem(rt2x00dev); + rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, + entry->skb->len + padding_len); ++ rt2800_deselect_beacon_mem(rt2x00dev); ++ + rt2800_shared_mem_unlock(rt2x00dev); + __set_bit(ENTRY_BCN_ENABLED, &entry->flags); + +@@ -1080,6 +1120,8 @@ static inline void rt2800_clear_beacon_r + + rt2800_shared_mem_lock(rt2x00dev); + ++ rt2800_select_beacon_mem(rt2x00dev); ++ + /* + * For the Beacon base registers we only need to clear + * the whole TXWI which (when set to 0) will invalidate +@@ -1088,6 +1130,8 @@ static inline void rt2800_clear_beacon_r + for (i = 0; i < txwi_desc_size; i += sizeof(__le32)) + rt2800_register_write(rt2x00dev, beacon_base + i, 0); + ++ rt2800_deselect_beacon_mem(rt2x00dev); ++ + rt2800_shared_mem_unlock(rt2x00dev); + } + diff --git a/package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch b/package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch new file mode 100644 index 0000000..d04998a --- /dev/null +++ b/package/kernel/mac80211/patches/600-0005-rt2x00-rt2800lib-add-hw_beacon_count-field-to-struct.patch @@ -0,0 +1,62 @@ +From a058825fa7b53fab3b003d8928b60e5b686b3421 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 4 Aug 2013 14:36:11 +0200 +Subject: [PATCH] rt2x00: rt2800lib: add hw_beacon_count field to struct + rt2800_drv_data + +Some chipsets can handle more than 8 beacons at once. +Add a new field to the rt2800_drv_data structure which +will hold the number of supported beacons of the given +chipset. + +Update the rt2x00_init_registers function to get the +beacon count from the new field instead of using a +hardcoded value. + +In order to keep the current behaviour, initialize the +new field with the actually used value. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 5 ++++- + drivers/net/wireless/rt2x00/rt2800lib.h | 1 + + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -4614,6 +4614,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner); + */ + static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) + { ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + u32 reg; + u16 eeprom; + unsigned int i; +@@ -4979,7 +4980,7 @@ static int rt2800_init_registers(struct + /* + * Clear all beacons + */ +- for (i = 0; i < 8; i++) ++ for (i = 0; i < drv_data->hw_beacon_count; i++) + rt2800_clear_beacon_register(rt2x00dev, i); + + if (rt2x00_is_usb(rt2x00dev)) { +@@ -7826,6 +7827,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r + if (rt2x00_rt(rt2x00dev, RT3593)) + __set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags); + ++ drv_data->hw_beacon_count = 8; ++ + /* + * Allocate eeprom data. + */ +--- a/drivers/net/wireless/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/rt2x00/rt2800lib.h +@@ -35,6 +35,7 @@ struct rt2800_drv_data { + u8 txmixer_gain_24g; + u8 txmixer_gain_5g; + unsigned int tbtt_tick; ++ unsigned int hw_beacon_count; + DECLARE_BITMAP(sta_ids, STA_IDS_SIZE); + + unsigned long rt2800_flags; diff --git a/package/kernel/mac80211/patches/600-0006-rt2x00-rt2800lib-init-additional-beacon-offset-regis.patch b/package/kernel/mac80211/patches/600-0006-rt2x00-rt2800lib-init-additional-beacon-offset-regis.patch new file mode 100644 index 0000000..f5231f0 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0006-rt2x00-rt2800lib-init-additional-beacon-offset-regis.patch @@ -0,0 +1,67 @@ +From 1bfa43ca8f30be53ce4fa79cfc3e219642a812b6 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Mon, 2 Sep 2013 10:58:32 +0200 +Subject: [PATCH] rt2x00: rt2800lib: init additional beacon offset registers + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800.h | 14 ++++++++++++++ + drivers/net/wireless/rt2x00/rt2800lib.c | 24 ++++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -629,6 +629,20 @@ + */ + #define PBF_DBG 0x043c + ++/* BCN_OFFSET2 */ ++#define BCN_OFFSET2 0x0444 ++#define BCN_OFFSET2_BCN8 FIELD32(0x000000ff) ++#define BCN_OFFSET2_BCN9 FIELD32(0x0000ff00) ++#define BCN_OFFSET2_BCN10 FIELD32(0x00ff0000) ++#define BCN_OFFSET2_BCN11 FIELD32(0xff000000) ++ ++/* BCN_OFFSET3 */ ++#define BCN_OFFSET3 0x0448 ++#define BCN_OFFSET3_BCN12 FIELD32(0x000000ff) ++#define BCN_OFFSET3_BCN13 FIELD32(0x0000ff00) ++#define BCN_OFFSET3_BCN14 FIELD32(0x00ff0000) ++#define BCN_OFFSET3_BCN15 FIELD32(0xff000000) ++ + /* + * RF registers + */ +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -4626,6 +4626,30 @@ static int rt2800_init_registers(struct + if (ret) + return ret; + ++ if (drv_data->hw_beacon_count == 16) { ++ rt2800_register_read(rt2x00dev, BCN_OFFSET2, ®); ++ rt2x00_set_field32(®, BCN_OFFSET2_BCN8, ++ rt2800_get_beacon_offset(rt2x00dev, 8)); ++ rt2x00_set_field32(®, BCN_OFFSET2_BCN9, ++ rt2800_get_beacon_offset(rt2x00dev, 9)); ++ rt2x00_set_field32(®, BCN_OFFSET2_BCN10, ++ rt2800_get_beacon_offset(rt2x00dev, 10)); ++ rt2x00_set_field32(®, BCN_OFFSET2_BCN11, ++ rt2800_get_beacon_offset(rt2x00dev, 11)); ++ rt2800_register_write(rt2x00dev, BCN_OFFSET2, reg); ++ ++ rt2800_register_read(rt2x00dev, BCN_OFFSET3, ®); ++ rt2x00_set_field32(®, BCN_OFFSET3_BCN12, ++ rt2800_get_beacon_offset(rt2x00dev, 12)); ++ rt2x00_set_field32(®, BCN_OFFSET3_BCN13, ++ rt2800_get_beacon_offset(rt2x00dev, 13)); ++ rt2x00_set_field32(®, BCN_OFFSET3_BCN14, ++ rt2800_get_beacon_offset(rt2x00dev, 14)); ++ rt2x00_set_field32(®, BCN_OFFSET3_BCN15, ++ rt2800_get_beacon_offset(rt2x00dev, 15)); ++ rt2800_register_write(rt2x00dev, BCN_OFFSET3, reg); ++ } ++ + rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); + rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + diff --git a/package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch b/package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch new file mode 100644 index 0000000..4b21eae --- /dev/null +++ b/package/kernel/mac80211/patches/600-0007-rt2x00-rt2800lib-fix-max-supported-beacon-count-for-.patch @@ -0,0 +1,24 @@ +From 9bea8b61f6025cd633bd5ac71be258620b49bcb3 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Mon, 2 Sep 2013 11:00:06 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix max supported beacon count for RT3593 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7851,7 +7851,10 @@ int rt2800_probe_hw(struct rt2x00_dev *r + if (rt2x00_rt(rt2x00dev, RT3593)) + __set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags); + +- drv_data->hw_beacon_count = 8; ++ if (rt2x00_rt(rt2x00dev, RT3593)) ++ drv_data->hw_beacon_count = 16; ++ else ++ drv_data->hw_beacon_count = 8; + + /* + * Allocate eeprom data. diff --git a/package/kernel/mac80211/patches/600-0008-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch b/package/kernel/mac80211/patches/600-0008-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch new file mode 100644 index 0000000..8a10c6e --- /dev/null +++ b/package/kernel/mac80211/patches/600-0008-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch @@ -0,0 +1,30 @@ +From 91094ed065f7794886b4a5490fd6de942f036bb4 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:26 +0100 +Subject: [PATCH] rt2x00: allow to build rt2800soc module for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/Kconfig ++++ b/drivers/net/wireless/rt2x00/Kconfig +@@ -210,7 +210,7 @@ endif + config RT2800SOC + tristate "Ralink WiSoC support" + depends on m +- depends on SOC_RT288X || SOC_RT305X ++ depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 + select RT2X00_LIB_SOC + select RT2X00_LIB_MMIO + select RT2X00_LIB_CRYPTO +@@ -245,7 +245,7 @@ config RT2X00_LIB_PCI + + config RT2X00_LIB_SOC + tristate "RT2x00 SoC support" +- depends on SOC_RT288X || SOC_RT305X ++ depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 + depends on m + select RT2X00_LIB + diff --git a/package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch b/package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch new file mode 100644 index 0000000..e77cd86 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0009-rt2x00-rt2800lib-enable-support-for-RT3883.patch @@ -0,0 +1,20 @@ +From 4f16582c93a71eba9d389e0f0a8aa9099a9587cd Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:26 +0100 +Subject: [PATCH] rt2x00: rt2800lib: enable support for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7821,6 +7821,7 @@ static int rt2800_probe_rt(struct rt2x00 + case RT3390: + case RT3572: + case RT3593: ++ case RT3883: + case RT5390: + case RT5392: + case RT5592: diff --git a/package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch b/package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch new file mode 100644 index 0000000..780c1dd --- /dev/null +++ b/package/kernel/mac80211/patches/600-0010-rt2x00-rt2800lib-add-rf_vals-for-RF3853.patch @@ -0,0 +1,112 @@ +From ecb394ccf248d8652c463133c4f404458a57a9c1 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:26 +0100 +Subject: [PATCH] rt2x00: rt2800lib: add rf_vals for RF3853 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800.h | 4 +- + drivers/net/wireless/rt2x00/rt2800lib.c | 65 +++++++++++++++++++++++++++++++ + 2 files changed, 68 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -48,7 +48,8 @@ + * RF2853 2.4G/5G 3T3R + * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390) + * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392) +- * RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662) ++ * RF3053 2.4G/5G 3T3R(RT3563/RT3573/RT3593) ++ * RF3853 2.4G/5G 3T3R(RT3883/RT3662) + * RF5592 2.4G/5G 2T2R + * RF3070 2.4G 1T1R + * RF5360 2.4G 1T1R +@@ -72,6 +73,7 @@ + #define RF5592 0x000f + #define RF3070 0x3070 + #define RF3290 0x3290 ++#define RF3853 0x3853 + #define RF5360 0x5360 + #define RF5362 0x5362 + #define RF5370 0x5370 +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7441,6 +7441,66 @@ static const struct rf_channel rf_vals_3 + {173, 0x61, 0, 9}, + }; + ++static const struct rf_channel rf_vals_3853[] = { ++ {1, 241, 6, 2}, ++ {2, 241, 6, 7}, ++ {3, 242, 6, 2}, ++ {4, 242, 6, 7}, ++ {5, 243, 6, 2}, ++ {6, 243, 6, 7}, ++ {7, 244, 6, 2}, ++ {8, 244, 6, 7}, ++ {9, 245, 6, 2}, ++ {10, 245, 6, 7}, ++ {11, 246, 6, 2}, ++ {12, 246, 6, 7}, ++ {13, 247, 6, 2}, ++ {14, 248, 6, 4}, ++ ++ {36, 0x56, 8, 4}, ++ {38, 0x56, 8, 6}, ++ {40, 0x56, 8, 8}, ++ {44, 0x57, 8, 0}, ++ {46, 0x57, 8, 2}, ++ {48, 0x57, 8, 4}, ++ {52, 0x57, 8, 8}, ++ {54, 0x57, 8, 10}, ++ {56, 0x58, 8, 0}, ++ {60, 0x58, 8, 4}, ++ {62, 0x58, 8, 6}, ++ {64, 0x58, 8, 8}, ++ ++ {100, 0x5b, 8, 8}, ++ {102, 0x5b, 8, 10}, ++ {104, 0x5c, 8, 0}, ++ {108, 0x5c, 8, 4}, ++ {110, 0x5c, 8, 6}, ++ {112, 0x5c, 8, 8}, ++ {114, 0x5c, 8, 10}, ++ {116, 0x5d, 8, 0}, ++ {118, 0x5d, 8, 2}, ++ {120, 0x5d, 8, 4}, ++ {124, 0x5d, 8, 8}, ++ {126, 0x5d, 8, 10}, ++ {128, 0x5e, 8, 0}, ++ {132, 0x5e, 8, 4}, ++ {134, 0x5e, 8, 6}, ++ {136, 0x5e, 8, 8}, ++ {140, 0x5f, 8, 0}, ++ ++ {149, 0x5f, 8, 9}, ++ {151, 0x5f, 8, 11}, ++ {153, 0x60, 8, 1}, ++ {157, 0x60, 8, 5}, ++ {159, 0x60, 8, 7}, ++ {161, 0x60, 8, 9}, ++ {165, 0x61, 8, 1}, ++ {167, 0x61, 8, 3}, ++ {169, 0x61, 8, 5}, ++ {171, 0x61, 8, 7}, ++ {173, 0x61, 8, 9}, ++}; ++ + static const struct rf_channel rf_vals_5592_xtal20[] = { + /* Channel, N, K, mod, R */ + {1, 482, 4, 10, 3}, +@@ -7668,6 +7728,11 @@ static int rt2800_probe_hw_mode(struct r + spec->channels = rf_vals_3x; + break; + ++ case RF3853: ++ spec->num_channels = ARRAY_SIZE(rf_vals_3853); ++ spec->channels = rf_vals_3853; ++ break; ++ + case RF5592: + rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX, ®); + if (rt2x00_get_field32(reg, MAC_DEBUG_INDEX_XTAL)) { diff --git a/package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch b/package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch new file mode 100644 index 0000000..858dece --- /dev/null +++ b/package/kernel/mac80211/patches/600-0011-rt2x00-rt2800lib-enable-VCO-calibration-for-RF3853.patch @@ -0,0 +1,28 @@ +From f8e3fcf18e1f2d7f9e6a9680c5452da090f33d88 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Thu, 1 Aug 2013 14:40:44 +0200 +Subject: [PATCH] rt2x00: rt2800lib: enable VCO calibration for RF3853 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -4378,6 +4378,7 @@ void rt2800_vco_calibration(struct rt2x0 + case RF3053: + case RF3070: + case RF3290: ++ case RF3853: + case RF5360: + case RF5362: + case RF5370: +@@ -7847,6 +7848,7 @@ static int rt2800_probe_hw_mode(struct r + case RF3053: + case RF3070: + case RF3290: ++ case RF3853: + case RF5360: + case RF5362: + case RF5370: diff --git a/package/kernel/mac80211/patches/600-0012-rt2x00-rt2800lib-add-channel-configuration-function-.patch b/package/kernel/mac80211/patches/600-0012-rt2x00-rt2800lib-add-channel-configuration-function-.patch new file mode 100644 index 0000000..ed82e44 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0012-rt2x00-rt2800lib-add-channel-configuration-function-.patch @@ -0,0 +1,235 @@ +From 6e3a17190815c6aa4dc53c2cfe9125fb1154f187 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:27 +0100 +Subject: [PATCH] rt2x00: rt2800lib: add channel configuration function for + RF3853 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 208 +++++++++++++++++++++++++++++++ + 1 file changed, 208 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -2625,6 +2625,211 @@ static void rt2800_config_channel_rf3053 + } + } + ++static void rt2800_config_channel_rf3853(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_conf *conf, ++ struct rf_channel *rf, ++ struct channel_info *info) ++{ ++ u8 rfcsr; ++ u8 bbp; ++ u8 pwr1, pwr2, pwr3; ++ ++ const bool txbf_enabled = false; /* TODO */ ++ ++ /* TODO: add band selection */ ++ ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 6, 0x40); ++ else if (rf->channel < 132) ++ rt2800_rfcsr_write(rt2x00dev, 6, 0x80); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 6, 0x40); ++ ++ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); ++ rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); ++ ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x46); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x48); ++ ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 12, 0x1a); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 12, 0x52); ++ ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x12); ++ ++ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); ++ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); ++ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); ++ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); ++ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); ++ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); ++ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0); ++ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); ++ rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); ++ ++ switch (rt2x00dev->default_ant.tx_chain_num) { ++ case 3: ++ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); ++ /* fallthrough */ ++ case 2: ++ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); ++ /* fallthrough */ ++ case 1: ++ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); ++ break; ++ } ++ ++ switch (rt2x00dev->default_ant.rx_chain_num) { ++ case 3: ++ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); ++ /* fallthrough */ ++ case 2: ++ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); ++ /* fallthrough */ ++ case 1: ++ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); ++ break; ++ } ++ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); ++ ++ rt2800_adjust_freq_offset(rt2x00dev); ++ ++ rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); ++ if (!conf_is_ht40(conf)) ++ rfcsr &= ~(0x06); ++ else ++ rfcsr |= 0x06; ++ rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); ++ ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 31, 0xa0); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 31, 0x80); ++ ++ if (conf_is_ht40(conf)) ++ rt2800_rfcsr_write(rt2x00dev, 32, 0x80); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 32, 0xd8); ++ ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 34, 0x3c); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 34, 0x20); ++ ++ /* loopback RF_BS */ ++ rt2800_rfcsr_read(rt2x00dev, 36, &rfcsr); ++ if (rf->channel <= 14) ++ rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 1); ++ else ++ rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 0); ++ rt2800_rfcsr_write(rt2x00dev, 36, rfcsr); ++ ++ if (rf->channel <= 14) ++ rfcsr = 0x23; ++ else if (rf->channel < 100) ++ rfcsr = 0x36; ++ else if (rf->channel < 132) ++ rfcsr = 0x32; ++ else ++ rfcsr = 0x30; ++ ++ if (txbf_enabled) ++ rfcsr |= 0x40; ++ ++ rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); ++ ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 44, 0x93); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 44, 0x9b); ++ ++ if (rf->channel <= 14) ++ rfcsr = 0xbb; ++ else if (rf->channel < 100) ++ rfcsr = 0xeb; ++ else if (rf->channel < 132) ++ rfcsr = 0xb3; ++ else ++ rfcsr = 0x9b; ++ rt2800_rfcsr_write(rt2x00dev, 45, rfcsr); ++ ++ if (rf->channel <= 14) ++ rfcsr = 0x8e; ++ else ++ rfcsr = 0x8a; ++ ++ if (txbf_enabled) ++ rfcsr |= 0x20; ++ ++ rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); ++ ++ rt2800_rfcsr_write(rt2x00dev, 50, 0x86); ++ ++ rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 51, 0x75); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 51, 0x51); ++ ++ rt2800_rfcsr_read(rt2x00dev, 52, &rfcsr); ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 52, 0x45); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 52, 0x05); ++ ++ if (rf->channel <= 14) { ++ pwr1 = info->default_power1 & 0x1f; ++ pwr2 = info->default_power2 & 0x1f; ++ pwr3 = info->default_power3 & 0x1f; ++ } else { ++ pwr1 = 0x48 | ((info->default_power1 & 0x18) << 1) | ++ (info->default_power1 & 0x7); ++ pwr2 = 0x48 | ((info->default_power2 & 0x18) << 1) | ++ (info->default_power2 & 0x7); ++ pwr3 = 0x48 | ((info->default_power3 & 0x18) << 1) | ++ (info->default_power3 & 0x7); ++ } ++ ++ rt2800_rfcsr_write(rt2x00dev, 53, pwr1); ++ rt2800_rfcsr_write(rt2x00dev, 54, pwr2); ++ rt2800_rfcsr_write(rt2x00dev, 55, pwr3); ++ ++ rt2x00_dbg(rt2x00dev, "Channel:%d, pwr1:%02x, pwr2:%02x, pwr3:%02x\n", ++ rf->channel, pwr1, pwr2, pwr3); ++ ++ bbp = (info->default_power1 >> 5) | ++ ((info->default_power2 & 0xe0) >> 1); ++ rt2800_bbp_write(rt2x00dev, 109, bbp); ++ ++ rt2800_bbp_read(rt2x00dev, 110, &bbp); ++ bbp &= 0x0f; ++ bbp |= (info->default_power3 & 0xe0) >> 1; ++ rt2800_bbp_write(rt2x00dev, 110, bbp); ++ ++ rt2800_rfcsr_read(rt2x00dev, 57, &rfcsr); ++ if (rf->channel <= 14) ++ rt2800_rfcsr_write(rt2x00dev, 57, 0x6e); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 57, 0x3e); ++ ++ /* Enable RF tuning */ ++ rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); ++ rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); ++ rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); ++ ++ udelay(2000); ++ ++ rt2800_bbp_read(rt2x00dev, 49, &bbp); ++ /* clear update flag */ ++ rt2800_bbp_write(rt2x00dev, 49, bbp & 0xfe); ++ rt2800_bbp_write(rt2x00dev, 49, bbp); ++ ++ /* TODO: add calibration for TxBF */ ++} ++ + #define POWER_BOUND 0x27 + #define POWER_BOUND_5G 0x2b + +@@ -3237,6 +3442,9 @@ static void rt2800_config_channel(struct + case RF3322: + rt2800_config_channel_rf3322(rt2x00dev, conf, rf, info); + break; ++ case RF3853: ++ rt2800_config_channel_rf3853(rt2x00dev, conf, rf, info); ++ break; + case RF3070: + case RF5360: + case RF5362: diff --git a/package/kernel/mac80211/patches/600-0013-rt2x00-rt2800lib-enable-RF3853-support.patch b/package/kernel/mac80211/patches/600-0013-rt2x00-rt2800lib-enable-RF3853-support.patch new file mode 100644 index 0000000..33cbc4c --- /dev/null +++ b/package/kernel/mac80211/patches/600-0013-rt2x00-rt2800lib-enable-RF3853-support.patch @@ -0,0 +1,20 @@ +From afd38ae82226551bf879b6c7c4b620c271fee9d2 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Thu, 1 Aug 2013 14:42:05 +0200 +Subject: [PATCH] rt2x00: rt2800lib: enable RF3853 support + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7406,6 +7406,7 @@ static int rt2800_init_eeprom(struct rt2 + case RF3290: + case RF3320: + case RF3322: ++ case RF3853: + case RF5360: + case RF5362: + case RF5370: diff --git a/package/kernel/mac80211/patches/600-0014-rt2x00-rt2800lib-add-MAC-register-initialization-for.patch b/package/kernel/mac80211/patches/600-0014-rt2x00-rt2800lib-add-MAC-register-initialization-for.patch new file mode 100644 index 0000000..c3a4798 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0014-rt2x00-rt2800lib-add-MAC-register-initialization-for.patch @@ -0,0 +1,77 @@ +From 0094872a5e8e4664c6ea1b2dfa487063d39ae363 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:26 +0100 +Subject: [PATCH] rt2x00: rt2800lib: add MAC register initialization for + RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800.h | 14 ++++++++++++++ + drivers/net/wireless/rt2x00/rt2800lib.c | 19 ++++++++++++++++--- + 2 files changed, 30 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -1588,6 +1588,20 @@ + #define TX_PWR_CFG_9_STBC7_CH2 FIELD32(0x00000f00) + + /* ++ * TX_TXBF_CFG: ++ */ ++#define TX_TXBF_CFG_0 0x138c ++#define TX_TXBF_CFG_1 0x13a4 ++#define TX_TXBF_CFG_2 0x13a8 ++#define TX_TXBF_CFG_3 0x13ac ++ ++/* ++ * TX_FBK_CFG_3S: ++ */ ++#define TX_FBK_CFG_3S_0 0x13c4 ++#define TX_FBK_CFG_3S_1 0x13c8 ++ ++/* + * RX_FILTER_CFG: RX configuration register. + */ + #define RX_FILTER_CFG 0x1400 +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -4981,6 +4981,12 @@ static int rt2800_init_registers(struct + rt2800_register_write(rt2x00dev, TX_SW_CFG2, + 0x00000000); + } ++ } else if (rt2x00_rt(rt2x00dev, RT3883)) { ++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00040000); ++ rt2800_register_write(rt2x00dev, TX_TXBF_CFG_0, 0x8000fc21); ++ rt2800_register_write(rt2x00dev, TX_TXBF_CFG_3, 0x00009c40); + } else if (rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392) || + rt2x00_rt(rt2x00dev, RT5592)) { +@@ -5011,9 +5017,11 @@ static int rt2800_init_registers(struct + + rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); +- if (rt2x00_rt_rev_gte(rt2x00dev, RT2872, REV_RT2872E) || +- rt2x00_rt(rt2x00dev, RT2883) || +- rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070E)) ++ if (rt2x00_rt(rt2x00dev, RT3883)) ++ rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 3); ++ else if (rt2x00_rt_rev_gte(rt2x00dev, RT2872, REV_RT2872E) || ++ rt2x00_rt(rt2x00dev, RT2883) || ++ rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070E)) + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); + else + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); +@@ -5166,6 +5174,11 @@ static int rt2800_init_registers(struct + reg = rt2x00_rt(rt2x00dev, RT5592) ? 0x00000082 : 0x00000002; + rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, reg); + ++ if (rt2x00_rt(rt2x00dev, RT3883)) { ++ rt2800_register_write(rt2x00dev, TX_FBK_CFG_3S_0, 0x12111008); ++ rt2800_register_write(rt2x00dev, TX_FBK_CFG_3S_1, 0x16151413); ++ } ++ + rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, diff --git a/package/kernel/mac80211/patches/600-0015-rt2x00-rt2800soc-fix-rt2800soc_disable_radio-for-RT3.patch b/package/kernel/mac80211/patches/600-0015-rt2x00-rt2800soc-fix-rt2800soc_disable_radio-for-RT3.patch new file mode 100644 index 0000000..837c025 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0015-rt2x00-rt2800soc-fix-rt2800soc_disable_radio-for-RT3.patch @@ -0,0 +1,30 @@ +From 6c2d32478159fffff0b85abb6817a21bb2338231 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:27 +0100 +Subject: [PATCH] rt2x00: rt2800soc: fix rt2800soc_disable_radio for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800soc.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800soc.c ++++ b/drivers/net/wireless/rt2x00/rt2800soc.c +@@ -51,9 +51,16 @@ static bool rt2800soc_hwcrypt_disabled(s + + static void rt2800soc_disable_radio(struct rt2x00_dev *rt2x00dev) + { ++ u32 reg; ++ + rt2800_disable_radio(rt2x00dev); + rt2x00mmio_register_write(rt2x00dev, PWR_PIN_CFG, 0); +- rt2x00mmio_register_write(rt2x00dev, TX_PIN_CFG, 0); ++ ++ reg = 0; ++ if (rt2x00_rt(rt2x00dev, RT3883)) ++ rt2x00_set_field32(®, TX_PIN_CFG_RFTR_EN, 1); ++ ++ rt2x00mmio_register_write(rt2x00dev, TX_PIN_CFG, reg); + } + + static int rt2800soc_set_device_state(struct rt2x00_dev *rt2x00dev, diff --git a/package/kernel/mac80211/patches/600-0016-rt2x00-rt2800lib-add-BBP-register-initialization-for.patch b/package/kernel/mac80211/patches/600-0016-rt2x00-rt2800lib-add-BBP-register-initialization-for.patch new file mode 100644 index 0000000..e647777 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0016-rt2x00-rt2800lib-add-BBP-register-initialization-for.patch @@ -0,0 +1,71 @@ +From 84833056aa7dd25f5b097e31c78f2a0914c5160c Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:26 +0100 +Subject: [PATCH] rt2x00: rt2800lib: add BBP register initialization for + RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 44 +++++++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -5784,6 +5784,47 @@ static void rt2800_init_bbp_3593(struct + rt2800_bbp_write(rt2x00dev, 103, 0xc0); + } + ++static void rt2800_init_bbp_3883(struct rt2x00_dev *rt2x00dev) ++{ ++ rt2800_init_bbp_early(rt2x00dev); ++ ++ rt2800_bbp_write(rt2x00dev, 4, 0x50); ++ rt2800_bbp_write(rt2x00dev, 47, 0x48); ++ ++ rt2800_bbp_write(rt2x00dev, 86, 0x46); ++ rt2800_bbp_write(rt2x00dev, 88, 0x90); ++ ++ rt2800_bbp_write(rt2x00dev, 92, 0x02); ++ ++ rt2800_bbp_write(rt2x00dev, 103, 0xc0); ++ rt2800_bbp_write(rt2x00dev, 104, 0x92); ++ rt2800_bbp_write(rt2x00dev, 105, 0x34); ++ rt2800_bbp_write(rt2x00dev, 106, 0x12); ++ rt2800_bbp_write(rt2x00dev, 120, 0x50); ++ rt2800_bbp_write(rt2x00dev, 137, 0x0f); ++ rt2800_bbp_write(rt2x00dev, 163, 0x9d); ++ ++ /* 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); ++} ++ + static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) + { + int ant, div_mode; +@@ -6002,6 +6043,9 @@ static void rt2800_init_bbp(struct rt2x0 + case RT3593: + rt2800_init_bbp_3593(rt2x00dev); + return; ++ case RT3883: ++ rt2800_init_bbp_3883(rt2x00dev); ++ return; + case RT5390: + case RT5392: + rt2800_init_bbp_53xx(rt2x00dev); diff --git a/package/kernel/mac80211/patches/600-0017-rt2x00-rt2800lib-add-RFCSR-initialization-for-RT3883.patch b/package/kernel/mac80211/patches/600-0017-rt2x00-rt2800lib-add-RFCSR-initialization-for-RT3883.patch new file mode 100644 index 0000000..0fec3cd --- /dev/null +++ b/package/kernel/mac80211/patches/600-0017-rt2x00-rt2800lib-add-RFCSR-initialization-for-RT3883.patch @@ -0,0 +1,178 @@ +From 99c659cf345640fd0f733cbcaf4583cc2c868ec0 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Mon, 29 Apr 2013 13:21:48 +0200 +Subject: [PATCH] rt2x00: rt2800lib: add RFCSR initialization for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800.h | 1 + + drivers/net/wireless/rt2x00/rt2800lib.c | 141 +++++++++++++++++++++++++++++++ + 2 files changed, 142 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -2171,6 +2171,7 @@ struct mac_iveiv_entry { + /* + * RFCSR 2: + */ ++#define RFCSR2_RESCAL_BP FIELD8(0x40) + #define RFCSR2_RESCAL_EN FIELD8(0x80) + + /* +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -6819,6 +6819,144 @@ static void rt2800_init_rfcsr_3593(struc + /* TODO: enable stream mode support */ + } + ++static void rt2800_init_rfcsr_3883(struct rt2x00_dev *rt2x00dev) ++{ ++ u8 rfcsr; ++ ++ /* TODO: get the actual ECO value from the SoC */ ++ const unsigned int eco = 5; ++ ++ rt2800_rf_init_calibration(rt2x00dev, 2); ++ ++ rt2800_rfcsr_write(rt2x00dev, 0, 0xe0); ++ rt2800_rfcsr_write(rt2x00dev, 1, 0x03); ++ rt2800_rfcsr_write(rt2x00dev, 2, 0x50); ++ rt2800_rfcsr_write(rt2x00dev, 3, 0x20); ++ rt2800_rfcsr_write(rt2x00dev, 4, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 5, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 6, 0x40); ++ rt2800_rfcsr_write(rt2x00dev, 7, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 8, 0x5b); ++ rt2800_rfcsr_write(rt2x00dev, 9, 0x08); ++ rt2800_rfcsr_write(rt2x00dev, 10, 0xd3); ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x48); ++ rt2800_rfcsr_write(rt2x00dev, 12, 0x1a); ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x12); ++ rt2800_rfcsr_write(rt2x00dev, 14, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 15, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 16, 0x00); ++ ++ /* RFCSR 17 will be initialized later based on the ++ * frequency offset stored in the EEPROM ++ */ ++ ++ rt2800_rfcsr_write(rt2x00dev, 18, 0x40); ++ rt2800_rfcsr_write(rt2x00dev, 19, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 20, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 21, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 22, 0x20); ++ rt2800_rfcsr_write(rt2x00dev, 23, 0xc0); ++ rt2800_rfcsr_write(rt2x00dev, 24, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 25, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 26, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 27, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x00); ++ 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, 0x20); ++ rt2800_rfcsr_write(rt2x00dev, 35, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 36, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 37, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 38, 0x86); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x23); ++ rt2800_rfcsr_write(rt2x00dev, 40, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 41, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 43, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 44, 0x93); ++ rt2800_rfcsr_write(rt2x00dev, 45, 0xbb); ++ rt2800_rfcsr_write(rt2x00dev, 46, 0x60); ++ rt2800_rfcsr_write(rt2x00dev, 47, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 48, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 49, 0x8e); ++ rt2800_rfcsr_write(rt2x00dev, 50, 0x86); ++ rt2800_rfcsr_write(rt2x00dev, 51, 0x51); ++ rt2800_rfcsr_write(rt2x00dev, 52, 0x05); ++ rt2800_rfcsr_write(rt2x00dev, 53, 0x76); ++ rt2800_rfcsr_write(rt2x00dev, 54, 0x76); ++ rt2800_rfcsr_write(rt2x00dev, 55, 0x76); ++ rt2800_rfcsr_write(rt2x00dev, 56, 0xdb); ++ rt2800_rfcsr_write(rt2x00dev, 57, 0x3e); ++ rt2800_rfcsr_write(rt2x00dev, 58, 0x00); ++ 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); ++ ++ /* TODO: rx filter calibration? */ ++ ++ rt2800_bbp_write(rt2x00dev, 137, 0x0f); ++ ++ rt2800_bbp_write(rt2x00dev, 163, 0x9d); ++ ++ rt2800_bbp_write(rt2x00dev, 105, 0x05); ++ ++ 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); ++ ++ 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 (eco == 5) { ++ rt2800_rfcsr_write(rt2x00dev, 32, 0xd8); ++ rt2800_rfcsr_write(rt2x00dev, 33, 0x32); ++ } ++ ++ rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); ++ rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_BP, 0); ++ rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1); ++ rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); ++ msleep(1); ++ rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 0); ++ rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); ++ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); ++ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); ++ rfcsr |= 0xc0; ++ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); ++ rfcsr |= 0x20; ++ rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 46, &rfcsr); ++ rfcsr |= 0x20; ++ rt2800_rfcsr_write(rt2x00dev, 46, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr); ++ rfcsr &= ~0xee; ++ rt2800_rfcsr_write(rt2x00dev, 20, rfcsr); ++} ++ + static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) + { + rt2800_rf_init_calibration(rt2x00dev, 2); +@@ -7050,6 +7188,9 @@ static void rt2800_init_rfcsr(struct rt2 + case RT3390: + rt2800_init_rfcsr_3390(rt2x00dev); + break; ++ case RT3883: ++ rt2800_init_rfcsr_3883(rt2x00dev); ++ break; + case RT3572: + rt2800_init_rfcsr_3572(rt2x00dev); + break; diff --git a/package/kernel/mac80211/patches/600-0018-rt2x00-rt2800lib-use-the-extended-EEPROM-map-for-RT3.patch b/package/kernel/mac80211/patches/600-0018-rt2x00-rt2800lib-use-the-extended-EEPROM-map-for-RT3.patch new file mode 100644 index 0000000..57af961 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0018-rt2x00-rt2800lib-use-the-extended-EEPROM-map-for-RT3.patch @@ -0,0 +1,22 @@ +From 86022438ffeb1b87dfcd018bf477fdbb43076691 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Wed, 8 May 2013 19:35:33 +0200 +Subject: [PATCH] rt2x00: rt2800lib: use the extended EEPROM map for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -342,7 +342,8 @@ static unsigned int rt2800_eeprom_word_i + wiphy_name(rt2x00dev->hw->wiphy), word)) + return 0; + +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + map = rt2800_eeprom_map_ext; + else + map = rt2800_eeprom_map; diff --git a/package/kernel/mac80211/patches/600-0019-rt2x00-rt2800lib-force-rf-type-to-RF3853-on-RT3883.patch b/package/kernel/mac80211/patches/600-0019-rt2x00-rt2800lib-force-rf-type-to-RF3853-on-RT3883.patch new file mode 100644 index 0000000..c9d1e06 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0019-rt2x00-rt2800lib-force-rf-type-to-RF3853-on-RT3883.patch @@ -0,0 +1,21 @@ +From 4cf5403f02fa65dc2207f61d223cffa9ae50e907 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Thu, 1 Aug 2013 14:48:21 +0200 +Subject: [PATCH] rt2x00: rt2800lib: force rf type to RF3853 on RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7587,6 +7587,8 @@ static int rt2800_init_eeprom(struct rt2 + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) + rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); ++ else if (rt2x00_rt(rt2x00dev, RT3883)) ++ rf = RF3853; + else + rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE); + diff --git a/package/kernel/mac80211/patches/600-0020-rt2x00-rt2800lib-add-channel-configuration-code-for-.patch b/package/kernel/mac80211/patches/600-0020-rt2x00-rt2800lib-add-channel-configuration-code-for-.patch new file mode 100644 index 0000000..12b9c33 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0020-rt2x00-rt2800lib-add-channel-configuration-code-for-.patch @@ -0,0 +1,136 @@ +From 269f19c848a2380db03a3f207cafb88e28d71c53 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:28 +0100 +Subject: [PATCH] rt2x00: rt2800lib: add channel configuration code for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 72 +++++++++++++++++++++++++++++-- + 1 file changed, 69 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -3405,6 +3405,36 @@ static char rt2800_txpower_to_dev(struct + return clamp_t(char, txpower, MIN_A_TXPOWER, MAX_A_TXPOWER); + } + ++static void rt3883_bbp_adjust(struct rt2x00_dev *rt2x00dev, ++ struct rf_channel *rf) ++{ ++ u8 bbp; ++ ++ bbp = (rf->channel > 14) ? 0x48 : 0x38; ++ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 69, 0x12); ++ ++ if (rf->channel <= 14) { ++ rt2800_bbp_write(rt2x00dev, 70, 0x0a); ++ } else { ++ /* Disable CCK packet detection */ ++ rt2800_bbp_write(rt2x00dev, 70, 0x00); ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 73, 0x10); ++ ++ if (rf->channel > 14) { ++ rt2800_bbp_write(rt2x00dev, 62, 0x1d); ++ rt2800_bbp_write(rt2x00dev, 63, 0x1d); ++ rt2800_bbp_write(rt2x00dev, 64, 0x1d); ++ } else { ++ rt2800_bbp_write(rt2x00dev, 62, 0x2d); ++ rt2800_bbp_write(rt2x00dev, 63, 0x2d); ++ rt2800_bbp_write(rt2x00dev, 64, 0x2d); ++ } ++} ++ + static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, +@@ -3423,6 +3453,12 @@ static void rt2800_config_channel(struct + rt2800_txpower_to_dev(rt2x00dev, rf->channel, + info->default_power3); + ++ switch (rt2x00dev->chip.rt) { ++ case RT3883: ++ rt3883_bbp_adjust(rt2x00dev, rf); ++ break; ++ } ++ + switch (rt2x00dev->chip.rf) { + case RF2020: + case RF3020: +@@ -3506,6 +3542,15 @@ static void rt2800_config_channel(struct + rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 77, 0x98); ++ } else if (rt2x00_rt(rt2x00dev, RT3883)) { ++ 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); ++ ++ if (rt2x00dev->default_ant.rx_chain_num > 1) ++ rt2800_bbp_write(rt2x00dev, 86, 0x46); ++ else ++ rt2800_bbp_write(rt2x00dev, 86, 0); + } else { + rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); +@@ -3518,6 +3563,7 @@ static void rt2800_config_channel(struct + !rt2x00_rt(rt2x00dev, RT5392)) { + if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { + rt2800_bbp_write(rt2x00dev, 82, 0x62); ++ rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 75, 0x46); + } else { + if (rt2x00_rt(rt2x00dev, RT3593)) +@@ -3526,19 +3572,22 @@ static void rt2800_config_channel(struct + rt2800_bbp_write(rt2x00dev, 82, 0x84); + rt2800_bbp_write(rt2x00dev, 75, 0x50); + } +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + rt2800_bbp_write(rt2x00dev, 83, 0x8a); + } + + } else { + if (rt2x00_rt(rt2x00dev, RT3572)) + rt2800_bbp_write(rt2x00dev, 82, 0x94); +- else if (rt2x00_rt(rt2x00dev, RT3593)) ++ else if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + rt2800_bbp_write(rt2x00dev, 82, 0x82); + else + rt2800_bbp_write(rt2x00dev, 82, 0xf2); + +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + rt2800_bbp_write(rt2x00dev, 83, 0x9a); + + if (rt2x00_has_cap_external_lna_a(rt2x00dev)) +@@ -3660,6 +3709,23 @@ static void rt2800_config_channel(struct + + rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg); + ++ usleep_range(1000, 1500); ++ } ++ ++ if (rt2x00_rt(rt2x00dev, RT3883)) { ++ if (!conf_is_ht40(conf)) ++ rt2800_bbp_write(rt2x00dev, 105, 0x34); ++ else ++ rt2800_bbp_write(rt2x00dev, 105, 0x04); ++ ++ /* AGC init */ ++ if (rf->channel <= 14) ++ reg = 0x2e + rt2x00dev->lna_gain; ++ else ++ reg = 0x20 + ((rt2x00dev->lna_gain * 5) / 3); ++ ++ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg); ++ + usleep_range(1000, 1500); + } + diff --git a/package/kernel/mac80211/patches/600-0021-rt2x00-rt2800lib-fix-txpower_to_dev-function-for-RT3.patch b/package/kernel/mac80211/patches/600-0021-rt2x00-rt2800lib-fix-txpower_to_dev-function-for-RT3.patch new file mode 100644 index 0000000..3f40b4e --- /dev/null +++ b/package/kernel/mac80211/patches/600-0021-rt2x00-rt2800lib-fix-txpower_to_dev-function-for-RT3.patch @@ -0,0 +1,30 @@ +From e37d93abaabe3ab72b0332a18092acc162307274 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Mon, 30 Sep 2013 13:57:26 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix txpower_to_dev function for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -3392,13 +3392,15 @@ static char rt2800_txpower_to_dev(struct + unsigned int channel, + char txpower) + { +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + txpower = rt2x00_get_field8(txpower, EEPROM_TXPOWER_ALC); + + if (channel <= 14) + return clamp_t(char, txpower, MIN_G_TXPOWER, MAX_G_TXPOWER); + +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + return clamp_t(char, txpower, MIN_A_TXPOWER_3593, + MAX_A_TXPOWER_3593); + else diff --git a/package/kernel/mac80211/patches/600-0022-rt2x00-rt2800lib-use-correct-txpower-calculation-fun.patch b/package/kernel/mac80211/patches/600-0022-rt2x00-rt2800lib-use-correct-txpower-calculation-fun.patch new file mode 100644 index 0000000..52baeec --- /dev/null +++ b/package/kernel/mac80211/patches/600-0022-rt2x00-rt2800lib-use-correct-txpower-calculation-fun.patch @@ -0,0 +1,23 @@ +From c4d79e344bd580d85821390d49f92dced7d8e125 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:29 +0100 +Subject: [PATCH] rt2x00: rt2800lib: use correct txpower calculation function + for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -4611,7 +4611,8 @@ static void rt2800_config_txpower(struct + struct ieee80211_channel *chan, + int power_level) + { +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + rt2800_config_txpower_rt3593(rt2x00dev, chan, power_level); + else + rt2800_config_txpower_rt28xx(rt2x00dev, chan, power_level); diff --git a/package/kernel/mac80211/patches/600-0023-rt2x00-rt2800lib-hardcode-txmixer-gain-values-to-zer.patch b/package/kernel/mac80211/patches/600-0023-rt2x00-rt2800lib-hardcode-txmixer-gain-values-to-zer.patch new file mode 100644 index 0000000..b9dafc6 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0023-rt2x00-rt2800lib-hardcode-txmixer-gain-values-to-zer.patch @@ -0,0 +1,33 @@ +From caea0671cd8fd9ade4f5969cbe0ee545e94ae105 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sat, 24 Aug 2013 11:49:55 +0200 +Subject: [PATCH] rt2x00: rt2800lib: hardcode txmixer gain values to zero for + RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7469,7 +7469,8 @@ static u8 rt2800_get_txmixer_gain_24g(st + { + u16 word; + +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + return 0; + + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); +@@ -7483,7 +7484,8 @@ static u8 rt2800_get_txmixer_gain_5g(str + { + u16 word; + +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + return 0; + + rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); diff --git a/package/kernel/mac80211/patches/600-0024-rt2x00-rt2800lib-use-correct-RT-XWI-size-for-RT3883.patch b/package/kernel/mac80211/patches/600-0024-rt2x00-rt2800lib-use-correct-RT-XWI-size-for-RT3883.patch new file mode 100644 index 0000000..53435aa --- /dev/null +++ b/package/kernel/mac80211/patches/600-0024-rt2x00-rt2800lib-use-correct-RT-XWI-size-for-RT3883.patch @@ -0,0 +1,20 @@ +From 11c40fb47c4a4dd6ad060c2ae127ced89ffb9fe1 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Thu, 18 Apr 2013 14:33:33 +0200 +Subject: [PATCH] rt2x00: rt2800lib: use correct [RT]XWI size for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -558,6 +558,7 @@ void rt2800_get_txwi_rxwi_size(struct rt + { + switch (rt2x00dev->chip.rt) { + case RT3593: ++ case RT3883: + *txwi_size = TXWI_DESC_SIZE_4WORDS; + *rxwi_size = RXWI_DESC_SIZE_5WORDS; + break; diff --git a/package/kernel/mac80211/patches/600-0025-rt2x00-rt2800lib-use-correct-beacon-base-for-RT3883.patch b/package/kernel/mac80211/patches/600-0025-rt2x00-rt2800lib-use-correct-beacon-base-for-RT3883.patch new file mode 100644 index 0000000..08f3f88 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0025-rt2x00-rt2800lib-use-correct-beacon-base-for-RT3883.patch @@ -0,0 +1,22 @@ +From b403bdfa00665ce6b53583bdb837ffad0b91c09f Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:29 +0100 +Subject: [PATCH] rt2x00: rt2800lib: use correct beacon base for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -983,7 +983,8 @@ EXPORT_SYMBOL_GPL(rt2800_txdone_entry); + static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, + unsigned int index) + { +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + return HW_BEACON_BASE_HIGH(index); + + return HW_BEACON_BASE(index); diff --git a/package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch b/package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch new file mode 100644 index 0000000..f09f803 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0026-rt2x00-rt2800lib-use-correct-beacon-count-for-RT3883.patch @@ -0,0 +1,22 @@ +From 74b7eaf75fc6eb86292056ef705e543f9cd6086b Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 18 Aug 2013 09:57:58 +0200 +Subject: [PATCH] rt2x00: rt2800lib: use correct beacon count for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -8402,7 +8402,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r + if (rt2x00_rt(rt2x00dev, RT3593)) + __set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags); + +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + drv_data->hw_beacon_count = 16; + else + drv_data->hw_beacon_count = 8; diff --git a/package/kernel/mac80211/patches/600-0027-rt2x00-rt2800lib-fix-antenna-configuration-for-RT388.patch b/package/kernel/mac80211/patches/600-0027-rt2x00-rt2800lib-fix-antenna-configuration-for-RT388.patch new file mode 100644 index 0000000..f7d23fc --- /dev/null +++ b/package/kernel/mac80211/patches/600-0027-rt2x00-rt2800lib-fix-antenna-configuration-for-RT388.patch @@ -0,0 +1,22 @@ +From fa5ad9c025610c22048add2f0ad03f62b6ca1e74 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Mon, 30 Sep 2013 16:53:33 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix antenna configuration for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -1937,7 +1937,8 @@ void rt2800_config_ant(struct rt2x00_dev + rt2800_bbp_write(rt2x00dev, 3, r3); + rt2800_bbp_write(rt2x00dev, 1, r1); + +- if (rt2x00_rt(rt2x00dev, RT3593)) { ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) { + if (ant->rx_chain_num == 1) + rt2800_bbp_write(rt2x00dev, 86, 0x00); + else diff --git a/package/kernel/mac80211/patches/600-0028-rt2x00-rt2800lib-fix-LNA-gain-configuration-for-RT38.patch b/package/kernel/mac80211/patches/600-0028-rt2x00-rt2800lib-fix-LNA-gain-configuration-for-RT38.patch new file mode 100644 index 0000000..4da750e --- /dev/null +++ b/package/kernel/mac80211/patches/600-0028-rt2x00-rt2800lib-fix-LNA-gain-configuration-for-RT38.patch @@ -0,0 +1,32 @@ +From 6d668fef3a1baa60bdd715ee062ddb6333d2647c Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Mon, 30 Sep 2013 16:58:23 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix LNA gain configuration for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -1960,7 +1960,8 @@ static void rt2800_config_lna_gain(struc + rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); + } else if (libconf->rf.channel <= 128) { +- if (rt2x00_rt(rt2x00dev, RT3593)) { ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) { + rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, + EEPROM_EXT_LNA2_A1); +@@ -1970,7 +1971,8 @@ static void rt2800_config_lna_gain(struc + EEPROM_RSSI_BG2_LNA_A1); + } + } else { +- if (rt2x00_rt(rt2x00dev, RT3593)) { ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) { + rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, + EEPROM_EXT_LNA2_A2); diff --git a/package/kernel/mac80211/patches/600-0029-rt2x00-rt2800lib-fix-VGC-setup-for-RT3883.patch b/package/kernel/mac80211/patches/600-0029-rt2x00-rt2800lib-fix-VGC-setup-for-RT3883.patch new file mode 100644 index 0000000..628b237 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0029-rt2x00-rt2800lib-fix-VGC-setup-for-RT3883.patch @@ -0,0 +1,44 @@ +From c49b2d829aa1c816a46a577cdec6d2ff14d9f06e Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Tue, 1 Oct 2013 15:40:08 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix VGC setup for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -4811,7 +4811,8 @@ static u8 rt2800_get_default_vgc(struct + else + vgc = 0x2e + rt2x00dev->lna_gain; + } else { /* 5GHZ band */ +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + vgc = 0x20 + (rt2x00dev->lna_gain * 5) / 3; + else if (rt2x00_rt(rt2x00dev, RT5592)) + vgc = 0x24 + (2 * rt2x00dev->lna_gain); +@@ -4831,7 +4832,8 @@ static inline void rt2800_set_vgc(struct + { + if (qual->vgc_level != vgc_level) { + if (rt2x00_rt(rt2x00dev, RT3572) || +- rt2x00_rt(rt2x00dev, RT3593)) { ++ rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) { + rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, + vgc_level); + } else if (rt2x00_rt(rt2x00dev, RT5592)) { +@@ -4878,6 +4880,11 @@ void rt2800_link_tuner(struct rt2x00_dev + } + break; + ++ case RT3883: ++ if (qual->rssi > -65) ++ vgc += 0x10; ++ break; ++ + case RT5592: + if (qual->rssi > -65) + vgc += 0x20; diff --git a/package/kernel/mac80211/patches/600-0030-rt2x00-rt2800lib-fix-EEPROM-LNA-validation-for-RT388.patch b/package/kernel/mac80211/patches/600-0030-rt2x00-rt2800lib-fix-EEPROM-LNA-validation-for-RT388.patch new file mode 100644 index 0000000..216b8b6 --- /dev/null +++ b/package/kernel/mac80211/patches/600-0030-rt2x00-rt2800lib-fix-EEPROM-LNA-validation-for-RT388.patch @@ -0,0 +1,42 @@ +From 1616650aea676541d4dc8adc6f4219856d193c8b Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Tue, 1 Oct 2013 17:27:57 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix EEPROM LNA validation for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7606,7 +7606,8 @@ static int rt2800_validate_eeprom(struct + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); +- if (!rt2x00_rt(rt2x00dev, RT3593)) { ++ if (!rt2x00_rt(rt2x00dev, RT3593) && ++ !rt2x00_rt(rt2x00dev, RT3883)) { + if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, +@@ -7626,7 +7627,8 @@ static int rt2800_validate_eeprom(struct + rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); +- if (!rt2x00_rt(rt2x00dev, RT3593)) { ++ if (!rt2x00_rt(rt2x00dev, RT3593) && ++ !rt2x00_rt(rt2x00dev, RT3883)) { + if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, +@@ -7634,7 +7636,8 @@ static int rt2800_validate_eeprom(struct + } + rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + +- if (rt2x00_rt(rt2x00dev, RT3593)) { ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) { + rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &word); + if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0xff) diff --git a/package/kernel/mac80211/patches/600-0031-rt2x00-rt2800lib-fix-txpower-compensation-for-RT3883.patch b/package/kernel/mac80211/patches/600-0031-rt2x00-rt2800lib-fix-txpower-compensation-for-RT3883.patch new file mode 100644 index 0000000..515086f --- /dev/null +++ b/package/kernel/mac80211/patches/600-0031-rt2x00-rt2800lib-fix-txpower-compensation-for-RT3883.patch @@ -0,0 +1,22 @@ +From e3871034a0e7c8a95152dc3eafbcc4535398cbdc Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Wed, 2 Oct 2013 10:11:59 +0200 +Subject: [PATCH] rt2x00: rt2800lib: fix txpower compensation for RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -3981,6 +3981,9 @@ static u8 rt2800_compensate_txpower(stru + if (rt2x00_rt(rt2x00dev, RT3593)) + return min_t(u8, txpower, 0xc); + ++ if (rt2x00_rt(rt2x00dev, RT3883)) ++ return min_t(u8, txpower, 0xf); ++ + if (rt2x00_has_cap_power_limit(rt2x00dev)) { + /* + * Check if eirp txpower exceed txpower_limit. diff --git a/package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch b/package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch new file mode 100644 index 0000000..77e3f1b --- /dev/null +++ b/package/kernel/mac80211/patches/600-0032-rt2x00-rt2800lib-enable-RT2800_HAS_HIGH_SHARED_MEM-f.patch @@ -0,0 +1,23 @@ +From f6734ec72da936989a8ce4186b3ede28fbc47836 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 18 Aug 2013 21:57:34 +0200 +Subject: [PATCH] rt2x00: rt2800lib: enable RT2800_HAS_HIGH_SHARED_MEM for + RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -8415,7 +8415,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r + if (retval) + return retval; + +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + __set_bit(RT2800_HAS_HIGH_SHARED_MEM, &drv_data->rt2800_flags); + + if (rt2x00_rt(rt2x00dev, RT3593) || diff --git a/package/kernel/mac80211/patches/600-0033-rt2x00-rt2800lib-use-high-memory-for-beacons-on-RT38.patch b/package/kernel/mac80211/patches/600-0033-rt2x00-rt2800lib-use-high-memory-for-beacons-on-RT38.patch new file mode 100644 index 0000000..dc06e6a --- /dev/null +++ b/package/kernel/mac80211/patches/600-0033-rt2x00-rt2800lib-use-high-memory-for-beacons-on-RT38.patch @@ -0,0 +1,22 @@ +From f1acfc2f397e86548ae1b479c198d4bef57050f6 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 29 Sep 2013 18:10:34 +0200 +Subject: [PATCH] rt2x00: rt2800lib: use high memory for beacons on RT3883 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -97,7 +97,8 @@ static inline void rt2800_shared_mem_sel + + static inline bool rt2800_beacon_uses_high_mem(struct rt2x00_dev *rt2x00dev) + { +- if (rt2x00_rt(rt2x00dev, RT3593)) ++ if (rt2x00_rt(rt2x00dev, RT3593) || ++ rt2x00_rt(rt2x00dev, RT3883)) + return true; + + return false; diff --git a/package/kernel/mac80211/patches/600-0034-rt2x00-rt2800mmio-add-a-workaround-for-spurious-TX_F.patch b/package/kernel/mac80211/patches/600-0034-rt2x00-rt2800mmio-add-a-workaround-for-spurious-TX_F.patch new file mode 100644 index 0000000..212eb4e --- /dev/null +++ b/package/kernel/mac80211/patches/600-0034-rt2x00-rt2800mmio-add-a-workaround-for-spurious-TX_F.patch @@ -0,0 +1,136 @@ +From 5e67d4f8a46d19748b501c2ef86de3f50d3cfd51 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Sun, 24 Mar 2013 19:26:27 +0100 +Subject: [PATCH] rt2x00: rt2800mmio: add a workaround for spurious + TX_FIFO_STATUS interrupts + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800mmio.c | 72 +++++++++++++++++++++++++----- + drivers/net/wireless/rt2x00/rt2x00.h | 5 +++ + 2 files changed, 65 insertions(+), 12 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2800mmio.c ++++ b/drivers/net/wireless/rt2x00/rt2800mmio.c +@@ -415,9 +415,9 @@ void rt2800mmio_autowake_tasklet(unsigne + } + EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet); + +-static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) ++static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev, ++ u32 status) + { +- u32 status; + int i; + + /* +@@ -438,29 +438,77 @@ static void rt2800mmio_txstatus_interrup + * Since we have only one producer and one consumer we don't + * need to lock the kfifo. + */ +- for (i = 0; i < rt2x00dev->tx->limit; i++) { +- rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status); +- +- if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) +- break; +- ++ i = 0; ++ do { + if (!kfifo_put(&rt2x00dev->txstatus_fifo, status)) { +- rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n"); ++ rt2x00_warn(rt2x00dev, ++ "TX status FIFO overrun, drop TX status report\n"); + break; + } +- } ++ ++ if (++i >= rt2x00dev->tx->limit) ++ break; ++ ++ rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status); ++ } while (rt2x00_get_field32(status, TX_STA_FIFO_VALID)); + + /* Schedule the tasklet for processing the tx status. */ + tasklet_schedule(&rt2x00dev->txstatus_tasklet); + } + ++#define RT2800MMIO_TXSTATUS_IRQ_MAX_RETRIES 4 ++ ++static bool rt2800mmio_txstatus_is_spurious(struct rt2x00_dev *rt2x00dev, ++ u32 txstatus) ++{ ++ if (likely(rt2x00_get_field32(txstatus, TX_STA_FIFO_VALID))) { ++ rt2x00dev->txstatus_irq_retries = 0; ++ return false; ++ } ++ ++ rt2x00dev->txstatus_irq_retries++; ++ ++ /* Ensure that we don't go into an infinite IRQ loop. */ ++ if (rt2x00dev->txstatus_irq_retries >= ++ RT2800MMIO_TXSTATUS_IRQ_MAX_RETRIES) { ++ rt2x00_warn(rt2x00dev, ++ "%u spurious TX_FIFO_STATUS interrupt(s)\n", ++ rt2x00dev->txstatus_irq_retries); ++ rt2x00dev->txstatus_irq_retries = 0; ++ return false; ++ } ++ ++ return true; ++} ++ + irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) + { + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg, mask; ++ u32 txstatus = 0; + +- /* Read status and ACK all interrupts */ ++ /* Read status */ + rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); ++ ++ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) { ++ /* Due to unknown reason the hardware generates a ++ * TX_FIFO_STATUS interrupt before the TX_STA_FIFO ++ * register contain valid data. Read the TX status ++ * here to see if we have to process the actual ++ * request. ++ */ ++ rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &txstatus); ++ if (rt2800mmio_txstatus_is_spurious(rt2x00dev, txstatus)) { ++ /* Remove the TX_FIFO_STATUS bit so it won't be ++ * processed in this turn. The hardware will ++ * generate another IRQ for us. ++ */ ++ rt2x00_set_field32(®, ++ INT_SOURCE_CSR_TX_FIFO_STATUS, 0); ++ } ++ } ++ ++ /* ACK interrupts */ + rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + if (!reg) +@@ -477,7 +525,7 @@ irqreturn_t rt2800mmio_interrupt(int irq + mask = ~reg; + + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) { +- rt2800mmio_txstatus_interrupt(rt2x00dev); ++ rt2800mmio_txstatus_interrupt(rt2x00dev, txstatus); + /* + * Never disable the TX_FIFO_STATUS interrupt. + */ +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -987,6 +987,11 @@ struct rt2x00_dev { + int rf_channel; + + /* ++ * Counter for tx status irq retries (rt2800pci). ++ */ ++ unsigned int txstatus_irq_retries; ++ ++ /* + * Protect the interrupt mask register. + */ + spinlock_t irqmask_lock; diff --git a/package/kernel/mac80211/patches/601-rt2x00-set_pci_mwi.patch b/package/kernel/mac80211/patches/601-rt2x00-set_pci_mwi.patch new file mode 100644 index 0000000..08c8fa6 --- /dev/null +++ b/package/kernel/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 +@@ -94,8 +94,10 @@ int rt2x00pci_probe(struct pci_dev *pci_ + + pci_set_master(pci_dev); + ++#ifdef CONFIG_PCI_SET_MWI + if (pci_set_mwi(pci_dev)) + rt2x00_probe_err("MWI not available\n"); ++#endif + + if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) { + rt2x00_probe_err("PCI DMA not supported\n"); diff --git a/package/kernel/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch b/package/kernel/mac80211/patches/602-rt2x00-introduce-rt2x00_platform_h.patch new file mode 100644 index 0000000..8c71075 --- /dev/null +++ b/package/kernel/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 +@@ -38,6 +38,7 @@ + #include <linux/kfifo.h> + #include <linux/hrtimer.h> + #include <linux/average.h> ++#include <linux/rt2x00_platform.h> + + #include <net/mac80211.h> + diff --git a/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch b/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch new file mode 100644 index 0000000..44b629f --- /dev/null +++ b/package/kernel/mac80211/patches/603-rt2x00-introduce-rt2x00eeprom.patch @@ -0,0 +1,301 @@ +--- a/.local-symbols ++++ b/.local-symbols +@@ -312,6 +312,7 @@ RT2X00_LIB_FIRMWARE= + RT2X00_LIB_CRYPTO= + RT2X00_LIB_LEDS= + RT2X00_LIB_DEBUGFS= ++RT2X00_LIB_EEPROM= + RT2X00_DEBUG= + WL_MEDIATEK= + MT7601U= +--- a/drivers/net/wireless/rt2x00/Kconfig ++++ b/drivers/net/wireless/rt2x00/Kconfig +@@ -69,6 +69,7 @@ config RT2800PCI + select RT2X00_LIB_MMIO + select RT2X00_LIB_PCI + select RT2X00_LIB_FIRMWARE ++ select RT2X00_LIB_EEPROM + select RT2X00_LIB_CRYPTO + depends on CRC_CCITT + depends on EEPROM_93CX6 +@@ -215,6 +216,7 @@ config RT2800SOC + select RT2X00_LIB_MMIO + select RT2X00_LIB_CRYPTO + select RT2X00_LIB_FIRMWARE ++ select RT2X00_LIB_EEPROM + select RT2800_LIB + select RT2800_LIB_MMIO + ---help--- +@@ -266,6 +268,9 @@ config RT2X00_LIB_FIRMWARE + config RT2X00_LIB_CRYPTO + bool + ++config RT2X00_LIB_EEPROM ++ boolean ++ + config RT2X00_LIB_LEDS + bool + default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) +--- a/drivers/net/wireless/rt2x00/Makefile ++++ b/drivers/net/wireless/rt2x00/Makefile +@@ -7,6 +7,7 @@ rt2x00lib-$(CPTCFG_RT2X00_LIB_DEBUGFS) + + rt2x00lib-$(CPTCFG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o + rt2x00lib-$(CPTCFG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o + rt2x00lib-$(CPTCFG_RT2X00_LIB_LEDS) += rt2x00leds.o ++rt2x00lib-$(CPTCFG_RT2X00_LIB_EEPROM) += rt2x00eeprom.o + + obj-$(CPTCFG_RT2X00_LIB) += rt2x00lib.o + obj-$(CPTCFG_RT2X00_LIB_MMIO) += rt2x00mmio.o +--- a/drivers/net/wireless/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/rt2x00/rt2800lib.h +@@ -46,6 +46,8 @@ struct rt2800_drv_data { + } shmem_lock; + }; + ++#include "rt2800.h" ++ + struct rt2800_ops { + void (*register_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value); +@@ -179,6 +181,15 @@ static inline int rt2800_read_eeprom(str + { + const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; + ++ if (rt2x00dev->eeprom_file) { ++ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data, ++ EEPROM_SIZE); ++ return 0; ++ } ++ ++ if (!rt2800ops->read_eeprom) ++ return -EINVAL; ++ + return rt2800ops->read_eeprom(rt2x00dev); + } + +--- a/drivers/net/wireless/rt2x00/rt2800soc.c ++++ b/drivers/net/wireless/rt2x00/rt2800soc.c +@@ -102,19 +102,6 @@ static int rt2800soc_set_device_state(st + return retval; + } + +-static int rt2800soc_read_eeprom(struct rt2x00_dev *rt2x00dev) +-{ +- void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); +- +- if (!base_addr) +- return -ENOMEM; +- +- memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE); +- +- iounmap(base_addr); +- return 0; +-} +- + /* Firmware functions */ + static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev) + { +@@ -178,7 +165,6 @@ static const struct rt2800_ops rt2800soc + .register_multiread = rt2x00mmio_register_multiread, + .register_multiwrite = rt2x00mmio_register_multiwrite, + .regbusy_read = rt2x00mmio_regbusy_read, +- .read_eeprom = rt2800soc_read_eeprom, + .hwcrypt_disabled = rt2800soc_hwcrypt_disabled, + .drv_write_firmware = rt2800soc_write_firmware, + .drv_init_registers = rt2800mmio_init_registers, +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -695,6 +695,7 @@ enum rt2x00_capability_flags { + REQUIRE_HT_TX_DESC, + REQUIRE_PS_AUTOWAKE, + REQUIRE_DELAYED_RFKILL, ++ REQUIRE_EEPROM_FILE, + + /* + * Capabilities +@@ -964,6 +965,11 @@ struct rt2x00_dev { + const struct firmware *fw; + + /* ++ * EEPROM image. ++ */ ++ const struct firmware *eeprom_file; ++ ++ /* + * FIFO for storing tx status reports between isr and tasklet. + */ + DECLARE_KFIFO_PTR(txstatus_fifo, u32); +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -1334,6 +1334,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de + INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); + INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep); + ++ retval = rt2x00lib_load_eeprom_file(rt2x00dev); ++ if (retval) ++ goto exit; ++ + /* + * Let the driver probe the device to detect the capabilities. + */ +@@ -1474,6 +1478,11 @@ void rt2x00lib_remove_dev(struct rt2x00_ + * Free the driver data. + */ + kfree(rt2x00dev->drv_data); ++ ++ /* ++ * Free EEPROM image. ++ */ ++ rt2x00lib_free_eeprom_file(rt2x00dev); + } + EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); + +--- /dev/null ++++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c +@@ -0,0 +1,111 @@ ++/* ++ 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 const char * ++rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data; ++ ++ if (pdata && pdata->eeprom_file_name) ++ return pdata->eeprom_file_name; ++ ++ return NULL ++} ++ ++static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct firmware *ee; ++ const char *ee_name; ++ int retval; ++ ++ ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev); ++ if (!ee_name) { ++ rt2x00_err(rt2x00dev, ++ "Invalid EEPROM filename.\n" ++ "Please file bug report to %s.\n", DRV_PROJECT); ++ return -EINVAL; ++ } ++ ++ rt2x00_info(rt2x00dev, "Loading EEPROM data from '%s'.\n", ee_name); ++ ++ retval = request_firmware(&ee, ee_name, rt2x00dev->dev); ++ if (retval) { ++ rt2x00_err(rt2x00dev, "Failed to request EEPROM.\n"); ++ return retval; ++ } ++ ++ if (!ee || !ee->size || !ee->data) { ++ rt2x00_err(rt2x00dev, "Failed to read EEPROM file.\n"); ++ retval = -ENOENT; ++ goto err_exit; ++ } ++ ++ if (ee->size != rt2x00dev->ops->eeprom_size) { ++ rt2x00_err(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 (!rt2x00lib_get_eeprom_file_name(rt2x00dev)) ++ return 0; ++ ++ set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags); ++ ++ if (!rt2x00dev->eeprom_file) { ++ retval = rt2x00lib_request_eeprom_file(rt2x00dev); ++ if (retval) ++ 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/rt2x00lib.h ++++ b/drivers/net/wireless/rt2x00/rt2x00lib.h +@@ -320,6 +320,22 @@ static inline void rt2x00lib_free_firmwa + #endif /* CPTCFG_RT2X00_LIB_FIRMWARE */ + + /* ++ * EEPROM file handlers. ++ */ ++#ifdef CPTCFG_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 /* CPTCFG_RT2X00_LIB_EEPROM */ ++ ++/* + * Debugfs handlers. + */ + #ifdef CPTCFG_RT2X00_LIB_DEBUGFS +--- a/drivers/net/wireless/rt2x00/rt2x00soc.c ++++ b/drivers/net/wireless/rt2x00/rt2x00soc.c +@@ -92,6 +92,7 @@ int rt2x00soc_probe(struct platform_devi + rt2x00dev->hw = hw; + rt2x00dev->irq = platform_get_irq(pdev, 0); + rt2x00dev->name = pdev->dev.driver->name; ++ set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags); + + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); + diff --git a/package/kernel/mac80211/patches/604-rt2x00-of_load_eeprom_filename.patch b/package/kernel/mac80211/patches/604-rt2x00-of_load_eeprom_filename.patch new file mode 100644 index 0000000..4bc6f37 --- /dev/null +++ b/package/kernel/mac80211/patches/604-rt2x00-of_load_eeprom_filename.patch @@ -0,0 +1,33 @@ +--- a/drivers/net/wireless/rt2x00/rt2x00eeprom.c ++++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c +@@ -26,6 +26,7 @@ + + #include <linux/kernel.h> + #include <linux/module.h> ++#include <linux/of.h> + + #include "rt2x00.h" + #include "rt2x00lib.h" +@@ -34,11 +35,21 @@ static const char * + rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev) + { + struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data; ++#ifdef CONFIG_OF ++ struct device_node *np; ++ const char *eep; ++#endif + + if (pdata && pdata->eeprom_file_name) + return pdata->eeprom_file_name; + +- return NULL ++#ifdef CONFIG_OF ++ np = rt2x00dev->dev->of_node; ++ if (np && of_property_read_string(np, "ralink,eeprom", &eep) == 0) ++ return eep; ++#endif ++ ++ return NULL; + } + + static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev) diff --git a/package/kernel/mac80211/patches/605-rt2x00-load-eeprom-on-SoC-from-a-mtd-device-defines-.patch b/package/kernel/mac80211/patches/605-rt2x00-load-eeprom-on-SoC-from-a-mtd-device-defines-.patch new file mode 100644 index 0000000..75f0415 --- /dev/null +++ b/package/kernel/mac80211/patches/605-rt2x00-load-eeprom-on-SoC-from-a-mtd-device-defines-.patch @@ -0,0 +1,101 @@ +From 339fe73f340161a624cc08e738d2244814852c3e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sun, 17 Mar 2013 00:55:04 +0100 +Subject: [PATCH] rt2x00: load eeprom on SoC from a mtd device defines inside + OF + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/net/wireless/rt2x00/Kconfig | 1 + + drivers/net/wireless/rt2x00/rt2800pci.c | 44 ++++++++++++++++++++++++++----- + 2 files changed, 39 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/rt2x00/Kconfig ++++ b/drivers/net/wireless/rt2x00/Kconfig +@@ -219,6 +219,7 @@ config RT2800SOC + select RT2X00_LIB_EEPROM + select RT2800_LIB + select RT2800_LIB_MMIO ++ select MTD if SOC_RT288X || SOC_RT305X + ---help--- + This adds support for Ralink WiSoC devices. + Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352. +--- a/drivers/net/wireless/rt2x00/rt2x00eeprom.c ++++ b/drivers/net/wireless/rt2x00/rt2x00eeprom.c +@@ -26,11 +26,66 @@ + + #include <linux/kernel.h> + #include <linux/module.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> + #include <linux/of.h> + + #include "rt2x00.h" + #include "rt2x00lib.h" + ++static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev) ++{ ++ int ret = -EINVAL; ++#ifdef CONFIG_OF ++ static struct firmware mtd_fw; ++ struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL; ++ size_t retlen, len = rt2x00dev->ops->eeprom_size; ++ int size, offset = 0; ++ struct mtd_info *mtd; ++ const char *part; ++ const __be32 *list; ++ phandle phandle; ++ ++ list = of_get_property(np, "ralink,mtd-eeprom", &size); ++ if (!list) { ++ dev_err(rt2x00dev->dev, "failed to load eeprom property\n"); ++ return -ENOENT; ++ } ++ ++ phandle = be32_to_cpup(list++); ++ if (phandle) ++ mtd_np = of_find_node_by_phandle(phandle); ++ if (!mtd_np) { ++ dev_err(rt2x00dev->dev, "failed to load mtd phandle\n"); ++ return -EINVAL; ++ } ++ ++ part = of_get_property(mtd_np, "label", NULL); ++ if (!part) ++ part = mtd_np->name; ++ ++ mtd = get_mtd_device_nm(part); ++ if (IS_ERR(mtd)) { ++ dev_err(rt2x00dev->dev, "failed to get mtd device \"%s\"\n", part); ++ return PTR_ERR(mtd); ++ } ++ ++ if (size > sizeof(*list)) ++ offset = be32_to_cpup(list); ++ ++ ret = mtd_read(mtd, offset, len, &retlen, (u_char *) rt2x00dev->eeprom); ++ put_mtd_device(mtd); ++ ++ if (!ret) { ++ rt2x00dev->eeprom_file = &mtd_fw; ++ mtd_fw.size = len; ++ mtd_fw.data = rt2x00dev->eeprom; ++ } ++#endif ++ ++ return ret; ++} ++ + static const char * + rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev) + { +@@ -58,6 +113,9 @@ static int rt2x00lib_request_eeprom_file + const char *ee_name; + int retval; + ++ if (!rt2800lib_read_eeprom_mtd(rt2x00dev)) ++ return 0; ++ + ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev); + if (!ee_name) { + rt2x00_err(rt2x00dev, diff --git a/package/kernel/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch b/package/kernel/mac80211/patches/607-rt2x00-allow_disabling_bands_through_platform_data.patch new file mode 100644 index 0000000..70f7b78 --- /dev/null +++ b/package/kernel/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 +@@ -940,6 +940,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) { ++ rt2x00_err(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 +@@ -403,6 +403,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/kernel/mac80211/patches/608-add_platform_data_mac_addr.patch b/package/kernel/mac80211/patches/608-add_platform_data_mac_addr.patch new file mode 100644 index 0000000..16a579d --- /dev/null +++ b/package/kernel/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 +@@ -931,6 +931,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 +@@ -1410,6 +1410,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 +@@ -2390,6 +2390,7 @@ static int rt61pci_validate_eeprom(struc + u32 reg; + u16 word; + u8 *mac; ++ const u8 *pdata_mac; + s8 value; + + rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); +@@ -2410,7 +2411,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); + rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac); diff --git a/package/kernel/mac80211/patches/609-rt2x00-allow_disabling_bands_through_dts.patch b/package/kernel/mac80211/patches/609-rt2x00-allow_disabling_bands_through_dts.patch new file mode 100644 index 0000000..63a8641 --- /dev/null +++ b/package/kernel/mac80211/patches/609-rt2x00-allow_disabling_bands_through_dts.patch @@ -0,0 +1,27 @@ +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -26,6 +26,7 @@ + #include <linux/module.h> + #include <linux/slab.h> + #include <linux/log2.h> ++#include <linux/of.h> + + #include "rt2x00.h" + #include "rt2x00lib.h" +@@ -951,6 +952,16 @@ static int rt2x00lib_probe_hw_modes(stru + struct ieee80211_rate *rates; + unsigned int num_rates; + unsigned int i; ++#ifdef CONFIG_OF ++ struct device_node *np = rt2x00dev->dev->of_node; ++ unsigned int enabled; ++ if (!of_property_read_u32(np, "ralink,2ghz", ++ &enabled) && !enabled) ++ spec->supported_bands &= ~SUPPORT_BAND_2GHZ; ++ if (!of_property_read_u32(np, "ralink,5ghz", ++ &enabled) && !enabled) ++ spec->supported_bands &= ~SUPPORT_BAND_5GHZ; ++#endif /* CONFIG_OF */ + + if (rt2x00dev->dev->platform_data) { + struct rt2x00_platform_data *pdata; diff --git a/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch b/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch new file mode 100644 index 0000000..39b1ccc --- /dev/null +++ b/package/kernel/mac80211/patches/610-rt2x00-fix-rt3352-ext-pa.patch @@ -0,0 +1,211 @@ +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -3528,11 +3528,18 @@ static void rt2800_config_channel(struct + /* + * Change BBP settings + */ ++ + if (rt2x00_rt(rt2x00dev, RT3352)) { ++ 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, 27, 0x0); + rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 27, 0x20); + rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain); ++ rt2800_bbp_write(rt2x00dev, 86, 0x38); ++ rt2800_bbp_write(rt2x00dev, 83, 0x6a); + } else if (rt2x00_rt(rt2x00dev, RT3593)) { + if (rf->channel > 14) { + /* Disable CCK Packet detection on 5GHz */ +@@ -6594,6 +6601,12 @@ static void rt2800_init_rfcsr_3290(struc + + static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev) + { ++ int tx0_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX0, ++ &rt2x00dev->cap_flags); ++ int tx1_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX1, ++ &rt2x00dev->cap_flags); ++ u8 rfcsr; ++ + rt2800_rf_init_calibration(rt2x00dev, 30); + + rt2800_rfcsr_write(rt2x00dev, 0, 0xf0); +@@ -6629,15 +6642,30 @@ static void rt2800_init_rfcsr_3352(struc + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 34, 0x01); ++ rfcsr = 0x01; ++ if (!tx0_int_pa) ++ rt2x00_set_field8(&rfcsr, RFCSR34_TX0_EXT_PA, 1); ++ if (!tx1_int_pa) ++ rt2x00_set_field8(&rfcsr, RFCSR34_TX1_EXT_PA, 1); ++ rt2800_rfcsr_write(rt2x00dev, 34, rfcsr); + 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); ++ rfcsr = 0x52; ++ if (tx0_int_pa) { ++ rt2x00_set_field8(&rfcsr, RFCSR41_BIT1, 1); ++ rt2x00_set_field8(&rfcsr, RFCSR41_BIT4, 1); ++ } ++ rt2800_rfcsr_write(rt2x00dev, 41, rfcsr); ++ rfcsr = 0x52; ++ if (tx1_int_pa) { ++ rt2x00_set_field8(&rfcsr, RFCSR42_BIT1, 1); ++ rt2x00_set_field8(&rfcsr, RFCSR42_BIT4, 1); ++ } ++ rt2800_rfcsr_write(rt2x00dev, 42, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 43, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 44, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 45, 0xdb); +@@ -6645,15 +6673,20 @@ static void rt2800_init_rfcsr_3352(struc + rt2800_rfcsr_write(rt2x00dev, 47, 0x0d); + rt2800_rfcsr_write(rt2x00dev, 48, 0x14); + rt2800_rfcsr_write(rt2x00dev, 49, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 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); ++ rfcsr = 0x2d; ++ if (!tx0_int_pa) ++ rt2x00_set_field8(&rfcsr, RFCSR50_TX0_EXT_PA, 1); ++ if (!tx1_int_pa) ++ rt2x00_set_field8(&rfcsr, RFCSR50_TX1_EXT_PA, 1); ++ rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); ++ rt2800_rfcsr_write(rt2x00dev, 51, (tx0_int_pa ? 0x7f : 0x52)); ++ rt2800_rfcsr_write(rt2x00dev, 52, (tx0_int_pa ? 0x00 : 0xc0)); ++ rt2800_rfcsr_write(rt2x00dev, 53, (tx0_int_pa ? 0x52 : 0xd2)); ++ rt2800_rfcsr_write(rt2x00dev, 54, (tx0_int_pa ? 0x1b : 0xc0)); ++ rt2800_rfcsr_write(rt2x00dev, 55, (tx1_int_pa ? 0x7f : 0x52)); ++ rt2800_rfcsr_write(rt2x00dev, 56, (tx1_int_pa ? 0x00 : 0xc0)); ++ rt2800_rfcsr_write(rt2x00dev, 57, (tx0_int_pa ? 0x52 : 0x49)); ++ rt2800_rfcsr_write(rt2x00dev, 58, (tx1_int_pa ? 0x1b : 0xc0)); + rt2800_rfcsr_write(rt2x00dev, 59, 0x00); + rt2800_rfcsr_write(rt2x00dev, 60, 0x00); + rt2800_rfcsr_write(rt2x00dev, 61, 0x00); +@@ -7674,6 +7707,7 @@ static int rt2800_init_eeprom(struct rt2 + * RT53xx: defined in "EEPROM_CHIP_ID" field + */ + if (rt2x00_rt(rt2x00dev, RT3290) || ++ rt2x00_rt(rt2x00dev, RT3352) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) + rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); +@@ -7769,7 +7803,8 @@ static int rt2800_init_eeprom(struct rt2 + /* + * Detect if this device has Bluetooth co-existence. + */ +- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) ++ if (!rt2x00_rt(rt2x00dev, RT3352) && ++ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) + __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags); + + /* +@@ -7798,6 +7833,22 @@ static int rt2800_init_eeprom(struct rt2 + EIRP_MAX_TX_POWER_LIMIT) + __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags); + ++ /* ++ * Detect if device uses internal or external PA ++ */ ++ rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); ++ ++ if (rt2x00_rt(rt2x00dev, RT3352)) { ++ if (!rt2x00_get_field16(eeprom, ++ EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352)) ++ __set_bit(CAPABILITY_INTERNAL_PA_TX0, ++ &rt2x00dev->cap_flags); ++ if (!rt2x00_get_field16(eeprom, ++ EEPROM_NIC_CONF1_EXTERNAL_TX1_PA_3352)) ++ __set_bit(CAPABILITY_INTERNAL_PA_TX1, ++ &rt2x00dev->cap_flags); ++ } ++ + return 0; + } + +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -2335,6 +2335,12 @@ struct mac_iveiv_entry { + #define RFCSR36_RF_BS FIELD8(0x80) + + /* ++ * RFCSR 34: ++ */ ++#define RFCSR34_TX0_EXT_PA FIELD8(0x04) ++#define RFCSR34_TX1_EXT_PA FIELD8(0x08) ++ ++/* + * RFCSR 38: + */ + #define RFCSR38_RX_LO1_EN FIELD8(0x20) +@@ -2346,6 +2352,18 @@ struct mac_iveiv_entry { + #define RFCSR39_RX_LO2_EN FIELD8(0x80) + + /* ++ * RFCSR 41: ++ */ ++#define RFCSR41_BIT1 FIELD8(0x01) ++#define RFCSR41_BIT4 FIELD8(0x08) ++ ++/* ++ * RFCSR 42: ++ */ ++#define RFCSR42_BIT1 FIELD8(0x01) ++#define RFCSR42_BIT4 FIELD8(0x08) ++ ++/* + * RFCSR 49: + */ + #define RFCSR49_TX FIELD8(0x3f) +@@ -2358,6 +2376,8 @@ struct mac_iveiv_entry { + * RFCSR 50: + */ + #define RFCSR50_TX FIELD8(0x3f) ++#define RFCSR50_TX0_EXT_PA FIELD8(0x02) ++#define RFCSR50_TX1_EXT_PA FIELD8(0x10) + #define RFCSR50_EP FIELD8(0xc0) + /* bits for RT3593 */ + #define RFCSR50_TX_LO1_EN FIELD8(0x20) +@@ -2505,6 +2525,8 @@ enum rt2800_eeprom_word { + * INTERNAL_TX_ALC: 0: disable, 1: enable + * BT_COEXIST: 0: disable, 1: enable + * DAC_TEST: 0: disable, 1: enable ++ * EXTERNAL_TX0_PA: 0: disable, 1: enable (only on RT3352) ++ * EXTERNAL_TX1_PA: 0: disable, 1: enable (only on RT3352) + */ + #define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001) + #define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC FIELD16(0x0002) +@@ -2521,6 +2543,8 @@ enum rt2800_eeprom_word { + #define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000) + #define EEPROM_NIC_CONF1_BT_COEXIST FIELD16(0x4000) + #define EEPROM_NIC_CONF1_DAC_TEST FIELD16(0x8000) ++#define EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352 FIELD16(0x4000) ++#define EEPROM_NIC_CONF1_EXTERNAL_TX1_PA_3352 FIELD16(0x8000) + + /* + * EEPROM frequency +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -715,6 +715,8 @@ enum rt2x00_capability_flags { + CAPABILITY_DOUBLE_ANTENNA, + CAPABILITY_BT_COEXIST, + CAPABILITY_VCO_RECALIBRATION, ++ CAPABILITY_INTERNAL_PA_TX0, ++ CAPABILITY_INTERNAL_PA_TX1, + }; + + /* diff --git a/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch b/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch new file mode 100644 index 0000000..dcecba4 --- /dev/null +++ b/package/kernel/mac80211/patches/611-rt2x00-rf_vals-rt3352-xtal20.patch @@ -0,0 +1,106 @@ +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -8185,6 +8185,27 @@ static const struct rf_channel rf_vals_5 + {196, 83, 0, 12, 1}, + }; + ++/* ++ * RF value list for rt3xxx with Xtal20MHz ++ * Supports: 2.4 GHz (all) (RF3322) ++ */ ++static const struct rf_channel rf_vals_xtal20mhz_3x[] = { ++ {1, 0xE2, 2, 0x14}, ++ {2, 0xE3, 2, 0x14}, ++ {3, 0xE4, 2, 0x14}, ++ {4, 0xE5, 2, 0x14}, ++ {5, 0xE6, 2, 0x14}, ++ {6, 0xE7, 2, 0x14}, ++ {7, 0xE8, 2, 0x14}, ++ {8, 0xE9, 2, 0x14}, ++ {9, 0xEA, 2, 0x14}, ++ {10, 0xEB, 2, 0x14}, ++ {11, 0xEC, 2, 0x14}, ++ {12, 0xED, 2, 0x14}, ++ {13, 0xEE, 2, 0x14}, ++ {14, 0xF0, 2, 0x18}, ++}; ++ + static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) + { + struct hw_mode_spec *spec = &rt2x00dev->spec; +@@ -8271,7 +8292,10 @@ static int rt2800_probe_hw_mode(struct r + case RF5390: + case RF5392: + spec->num_channels = 14; +- spec->channels = rf_vals_3x; ++ if (spec->clk_is_20mhz) ++ spec->channels = rf_vals_xtal20mhz_3x; ++ else ++ spec->channels = rf_vals_3x; + break; + + case RF3052: +@@ -8455,6 +8479,19 @@ static int rt2800_probe_rt(struct rt2x00 + return 0; + } + ++int rt2800_probe_clk(struct rt2x00_dev *rt2x00dev) ++{ ++ struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data; ++ struct hw_mode_spec *spec = &rt2x00dev->spec; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ spec->clk_is_20mhz = pdata->clk_is_20mhz; ++ ++ return 0; ++} ++ + int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) + { + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; +@@ -8497,6 +8534,15 @@ int rt2800_probe_hw(struct rt2x00_dev *r + rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); + + /* ++ * Probe SoC clock. ++ */ ++ if (rt2x00_is_soc(rt2x00dev)) { ++ retval = rt2800_probe_clk(rt2x00dev); ++ if (retval) ++ return retval; ++ } ++ ++ /* + * Initialize hw specifications. + */ + retval = rt2800_probe_hw_mode(rt2x00dev); +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -398,6 +398,7 @@ static inline struct rt2x00_intf* vif_to + * @channels: Device/chipset specific channel values (See &struct rf_channel). + * @channels_info: Additional information for channels (See &struct channel_info). + * @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap). ++ * @clk_is_20mhz: External crystal of WiSoC is 20MHz instead of 40MHz + */ + struct hw_mode_spec { + unsigned int supported_bands; +@@ -414,6 +415,7 @@ struct hw_mode_spec { + const struct channel_info *channels_info; + + struct ieee80211_sta_ht_cap ht; ++ int clk_is_20mhz; + }; + + /* +--- a/include/linux/rt2x00_platform.h ++++ b/include/linux/rt2x00_platform.h +@@ -18,6 +18,7 @@ struct rt2x00_platform_data { + + int disable_2ghz; + int disable_5ghz; ++ int clk_is_20mhz; + }; + + #endif /* _RT2X00_PLATFORM_H */ diff --git a/package/kernel/mac80211/patches/612-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch b/package/kernel/mac80211/patches/612-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch new file mode 100644 index 0000000..1970efc --- /dev/null +++ b/package/kernel/mac80211/patches/612-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch @@ -0,0 +1,33 @@ +From 04dbd87265f6ba4a373b211ba324b437d224fb2d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Sun, 17 Mar 2013 00:03:31 +0100 +Subject: [PATCH 21/38] rt2x00: make wmac loadable via OF on rt288x/305x SoC + +This patch ads the match table to allow loading the wmac support from a +devicetree. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + drivers/net/wireless/rt2x00/rt2800pci.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/net/wireless/rt2x00/rt2800soc.c ++++ b/drivers/net/wireless/rt2x00/rt2800soc.c +@@ -237,10 +237,17 @@ static int rt2800soc_probe(struct platfo + return rt2x00soc_probe(pdev, &rt2800soc_ops); + } + ++static const struct of_device_id rt2880_wmac_match[] = { ++ { .compatible = "ralink,rt2880-wmac" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rt2880_wmac_match); ++ + static struct platform_driver rt2800soc_driver = { + .driver = { + .name = "rt2800_wmac", + .mod_name = KBUILD_MODNAME, ++ .of_match_table = rt2880_wmac_match, + }, + .probe = rt2800soc_probe, + .remove = rt2x00soc_remove, diff --git a/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch b/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch new file mode 100644 index 0000000..9f11862 --- /dev/null +++ b/package/kernel/mac80211/patches/615-rt2x00-fix_20mhz_clk.patch @@ -0,0 +1,29 @@ +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -36,6 +36,7 @@ + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/slab.h> ++#include <linux/clk.h> + + #include "rt2x00.h" + #include "rt2800lib.h" +@@ -8481,13 +8482,14 @@ static int rt2800_probe_rt(struct rt2x00 + + int rt2800_probe_clk(struct rt2x00_dev *rt2x00dev) + { +- struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data; + struct hw_mode_spec *spec = &rt2x00dev->spec; ++ struct clk *clk = clk_get(rt2x00dev->dev, NULL); + +- if (!pdata) +- return -EINVAL; ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); + +- spec->clk_is_20mhz = pdata->clk_is_20mhz; ++ if (clk_get_rate(clk) == 20000000) ++ spec->clk_is_20mhz = 1; + + return 0; + } diff --git a/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch b/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch new file mode 100644 index 0000000..9679d71 --- /dev/null +++ b/package/kernel/mac80211/patches/616-rt2x00-support-rt5350.patch @@ -0,0 +1,276 @@ +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -74,6 +74,7 @@ + #define RF3070 0x3070 + #define RF3290 0x3290 + #define RF3853 0x3853 ++#define RF5350 0x5350 + #define RF5360 0x5360 + #define RF5362 0x5362 + #define RF5370 0x5370 +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -3014,6 +3014,13 @@ static void rt2800_config_channel_rf53xx + + rt2800_rfcsr_write(rt2x00dev, 59, + r59_non_bt[idx]); ++ } else if (rt2x00_rt(rt2x00dev, RT5350)) { ++ static const char r59_non_bt[] = {0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, ++ 0x0a, 0x09, 0x08, 0x07, 0x07, 0x06}; ++ ++ rt2800_rfcsr_write(rt2x00dev, 59, ++ r59_non_bt[idx]); + } + } + } +@@ -3492,6 +3499,7 @@ static void rt2800_config_channel(struct + rt2800_config_channel_rf3853(rt2x00dev, conf, rf, info); + break; + case RF3070: ++ case RF5350: + case RF5360: + case RF5362: + case RF5370: +@@ -3510,6 +3518,7 @@ static void rt2800_config_channel(struct + if (rt2x00_rf(rt2x00dev, RF3070) || + rt2x00_rf(rt2x00dev, RF3290) || + rt2x00_rf(rt2x00dev, RF3322) || ++ rt2x00_rf(rt2x00dev, RF5350) || + rt2x00_rf(rt2x00dev, RF5360) || + rt2x00_rf(rt2x00dev, RF5362) || + rt2x00_rf(rt2x00dev, RF5370) || +@@ -3788,7 +3797,8 @@ static void rt2800_config_channel(struct + /* + * Clear update flag + */ +- if (rt2x00_rt(rt2x00dev, RT3352)) { ++ if (rt2x00_rt(rt2x00dev, RT3352) || ++ rt2x00_rt(rt2x00dev, RT5350)) { + rt2800_bbp_read(rt2x00dev, 49, &bbp); + rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0); + rt2800_bbp_write(rt2x00dev, 49, bbp); +@@ -4674,6 +4684,7 @@ void rt2800_vco_calibration(struct rt2x0 + case RF3070: + case RF3290: + case RF3853: ++ case RF5350: + case RF5360: + case RF5362: + case RF5370: +@@ -5087,6 +5098,8 @@ static int rt2800_init_registers(struct + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); ++ } else if (rt2x00_rt(rt2x00dev, RT5350)) { ++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); + } else { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); +@@ -5742,9 +5755,13 @@ static void rt2800_init_bbp_3352(struct + + rt2800_bbp_write(rt2x00dev, 82, 0x62); + +- rt2800_bbp_write(rt2x00dev, 83, 0x6a); +- +- rt2800_bbp_write(rt2x00dev, 84, 0x99); ++ if (rt2x00_rt(rt2x00dev, RT5350)) { ++ rt2800_bbp_write(rt2x00dev, 83, 0x7a); ++ rt2800_bbp_write(rt2x00dev, 84, 0x9a); ++ } else { ++ rt2800_bbp_write(rt2x00dev, 83, 0x6a); ++ rt2800_bbp_write(rt2x00dev, 84, 0x99); ++ } + + rt2800_bbp_write(rt2x00dev, 86, 0x38); + +@@ -5758,9 +5775,13 @@ static void rt2800_init_bbp_3352(struct + + rt2800_bbp_write(rt2x00dev, 104, 0x92); + +- rt2800_bbp_write(rt2x00dev, 105, 0x34); +- +- rt2800_bbp_write(rt2x00dev, 106, 0x05); ++ if (rt2x00_rt(rt2x00dev, RT5350)) { ++ rt2800_bbp_write(rt2x00dev, 105, 0x3c); ++ rt2800_bbp_write(rt2x00dev, 106, 0x03); ++ } else { ++ rt2800_bbp_write(rt2x00dev, 105, 0x34); ++ rt2800_bbp_write(rt2x00dev, 106, 0x05); ++ } + + rt2800_bbp_write(rt2x00dev, 120, 0x50); + +@@ -5785,6 +5806,13 @@ static void rt2800_init_bbp_3352(struct + rt2800_bbp_write(rt2x00dev, 143, 0xa2); + + rt2800_bbp_write(rt2x00dev, 148, 0xc8); ++ ++ if (rt2x00_rt(rt2x00dev, RT5350)) { ++ rt2800_bbp_write(rt2x00dev, 150, 0x40); /* Antenna Software OFDM */ ++ rt2800_bbp_write(rt2x00dev, 151, 0x30); /* Antenna Software CCK */ ++ rt2800_bbp_write(rt2x00dev, 152, 0xa3); ++ rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ ++ } + } + + static void rt2800_init_bbp_3390(struct rt2x00_dev *rt2x00dev) +@@ -6126,6 +6154,7 @@ static void rt2800_init_bbp(struct rt2x0 + rt2800_init_bbp_3290(rt2x00dev); + break; + case RT3352: ++ case RT5350: + rt2800_init_bbp_3352(rt2x00dev); + break; + case RT3390: +@@ -7077,6 +7106,76 @@ static void rt2800_init_rfcsr_3883(struc + rt2800_rfcsr_write(rt2x00dev, 20, rfcsr); + } + ++static void rt2800_init_rfcsr_5350(struct rt2x00_dev *rt2x00dev) ++{ ++ rt2800_rfcsr_write(rt2x00dev, 0, 0xf0); ++ rt2800_rfcsr_write(rt2x00dev, 1, 0x23); ++ rt2800_rfcsr_write(rt2x00dev, 2, 0x50); ++ rt2800_rfcsr_write(rt2x00dev, 3, 0x08); ++ rt2800_rfcsr_write(rt2x00dev, 4, 0x49); ++ rt2800_rfcsr_write(rt2x00dev, 5, 0x10); ++ rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); ++ rt2800_rfcsr_write(rt2x00dev, 7, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 8, 0xf1); ++ rt2800_rfcsr_write(rt2x00dev, 9, 0x02); ++ rt2800_rfcsr_write(rt2x00dev, 10, 0x53); ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); ++ rt2800_rfcsr_write(rt2x00dev, 12, 0x46); ++ if(rt2x00dev->spec.clk_is_20mhz) ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x1f); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); ++ rt2800_rfcsr_write(rt2x00dev, 14, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 15, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 16, 0xc0); ++ rt2800_rfcsr_write(rt2x00dev, 18, 0x03); ++ rt2800_rfcsr_write(rt2x00dev, 19, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 20, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 21, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 22, 0x20); ++ 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, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0xd0); ++ 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, 0x07); ++ rt2800_rfcsr_write(rt2x00dev, 35, 0x12); ++ rt2800_rfcsr_write(rt2x00dev, 36, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 37, 0x08); ++ rt2800_rfcsr_write(rt2x00dev, 38, 0x85); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); ++ rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); ++ rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); ++ rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); ++ rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); ++ rt2800_rfcsr_write(rt2x00dev, 44, 0x0c); ++ rt2800_rfcsr_write(rt2x00dev, 45, 0xa6); ++ rt2800_rfcsr_write(rt2x00dev, 46, 0x73); ++ rt2800_rfcsr_write(rt2x00dev, 47, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 48, 0x10); ++ rt2800_rfcsr_write(rt2x00dev, 49, 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 50, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 51, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 52, 0x38); ++ rt2800_rfcsr_write(rt2x00dev, 53, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 54, 0x38); ++ rt2800_rfcsr_write(rt2x00dev, 55, 0x43); ++ rt2800_rfcsr_write(rt2x00dev, 56, 0x82); ++ rt2800_rfcsr_write(rt2x00dev, 57, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 58, 0x39); ++ rt2800_rfcsr_write(rt2x00dev, 59, 0x0b); ++ rt2800_rfcsr_write(rt2x00dev, 60, 0x45); ++ rt2800_rfcsr_write(rt2x00dev, 61, 0xd1); ++ rt2800_rfcsr_write(rt2x00dev, 62, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 63, 0x00); ++} ++ + static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev) + { + rt2800_rf_init_calibration(rt2x00dev, 2); +@@ -7317,6 +7416,9 @@ static void rt2800_init_rfcsr(struct rt2 + case RT3593: + rt2800_init_rfcsr_3593(rt2x00dev); + break; ++ case RT5350: ++ rt2800_init_rfcsr_5350(rt2x00dev); ++ break; + case RT5390: + rt2800_init_rfcsr_5390(rt2x00dev); + break; +@@ -7576,6 +7678,12 @@ static int rt2800_validate_eeprom(struct + rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820); + rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); + rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); ++ } else if (rt2x00_rt(rt2x00dev, RT5350)) { ++ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 1); ++ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1); ++ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF3320); ++ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); ++ rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); + } else if (rt2x00_rt(rt2x00dev, RT2860) || + rt2x00_rt(rt2x00dev, RT2872)) { + /* +@@ -7714,6 +7822,8 @@ static int rt2800_init_eeprom(struct rt2 + rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); + else if (rt2x00_rt(rt2x00dev, RT3883)) + rf = RF3853; ++ else if (rt2x00_rt(rt2x00dev, RT5350)) ++ rf = RF5350; + else + rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE); + +@@ -7733,6 +7843,7 @@ static int rt2800_init_eeprom(struct rt2 + case RF3320: + case RF3322: + case RF3853: ++ case RF5350: + case RF5360: + case RF5362: + case RF5370: +@@ -8286,6 +8397,7 @@ static int rt2800_probe_hw_mode(struct r + case RF3290: + case RF3320: + case RF3322: ++ case RF5350: + case RF5360: + case RF5362: + case RF5370: +@@ -8425,6 +8537,7 @@ static int rt2800_probe_hw_mode(struct r + case RF3070: + case RF3290: + case RF3853: ++ case RF5350: + case RF5360: + case RF5362: + case RF5370: +@@ -8465,6 +8578,7 @@ static int rt2800_probe_rt(struct rt2x00 + case RT3572: + case RT3593: + case RT3883: ++ case RT5350: + case RT5390: + case RT5392: + case RT5592: +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -169,6 +169,7 @@ struct rt2x00_chip { + #define RT3572 0x3572 + #define RT3593 0x3593 + #define RT3883 0x3883 /* WSOC */ ++#define RT5350 0x5350 /* WSOC 2.4GHz */ + #define RT5390 0x5390 /* 2.4GHz */ + #define RT5392 0x5392 /* 2.4GHz */ + #define RT5592 0x5592 diff --git a/package/kernel/mac80211/patches/619-rt2x00-change-led-polarity-from-OF.patch b/package/kernel/mac80211/patches/619-rt2x00-change-led-polarity-from-OF.patch new file mode 100644 index 0000000..b085c5e --- /dev/null +++ b/package/kernel/mac80211/patches/619-rt2x00-change-led-polarity-from-OF.patch @@ -0,0 +1,40 @@ +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -37,6 +37,7 @@ + #include <linux/module.h> + #include <linux/slab.h> + #include <linux/clk.h> ++#include <linux/of.h> + + #include "rt2x00.h" + #include "rt2800lib.h" +@@ -7933,6 +7934,17 @@ static int rt2800_init_eeprom(struct rt2 + rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + ++ { ++ struct device_node *np = rt2x00dev->dev->of_node; ++ unsigned int led_polarity; ++ ++ /* Allow overriding polarity from OF */ ++ if (!of_property_read_u32(np, "ralink,led-polarity", ++ &led_polarity)) ++ rt2x00_set_field16(&eeprom, EEPROM_FREQ_LED_POLARITY, ++ led_polarity); ++ } ++ + rt2x00dev->led_mcu_reg = eeprom; + #endif /* CPTCFG_RT2X00_LIB_LEDS */ + +--- a/drivers/net/wireless/rt2x00/rt2x00leds.c ++++ b/drivers/net/wireless/rt2x00/rt2x00leds.c +@@ -109,6 +109,9 @@ static int rt2x00leds_register_led(struc + led->led_dev.name = name; + led->led_dev.brightness = LED_OFF; + ++ if (rt2x00_is_soc(rt2x00dev)) ++ led->led_dev.brightness_set(&led->led_dev, LED_OFF); ++ + retval = led_classdev_register(device, &led->led_dev); + if (retval) { + rt2x00_err(rt2x00dev, "Failed to register led handler\n"); diff --git a/package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch b/package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch new file mode 100644 index 0000000..2dbfd10 --- /dev/null +++ b/package/kernel/mac80211/patches/620-rt2x00-add-AP+STA-support.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -1283,7 +1283,7 @@ static inline void rt2x00lib_set_if_comb + */ + if_limit = &rt2x00dev->if_limits_ap; + if_limit->max = rt2x00dev->ops->max_ap_intf; +- if_limit->types = BIT(NL80211_IFTYPE_AP); ++ if_limit->types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION); + #ifdef CPTCFG_MAC80211_MESH + if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT); + #endif diff --git a/package/kernel/mac80211/patches/620-rt2x00-rt3352-rf-id.patch b/package/kernel/mac80211/patches/620-rt2x00-rt3352-rf-id.patch new file mode 100644 index 0000000..259cb1f --- /dev/null +++ b/package/kernel/mac80211/patches/620-rt2x00-rt3352-rf-id.patch @@ -0,0 +1,15 @@ +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7817,10 +7817,11 @@ static int rt2800_init_eeprom(struct rt2 + * RT53xx: defined in "EEPROM_CHIP_ID" field + */ + if (rt2x00_rt(rt2x00dev, RT3290) || +- rt2x00_rt(rt2x00dev, RT3352) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) + rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); ++ else if (rt2x00_rt(rt2x00dev, RT3352)) ++ rf = RF3322; + else if (rt2x00_rt(rt2x00dev, RT3883)) + rf = RF3853; + else if (rt2x00_rt(rt2x00dev, RT5350)) diff --git a/package/kernel/mac80211/patches/621-rt2x00-ht20_40_fix.patch b/package/kernel/mac80211/patches/621-rt2x00-ht20_40_fix.patch new file mode 100644 index 0000000..77d63fe --- /dev/null +++ b/package/kernel/mac80211/patches/621-rt2x00-ht20_40_fix.patch @@ -0,0 +1,29 @@ +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -2321,6 +2321,8 @@ struct mac_iveiv_entry { + #define RFCSR30_RX_H20M FIELD8(0x04) + #define RFCSR30_RX_VCM FIELD8(0x18) + #define RFCSR30_RF_CALIBRATION FIELD8(0x80) ++#define RF3322_RFCSR30_TX_H20M FIELD8(0x01) ++#define RF3322_RFCSR30_RX_H20M FIELD8(0x02) + + /* + * RFCSR 31: +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -3527,8 +3527,13 @@ static void rt2800_config_channel(struct + rt2x00_rf(rt2x00dev, RF5390) || + rt2x00_rf(rt2x00dev, RF5392)) { + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); +- rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0); +- rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0); ++ if(rt2x00_rf(rt2x00dev, RF3322)) { ++ rt2x00_set_field8(&rfcsr, RF3322_RFCSR30_TX_H20M, conf_is_ht40(conf)); ++ rt2x00_set_field8(&rfcsr, RF3322_RFCSR30_RX_H20M, conf_is_ht40(conf)); ++ } else { ++ rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, conf_is_ht40(conf)); ++ rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, conf_is_ht40(conf)); ++ } + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); diff --git a/package/kernel/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch b/package/kernel/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch new file mode 100644 index 0000000..f2a7663 --- /dev/null +++ b/package/kernel/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 +@@ -5678,6 +5678,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw") + MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); + + static const struct pci_device_id 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/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch b/package/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch new file mode 100644 index 0000000..3b8b756 --- /dev/null +++ b/package/kernel/mac80211/patches/801-libertas-configure-sysfs-links.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/wireless/libertas/cfg.c ++++ b/drivers/net/wireless/libertas/cfg.c +@@ -2083,6 +2083,8 @@ struct wireless_dev *lbs_cfg_alloc(struc + goto err_wiphy_new; + } + ++ set_wiphy_dev(wdev->wiphy, dev); ++ + lbs_deb_leave(LBS_DEB_CFG80211); + return wdev; + +--- a/drivers/net/wireless/libertas/main.c ++++ b/drivers/net/wireless/libertas/main.c +@@ -987,6 +987,7 @@ struct lbs_private *lbs_add_card(void *c + goto err_adapter; + } + ++ dev_net_set(dev, wiphy_net(wdev->wiphy)); + dev->ieee80211_ptr = wdev; + dev->ml_priv = priv; + SET_NETDEV_DEV(dev, dmdev); diff --git a/package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch b/package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch new file mode 100644 index 0000000..dace56b --- /dev/null +++ b/package/kernel/mac80211/patches/802-libertas-set-wireless-macaddr.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/libertas/cfg.c ++++ b/drivers/net/wireless/libertas/cfg.c +@@ -2173,6 +2173,8 @@ int lbs_cfg_register(struct lbs_private + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wdev->wiphy->reg_notifier = lbs_reg_notifier; + ++ memcpy(wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN); ++ + ret = wiphy_register(wdev->wiphy); + if (ret < 0) + pr_err("cannot register wiphy device\n"); diff --git a/package/kernel/mac80211/patches/805-b43-gpio-mask-module-option.patch b/package/kernel/mac80211/patches/805-b43-gpio-mask-module-option.patch new file mode 100644 index 0000000..95867ef --- /dev/null +++ b/package/kernel/mac80211/patches/805-b43-gpio-mask-module-option.patch @@ -0,0 +1,37 @@ +--- a/drivers/net/wireless/b43/b43.h ++++ b/drivers/net/wireless/b43/b43.h +@@ -839,6 +839,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, +@@ -2882,10 +2887,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/kernel/mac80211/patches/810-b43_no_pio.patch b/package/kernel/mac80211/patches/810-b43_no_pio.patch new file mode 100644 index 0000000..0979100 --- /dev/null +++ b/package/kernel/mac80211/patches/810-b43_no_pio.patch @@ -0,0 +1,86 @@ +--- a/drivers/net/wireless/b43/Makefile ++++ b/drivers/net/wireless/b43/Makefile +@@ -17,7 +17,7 @@ b43-$(CPTCFG_B43_PHY_AC) += phy_ac.o + b43-y += sysfs.o + b43-y += xmit.o + b43-y += dma.o +-b43-y += pio.o ++b43-$(CPTCFG_B43_PIO) += pio.o + b43-y += rfkill.o + b43-y += ppr.o + b43-$(CPTCFG_B43_LEDS) += leds.o +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -2008,10 +2008,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 CPTCFG_B43_PIO + b43err(dev->wl, "This device does not support DMA " + "on your system. It will now be switched to PIO.\n"); + /* Fall back to PIO transfers if we get fatal DMA errors! */ + 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 CPTCFG_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 /* CPTCFG_B43_PIO */ + + #endif /* B43_PIO_H_ */ +--- a/drivers/net/wireless/b43/Kconfig ++++ b/drivers/net/wireless/b43/Kconfig +@@ -118,7 +118,7 @@ config B43_BCMA_PIO + default y + + config B43_PIO +- bool ++ bool "Broadcom 43xx PIO support" + depends on B43 && B43_SSB + select SSB_BLOCKIO + default y diff --git a/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch b/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch new file mode 100644 index 0000000..dd82ce5 --- /dev/null +++ b/package/kernel/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 +@@ -1648,7 +1648,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. */ +@@ -3300,8 +3300,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); +@@ -4001,7 +4001,6 @@ static int b43_op_config(struct ieee8021 + struct b43_wldev *dev = wl->current_dev; + struct b43_phy *phy = &dev->phy; + struct ieee80211_conf *conf = &hw->conf; +- int antenna; + int err = 0; + + mutex_lock(&wl->mutex); +@@ -4044,11 +4043,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) { +@@ -5209,6 +5206,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, +@@ -5230,6 +5268,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. +@@ -5538,6 +5578,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; +@@ -5628,6 +5670,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 +@@ -840,6 +840,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/kernel/mac80211/patches/841-b43-reduce-number-of-RX-slots.patch b/package/kernel/mac80211/patches/841-b43-reduce-number-of-RX-slots.patch new file mode 100644 index 0000000..9c51ac6 --- /dev/null +++ b/package/kernel/mac80211/patches/841-b43-reduce-number-of-RX-slots.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/b43/dma.h ++++ b/drivers/net/wireless/b43/dma.h +@@ -169,7 +169,7 @@ struct b43_dmadesc_generic { + + /* DMA engine tuning knobs */ + #define B43_TXRING_SLOTS 256 +-#define B43_RXRING_SLOTS 256 ++#define B43_RXRING_SLOTS 32 + #define B43_DMA0_RX_FW598_BUFSIZE (B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN) + #define B43_DMA0_RX_FW351_BUFSIZE (B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN) + diff --git a/package/kernel/mac80211/patches/845-b43-only-use-gpio-0-1-for-led.patch b/package/kernel/mac80211/patches/845-b43-only-use-gpio-0-1-for-led.patch new file mode 100644 index 0000000..d4f9a88 --- /dev/null +++ b/package/kernel/mac80211/patches/845-b43-only-use-gpio-0-1-for-led.patch @@ -0,0 +1,17 @@ +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -2899,6 +2899,14 @@ static int b43_gpio_init(struct b43_wlde + } else if (dev->dev->chip_id == 0x5354) { + /* Don't allow overtaking buttons GPIOs */ + set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */ ++ } else if (dev->dev->chip_id == BCMA_CHIP_ID_BCM4716 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM47162 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM5356 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM5357 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM53572) { ++ /* just use gpio 0 and 1 for 2.4 GHz wifi led */ ++ set &= 0x3; ++ mask &= 0x3; + } + + if (0 /* FIXME: conditional unknown */ ) { diff --git a/package/kernel/mac80211/patches/847-b43-always-take-overlapping-devs.patch b/package/kernel/mac80211/patches/847-b43-always-take-overlapping-devs.patch new file mode 100644 index 0000000..9d1d419 --- /dev/null +++ b/package/kernel/mac80211/patches/847-b43-always-take-overlapping-devs.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -118,7 +118,7 @@ static int b43_modparam_pio = 0; + module_param_named(pio, b43_modparam_pio, int, 0644); + MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO"); + +-static int modparam_allhwsupport = !IS_ENABLED(CPTCFG_BRCMSMAC); ++static int modparam_allhwsupport = 1; + module_param_named(allhwsupport, modparam_allhwsupport, int, 0444); + MODULE_PARM_DESC(allhwsupport, "Enable support for all hardware (even it if overlaps with the brcmsmac driver)"); + diff --git a/package/kernel/mac80211/patches/850-brcmsmac-remove-extra-regulation-restriction.patch b/package/kernel/mac80211/patches/850-brcmsmac-remove-extra-regulation-restriction.patch new file mode 100644 index 0000000..185c427 --- /dev/null +++ b/package/kernel/mac80211/patches/850-brcmsmac-remove-extra-regulation-restriction.patch @@ -0,0 +1,27 @@ +--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c ++++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c +@@ -58,19 +58,12 @@ + (((c) < 149) ? 3 : 4)))) + + #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0) +-#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \ +- NL80211_RRF_NO_IR) ++#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, 0) + +-#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \ +- NL80211_RRF_NO_IR) +-#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \ +- NL80211_RRF_DFS | \ +- NL80211_RRF_NO_IR) +-#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \ +- NL80211_RRF_DFS | \ +- NL80211_RRF_NO_IR) +-#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \ +- NL80211_RRF_NO_IR) ++#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, 0) ++#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, 0) ++#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, 0) ++#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, 0) + + static const struct ieee80211_regdomain brcms_regdom_x2 = { + .n_reg_rules = 6, diff --git a/package/kernel/mac80211/patches/860-brcmfmac-use-bcm47xx-platform-NVRAM-as-fallback.patch b/package/kernel/mac80211/patches/860-brcmfmac-use-bcm47xx-platform-NVRAM-as-fallback.patch new file mode 100644 index 0000000..dbfb158 --- /dev/null +++ b/package/kernel/mac80211/patches/860-brcmfmac-use-bcm47xx-platform-NVRAM-as-fallback.patch @@ -0,0 +1,80 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Mon, 8 Jun 2015 16:59:31 +0200 +Subject: [PATCH] brcmfmac: use bcm47xx platform NVRAM as fallback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +@@ -19,6 +19,9 @@ + #include <linux/device.h> + #include <linux/firmware.h> + #include <linux/module.h> ++#if IS_ENABLED(CONFIG_BCM47XX_NVRAM) ++#include <linux/bcm47xx_nvram.h> ++#endif + + #include "debug.h" + #include "firmware.h" +@@ -424,17 +427,42 @@ struct brcmf_fw { + static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) + { + struct brcmf_fw *fwctx = ctx; ++#if IS_ENABLED(CONFIG_BCM47XX_NVRAM) ++ const u8 *bcm47xx_nvram = NULL; ++ size_t bcm47xx_nvram_len; ++#endif ++ const u8 *data = NULL; ++ size_t data_len; + u32 nvram_length = 0; + void *nvram = NULL; + + brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); +- if (!fw && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) ++ if (fw) { ++ data = fw->data; ++ data_len = fw->size; ++ } ++#if IS_ENABLED(CONFIG_BCM47XX_NVRAM) ++ else { ++ bcm47xx_nvram = bcm47xx_nvram_get_contents(&bcm47xx_nvram_len); ++ if (bcm47xx_nvram) { ++ data = bcm47xx_nvram; ++ data_len = bcm47xx_nvram_len; ++ brcmf_err("Found platform NVRAM (%zu B)\n", data_len); ++ } ++ } ++#endif ++ if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + goto fail; + +- if (fw) { +- nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length, ++ if (data) { ++ nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, + fwctx->domain_nr, fwctx->bus_nr); +- release_firmware(fw); ++ if (fw) ++ release_firmware(fw); ++#if IS_ENABLED(CONFIG_BCM47XX_NVRAM) ++ if (bcm47xx_nvram) ++ bcm47xx_nvram_release_contents(bcm47xx_nvram); ++#endif + if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + goto fail; + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h +@@ -17,6 +17,8 @@ + #ifndef BRCMFMAC_DEBUG_H + #define BRCMFMAC_DEBUG_H + ++#include <linux/net.h> ++ + /* message levels */ + #define BRCMF_TRACE_VAL 0x00000002 + #define BRCMF_INFO_VAL 0x00000004 diff --git a/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch new file mode 100644 index 0000000..685a5f9 --- /dev/null +++ b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch @@ -0,0 +1,114 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Mon, 8 Jun 2015 16:11:40 +0200 +Subject: [PATCH] brcmfmac: register wiphy(s) during module_init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is needed by OpenWrt which expects all PHYs to be created after +module loads successfully. + +Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -1213,6 +1213,7 @@ static int __init brcmfmac_module_init(v + #endif + if (!schedule_work(&brcmf_driver_work)) + return -EBUSY; ++ flush_work(&brcmf_driver_work); + + return 0; + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +@@ -422,13 +422,14 @@ struct brcmf_fw { + u16 bus_nr; + void (*done)(struct device *dev, const struct firmware *fw, + void *nvram_image, u32 nvram_len); ++ struct completion *completion; + }; + + static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) + { + struct brcmf_fw *fwctx = ctx; + #if IS_ENABLED(CONFIG_BCM47XX_NVRAM) +- const u8 *bcm47xx_nvram = NULL; ++ u8 *bcm47xx_nvram = NULL; + size_t bcm47xx_nvram_len; + #endif + const u8 *data = NULL; +@@ -468,6 +469,8 @@ static void brcmf_fw_request_nvram_done( + } + + fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length); ++ if (fwctx->completion) ++ complete(fwctx->completion); + kfree(fwctx); + return; + +@@ -475,6 +478,8 @@ fail: + brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); + release_firmware(fwctx->code); + device_release_driver(fwctx->dev); ++ if (fwctx->completion) ++ complete(fwctx->completion); + kfree(fwctx); + } + +@@ -490,6 +495,8 @@ static void brcmf_fw_request_code_done(c + /* only requested code so done here */ + if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM)) { + fwctx->done(fwctx->dev, fw, NULL, 0); ++ if (fwctx->completion) ++ complete(fwctx->completion); + kfree(fwctx); + return; + } +@@ -504,6 +511,8 @@ static void brcmf_fw_request_code_done(c + /* when nvram is optional call .done() callback here */ + if (fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL) { + fwctx->done(fwctx->dev, fw, NULL, 0); ++ if (fwctx->completion) ++ complete(fwctx->completion); + kfree(fwctx); + return; + } +@@ -513,6 +522,8 @@ static void brcmf_fw_request_code_done(c + fail: + brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); + device_release_driver(fwctx->dev); ++ if (fwctx->completion) ++ complete(fwctx->completion); + kfree(fwctx); + } + +@@ -524,6 +535,8 @@ int brcmf_fw_get_firmwares_pcie(struct d + u16 domain_nr, u16 bus_nr) + { + struct brcmf_fw *fwctx; ++ struct completion completion; ++ int err; + + brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); + if (!fw_cb || !code) +@@ -544,9 +557,17 @@ int brcmf_fw_get_firmwares_pcie(struct d + fwctx->domain_nr = domain_nr; + fwctx->bus_nr = bus_nr; + +- return request_firmware_nowait(THIS_MODULE, true, code, dev, ++ init_completion(&completion); ++ fwctx->completion = &completion; ++ ++ err = request_firmware_nowait(THIS_MODULE, true, code, dev, + GFP_KERNEL, fwctx, + brcmf_fw_request_code_done); ++ if (!err) ++ wait_for_completion_timeout(fwctx->completion, ++ msecs_to_jiffies(5000)); ++ fwctx->completion = NULL; ++ return err; + } + + int brcmf_fw_get_firmwares(struct device *dev, u16 flags, diff --git a/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch b/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch new file mode 100644 index 0000000..5fdfa37 --- /dev/null +++ b/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch @@ -0,0 +1,50 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Thu, 9 Jul 2015 00:07:59 +0200 +Subject: [PATCH] brcmfmac: workaround bug with some inconsistent BSSes state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -692,9 +692,37 @@ static struct wireless_dev *brcmf_cfg802 + u32 *flags, + struct vif_params *params) + { ++ struct net_device *dev; + struct wireless_dev *wdev; + int err; + ++ /* ++ * There is a bug with in-firmware BSS management. When adding virtual ++ * interface brcmfmac first tells firmware to create new BSS and then ++ * it creates new struct net_device. ++ * ++ * If creating/registering netdev(ice) fails, BSS remains in some bugged ++ * state. It conflicts with existing BSSes by overtaking their auth ++ * requests. ++ * ++ * It results in one BSS (addresss X) sending beacons and another BSS ++ * (address Y) replying to authentication requests. This makes interface ++ * unusable as AP. ++ * ++ * To workaround this bug we may try to guess if register_netdev(ice) ++ * will fail. The most obvious case is using interface name that already ++ * exists. This is actually quite likely with brcmfmac & some user space ++ * scripts as brcmfmac doesn't allow deleting virtual interfaces. ++ * So this bug can be triggered even by something trivial like: ++ * iw dev wlan0 delete ++ * iw phy phy0 interface add wlan0 type __ap ++ */ ++ dev = dev_get_by_name(&init_net, name); ++ if (dev) { ++ dev_put(dev); ++ return ERR_PTR(-EEXIST); ++ } ++ + brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); + err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); + if (err) { diff --git a/package/kernel/mac80211/patches/910-00-rt2x00-enable-rt2800soc-for-mt7620.patch b/package/kernel/mac80211/patches/910-00-rt2x00-enable-rt2800soc-for-mt7620.patch new file mode 100644 index 0000000..e6b2d7b --- /dev/null +++ b/package/kernel/mac80211/patches/910-00-rt2x00-enable-rt2800soc-for-mt7620.patch @@ -0,0 +1,20 @@ +--- a/drivers/net/wireless/rt2x00/Kconfig ++++ b/drivers/net/wireless/rt2x00/Kconfig +@@ -211,7 +211,7 @@ endif + config RT2800SOC + tristate "Ralink WiSoC support" + depends on m +- depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 ++ depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620 + select RT2X00_LIB_SOC + select RT2X00_LIB_MMIO + select RT2X00_LIB_CRYPTO +@@ -248,7 +248,7 @@ config RT2X00_LIB_PCI + + config RT2X00_LIB_SOC + tristate "RT2x00 SoC support" +- depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 ++ depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620 + depends on m + select RT2X00_LIB + diff --git a/package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch b/package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch new file mode 100644 index 0000000..b0536ce --- /dev/null +++ b/package/kernel/mac80211/patches/910-01-add-support-for-mt7620.patch @@ -0,0 +1,1202 @@ +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -81,6 +81,7 @@ + #define RF5372 0x5372 + #define RF5390 0x5390 + #define RF5392 0x5392 ++#define RF7620 0x7620 + + /* + * Chipset revisions. +@@ -656,6 +657,14 @@ + #define RF_CSR_CFG_BUSY FIELD32(0x00020000) + + /* ++ * mt7620 RF registers (reversed order) ++ */ ++#define RF_CSR_CFG_DATA_MT7620 FIELD32(0x0000ff00) ++#define RF_CSR_CFG_REGNUM_MT7620 FIELD32(0x03ff0000) ++#define RF_CSR_CFG_WRITE_MT7620 FIELD32(0x00000010) ++#define RF_CSR_CFG_BUSY_MT7620 FIELD32(0x00000001) ++ ++/* + * EFUSE_CSR: RT30x0 EEPROM + */ + #define EFUSE_CTRL 0x0580 +@@ -1039,6 +1048,11 @@ + #define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000) + + /* ++ * mt7620 ++ */ ++#define MIMO_PS_CFG 0x1210 ++ ++/* + * EDCA_AC0_CFG: + */ + #define EDCA_AC0_CFG 0x1300 +@@ -1218,6 +1232,8 @@ + #define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) + #define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) + #define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) ++#define TX_PIN_CFG_RFRX_EN FIELD32(0x00100000) /* mt7620 */ ++#define TX_PIN_CFG_RFRX_POL FIELD32(0x00200000) /* mt7620 */ + #define TX_PIN_CFG_PA_PE_A2_EN FIELD32(0x01000000) + #define TX_PIN_CFG_PA_PE_G2_EN FIELD32(0x02000000) + #define TX_PIN_CFG_PA_PE_A2_POL FIELD32(0x04000000) +@@ -1564,6 +1580,17 @@ + #define TX_PWR_CFG_4_EXT_STBC4_CH2 FIELD32(0x0000000f) + #define TX_PWR_CFG_4_EXT_STBC6_CH2 FIELD32(0x00000f00) + ++/* mt7620 */ ++#define TX0_RF_GAIN_CORRECT 0x13a0 ++#define TX1_RF_GAIN_CORRECT 0x13a4 ++#define TX0_RF_GAIN_ATTEN 0x13a8 ++#define TX1_RF_GAIN_ATTEN 0x13ac ++#define TX_ALG_CFG_0 0x13b0 ++#define TX_ALG_CFG_1 0x13b4 ++#define TX0_BB_GAIN_ATTEN 0x13c0 ++#define TX1_BB_GAIN_ATTEN 0x13c4 ++#define TX_ALC_VGA3 0x13c8 ++ + /* TX_PWR_CFG_7 */ + #define TX_PWR_CFG_7 0x13d4 + #define TX_PWR_CFG_7_OFDM54_CH0 FIELD32(0x0000000f) +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -61,6 +61,8 @@ + rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) + #define WAIT_FOR_RFCSR(__dev, __reg) \ + rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) ++#define WAIT_FOR_RFCSR_MT7620(__dev, __reg) \ ++ rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY_MT7620, (__reg)) + #define WAIT_FOR_RF(__dev, __reg) \ + rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) + #define WAIT_FOR_MCU(__dev, __reg) \ +@@ -186,19 +188,55 @@ static void rt2800_rfcsr_write(struct rt + * Wait until the RFCSR becomes available, afterwards we + * can safely write the new data into the register. + */ +- if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { +- reg = 0; +- rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); +- rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); +- rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); +- rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); ++ switch (rt2x00dev->chip.rf) { ++ case RF7620: ++ if (WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®)) { ++ reg = 0; ++ rt2x00_set_field32(®, RF_CSR_CFG_DATA_MT7620, value); ++ rt2x00_set_field32(®, RF_CSR_CFG_REGNUM_MT7620, word); ++ rt2x00_set_field32(®, RF_CSR_CFG_WRITE_MT7620, 1); ++ rt2x00_set_field32(®, RF_CSR_CFG_BUSY_MT7620, 1); ++ ++ rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); ++ } ++ break; ++ ++ default: ++ if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { ++ reg = 0; ++ rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); ++ rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); ++ rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); ++ rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + +- rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); ++ rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); ++ } ++ break; + } + + mutex_unlock(&rt2x00dev->csr_mutex); + } + ++static void rt2800_rfcsr_write_bank(struct rt2x00_dev *rt2x00dev, const u8 bank, ++ const unsigned int reg, const u8 value) ++{ ++ rt2800_rfcsr_write(rt2x00dev, (reg | (bank << 6)), value); ++} ++ ++static void rt2800_rfcsr_write_chanreg(struct rt2x00_dev *rt2x00dev, ++ const unsigned int reg, const u8 value) ++{ ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, reg, value); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, reg, value); ++} ++ ++static void rt2800_rfcsr_write_dccal(struct rt2x00_dev *rt2x00dev, ++ const unsigned int reg, const u8 value) ++{ ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, reg, value); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, reg, value); ++} ++ + static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) + { +@@ -214,22 +252,47 @@ static void rt2800_rfcsr_read(struct rt2 + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ +- if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { +- reg = 0; +- rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); +- rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); +- rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); ++ switch (rt2x00dev->chip.rf) { ++ case RF7620: ++ if (WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®)) { ++ reg = 0; ++ rt2x00_set_field32(®, RF_CSR_CFG_REGNUM_MT7620, word); ++ rt2x00_set_field32(®, RF_CSR_CFG_WRITE_MT7620, 0); ++ rt2x00_set_field32(®, RF_CSR_CFG_BUSY_MT7620, 1); + +- rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); ++ rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); + +- WAIT_FOR_RFCSR(rt2x00dev, ®); +- } ++ WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®); ++ } + +- *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); ++ *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA_MT7620); ++ break; ++ ++ default: ++ if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { ++ reg = 0; ++ rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); ++ rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); ++ rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); ++ ++ rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); ++ ++ WAIT_FOR_RFCSR(rt2x00dev, ®); ++ } ++ ++ *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); ++ break; ++ } + + mutex_unlock(&rt2x00dev->csr_mutex); + } + ++static void rt2800_rfcsr_read_bank(struct rt2x00_dev *rt2x00dev, const u8 bank, ++ const unsigned int reg, u8 *value) ++{ ++ rt2800_rfcsr_read(rt2x00dev, (reg | (bank << 6)), value); ++} ++ + static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) + { +@@ -566,6 +629,16 @@ void rt2800_get_txwi_rxwi_size(struct rt + *rxwi_size = RXWI_DESC_SIZE_5WORDS; + break; + ++ case RT5390: ++ if ( rt2x00dev->chip.rf == RF7620 ) { ++ *txwi_size = TXWI_DESC_SIZE_5WORDS; ++ *rxwi_size = RXWI_DESC_SIZE_6WORDS; ++ } else { ++ *txwi_size = TXWI_DESC_SIZE_4WORDS; ++ *rxwi_size = RXWI_DESC_SIZE_4WORDS; ++ } ++ break; ++ + case RT5592: + *txwi_size = TXWI_DESC_SIZE_5WORDS; + *rxwi_size = RXWI_DESC_SIZE_6WORDS; +@@ -3302,6 +3375,312 @@ static void rt2800_config_channel_rf55xx + rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x19 : 0x7F); + } + ++typedef struct mt7620_freqconfig { ++ u8 Channel; ++ u8 Rdiv; ++ u16 N; ++ u8 K; ++ u8 D; ++ u32 Ksd; ++} mt7620_freqconfig; ++ ++mt7620_freqconfig mt7620_chanconfig[] = ++{ ++ /* 2.4 to 2.483 GHz ++ * CH Rdiv N K D Ksd */ ++ { 0, 0, 0, 0, 0, 0 }, ++ { 1, 3, 0x50, 0, 0, 0x19999 }, ++ { 2, 3, 0x50, 0, 0, 0x24444 }, ++ { 3, 3, 0x50, 0, 0, 0x2EEEE }, ++ { 4, 3, 0x50, 0, 0, 0x39999 }, ++ { 5, 3, 0x51, 0, 0, 0x04444 }, ++ { 6, 3, 0x51, 0, 0, 0x0EEEE }, ++ { 7, 3, 0x51, 0, 0, 0x19999 }, ++ { 8, 3, 0x51, 0, 0, 0x24444 }, ++ { 9, 3, 0x51, 0, 0, 0x2EEEE }, ++ { 10, 3, 0x51, 0, 0, 0x39999 }, ++ { 11, 3, 0x52, 0, 0, 0x04444 }, ++ { 12, 3, 0x52, 0, 0, 0x0EEEE }, ++ { 13, 3, 0x52, 0, 0, 0x19999 }, ++ { 14, 3, 0x52, 0, 0, 0x33333 }, ++}; ++ ++static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_conf *conf, ++ struct rf_channel *rf, ++ struct channel_info *info) ++{ ++ int i; ++ u8 bbp; ++ u8 rfcsr; ++ u8 txrx_agc_fc; ++ u32 reg; ++ u16 eeprom, target_power; ++ u32 mac_sys_ctrl, mac_status; ++ u32 tx_pin = 0x00150F0F; ++ struct hw_mode_spec *spec = &rt2x00dev->spec; ++ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; ++ ++ /* Frequeny plan setting */ ++ /* ++ * Rdiv setting ++ * R13[1:0] ++ */ ++ rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); ++ rfcsr = rfcsr & (~0x03); ++ if (spec->clk_is_20mhz) ++ rfcsr |= (mt7620_chanconfig[rf->channel].Rdiv & 0x3); ++ rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); ++ ++ /* ++ * N setting ++ * R21[0], R20[7:0] ++ */ ++ rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr); ++ rfcsr = (mt7620_chanconfig[rf->channel].N & 0x00ff); ++ rt2800_rfcsr_write(rt2x00dev, 20, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); ++ rfcsr = rfcsr & (~0x01); ++ rfcsr |= ((mt7620_chanconfig[rf->channel].N & 0x0100) >> 8); ++ rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); ++ ++ /* ++ * K setting ++ * R16[3:0] (RF PLL freq selection) ++ */ ++ rt2800_rfcsr_read(rt2x00dev, 16, &rfcsr); ++ rfcsr = rfcsr & (~0x0f); ++ rfcsr |= (mt7620_chanconfig[rf->channel].K & 0x0f); ++ rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); ++ ++ /* ++ * D setting ++ * R22[2:0] (D=15, R22[2:0]=<111>) ++ */ ++ rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); ++ rfcsr = rfcsr & (~0x07); ++ rfcsr |= (mt7620_chanconfig[rf->channel].D & 0x07); ++ rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); ++ ++ /* ++ * Ksd setting ++ * Ksd: R19<1:0>,R18<7:0>,R17<7:0> ++ */ ++ rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); ++ rfcsr = (mt7620_chanconfig[rf->channel].Ksd & 0x000000ff); ++ rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr); ++ rfcsr = ((mt7620_chanconfig[rf->channel].Ksd & 0x0000ff00) >> 8); ++ rt2800_rfcsr_write(rt2x00dev, 18, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 19, &rfcsr); ++ rfcsr = rfcsr & (~0x03); ++ rfcsr |= ((mt7620_chanconfig[rf->channel].Ksd & 0x00030000) >> 16); ++ rt2800_rfcsr_write(rt2x00dev, 19, rfcsr); ++ ++ /* Default: XO=20MHz , SDM mode */ ++ rt2800_rfcsr_read(rt2x00dev, 16, &rfcsr); ++ rfcsr = rfcsr & (~0xE0); ++ rfcsr |= 0x80; ++ rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); ++ rfcsr |= 0x80; ++ rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); ++ if (rt2x00dev->default_ant.tx_chain_num == 1) ++ rfcsr &= (~0x2); ++ else ++ rfcsr |= 0x2; ++ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); ++ if (rt2x00dev->default_ant.tx_chain_num == 1) ++ rfcsr &= (~0x20); ++ else ++ rfcsr |= 0x20; ++ if (rt2x00dev->default_ant.rx_chain_num == 1) ++ rfcsr &= (~0x02); ++ else ++ rfcsr |= 0x02; ++ rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); ++ ++ rt2800_rfcsr_read(rt2x00dev, 42, &rfcsr); ++ if (rt2x00dev->default_ant.tx_chain_num == 1) ++ rfcsr &= (~0x40); ++ else ++ rfcsr |= 0x40; ++ rt2800_rfcsr_write(rt2x00dev, 42, rfcsr); ++ ++ /* RF for DC Cal BW */ ++ if (conf_is_ht40(conf)) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 6, 0x10); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 7, 0x10); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 8, 0x04); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x10); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x10); ++ } else { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 6, 0x20); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 7, 0x20); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 8, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x20); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20); ++ } ++ ++ if (conf_is_ht40(conf)) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08); ++ } else { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28); ++ } ++ ++ rt2800_rfcsr_read(rt2x00dev, 28, &rfcsr); ++ if (conf_is_ht40(conf) && (rf->channel == 11)) ++ rfcsr |= 0x4; ++ else ++ rfcsr &= (~0x4); ++ rt2800_rfcsr_write(rt2x00dev, 28, rfcsr); ++ ++ /*if (bScan == FALSE)*/ ++ if (conf_is_ht40(conf)) { ++ txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw40, ++ RFCSR24_TX_AGC_FC); ++ } else { ++ txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw20, ++ RFCSR24_TX_AGC_FC); ++ } ++ rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 6, rfcsr); ++ rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 7, rfcsr); ++ rt2800_rfcsr_read_bank(rt2x00dev, 7, 6, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 6, rfcsr); ++ rt2800_rfcsr_read_bank(rt2x00dev, 7, 7, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 7, rfcsr); ++ ++ rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 58, rfcsr); ++ rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 59, rfcsr); ++ rt2800_rfcsr_read_bank(rt2x00dev, 7, 58, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 58, rfcsr); ++ rt2800_rfcsr_read_bank(rt2x00dev, 7, 59, &rfcsr); ++ rfcsr &= (~0x3F); ++ rfcsr |= txrx_agc_fc; ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 59, rfcsr); ++ ++ rt2800_register_read(rt2x00dev, TX_ALG_CFG_0, ®); ++ reg = reg & (~0x3F3F); ++ reg |= info->default_power1; ++ reg |= (info->default_power2 << 8); ++ reg |= (0x2F << 16); ++ reg |= (0x2F << 24); ++ ++ rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); ++ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_INTERNAL_TX_ALC)) { ++ /* init base power by e2p target power */ ++ rt2800_eeprom_read(rt2x00dev, 0xD0, &target_power); ++ target_power &= 0x3F; ++ reg = reg & (~0x3F3F); ++ reg |= target_power; ++ reg |= (target_power << 8); ++ } ++ rt2800_register_write(rt2x00dev, TX_ALG_CFG_0, reg); ++ ++ rt2800_register_read(rt2x00dev, TX_ALG_CFG_1, ®); ++ reg = reg & (~0x3F); ++ rt2800_register_write(rt2x00dev, TX_ALG_CFG_1, reg); ++ ++ /*if (bScan == FALSE)*/ ++ /* Save MAC SYS CTRL registers */ ++ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &mac_sys_ctrl); ++ /* Disable Tx/Rx */ ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); ++ /* Check MAC Tx/Rx idle */ ++ for (i = 0; i < 10000; i++) { ++ rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, &mac_status); ++ if (mac_status & 0x3) ++ udelay(50); ++ else ++ break; ++ } ++ ++ if (i == 10000) ++ rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n"); ++ ++ if (rf->channel > 10) { ++ rt2800_bbp_read(rt2x00dev, 30, &bbp); ++ bbp = 0x40; ++ rt2800_bbp_write(rt2x00dev, 30, bbp); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0); ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x7b); ++ } else { ++ rt2800_bbp_read(rt2x00dev, 30, &bbp); ++ bbp = 0x1f; ++ rt2800_bbp_write(rt2x00dev, 30, bbp); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); ++ } ++ ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl); ++ ++ rt2800_rfcsr_write(rt2x00dev, 5, 0x40); ++ rt2800_rfcsr_write(rt2x00dev, 4, 0x0C); ++ ++ /* vcocal_en (initiate VCO calibration (reset after completion)) */ ++ rt2800_rfcsr_read(rt2x00dev, 4, &rfcsr); ++ rfcsr = ((rfcsr & ~0x80) | 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 4, rfcsr); ++ mdelay(2); ++ ++ rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); ++ ++ if (rt2x00dev->default_ant.tx_chain_num == 1) { ++ rt2800_bbp_write(rt2x00dev, 91, 0x07); ++ rt2800_bbp_write(rt2x00dev, 95, 0x1A); ++ rt2800_bbp_write(rt2x00dev, 195, 128); ++ rt2800_bbp_write(rt2x00dev, 196, 0xA0); ++ rt2800_bbp_write(rt2x00dev, 195, 170); ++ rt2800_bbp_write(rt2x00dev, 196, 0x12); ++ rt2800_bbp_write(rt2x00dev, 195, 171); ++ rt2800_bbp_write(rt2x00dev, 196, 0x10); ++ } else { ++ rt2800_bbp_write(rt2x00dev, 91, 0x06); ++ rt2800_bbp_write(rt2x00dev, 95, 0x9A); ++ rt2800_bbp_write(rt2x00dev, 195, 128); ++ rt2800_bbp_write(rt2x00dev, 196, 0xE0); ++ rt2800_bbp_write(rt2x00dev, 195, 170); ++ rt2800_bbp_write(rt2x00dev, 196, 0x30); ++ rt2800_bbp_write(rt2x00dev, 195, 171); ++ rt2800_bbp_write(rt2x00dev, 196, 0x30); ++ } ++ ++ /* On 11A, We should delay and wait RF/BBP to be stable*/ ++ /* and the appropriate time should be 1000 micro seconds */ ++ /* 2005/06/05 - On 11G, We also need this delay time. ++ * Otherwise it's difficult to pass the WHQL.*/ ++ udelay(1000); ++} ++ ++ + static void rt2800_bbp_write_with_rx_chain(struct rt2x00_dev *rt2x00dev, + const unsigned int word, + const u8 value) +@@ -3458,7 +3837,7 @@ static void rt2800_config_channel(struct + struct channel_info *info) + { + u32 reg; +- unsigned int tx_pin; ++ u32 tx_pin; + u8 bbp, rfcsr; + + info->default_power1 = rt2800_txpower_to_dev(rt2x00dev, rf->channel, +@@ -3512,6 +3891,9 @@ static void rt2800_config_channel(struct + case RF5592: + rt2800_config_channel_rf55xx(rt2x00dev, conf, rf, info); + break; ++ case RF7620: ++ rt2800_config_channel_rf7620(rt2x00dev, conf, rf, info); ++ break; + default: + rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); + } +@@ -3614,7 +3996,7 @@ static void rt2800_config_channel(struct + else if (rt2x00_rt(rt2x00dev, RT3593) || + rt2x00_rt(rt2x00dev, RT3883)) + rt2800_bbp_write(rt2x00dev, 82, 0x82); +- else ++ else if (rt2x00dev->chip.rf != RF7620) + rt2800_bbp_write(rt2x00dev, 82, 0xf2); + + if (rt2x00_rt(rt2x00dev, RT3593) || +@@ -3636,7 +4018,7 @@ static void rt2800_config_channel(struct + if (rt2x00_rt(rt2x00dev, RT3572)) + rt2800_rfcsr_write(rt2x00dev, 8, 0); + +- tx_pin = 0; ++ rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); + + switch (rt2x00dev->default_ant.tx_chain_num) { + case 3: +@@ -3685,6 +4067,7 @@ static void rt2800_config_channel(struct + + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFRX_EN, 1); /* mt7620 */ + + rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + +@@ -4701,6 +5084,14 @@ void rt2800_vco_calibration(struct rt2x0 + rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); + rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); + break; ++ case RF7620: ++ rt2800_rfcsr_read(rt2x00dev, 4, &rfcsr); ++ /* vcocal_en (initiate VCO calibration (reset after completion)) ++ * It should be at the end of RF configuration. */ ++ rfcsr = ((rfcsr & ~0x80) | 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 4, rfcsr); ++ mdelay(1); ++ break; + default: + return; + } +@@ -5101,9 +5492,42 @@ static int rt2800_init_registers(struct + } else if (rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392) || + rt2x00_rt(rt2x00dev, RT5592)) { +- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); +- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); +- rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); ++ if (rt2x00dev->chip.rf == RF7620) { ++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, ++ 0x00000401); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG1, ++ 0x000C0000); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG2, ++ 0x00000000); ++ rt2800_register_write(rt2x00dev, MIMO_PS_CFG, ++ 0x00000002); ++ rt2800_register_write(rt2x00dev, TX_PIN_CFG, ++ 0x00150F0F); ++ rt2800_register_write(rt2x00dev, TX_ALC_VGA3, ++ 0x06060606); ++ rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, ++ 0x0); ++ rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, ++ 0x0); ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, ++ 0x6C6C666C); ++ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, ++ 0x6C6C666C); ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, ++ 0x3630363A); ++ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT, ++ 0x3630363A); ++ rt2800_register_read(rt2x00dev, TX_ALG_CFG_1, ®); ++ reg = reg & (~0x80000000); ++ rt2800_register_write(rt2x00dev, TX_ALG_CFG_1, reg); ++ } else { ++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, ++ 0x00000404); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG1, ++ 0x00080606); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG2, ++ 0x00000000); ++ } + } else if (rt2x00_rt(rt2x00dev, RT5350)) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); + } else { +@@ -6135,6 +6559,225 @@ static void rt2800_init_bbp_5592(struct + rt2800_bbp_write(rt2x00dev, 103, 0xc0); + } + ++static void rt2800_bbp_glrt_write(struct rt2x00_dev *rt2x00dev, ++ const u8 reg, const u8 value) ++{ ++ rt2800_bbp_write(rt2x00dev, 195, reg); ++ rt2800_bbp_write(rt2x00dev, 196, value); ++} ++ ++static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev, ++ const u8 reg, const u8 value) ++{ ++ rt2800_bbp_write(rt2x00dev, 158, reg); ++ rt2800_bbp_write(rt2x00dev, 159, value); ++} ++ ++static void rt2800_init_bbp_7620(struct rt2x00_dev *rt2x00dev) ++{ ++ u8 bbp; ++ ++ /* Apply Maximum Likelihood Detection (MLD) for 2 stream case */ ++ rt2800_bbp_read(rt2x00dev, 105, &bbp); ++ rt2x00_set_field8(&bbp, BBP105_MLD, ++ rt2x00dev->default_ant.rx_chain_num == 2); ++ rt2800_bbp_write(rt2x00dev, 105, bbp); ++ ++ /* Avoid data loss and CRC errors */ ++ /* MAC interface control (MAC_IF_80M, 1: 80 MHz) */ ++ rt2800_bbp4_mac_if_ctrl(rt2x00dev); ++ ++ /* Fix I/Q swap issue */ ++ rt2800_bbp_read(rt2x00dev, 1, &bbp); ++ bbp |= 0x04; ++ rt2800_bbp_write(rt2x00dev, 1, bbp); ++ ++ /* BBP for G band */ ++ rt2800_bbp_write(rt2x00dev, 3, 0x08); ++ rt2800_bbp_write(rt2x00dev, 4, 0x00); /* rt2800_bbp4_mac_if_ctrl? */ ++ rt2800_bbp_write(rt2x00dev, 6, 0x08); ++ rt2800_bbp_write(rt2x00dev, 14, 0x09); ++ rt2800_bbp_write(rt2x00dev, 15, 0xFF); ++ rt2800_bbp_write(rt2x00dev, 16, 0x01); ++ rt2800_bbp_write(rt2x00dev, 20, 0x06); ++ rt2800_bbp_write(rt2x00dev, 21, 0x00); ++ rt2800_bbp_write(rt2x00dev, 22, 0x00); ++ rt2800_bbp_write(rt2x00dev, 27, 0x00); ++ rt2800_bbp_write(rt2x00dev, 28, 0x00); ++ rt2800_bbp_write(rt2x00dev, 30, 0x00); ++ rt2800_bbp_write(rt2x00dev, 31, 0x48); ++ rt2800_bbp_write(rt2x00dev, 47, 0x40); ++ rt2800_bbp_write(rt2x00dev, 62, 0x00); ++ rt2800_bbp_write(rt2x00dev, 63, 0x00); ++ rt2800_bbp_write(rt2x00dev, 64, 0x00); ++ rt2800_bbp_write(rt2x00dev, 65, 0x2C); ++ rt2800_bbp_write(rt2x00dev, 66, 0x1C); ++ rt2800_bbp_write(rt2x00dev, 67, 0x20); ++ rt2800_bbp_write(rt2x00dev, 68, 0xDD); ++ rt2800_bbp_write(rt2x00dev, 69, 0x10); ++ rt2800_bbp_write(rt2x00dev, 70, 0x05); ++ rt2800_bbp_write(rt2x00dev, 73, 0x18); ++ rt2800_bbp_write(rt2x00dev, 74, 0x0F); ++ rt2800_bbp_write(rt2x00dev, 75, 0x60); ++ rt2800_bbp_write(rt2x00dev, 76, 0x44); ++ rt2800_bbp_write(rt2x00dev, 77, 0x59); ++ rt2800_bbp_write(rt2x00dev, 78, 0x1E); ++ rt2800_bbp_write(rt2x00dev, 79, 0x1C); ++ rt2800_bbp_write(rt2x00dev, 80, 0x0C); ++ rt2800_bbp_write(rt2x00dev, 81, 0x3A); ++ rt2800_bbp_write(rt2x00dev, 82, 0xB6); ++ rt2800_bbp_write(rt2x00dev, 83, 0x9A); ++ rt2800_bbp_write(rt2x00dev, 84, 0x9A); ++ rt2800_bbp_write(rt2x00dev, 86, 0x38); ++ rt2800_bbp_write(rt2x00dev, 88, 0x90); ++ rt2800_bbp_write(rt2x00dev, 91, 0x04); ++ rt2800_bbp_write(rt2x00dev, 92, 0x02); ++ rt2800_bbp_write(rt2x00dev, 95, 0x9A); ++ rt2800_bbp_write(rt2x00dev, 96, 0x00); ++ rt2800_bbp_write(rt2x00dev, 103, 0xC0); ++ rt2800_bbp_write(rt2x00dev, 104, 0x92); ++ /* FIXME BBP105 owerwrite */ ++ rt2800_bbp_write(rt2x00dev, 105, 0x3C); ++ rt2800_bbp_write(rt2x00dev, 106, 0x12); ++ rt2800_bbp_write(rt2x00dev, 109, 0x00); ++ rt2800_bbp_write(rt2x00dev, 134, 0x10); ++ rt2800_bbp_write(rt2x00dev, 135, 0xA6); ++ rt2800_bbp_write(rt2x00dev, 137, 0x04); ++ rt2800_bbp_write(rt2x00dev, 142, 0x30); ++ rt2800_bbp_write(rt2x00dev, 143, 0xF7); ++ rt2800_bbp_write(rt2x00dev, 160, 0xEC); ++ rt2800_bbp_write(rt2x00dev, 161, 0xC4); ++ rt2800_bbp_write(rt2x00dev, 162, 0x77); ++ rt2800_bbp_write(rt2x00dev, 163, 0xF9); ++ rt2800_bbp_write(rt2x00dev, 164, 0x00); ++ rt2800_bbp_write(rt2x00dev, 165, 0x00); ++ rt2800_bbp_write(rt2x00dev, 186, 0x00); ++ rt2800_bbp_write(rt2x00dev, 187, 0x00); ++ rt2800_bbp_write(rt2x00dev, 188, 0x00); ++ rt2800_bbp_write(rt2x00dev, 186, 0x00); ++ rt2800_bbp_write(rt2x00dev, 187, 0x01); ++ rt2800_bbp_write(rt2x00dev, 188, 0x00); ++ rt2800_bbp_write(rt2x00dev, 189, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 91, 0x06); ++ rt2800_bbp_write(rt2x00dev, 92, 0x04); ++ rt2800_bbp_write(rt2x00dev, 93, 0x54); ++ rt2800_bbp_write(rt2x00dev, 99, 0x50); ++ rt2800_bbp_write(rt2x00dev, 148, 0x84); ++ rt2800_bbp_write(rt2x00dev, 167, 0x80); ++ rt2800_bbp_write(rt2x00dev, 178, 0xFF); ++ rt2800_bbp_write(rt2x00dev, 106, 0x13); ++ ++ /* BBP for G band GLRT function (BBP_128 ~ BBP_221) */ ++ rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00); ++ rt2800_bbp_glrt_write(rt2x00dev, 1, 0x14); /* ? see above */ ++ rt2800_bbp_glrt_write(rt2x00dev, 2, 0x20); ++ rt2800_bbp_glrt_write(rt2x00dev, 3, 0x0A); ++ rt2800_bbp_glrt_write(rt2x00dev, 10, 0x16); ++ rt2800_bbp_glrt_write(rt2x00dev, 11, 0x06); ++ rt2800_bbp_glrt_write(rt2x00dev, 12, 0x02); ++ rt2800_bbp_glrt_write(rt2x00dev, 13, 0x07); ++ rt2800_bbp_glrt_write(rt2x00dev, 14, 0x05); ++ rt2800_bbp_glrt_write(rt2x00dev, 15, 0x09); ++ rt2800_bbp_glrt_write(rt2x00dev, 16, 0x20); ++ rt2800_bbp_glrt_write(rt2x00dev, 17, 0x08); ++ rt2800_bbp_glrt_write(rt2x00dev, 18, 0x4A); ++ rt2800_bbp_glrt_write(rt2x00dev, 19, 0x00); ++ rt2800_bbp_glrt_write(rt2x00dev, 20, 0x00); ++ rt2800_bbp_glrt_write(rt2x00dev, 128, 0xE0); ++ rt2800_bbp_glrt_write(rt2x00dev, 129, 0x1F); ++ rt2800_bbp_glrt_write(rt2x00dev, 130, 0x4F); ++ rt2800_bbp_glrt_write(rt2x00dev, 131, 0x32); ++ rt2800_bbp_glrt_write(rt2x00dev, 132, 0x08); ++ rt2800_bbp_glrt_write(rt2x00dev, 133, 0x28); ++ rt2800_bbp_glrt_write(rt2x00dev, 134, 0x19); ++ rt2800_bbp_glrt_write(rt2x00dev, 135, 0x0A); ++ rt2800_bbp_glrt_write(rt2x00dev, 138, 0x16); ++ rt2800_bbp_glrt_write(rt2x00dev, 139, 0x10); ++ rt2800_bbp_glrt_write(rt2x00dev, 140, 0x10); ++ rt2800_bbp_glrt_write(rt2x00dev, 141, 0x1A); ++ rt2800_bbp_glrt_write(rt2x00dev, 142, 0x36); ++ rt2800_bbp_glrt_write(rt2x00dev, 143, 0x2C); ++ rt2800_bbp_glrt_write(rt2x00dev, 144, 0x26); ++ rt2800_bbp_glrt_write(rt2x00dev, 145, 0x24); ++ rt2800_bbp_glrt_write(rt2x00dev, 146, 0x42); ++ rt2800_bbp_glrt_write(rt2x00dev, 147, 0x40); ++ rt2800_bbp_glrt_write(rt2x00dev, 148, 0x30); ++ rt2800_bbp_glrt_write(rt2x00dev, 149, 0x29); ++ rt2800_bbp_glrt_write(rt2x00dev, 150, 0x4C); ++ rt2800_bbp_glrt_write(rt2x00dev, 151, 0x46); ++ rt2800_bbp_glrt_write(rt2x00dev, 152, 0x3D); ++ rt2800_bbp_glrt_write(rt2x00dev, 153, 0x40); ++ rt2800_bbp_glrt_write(rt2x00dev, 154, 0x3E); ++ rt2800_bbp_glrt_write(rt2x00dev, 155, 0x38); ++ rt2800_bbp_glrt_write(rt2x00dev, 156, 0x3D); ++ rt2800_bbp_glrt_write(rt2x00dev, 157, 0x2F); ++ rt2800_bbp_glrt_write(rt2x00dev, 158, 0x3C); ++ rt2800_bbp_glrt_write(rt2x00dev, 159, 0x34); ++ rt2800_bbp_glrt_write(rt2x00dev, 160, 0x2C); ++ rt2800_bbp_glrt_write(rt2x00dev, 161, 0x2F); ++ rt2800_bbp_glrt_write(rt2x00dev, 162, 0x3C); ++ rt2800_bbp_glrt_write(rt2x00dev, 163, 0x35); ++ rt2800_bbp_glrt_write(rt2x00dev, 164, 0x2E); ++ rt2800_bbp_glrt_write(rt2x00dev, 165, 0x2F); ++ rt2800_bbp_glrt_write(rt2x00dev, 166, 0x49); ++ rt2800_bbp_glrt_write(rt2x00dev, 167, 0x41); ++ rt2800_bbp_glrt_write(rt2x00dev, 168, 0x36); ++ rt2800_bbp_glrt_write(rt2x00dev, 169, 0x39); ++ rt2800_bbp_glrt_write(rt2x00dev, 170, 0x30); ++ rt2800_bbp_glrt_write(rt2x00dev, 171, 0x30); ++ rt2800_bbp_glrt_write(rt2x00dev, 172, 0x0E); ++ rt2800_bbp_glrt_write(rt2x00dev, 173, 0x0D); ++ rt2800_bbp_glrt_write(rt2x00dev, 174, 0x28); ++ rt2800_bbp_glrt_write(rt2x00dev, 175, 0x21); ++ rt2800_bbp_glrt_write(rt2x00dev, 176, 0x1C); ++ rt2800_bbp_glrt_write(rt2x00dev, 177, 0x16); ++ rt2800_bbp_glrt_write(rt2x00dev, 178, 0x50); ++ rt2800_bbp_glrt_write(rt2x00dev, 179, 0x4A); ++ rt2800_bbp_glrt_write(rt2x00dev, 180, 0x43); ++ rt2800_bbp_glrt_write(rt2x00dev, 181, 0x50); ++ rt2800_bbp_glrt_write(rt2x00dev, 182, 0x10); ++ rt2800_bbp_glrt_write(rt2x00dev, 183, 0x10); ++ rt2800_bbp_glrt_write(rt2x00dev, 184, 0x10); ++ rt2800_bbp_glrt_write(rt2x00dev, 185, 0x10); ++ rt2800_bbp_glrt_write(rt2x00dev, 200, 0x7D); ++ rt2800_bbp_glrt_write(rt2x00dev, 201, 0x14); ++ rt2800_bbp_glrt_write(rt2x00dev, 202, 0x32); ++ rt2800_bbp_glrt_write(rt2x00dev, 203, 0x2C); ++ rt2800_bbp_glrt_write(rt2x00dev, 204, 0x36); ++ rt2800_bbp_glrt_write(rt2x00dev, 205, 0x4C); ++ rt2800_bbp_glrt_write(rt2x00dev, 206, 0x43); ++ rt2800_bbp_glrt_write(rt2x00dev, 207, 0x2C); ++ rt2800_bbp_glrt_write(rt2x00dev, 208, 0x2E); ++ rt2800_bbp_glrt_write(rt2x00dev, 209, 0x36); ++ rt2800_bbp_glrt_write(rt2x00dev, 210, 0x30); ++ rt2800_bbp_glrt_write(rt2x00dev, 211, 0x6E); ++ ++ /* BBP for G band DCOC function */ ++ rt2800_bbp_dcoc_write(rt2x00dev, 140, 0x0C); ++ rt2800_bbp_dcoc_write(rt2x00dev, 141, 0x00); ++ rt2800_bbp_dcoc_write(rt2x00dev, 142, 0x10); ++ rt2800_bbp_dcoc_write(rt2x00dev, 143, 0x10); ++ rt2800_bbp_dcoc_write(rt2x00dev, 144, 0x10); ++ rt2800_bbp_dcoc_write(rt2x00dev, 145, 0x10); ++ rt2800_bbp_dcoc_write(rt2x00dev, 146, 0x08); ++ rt2800_bbp_dcoc_write(rt2x00dev, 147, 0x40); ++ rt2800_bbp_dcoc_write(rt2x00dev, 148, 0x04); ++ rt2800_bbp_dcoc_write(rt2x00dev, 149, 0x04); ++ rt2800_bbp_dcoc_write(rt2x00dev, 150, 0x08); ++ rt2800_bbp_dcoc_write(rt2x00dev, 151, 0x08); ++ rt2800_bbp_dcoc_write(rt2x00dev, 152, 0x03); ++ rt2800_bbp_dcoc_write(rt2x00dev, 153, 0x03); ++ rt2800_bbp_dcoc_write(rt2x00dev, 154, 0x03); ++ rt2800_bbp_dcoc_write(rt2x00dev, 155, 0x02); ++ rt2800_bbp_dcoc_write(rt2x00dev, 156, 0x40); ++ rt2800_bbp_dcoc_write(rt2x00dev, 157, 0x40); ++ rt2800_bbp_dcoc_write(rt2x00dev, 158, 0x64); ++ rt2800_bbp_dcoc_write(rt2x00dev, 159, 0x64); ++ ++ rt2800_bbp4_mac_if_ctrl(rt2x00dev); ++} ++ + static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) + { + unsigned int i; +@@ -6177,7 +6820,10 @@ static void rt2800_init_bbp(struct rt2x0 + return; + case RT5390: + case RT5392: +- rt2800_init_bbp_53xx(rt2x00dev); ++ if (rt2x00dev->chip.rf == RF7620) ++ rt2800_init_bbp_7620(rt2x00dev); ++ else ++ rt2800_init_bbp_53xx(rt2x00dev); + break; + case RT5592: + rt2800_init_bbp_5592(rt2x00dev); +@@ -7391,6 +8037,296 @@ static void rt2800_init_rfcsr_5592(struc + rt2800_led_open_drain_enable(rt2x00dev); + } + ++static void rt2800_init_rfcsr_7620(struct rt2x00_dev *rt2x00dev) ++{ ++ u16 freq; ++ u8 rfvalue; ++ struct hw_mode_spec *spec = &rt2x00dev->spec; ++ ++ /* Initialize RF central register to default value */ ++ rt2800_rfcsr_write(rt2x00dev, 0, 0x02); ++ rt2800_rfcsr_write(rt2x00dev, 1, 0x03); ++ rt2800_rfcsr_write(rt2x00dev, 2, 0x33); ++ rt2800_rfcsr_write(rt2x00dev, 3, 0xFF); ++ rt2800_rfcsr_write(rt2x00dev, 4, 0x0C); ++ rt2800_rfcsr_write(rt2x00dev, 5, 0x40); /* Read only */ ++ rt2800_rfcsr_write(rt2x00dev, 6, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 7, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 8, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 9, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 10, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x00); ++ /* rt2800_rfcsr_write(rt2x00dev, 12, 0x43); *//* EEPROM */ ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 14, 0x40); ++ rt2800_rfcsr_write(rt2x00dev, 15, 0x22); ++ rt2800_rfcsr_write(rt2x00dev, 16, 0x4C); ++ rt2800_rfcsr_write(rt2x00dev, 17, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 18, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 19, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 20, 0xA0); ++ rt2800_rfcsr_write(rt2x00dev, 21, 0x12); ++ rt2800_rfcsr_write(rt2x00dev, 22, 0x07); ++ rt2800_rfcsr_write(rt2x00dev, 23, 0x13); ++ rt2800_rfcsr_write(rt2x00dev, 24, 0xFE); ++ rt2800_rfcsr_write(rt2x00dev, 25, 0x24); ++ rt2800_rfcsr_write(rt2x00dev, 26, 0x7A); ++ rt2800_rfcsr_write(rt2x00dev, 27, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0x05); ++ rt2800_rfcsr_write(rt2x00dev, 30, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 31, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 32, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 33, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 34, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 35, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 36, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 37, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 38, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 40, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 41, 0xD0); ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x5B); ++ rt2800_rfcsr_write(rt2x00dev, 43, 0x00); ++ ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x21); ++ if (spec->clk_is_20mhz) ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x03); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 14, 0x7C); ++ rt2800_rfcsr_write(rt2x00dev, 16, 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 17, 0x99); ++ rt2800_rfcsr_write(rt2x00dev, 18, 0x99); ++ rt2800_rfcsr_write(rt2x00dev, 19, 0x09); ++ rt2800_rfcsr_write(rt2x00dev, 20, 0x50); ++ rt2800_rfcsr_write(rt2x00dev, 21, 0xB0); ++ rt2800_rfcsr_write(rt2x00dev, 22, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 23, 0x06); ++ rt2800_rfcsr_write(rt2x00dev, 24, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 25, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 26, 0x5D); ++ rt2800_rfcsr_write(rt2x00dev, 27, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x61); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0xB5); ++ rt2800_rfcsr_write(rt2x00dev, 43, 0x02); ++ ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x62); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0xAD); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ /* RTMP_TEMPERATURE_CALIBRATION */ ++ /* rt2800_rfcsr_write(rt2x00dev, 34, 0x23); */ ++ /* rt2800_rfcsr_write(rt2x00dev, 35, 0x01); */ ++ ++ /* use rt2800_adjust_freq_offset ? */ ++ rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &freq); ++ rfvalue = freq & 0xff; ++ rt2800_rfcsr_write(rt2x00dev, 12, rfvalue); ++ ++ /* Initialize RF channel register to default value */ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 1, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 2, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 3, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 4, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 5, 0x08); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 6, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 7, 0x51); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x16); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x61); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 12, 0x22); ++ /* rt2800_rfcsr_write_chanreg(rt2x00dev, 13, 0x3D); */ /* fails */ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 15, 0x13); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 16, 0x22); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x01); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x52); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 22, 0x80); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 23, 0xB3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 24, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 25, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 26, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 27, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x5C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0x6B); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 30, 0x6B); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 31, 0x31); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x5D); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 33, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xE6); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 35, 0x55); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 37, 0xBB); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 39, 0xB3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 40, 0x03); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 41, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 42, 0x00); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xB3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xD3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x07); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x68); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xEF); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x07); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0xA8); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0x85); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x10); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x07); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6A); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0x85); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x10); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 62, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 63, 0x00); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5); ++ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x69); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x20); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09); ++ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16); ++ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); ++ ++ /* Initialize RF channel register for DRQFN */ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7); ++ ++ /* reduce power consumption */ ++/* rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x64); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0x4F); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0x4F); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x64); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0x4F); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x02); ++*/ ++ /* Initialize RF DC calibration register to default value */ ++ rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 1, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 2, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 6, 0x10); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 7, 0x10); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 8, 0x04); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 9, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 10, 0x07); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 11, 0x01); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 12, 0x07); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 13, 0x07); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 14, 0x07); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 15, 0x20); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 16, 0x22); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 18, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 19, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 20, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 21, 0xF1); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 22, 0x11); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 23, 0x02); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 24, 0x41); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 25, 0x20); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 26, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 27, 0xD7); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 28, 0xA2); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 29, 0x20); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 30, 0x49); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 31, 0x20); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 32, 0x04); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 33, 0xF1); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 34, 0xA1); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 35, 0x01); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 41, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 42, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 43, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 44, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 45, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 46, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 47, 0x3E); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 48, 0x3D); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 49, 0x3E); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 50, 0x3D); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 51, 0x3E); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 52, 0x3D); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 53, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 54, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 55, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 56, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 57, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x10); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x10); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 60, 0x0A); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 61, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00); ++ ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20); ++ ++ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); ++} ++ + static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) + { + if (rt2800_is_305x_soc(rt2x00dev)) { +@@ -7426,7 +8362,10 @@ static void rt2800_init_rfcsr(struct rt2 + rt2800_init_rfcsr_5350(rt2x00dev); + break; + case RT5390: +- rt2800_init_rfcsr_5390(rt2x00dev); ++ if (rt2x00dev->chip.rf == RF7620) ++ rt2800_init_rfcsr_7620(rt2x00dev); ++ else ++ rt2800_init_rfcsr_5390(rt2x00dev); + break; + case RT5392: + rt2800_init_rfcsr_5392(rt2x00dev); +@@ -7858,6 +8797,7 @@ static int rt2800_init_eeprom(struct rt2 + case RF5390: + case RF5392: + case RF5592: ++ case RF7620: + break; + default: + rt2x00_err(rt2x00dev, "Invalid RF chipset 0x%04x detected\n", +@@ -8422,6 +9362,7 @@ static int rt2800_probe_hw_mode(struct r + case RF5372: + case RF5390: + case RF5392: ++ case RF7620: + spec->num_channels = 14; + if (spec->clk_is_20mhz) + spec->channels = rf_vals_xtal20mhz_3x; +@@ -8562,6 +9503,7 @@ static int rt2800_probe_hw_mode(struct r + case RF5372: + case RF5390: + case RF5392: ++ case RF7620: + __set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags); + break; + } diff --git a/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch new file mode 100644 index 0000000..93196e1 --- /dev/null +++ b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch @@ -0,0 +1,33 @@ +From: Sven Eckelmann <sven@open-mesh.com> +Date: Tue, 18 Nov 2014 12:29:28 +0100 +Subject: [PATCH] ath10k: Don't initialize devices asynchronously + +OpenWrt requires all PHYs to be initialized to create the configuration files +during bootup. ath10k violates this because it delays the creation of the PHY +to a not well defined point in the future. + +Forcing the work to be done immediately works around this problem but may also +delay the boot when firmware images cannot be found. + +Signed-off-by: Sven Eckelmann <sven@open-mesh.com> +--- + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -1520,6 +1520,16 @@ int ath10k_core_register(struct ath10k * + ar->chip_id = chip_id; + queue_work(ar->workqueue, &ar->register_work); + ++ /* OpenWrt requires all PHYs to be initialized to create the ++ * configuration files during bootup. ath10k violates this ++ * because it delays the creation of the PHY to a not well defined ++ * point in the future. ++ * ++ * Forcing the work to be done immediately works around this problem ++ * but may also delay the boot when firmware images cannot be found. ++ */ ++ flush_workqueue(ar->workqueue); ++ + return 0; + } + EXPORT_SYMBOL(ath10k_core_register); diff --git a/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch new file mode 100644 index 0000000..34910a0 --- /dev/null +++ b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch @@ -0,0 +1,37 @@ +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -6804,6 +6804,21 @@ struct ath10k_vif *ath10k_get_arvif(stru + return arvif_iter.arvif; + } + ++#ifdef CPTCFG_MAC80211_LEDS ++static const struct ieee80211_tpt_blink ath10k_tpt_blink[] = { ++ { .throughput = 0 * 1024, .blink_time = 334 }, ++ { .throughput = 1 * 1024, .blink_time = 260 }, ++ { .throughput = 2 * 1024, .blink_time = 220 }, ++ { .throughput = 5 * 1024, .blink_time = 190 }, ++ { .throughput = 10 * 1024, .blink_time = 170 }, ++ { .throughput = 25 * 1024, .blink_time = 150 }, ++ { .throughput = 54 * 1024, .blink_time = 130 }, ++ { .throughput = 120 * 1024, .blink_time = 110 }, ++ { .throughput = 265 * 1024, .blink_time = 80 }, ++ { .throughput = 586 * 1024, .blink_time = 50 }, ++}; ++#endif ++ + int ath10k_mac_register(struct ath10k *ar) + { + static const u32 cipher_suites[] = { +@@ -7025,6 +7040,12 @@ int ath10k_mac_register(struct ath10k *a + ar->hw->wiphy->cipher_suites = cipher_suites; + ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + ++#if CPTCFG_MAC80211_LEDS ++ ieee80211_create_tpt_led_trigger(ar->hw, ++ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath10k_tpt_blink, ++ ARRAY_SIZE(ath10k_tpt_blink)); ++#endif ++ + ret = ieee80211_register_hw(ar->hw); + if (ret) { + ath10k_err(ar, "failed to register ieee80211: %d\n", ret); diff --git a/package/kernel/mac80211/patches/940-mwl8k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/940-mwl8k_init_devices_synchronously.patch new file mode 100644 index 0000000..75d8212 --- /dev/null +++ b/package/kernel/mac80211/patches/940-mwl8k_init_devices_synchronously.patch @@ -0,0 +1,20 @@ +--- a/drivers/net/wireless/mwl8k.c ++++ b/drivers/net/wireless/mwl8k.c +@@ -6261,6 +6261,8 @@ static int mwl8k_probe(struct pci_dev *p + + priv->running_bsses = 0; + ++ wait_for_completion(&priv->firmware_loading_complete); ++ + return rc; + + err_stop_firmware: +@@ -6294,8 +6296,6 @@ static void mwl8k_remove(struct pci_dev + return; + priv = hw->priv; + +- wait_for_completion(&priv->firmware_loading_complete); +- + if (priv->fw_state == FW_STATE_ERROR) { + mwl8k_hw_reset(priv); + goto unmap; |