mirror of
https://github.com/hak5/wifipineapple-openwrt.git
synced 2025-10-29 16:57:19 +00:00
mac80211: backport from trunk r48782 + required kernel patches and mt76, mwlwifi
Signed-off-by: Felix Fietkau <nbd@openwrt.org> git-svn-id: svn://svn.openwrt.org/openwrt/branches/chaos_calmer@48822 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
5db86ba649
commit
f3a1db04f0
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@
|
||||
@set -e ; test -f .local-symbols || ( \
|
||||
echo "/--------------" ;\
|
||||
echo "| You shouldn't run make in the backports tree, but only in" ;\
|
||||
@@ -60,56 +62,60 @@ mrproper:
|
||||
@@ -60,57 +62,61 @@ mrproper:
|
||||
echo "| (that isn't currently running.)" ;\
|
||||
echo "\\--" ;\
|
||||
false)
|
||||
@ -56,11 +56,12 @@
|
||||
- done \
|
||||
- ) > Kconfig.kernel ;\
|
||||
- kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion | \
|
||||
- sed 's/^\(\(3\|2\.6\)\.[0-9]\+\).*/\1/;t;d') ;\
|
||||
- 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 99 | sed 's/^/3./')" ;\
|
||||
- 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 \
|
||||
@ -111,11 +112,12 @@
|
||||
+
|
||||
+Kconfig.versions: Kconfig.kernel
|
||||
+ @kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion | \
|
||||
+ sed 's/^\(\(3\|2\.6\)\.[0-9]\+\).*/\1/;t;d') ;\
|
||||
+ 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 99 | sed 's/^/3./')" ;\
|
||||
+ 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 \
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--- a/kconf/conf.c
|
||||
+++ b/kconf/conf.c
|
||||
@@ -578,40 +578,12 @@ int main(int ac, char **av)
|
||||
@@ -593,40 +593,12 @@ int main(int ac, char **av)
|
||||
case oldconfig:
|
||||
case listnewconfig:
|
||||
case olddefconfig:
|
||||
@ -42,3 +42,23 @@
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
--- a/kconf/confdata.c
|
||||
+++ b/kconf/confdata.c
|
||||
@@ -1169,6 +1169,8 @@ bool conf_set_all_new_symbols(enum conf_
|
||||
}
|
||||
bool has_changed = false;
|
||||
|
||||
+ sym_clear_all_valid();
|
||||
+
|
||||
for_all_symbols(i, sym) {
|
||||
if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
|
||||
continue;
|
||||
@@ -1212,8 +1214,6 @@ bool conf_set_all_new_symbols(enum conf_
|
||||
|
||||
}
|
||||
|
||||
- sym_clear_all_valid();
|
||||
-
|
||||
/*
|
||||
* We have different type of choice blocks.
|
||||
* If curr.tri equals to mod then we can select several
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 28 Jan 2016 15:16:35 +0100
|
||||
Subject: [PATCH] backports: add skb_free_frag()
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/backport-include/linux/skbuff.h
|
||||
+++ b/backport-include/linux/skbuff.h
|
||||
@@ -300,4 +300,11 @@ int skb_ensure_writable(struct sk_buff *
|
||||
|
||||
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) */
|
||||
|
||||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
|
||||
+static inline void skb_free_frag(void *data)
|
||||
+{
|
||||
+ put_page(virt_to_head_page(data));
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
#endif /* __BACKPORT_SKBUFF_H */
|
||||
@ -1,10 +0,0 @@
|
||||
--- a/backport-include/linux/debugfs.h
|
||||
+++ b/backport-include/linux/debugfs.h
|
||||
@@ -3,6 +3,7 @@
|
||||
#include_next <linux/debugfs.h>
|
||||
#include <linux/version.h>
|
||||
#include <generated/utsrelease.h>
|
||||
+#include <linux/device.h>
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name,
|
||||
@ -0,0 +1,20 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 28 Jan 2016 15:19:22 +0100
|
||||
Subject: [PATCH] backports: add napi_alloc_frag
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/backport-include/linux/netdevice.h
|
||||
+++ b/backport-include/linux/netdevice.h
|
||||
@@ -232,6 +232,10 @@ static inline void backport_unregister_n
|
||||
#define unregister_netdevice_many LINUX_BACKPORT(unregister_netdevice_many)
|
||||
#endif
|
||||
|
||||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
|
||||
+#define napi_alloc_frag netdev_alloc_frag
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Complicated way of saying: We only backport netdev_rss_key stuff on kernels
|
||||
* that either already have net_get_random_once() (>= 3.13) or where we've been
|
||||
@ -1,16 +0,0 @@
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1858,6 +1858,13 @@ void ieee80211_remove_interfaces(struct
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
unregister_netdevice_many(&unreg_list);
|
||||
+#if (!(LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,45) && \
|
||||
+ LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)) && \
|
||||
+ !(LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,9) && \
|
||||
+ LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)) && \
|
||||
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)))
|
||||
+ list_del(&unreg_list);
|
||||
+#endif
|
||||
|
||||
list_for_each_entry_safe(sdata, tmp, &wdev_list, list) {
|
||||
list_del(&sdata->list);
|
||||
@ -1,37 +0,0 @@
|
||||
--- /dev/null
|
||||
+++ b/include/uapi/linux/mpls.h
|
||||
@@ -0,0 +1,34 @@
|
||||
+#ifndef _UAPI_MPLS_H
|
||||
+#define _UAPI_MPLS_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+#include <asm/byteorder.h>
|
||||
+
|
||||
+/* Reference: RFC 5462, RFC 3032
|
||||
+ *
|
||||
+ * 0 1 2 3
|
||||
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
+ * | Label | TC |S| TTL |
|
||||
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
+ *
|
||||
+ * Label: Label Value, 20 bits
|
||||
+ * TC: Traffic Class field, 3 bits
|
||||
+ * S: Bottom of Stack, 1 bit
|
||||
+ * TTL: Time to Live, 8 bits
|
||||
+ */
|
||||
+
|
||||
+struct mpls_label {
|
||||
+ __be32 entry;
|
||||
+};
|
||||
+
|
||||
+#define MPLS_LS_LABEL_MASK 0xFFFFF000
|
||||
+#define MPLS_LS_LABEL_SHIFT 12
|
||||
+#define MPLS_LS_TC_MASK 0x00000E00
|
||||
+#define MPLS_LS_TC_SHIFT 9
|
||||
+#define MPLS_LS_S_MASK 0x00000100
|
||||
+#define MPLS_LS_S_SHIFT 8
|
||||
+#define MPLS_LS_TTL_MASK 0x000000FF
|
||||
+#define MPLS_LS_TTL_SHIFT 0
|
||||
+
|
||||
+#endif /* _UAPI_MPLS_H */
|
||||
@ -1,5 +1,5 @@
|
||||
--- a/drivers/net/wireless/rt2x00/Kconfig
|
||||
+++ b/drivers/net/wireless/rt2x00/Kconfig
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
|
||||
@@ -225,36 +225,37 @@ config RT2800SOC
|
||||
|
||||
|
||||
@ -43,5 +43,5 @@
|
||||
- tristate
|
||||
+ tristate "RT2x00 support"
|
||||
depends on m
|
||||
select BPAUTO_AVERAGE
|
||||
|
||||
config RT2X00_LIB_FIRMWARE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
--- a/drivers/net/wireless/brcm80211/Kconfig
|
||||
+++ b/drivers/net/wireless/brcm80211/Kconfig
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/Kconfig
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig
|
||||
@@ -1,5 +1,5 @@
|
||||
config BRCMUTIL
|
||||
- tristate
|
||||
|
||||
@ -1,104 +0,0 @@
|
||||
--- a/drivers/bcma/driver_pci.c
|
||||
+++ b/drivers/bcma/driver_pci.c
|
||||
@@ -282,39 +282,6 @@ void bcma_core_pci_power_save(struct bcm
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
|
||||
|
||||
-int bcma_core_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core,
|
||||
- bool enable)
|
||||
-{
|
||||
- struct pci_dev *pdev;
|
||||
- u32 coremask, tmp;
|
||||
- int err = 0;
|
||||
-
|
||||
- if (bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
||||
- /* This bcma device is not on a PCI host-bus. So the IRQs are
|
||||
- * not routed through the PCI core.
|
||||
- * So we must not enable routing through the PCI core. */
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- pdev = bus->host_pci;
|
||||
-
|
||||
- err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
- if (err)
|
||||
- goto out;
|
||||
-
|
||||
- coremask = BIT(core->core_index) << 8;
|
||||
- if (enable)
|
||||
- tmp |= coremask;
|
||||
- else
|
||||
- tmp &= ~coremask;
|
||||
-
|
||||
- err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
|
||||
-
|
||||
-out:
|
||||
- return err;
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
|
||||
-
|
||||
static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend)
|
||||
{
|
||||
u32 w;
|
||||
--- a/drivers/bcma/host_pci.c
|
||||
+++ b/drivers/bcma/host_pci.c
|
||||
@@ -351,3 +351,37 @@ void bcma_host_pci_down(struct bcma_bus
|
||||
bcma_core_pci_down(&bus->drv_pci[0]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_host_pci_down);
|
||||
+
|
||||
+/* See also si_pci_setup */
|
||||
+int bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core,
|
||||
+ bool enable)
|
||||
+{
|
||||
+ struct pci_dev *pdev;
|
||||
+ u32 coremask, tmp;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
||||
+ /* This bcma device is not on a PCI host-bus. So the IRQs are
|
||||
+ * not routed through the PCI core.
|
||||
+ * So we must not enable routing through the PCI core. */
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ pdev = bus->host_pci;
|
||||
+
|
||||
+ err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+
|
||||
+ coremask = BIT(core->core_index) << 8;
|
||||
+ if (enable)
|
||||
+ tmp |= coremask;
|
||||
+ else
|
||||
+ tmp &= ~coremask;
|
||||
+
|
||||
+ err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
|
||||
+
|
||||
+out:
|
||||
+ return err;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl);
|
||||
--- a/drivers/net/wireless/b43/main.c
|
||||
+++ b/drivers/net/wireless/b43/main.c
|
||||
@@ -4866,7 +4866,7 @@ static int b43_wireless_core_init(struct
|
||||
switch (dev->dev->bus_type) {
|
||||
#ifdef CPTCFG_B43_BCMA
|
||||
case B43_BUS_BCMA:
|
||||
- bcma_core_pci_irq_ctl(dev->dev->bdev->bus,
|
||||
+ bcma_host_pci_irq_ctl(dev->dev->bdev->bus,
|
||||
dev->dev->bdev, true);
|
||||
bcma_host_pci_up(dev->dev->bdev->bus);
|
||||
break;
|
||||
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
|
||||
@@ -4959,7 +4959,7 @@ static int brcms_b_up_prep(struct brcms_
|
||||
* Configure pci/pcmcia here instead of in brcms_c_attach()
|
||||
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
|
||||
*/
|
||||
- bcma_core_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
|
||||
+ bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
|
||||
true);
|
||||
|
||||
/*
|
||||
@ -1,6 +1,6 @@
|
||||
--- a/net/wireless/Kconfig
|
||||
+++ b/net/wireless/Kconfig
|
||||
@@ -174,7 +174,7 @@ config CFG80211_WEXT_EXPORT
|
||||
@@ -171,7 +171,7 @@ config CFG80211_WEXT_EXPORT
|
||||
wext compatibility symbols to be exported.
|
||||
|
||||
config LIB80211
|
||||
@ -9,7 +9,7 @@
|
||||
depends on m
|
||||
default n
|
||||
help
|
||||
@@ -184,15 +184,15 @@ config LIB80211
|
||||
@@ -181,15 +181,15 @@ config LIB80211
|
||||
Drivers should select this themselves if needed.
|
||||
|
||||
config LIB80211_CRYPT_WEP
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
--- a/.local-symbols
|
||||
+++ b/.local-symbols
|
||||
@@ -344,40 +344,3 @@ USB_CDC_PHONET=
|
||||
USB_IPHETH=
|
||||
@@ -476,44 +476,6 @@ USB_IPHETH=
|
||||
USB_SIERRA_NET=
|
||||
USB_VL600=
|
||||
USB_NET_CH9200=
|
||||
-SSB_POSSIBLE=
|
||||
-SSB=
|
||||
-SSB_SPROM=
|
||||
@ -15,6 +15,7 @@
|
||||
-SSB_PCMCIAHOST=
|
||||
-SSB_SDIOHOST_POSSIBLE=
|
||||
-SSB_SDIOHOST=
|
||||
-SSB_HOST_SOC=
|
||||
-SSB_SILENT=
|
||||
-SSB_DEBUG=
|
||||
-SSB_SERIAL=
|
||||
@ -32,28 +33,20 @@
|
||||
-BCMA_BLOCKIO=
|
||||
-BCMA_HOST_PCI_POSSIBLE=
|
||||
-BCMA_HOST_PCI=
|
||||
-BCMA_DRIVER_PCI_HOSTMODE=
|
||||
-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=
|
||||
--- 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/
|
||||
--- a/drivers/net/wireless/b43/main.c
|
||||
+++ b/drivers/net/wireless/b43/main.c
|
||||
NFC=
|
||||
NFC_DIGITAL=
|
||||
NFC_NCI=
|
||||
--- a/drivers/net/wireless/broadcom/b43/main.c
|
||||
+++ b/drivers/net/wireless/broadcom/b43/main.c
|
||||
@@ -2866,7 +2866,7 @@ static struct ssb_device *b43_ssb_gpio_d
|
||||
{
|
||||
struct ssb_bus *bus = dev->dev->sdev->bus;
|
||||
@ -63,7 +56,7 @@
|
||||
return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
|
||||
#else
|
||||
return bus->chipco.dev;
|
||||
@@ -4907,7 +4907,7 @@ static int b43_wireless_core_init(struct
|
||||
@@ -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. */
|
||||
@ -72,8 +65,8 @@
|
||||
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
|
||||
--- a/drivers/net/wireless/broadcom/b43legacy/main.c
|
||||
+++ b/drivers/net/wireless/broadcom/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. */
|
||||
@ -92,8 +85,8 @@
|
||||
pcidev = bus->pcicore.dev;
|
||||
#endif
|
||||
gpiodev = bus->chipco.dev ? : pcidev;
|
||||
--- a/drivers/net/wireless/brcm80211/brcmsmac/Makefile
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile
|
||||
@@ -43,6 +43,6 @@ brcmsmac-y := \
|
||||
brcms_trace_events.o \
|
||||
debug.o
|
||||
@ -102,8 +95,8 @@
|
||||
+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
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h
|
||||
@@ -22,7 +22,7 @@ struct brcms_led {
|
||||
bool active_low;
|
||||
};
|
||||
@ -116,12 +109,23 @@
|
||||
--- 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/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/net/nfc/Kconfig"
|
||||
|
||||
#source "$BACKPORT_DIR/drivers/media/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/
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
--- a/drivers/net/wireless/ath/Kconfig
|
||||
+++ b/drivers/net/wireless/ath/Kconfig
|
||||
@@ -6,6 +6,7 @@ menuconfig ATH_CARDS
|
||||
tristate "Atheros Wireless Cards"
|
||||
@@ -1,5 +1,5 @@
|
||||
config ATH_COMMON
|
||||
- tristate
|
||||
+ tristate "ath.ko"
|
||||
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
|
||||
|
||||
config WLAN_VENDOR_ATH
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
--- a/backport-include/linux/wait.h
|
||||
+++ b/backport-include/linux/wait.h
|
||||
@@ -23,7 +23,7 @@ backport_wait_on_bit_io(void *word, int
|
||||
|
||||
#endif
|
||||
|
||||
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
|
||||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,12)
|
||||
#define WQ_FLAG_WOKEN 0x02
|
||||
|
||||
#define wait_woken LINUX_BACKPORT(wait_woken)
|
||||
--- a/compat/backport-3.19.c
|
||||
+++ b/compat/backport-3.19.c
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,12)
|
||||
static inline bool is_kthread_should_stop(void)
|
||||
{
|
||||
return (current->flags & PF_KTHREAD) && kthread_should_stop();
|
||||
@@ -79,6 +80,7 @@ int woken_wake_function(wait_queue_t *wa
|
||||
return default_wake_function(wait, mode, sync, key);
|
||||
}
|
||||
EXPORT_SYMBOL(woken_wake_function);
|
||||
+#endif
|
||||
|
||||
#ifdef __BACKPORT_NETDEV_RSS_KEY_FILL
|
||||
u8 netdev_rss_key[NETDEV_RSS_KEY_LEN];
|
||||
@ -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
|
||||
---help---
|
||||
This option enables the hardware independent IEEE 802.11
|
||||
--- a/net/mac80211/Makefile
|
||||
+++ b/net/mac80211/Makefile
|
||||
@@ -16,9 +16,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
|
||||
@@ -307,7 +307,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;
|
||||
@@ -337,14 +338,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)
|
||||
@@ -352,6 +347,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] */
|
||||
@@ -463,7 +460,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);
|
||||
|
||||
@@ -534,7 +531,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,
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@ Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -856,7 +856,6 @@ static int ieee80211_stop_ap(struct wiph
|
||||
@@ -846,7 +846,6 @@ static int ieee80211_stop_ap(struct wiph
|
||||
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
|
||||
|
||||
__sta_info_flush(sdata, true);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -287,7 +287,7 @@ void ieee80211_restart_hw(struct ieee802
|
||||
@@ -291,7 +291,7 @@ void ieee80211_restart_hw(struct ieee802
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_restart_hw);
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
static int ieee80211_ifa_changed(struct notifier_block *nb,
|
||||
unsigned long data, void *arg)
|
||||
{
|
||||
@@ -346,7 +346,7 @@ static int ieee80211_ifa_changed(struct
|
||||
@@ -350,7 +350,7 @@ static int ieee80211_ifa_changed(struct
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -18,9 +18,9 @@
|
||||
static int ieee80211_ifa6_changed(struct notifier_block *nb,
|
||||
unsigned long data, void *arg)
|
||||
{
|
||||
@@ -1057,14 +1057,14 @@ int ieee80211_register_hw(struct ieee802
|
||||
if (result)
|
||||
goto fail_pm_qos;
|
||||
@@ -1087,14 +1087,14 @@ int ieee80211_register_hw(struct ieee802
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
-#ifdef CONFIG_INET
|
||||
+#ifdef __disabled__CONFIG_INET
|
||||
@ -35,7 +35,7 @@
|
||||
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
|
||||
result = register_inet6addr_notifier(&local->ifa6_notifier);
|
||||
if (result)
|
||||
@@ -1073,13 +1073,13 @@ int ieee80211_register_hw(struct ieee802
|
||||
@@ -1103,13 +1103,13 @@ int ieee80211_register_hw(struct ieee802
|
||||
|
||||
return 0;
|
||||
|
||||
@ -50,12 +50,12 @@
|
||||
-#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);
|
||||
@@ -1124,10 +1124,10 @@ void ieee80211_unregister_hw(struct ieee
|
||||
#endif
|
||||
rtnl_lock();
|
||||
@@ -1137,10 +1137,10 @@ void ieee80211_unregister_hw(struct ieee
|
||||
tasklet_kill(&local->tx_pending_tasklet);
|
||||
tasklet_kill(&local->tasklet);
|
||||
|
||||
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);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1963,7 +1963,7 @@ static int ieee80211_scan(struct wiphy *
|
||||
@@ -1999,7 +1999,7 @@ static int ieee80211_scan(struct wiphy *
|
||||
* the frames sent while scanning on other channel will be
|
||||
* lost)
|
||||
*/
|
||||
|
||||
@ -1,882 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Tue, 18 Nov 2014 23:58:51 +0100
|
||||
Subject: [PATCH] mac80211: add an intermediate software queue implementation
|
||||
|
||||
This allows drivers to request per-vif and per-sta-tid queues from which
|
||||
they can pull frames. This makes it easier to keep the hardware queues
|
||||
short, and to improve fairness between clients and vifs.
|
||||
|
||||
The task of scheduling packet transmission is left up to the driver -
|
||||
queueing is controlled by mac80211. Drivers can only dequeue packets by
|
||||
calling ieee80211_tx_dequeue. This makes it possible to add active queue
|
||||
management later without changing drivers using this code.
|
||||
|
||||
This can also be used as a starting point to implement A-MSDU
|
||||
aggregation in a way that does not add artificially induced latency.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -84,6 +84,39 @@
|
||||
*
|
||||
*/
|
||||
|
||||
+/**
|
||||
+ * DOC: mac80211 software tx queueing
|
||||
+ *
|
||||
+ * mac80211 provides an optional intermediate queueing implementation designed
|
||||
+ * to allow the driver to keep hardware queues short and provide some fairness
|
||||
+ * between different stations/interfaces.
|
||||
+ * In this model, the driver pulls data frames from the mac80211 queue instead
|
||||
+ * of letting mac80211 push them via drv_tx().
|
||||
+ * Other frames (e.g. control or management) are still pushed using drv_tx().
|
||||
+ *
|
||||
+ * Drivers indicate that they use this model by implementing the .wake_tx_queue
|
||||
+ * driver operation.
|
||||
+ *
|
||||
+ * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with a
|
||||
+ * single per-vif queue for multicast data frames.
|
||||
+ *
|
||||
+ * The driver is expected to initialize its private per-queue data for stations
|
||||
+ * and interfaces in the .add_interface and .sta_add ops.
|
||||
+ *
|
||||
+ * The driver can't access the queue directly. To dequeue a frame, it calls
|
||||
+ * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it
|
||||
+ * calls the .wake_tx_queue driver op.
|
||||
+ *
|
||||
+ * For AP powersave TIM handling, the driver only needs to indicate if it has
|
||||
+ * buffered packets in the driver specific data structures by calling
|
||||
+ * ieee80211_sta_set_buffered(). For frames buffered in the ieee80211_txq
|
||||
+ * struct, mac80211 sets the appropriate TIM PVB bits and calls
|
||||
+ * .release_buffered_frames().
|
||||
+ * In that callback the driver is therefore expected to release its own
|
||||
+ * buffered frames and afterwards also frames from the ieee80211_txq (obtained
|
||||
+ * via the usual ieee80211_tx_dequeue).
|
||||
+ */
|
||||
+
|
||||
struct device;
|
||||
|
||||
/**
|
||||
@@ -1246,6 +1279,7 @@ enum ieee80211_vif_flags {
|
||||
* monitor interface (if that is requested.)
|
||||
* @drv_priv: data area for driver use, will always be aligned to
|
||||
* sizeof(void *).
|
||||
+ * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
|
||||
*/
|
||||
struct ieee80211_vif {
|
||||
enum nl80211_iftype type;
|
||||
@@ -1257,6 +1291,8 @@ struct ieee80211_vif {
|
||||
u8 cab_queue;
|
||||
u8 hw_queue[IEEE80211_NUM_ACS];
|
||||
|
||||
+ struct ieee80211_txq *txq;
|
||||
+
|
||||
struct ieee80211_chanctx_conf __rcu *chanctx_conf;
|
||||
|
||||
u32 driver_flags;
|
||||
@@ -1501,6 +1537,7 @@ struct ieee80211_sta_rates {
|
||||
* @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
|
||||
* valid if the STA is a TDLS peer in the first place.
|
||||
* @mfp: indicates whether the STA uses management frame protection or not.
|
||||
+ * @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
|
||||
*/
|
||||
struct ieee80211_sta {
|
||||
u32 supp_rates[IEEE80211_NUM_BANDS];
|
||||
@@ -1519,6 +1556,8 @@ struct ieee80211_sta {
|
||||
bool tdls_initiator;
|
||||
bool mfp;
|
||||
|
||||
+ struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
|
||||
+
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
@@ -1547,6 +1586,27 @@ struct ieee80211_tx_control {
|
||||
};
|
||||
|
||||
/**
|
||||
+ * struct ieee80211_txq - Software intermediate tx queue
|
||||
+ *
|
||||
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
+ * @sta: station table entry, %NULL for per-vif queue
|
||||
+ * @tid: the TID for this queue (unused for per-vif queue)
|
||||
+ * @ac: the AC for this queue
|
||||
+ *
|
||||
+ * The driver can obtain packets from this queue by calling
|
||||
+ * ieee80211_tx_dequeue().
|
||||
+ */
|
||||
+struct ieee80211_txq {
|
||||
+ struct ieee80211_vif *vif;
|
||||
+ struct ieee80211_sta *sta;
|
||||
+ u8 tid;
|
||||
+ u8 ac;
|
||||
+
|
||||
+ /* must be last */
|
||||
+ u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* enum ieee80211_hw_flags - hardware flags
|
||||
*
|
||||
* These flags are used to indicate hardware capabilities to
|
||||
@@ -1770,6 +1830,8 @@ enum ieee80211_hw_flags {
|
||||
* within &struct ieee80211_sta.
|
||||
* @chanctx_data_size: size (in bytes) of the drv_priv data area
|
||||
* within &struct ieee80211_chanctx_conf.
|
||||
+ * @txq_data_size: size (in bytes) of the drv_priv data area
|
||||
+ * within @struct ieee80211_txq.
|
||||
*
|
||||
* @max_rates: maximum number of alternate rate retry stages the hw
|
||||
* can handle.
|
||||
@@ -1818,6 +1880,9 @@ enum ieee80211_hw_flags {
|
||||
* @n_cipher_schemes: a size of an array of cipher schemes definitions.
|
||||
* @cipher_schemes: a pointer to an array of cipher scheme definitions
|
||||
* supported by HW.
|
||||
+ *
|
||||
+ * @txq_ac_max_pending: maximum number of frames per AC pending in all txq
|
||||
+ * entries for a vif.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
@@ -1830,6 +1895,7 @@ struct ieee80211_hw {
|
||||
int vif_data_size;
|
||||
int sta_data_size;
|
||||
int chanctx_data_size;
|
||||
+ int txq_data_size;
|
||||
u16 queues;
|
||||
u16 max_listen_interval;
|
||||
s8 max_signal;
|
||||
@@ -1846,6 +1912,7 @@ struct ieee80211_hw {
|
||||
u8 uapsd_max_sp_len;
|
||||
u8 n_cipher_schemes;
|
||||
const struct ieee80211_cipher_scheme *cipher_schemes;
|
||||
+ int txq_ac_max_pending;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -3007,6 +3074,8 @@ enum ieee80211_reconfig_type {
|
||||
* response template is provided, together with the location of the
|
||||
* switch-timing IE within the template. The skb can only be used within
|
||||
* the function call.
|
||||
+ *
|
||||
+ * @wake_tx_queue: Called when new packets have been added to the queue.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
@@ -3238,6 +3307,9 @@ struct ieee80211_ops {
|
||||
void (*tdls_recv_channel_switch)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_tdls_ch_sw_params *params);
|
||||
+
|
||||
+ void (*wake_tx_queue)(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -5249,4 +5321,15 @@ void ieee80211_unreserve_tid(struct ieee
|
||||
*/
|
||||
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
|
||||
const u8 *ids, int n_ids, size_t offset);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_tx_dequeue - dequeue a packet from a software tx queue
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
+ *
|
||||
+ * Returns the skb if successful, %NULL if no frame was available.
|
||||
+ */
|
||||
+struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq);
|
||||
#endif /* MAC80211_H */
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1367,4 +1367,16 @@ drv_tdls_recv_channel_switch(struct ieee
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
+static inline void drv_wake_tx_queue(struct ieee80211_local *local,
|
||||
+ struct txq_info *txq)
|
||||
+{
|
||||
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
|
||||
+
|
||||
+ if (!check_sdata_in_driver(sdata))
|
||||
+ return;
|
||||
+
|
||||
+ trace_drv_wake_tx_queue(local, sdata, txq);
|
||||
+ local->ops->wake_tx_queue(&local->hw, &txq->txq);
|
||||
+}
|
||||
+
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -809,6 +809,19 @@ struct mac80211_qos_map {
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
+enum txq_info_flags {
|
||||
+ IEEE80211_TXQ_STOP,
|
||||
+ IEEE80211_TXQ_AMPDU,
|
||||
+};
|
||||
+
|
||||
+struct txq_info {
|
||||
+ struct sk_buff_head queue;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ /* keep last! */
|
||||
+ struct ieee80211_txq txq;
|
||||
+};
|
||||
+
|
||||
struct ieee80211_sub_if_data {
|
||||
struct list_head list;
|
||||
|
||||
@@ -853,6 +866,7 @@ struct ieee80211_sub_if_data {
|
||||
bool control_port_no_encrypt;
|
||||
int encrypt_headroom;
|
||||
|
||||
+ atomic_t txqs_len[IEEE80211_NUM_ACS];
|
||||
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
|
||||
struct mac80211_qos_map __rcu *qos_map;
|
||||
|
||||
@@ -1453,6 +1467,10 @@ static inline struct ieee80211_local *hw
|
||||
return container_of(hw, struct ieee80211_local, hw);
|
||||
}
|
||||
|
||||
+static inline struct txq_info *to_txq_info(struct ieee80211_txq *txq)
|
||||
+{
|
||||
+ return container_of(txq, struct txq_info, txq);
|
||||
+}
|
||||
|
||||
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
|
||||
{
|
||||
@@ -1905,6 +1923,9 @@ static inline bool ieee80211_can_run_wor
|
||||
return true;
|
||||
}
|
||||
|
||||
+void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
|
||||
+ struct sta_info *sta,
|
||||
+ struct txq_info *txq, int tid);
|
||||
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||
u16 transaction, u16 auth_alg, u16 status,
|
||||
const u8 *extra, size_t extra_len, const u8 *bssid,
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -969,6 +969,13 @@ static void ieee80211_do_stop(struct iee
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
+ if (sdata->vif.txq) {
|
||||
+ struct txq_info *txqi = to_txq_info(sdata->vif.txq);
|
||||
+
|
||||
+ ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
||||
+ atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
|
||||
+ }
|
||||
+
|
||||
if (local->open_count == 0)
|
||||
ieee80211_clear_tx_pending(local);
|
||||
|
||||
@@ -1674,6 +1681,7 @@ int ieee80211_if_add(struct ieee80211_lo
|
||||
{
|
||||
struct net_device *ndev = NULL;
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
+ struct txq_info *txqi;
|
||||
int ret, i;
|
||||
int txqs = 1;
|
||||
|
||||
@@ -1693,10 +1701,18 @@ int ieee80211_if_add(struct ieee80211_lo
|
||||
ieee80211_assign_perm_addr(local, wdev->address, type);
|
||||
memcpy(sdata->vif.addr, wdev->address, ETH_ALEN);
|
||||
} else {
|
||||
+ int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
|
||||
+ sizeof(void *));
|
||||
+ int txq_size = 0;
|
||||
+
|
||||
+ if (local->ops->wake_tx_queue)
|
||||
+ txq_size += sizeof(struct txq_info) +
|
||||
+ local->hw.txq_data_size;
|
||||
+
|
||||
if (local->hw.queues >= IEEE80211_NUM_ACS)
|
||||
txqs = IEEE80211_NUM_ACS;
|
||||
|
||||
- ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size,
|
||||
+ ndev = alloc_netdev_mqs(size + txq_size,
|
||||
name, NET_NAME_UNKNOWN,
|
||||
ieee80211_if_setup, txqs, 1);
|
||||
if (!ndev)
|
||||
@@ -1731,6 +1747,11 @@ int ieee80211_if_add(struct ieee80211_lo
|
||||
memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
|
||||
memcpy(sdata->name, ndev->name, IFNAMSIZ);
|
||||
|
||||
+ if (txq_size) {
|
||||
+ txqi = netdev_priv(ndev) + size;
|
||||
+ ieee80211_init_tx_queue(sdata, NULL, txqi, 0);
|
||||
+ }
|
||||
+
|
||||
sdata->dev = ndev;
|
||||
}
|
||||
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -1019,6 +1019,9 @@ int ieee80211_register_hw(struct ieee802
|
||||
|
||||
local->dynamic_ps_forced_timeout = -1;
|
||||
|
||||
+ if (!local->hw.txq_ac_max_pending)
|
||||
+ local->hw.txq_ac_max_pending = 64;
|
||||
+
|
||||
result = ieee80211_wep_init(local);
|
||||
if (result < 0)
|
||||
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -118,6 +118,16 @@ static void __cleanup_single_sta(struct
|
||||
atomic_dec(&ps->num_sta_ps);
|
||||
}
|
||||
|
||||
+ if (sta->sta.txq[0]) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
+ struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
+ int n = skb_queue_len(&txqi->queue);
|
||||
+
|
||||
+ ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
||||
+ atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
|
||||
ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
|
||||
@@ -234,6 +244,8 @@ void sta_info_free(struct ieee80211_loca
|
||||
|
||||
sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
|
||||
|
||||
+ if (sta->sta.txq[0])
|
||||
+ kfree(to_txq_info(sta->sta.txq[0]));
|
||||
kfree(rcu_dereference_raw(sta->sta.rates));
|
||||
kfree(sta);
|
||||
}
|
||||
@@ -285,11 +297,12 @@ struct sta_info *sta_info_alloc(struct i
|
||||
const u8 *addr, gfp_t gfp)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
+ struct ieee80211_hw *hw = &local->hw;
|
||||
struct sta_info *sta;
|
||||
struct timespec uptime;
|
||||
int i;
|
||||
|
||||
- sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
|
||||
+ sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
|
||||
if (!sta)
|
||||
return NULL;
|
||||
|
||||
@@ -321,11 +334,25 @@ struct sta_info *sta_info_alloc(struct i
|
||||
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
|
||||
ewma_init(&sta->chain_signal_avg[i], 1024, 8);
|
||||
|
||||
- if (sta_prepare_rate_control(local, sta, gfp)) {
|
||||
- kfree(sta);
|
||||
- return NULL;
|
||||
+ if (local->ops->wake_tx_queue) {
|
||||
+ void *txq_data;
|
||||
+ int size = sizeof(struct txq_info) +
|
||||
+ ALIGN(hw->txq_data_size, sizeof(void *));
|
||||
+
|
||||
+ txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);
|
||||
+ if (!txq_data)
|
||||
+ goto free;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
+ struct txq_info *txq = txq_data + i * size;
|
||||
+
|
||||
+ ieee80211_init_tx_queue(sdata, sta, txq, i);
|
||||
+ }
|
||||
}
|
||||
|
||||
+ if (sta_prepare_rate_control(local, sta, gfp))
|
||||
+ goto free_txq;
|
||||
+
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
/*
|
||||
* timer_to_tid must be initialized with identity mapping
|
||||
@@ -346,7 +373,7 @@ struct sta_info *sta_info_alloc(struct i
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||
struct ieee80211_supported_band *sband =
|
||||
- local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
|
||||
+ hw->wiphy->bands[ieee80211_get_sdata_band(sdata)];
|
||||
u8 smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >>
|
||||
IEEE80211_HT_CAP_SM_PS_SHIFT;
|
||||
/*
|
||||
@@ -371,6 +398,13 @@ struct sta_info *sta_info_alloc(struct i
|
||||
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
|
||||
|
||||
return sta;
|
||||
+
|
||||
+free_txq:
|
||||
+ if (sta->sta.txq[0])
|
||||
+ kfree(to_txq_info(sta->sta.txq[0]));
|
||||
+free:
|
||||
+ kfree(sta);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
static int sta_info_insert_check(struct sta_info *sta)
|
||||
@@ -640,6 +674,8 @@ static void __sta_info_recalc_tim(struct
|
||||
|
||||
indicate_tim |=
|
||||
sta->driver_buffered_tids & tids;
|
||||
+ indicate_tim |=
|
||||
+ sta->txq_buffered_tids & tids;
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -1071,7 +1107,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff_head pending;
|
||||
- int filtered = 0, buffered = 0, ac;
|
||||
+ int filtered = 0, buffered = 0, ac, i;
|
||||
unsigned long flags;
|
||||
struct ps_data *ps;
|
||||
|
||||
@@ -1090,10 +1126,22 @@ void ieee80211_sta_ps_deliver_wakeup(str
|
||||
|
||||
BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
|
||||
sta->driver_buffered_tids = 0;
|
||||
+ sta->txq_buffered_tids = 0;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
|
||||
|
||||
+ if (sta->sta.txq[0]) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
+ struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
+
|
||||
+ if (!skb_queue_len(&txqi->queue))
|
||||
+ continue;
|
||||
+
|
||||
+ drv_wake_tx_queue(local, txqi);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
skb_queue_head_init(&pending);
|
||||
|
||||
/* sync with ieee80211_tx_h_unicast_ps_buf */
|
||||
@@ -1275,8 +1323,10 @@ ieee80211_sta_ps_deliver_response(struct
|
||||
/* if we already have frames from software, then we can't also
|
||||
* release from hardware queues
|
||||
*/
|
||||
- if (skb_queue_empty(&frames))
|
||||
+ if (skb_queue_empty(&frames)) {
|
||||
driver_release_tids |= sta->driver_buffered_tids & tids;
|
||||
+ driver_release_tids |= sta->txq_buffered_tids & tids;
|
||||
+ }
|
||||
|
||||
if (driver_release_tids) {
|
||||
/* If the driver has data on more than one TID then
|
||||
@@ -1447,6 +1497,9 @@ ieee80211_sta_ps_deliver_response(struct
|
||||
|
||||
sta_info_recalc_tim(sta);
|
||||
} else {
|
||||
+ unsigned long tids = sta->txq_buffered_tids & driver_release_tids;
|
||||
+ int tid;
|
||||
+
|
||||
/*
|
||||
* We need to release a frame that is buffered somewhere in the
|
||||
* driver ... it'll have to handle that.
|
||||
@@ -1466,8 +1519,22 @@ ieee80211_sta_ps_deliver_response(struct
|
||||
* that the TID(s) became empty before returning here from the
|
||||
* release function.
|
||||
* Either way, however, when the driver tells us that the TID(s)
|
||||
- * became empty we'll do the TIM recalculation.
|
||||
+ * became empty or we find that a txq became empty, we'll do the
|
||||
+ * TIM recalculation.
|
||||
*/
|
||||
+
|
||||
+ if (!sta->sta.txq[0])
|
||||
+ return;
|
||||
+
|
||||
+ for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
+ struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
||||
+
|
||||
+ if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue))
|
||||
+ continue;
|
||||
+
|
||||
+ sta_info_recalc_tim(sta);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -274,6 +274,7 @@ struct sta_ampdu_mlme {
|
||||
* entered power saving state, these are also delivered to
|
||||
* the station when it leaves powersave or polls for frames
|
||||
* @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
|
||||
+ * @txq_buffered_tids: bitmap of TIDs that mac80211 has txq data buffered on
|
||||
* @rx_packets: Number of MSDUs received from this STA
|
||||
* @rx_bytes: Number of bytes received from this STA
|
||||
* @last_rx: time (in jiffies) when last frame was received from this STA
|
||||
@@ -368,6 +369,7 @@ struct sta_info {
|
||||
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
|
||||
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
|
||||
unsigned long driver_buffered_tids;
|
||||
+ unsigned long txq_buffered_tids;
|
||||
|
||||
/* Updated from RX path only, no locking requirements */
|
||||
unsigned long rx_packets;
|
||||
--- a/net/mac80211/trace.h
|
||||
+++ b/net/mac80211/trace.h
|
||||
@@ -2312,6 +2312,37 @@ TRACE_EVENT(drv_tdls_recv_channel_switch
|
||||
)
|
||||
);
|
||||
|
||||
+TRACE_EVENT(drv_wake_tx_queue,
|
||||
+ TP_PROTO(struct ieee80211_local *local,
|
||||
+ struct ieee80211_sub_if_data *sdata,
|
||||
+ struct txq_info *txq),
|
||||
+
|
||||
+ TP_ARGS(local, sdata, txq),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ LOCAL_ENTRY
|
||||
+ VIF_ENTRY
|
||||
+ STA_ENTRY
|
||||
+ __field(u8, ac)
|
||||
+ __field(u8, tid)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ struct ieee80211_sta *sta = txq->txq.sta;
|
||||
+
|
||||
+ LOCAL_ASSIGN;
|
||||
+ VIF_ASSIGN;
|
||||
+ STA_ASSIGN;
|
||||
+ __entry->ac = txq->txq.ac;
|
||||
+ __entry->tid = txq->txq.tid;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk(
|
||||
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ac:%d tid:%d",
|
||||
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ac, __entry->tid
|
||||
+ )
|
||||
+);
|
||||
+
|
||||
#ifdef CPTCFG_MAC80211_MESSAGE_TRACING
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM mac80211_msg
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -776,12 +776,22 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
+static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid)
|
||||
+{
|
||||
+ u16 *seq = &sta->tid_seq[tid];
|
||||
+ __le16 ret = cpu_to_le16(*seq);
|
||||
+
|
||||
+ /* Increase the sequence number. */
|
||||
+ *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
- u16 *seq;
|
||||
u8 *qc;
|
||||
int tid;
|
||||
|
||||
@@ -832,13 +842,10 @@ ieee80211_tx_h_sequence(struct ieee80211
|
||||
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
||||
- seq = &tx->sta->tid_seq[tid];
|
||||
tx->sta->tx_msdu[tid]++;
|
||||
|
||||
- hdr->seq_ctrl = cpu_to_le16(*seq);
|
||||
-
|
||||
- /* Increase the sequence number. */
|
||||
- *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;
|
||||
+ if (!tx->sta->sta.txq[0])
|
||||
+ hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
@@ -1067,7 +1074,7 @@ static bool ieee80211_tx_prep_agg(struct
|
||||
* nothing -- this aggregation session is being started
|
||||
* but that might still fail with the driver
|
||||
*/
|
||||
- } else {
|
||||
+ } else if (!tx->sta->sta.txq[tid]) {
|
||||
spin_lock(&tx->sta->lock);
|
||||
/*
|
||||
* Need to re-check now, because we may get here
|
||||
@@ -1201,13 +1208,102 @@ ieee80211_tx_prepare(struct ieee80211_su
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
+static void ieee80211_drv_tx(struct ieee80211_local *local,
|
||||
+ struct ieee80211_vif *vif,
|
||||
+ struct ieee80211_sta *pubsta,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
+ struct ieee80211_tx_control control = {
|
||||
+ .sta = pubsta,
|
||||
+ };
|
||||
+ struct ieee80211_txq *txq = NULL;
|
||||
+ struct txq_info *txqi;
|
||||
+ u8 ac;
|
||||
+
|
||||
+ if (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)
|
||||
+ goto tx_normal;
|
||||
+
|
||||
+ if (!ieee80211_is_data(hdr->frame_control))
|
||||
+ goto tx_normal;
|
||||
+
|
||||
+ if (pubsta) {
|
||||
+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
+
|
||||
+ txq = pubsta->txq[tid];
|
||||
+ } else if (vif) {
|
||||
+ txq = vif->txq;
|
||||
+ }
|
||||
+
|
||||
+ if (!txq)
|
||||
+ goto tx_normal;
|
||||
+
|
||||
+ ac = txq->ac;
|
||||
+ txqi = to_txq_info(txq);
|
||||
+ atomic_inc(&sdata->txqs_len[ac]);
|
||||
+ if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending)
|
||||
+ netif_stop_subqueue(sdata->dev, ac);
|
||||
+
|
||||
+ skb_queue_tail(&txqi->queue, skb);
|
||||
+ drv_wake_tx_queue(local, txqi);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+tx_normal:
|
||||
+ drv_tx(local, &control, skb);
|
||||
+}
|
||||
+
|
||||
+struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
|
||||
+ struct txq_info *txqi = container_of(txq, struct txq_info, txq);
|
||||
+ struct ieee80211_hdr *hdr;
|
||||
+ struct sk_buff *skb = NULL;
|
||||
+ u8 ac = txq->ac;
|
||||
+
|
||||
+ spin_lock_bh(&txqi->queue.lock);
|
||||
+
|
||||
+ if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
|
||||
+ goto out;
|
||||
+
|
||||
+ skb = __skb_dequeue(&txqi->queue);
|
||||
+ if (!skb)
|
||||
+ goto out;
|
||||
+
|
||||
+ atomic_dec(&sdata->txqs_len[ac]);
|
||||
+ if (__netif_subqueue_stopped(sdata->dev, ac))
|
||||
+ ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
|
||||
+
|
||||
+ hdr = (struct ieee80211_hdr *)skb->data;
|
||||
+ if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
+ struct sta_info *sta = container_of(txq->sta, struct sta_info,
|
||||
+ sta);
|
||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
+
|
||||
+ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid);
|
||||
+ if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
|
||||
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
|
||||
+ else
|
||||
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&txqi->queue.lock);
|
||||
+
|
||||
+ return skb;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
||||
+
|
||||
static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct sk_buff_head *skbs,
|
||||
bool txpending)
|
||||
{
|
||||
- struct ieee80211_tx_control control;
|
||||
struct sk_buff *skb, *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -1265,10 +1361,9 @@ static bool ieee80211_tx_frags(struct ie
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
info->control.vif = vif;
|
||||
- control.sta = sta;
|
||||
|
||||
__skb_unlink(skb, skbs);
|
||||
- drv_tx(local, &control, skb);
|
||||
+ ieee80211_drv_tx(local, vif, sta, skb);
|
||||
}
|
||||
|
||||
return true;
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -308,6 +308,11 @@ void ieee80211_propagate_queue_wake(stru
|
||||
for (ac = 0; ac < n_acs; ac++) {
|
||||
int ac_queue = sdata->vif.hw_queue[ac];
|
||||
|
||||
+ if (local->ops->wake_tx_queue &&
|
||||
+ (atomic_read(&sdata->txqs_len[ac]) >
|
||||
+ local->hw.txq_ac_max_pending))
|
||||
+ continue;
|
||||
+
|
||||
if (ac_queue == queue ||
|
||||
(sdata->vif.cab_queue == queue &&
|
||||
local->queue_stop_reasons[ac_queue] == 0 &&
|
||||
@@ -3307,3 +3312,20 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u
|
||||
|
||||
return buf;
|
||||
}
|
||||
+
|
||||
+void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
|
||||
+ struct sta_info *sta,
|
||||
+ struct txq_info *txqi, int tid)
|
||||
+{
|
||||
+ skb_queue_head_init(&txqi->queue);
|
||||
+ txqi->txq.vif = &sdata->vif;
|
||||
+
|
||||
+ if (sta) {
|
||||
+ txqi->txq.sta = &sta->sta;
|
||||
+ sta->sta.txq[tid] = &txqi->txq;
|
||||
+ txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
|
||||
+ } else {
|
||||
+ sdata->vif.txq = &txqi->txq;
|
||||
+ txqi->txq.ac = IEEE80211_AC_BE;
|
||||
+ }
|
||||
+}
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -1176,6 +1176,7 @@ static void sta_ps_start(struct sta_info
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ps_data *ps;
|
||||
+ int tid;
|
||||
|
||||
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
@@ -1189,6 +1190,18 @@ static void sta_ps_start(struct sta_info
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
|
||||
ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
|
||||
sta->sta.addr, sta->sta.aid);
|
||||
+
|
||||
+ if (!sta->sta.txq[0])
|
||||
+ return;
|
||||
+
|
||||
+ for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
+ struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
||||
+
|
||||
+ if (!skb_queue_len(&txqi->queue))
|
||||
+ set_bit(tid, &sta->txq_buffered_tids);
|
||||
+ else
|
||||
+ clear_bit(tid, &sta->txq_buffered_tids);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void sta_ps_end(struct sta_info *sta)
|
||||
--- a/net/mac80211/agg-tx.c
|
||||
+++ b/net/mac80211/agg-tx.c
|
||||
@@ -188,6 +188,43 @@ ieee80211_wake_queue_agg(struct ieee8021
|
||||
__release(agg_queue);
|
||||
}
|
||||
|
||||
+static void
|
||||
+ieee80211_agg_stop_txq(struct sta_info *sta, int tid)
|
||||
+{
|
||||
+ struct ieee80211_txq *txq = sta->sta.txq[tid];
|
||||
+ struct txq_info *txqi;
|
||||
+
|
||||
+ if (!txq)
|
||||
+ return;
|
||||
+
|
||||
+ txqi = to_txq_info(txq);
|
||||
+
|
||||
+ /* Lock here to protect against further seqno updates on dequeue */
|
||||
+ spin_lock_bh(&txqi->queue.lock);
|
||||
+ set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||
+ spin_unlock_bh(&txqi->queue.lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
|
||||
+{
|
||||
+ struct ieee80211_txq *txq = sta->sta.txq[tid];
|
||||
+ struct txq_info *txqi;
|
||||
+
|
||||
+ if (!txq)
|
||||
+ return;
|
||||
+
|
||||
+ txqi = to_txq_info(txq);
|
||||
+
|
||||
+ if (enable)
|
||||
+ set_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
|
||||
+ else
|
||||
+ clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
|
||||
+
|
||||
+ clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||
+ drv_wake_tx_queue(sta->sdata->local, txqi);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* splice packets from the STA's pending to the local pending,
|
||||
* requires a call to ieee80211_agg_splice_finish later
|
||||
@@ -247,6 +284,7 @@ static void ieee80211_remove_tid_tx(stru
|
||||
ieee80211_assign_tid_tx(sta, tid, NULL);
|
||||
|
||||
ieee80211_agg_splice_finish(sta->sdata, tid);
|
||||
+ ieee80211_agg_start_txq(sta, tid, false);
|
||||
|
||||
kfree_rcu(tid_tx, rcu_head);
|
||||
}
|
||||
@@ -418,6 +456,8 @@ void ieee80211_tx_ba_session_handle_star
|
||||
*/
|
||||
clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
|
||||
|
||||
+ ieee80211_agg_stop_txq(sta, tid);
|
||||
+
|
||||
/*
|
||||
* Make sure no packets are being processed. This ensures that
|
||||
* we have a valid starting sequence number and that in-flight
|
||||
@@ -440,6 +480,8 @@ void ieee80211_tx_ba_session_handle_star
|
||||
ieee80211_agg_splice_finish(sdata, tid);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
+ ieee80211_agg_start_txq(sta, tid, false);
|
||||
+
|
||||
kfree_rcu(tid_tx, rcu_head);
|
||||
return;
|
||||
}
|
||||
@@ -666,6 +708,8 @@ static void ieee80211_agg_tx_operational
|
||||
ieee80211_agg_splice_finish(sta->sdata, tid);
|
||||
|
||||
spin_unlock_bh(&sta->lock);
|
||||
+
|
||||
+ ieee80211_agg_start_txq(sta, tid, true);
|
||||
}
|
||||
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
|
||||
@ -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
|
||||
@@ -136,10 +136,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,
|
||||
@@ -1419,7 +1434,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);
|
||||
}
|
||||
|
||||
@@ -1450,7 +1465,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);
|
||||
@@ -1647,7 +1662,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;
|
||||
@@ -2293,7 +2308,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)
|
||||
@@ -2346,13 +2361,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);
|
||||
@@ -2390,7 +2405,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:
|
||||
@@ -2429,7 +2444,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)
|
||||
@@ -2932,7 +2947,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);
|
||||
@ -1,125 +0,0 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Wed, 11 Mar 2015 09:14:15 +0100
|
||||
Subject: [PATCH] mac80211: lock rate control
|
||||
|
||||
Both minstrel (reported by Sven Eckelmann) and the iwlwifi rate
|
||||
control aren't properly taking concurrency into account. It's
|
||||
likely that the same is true for other rate control algorithms.
|
||||
|
||||
In the case of minstrel this manifests itself in crashes when an
|
||||
update and other data access are run concurrently, for example
|
||||
when the stations change bandwidth or similar. In iwlwifi, this
|
||||
can cause firmware crashes.
|
||||
|
||||
Since fixing all rate control algorithms will be very difficult,
|
||||
just provide locking for invocations. This protects the internal
|
||||
data structures the algorithms maintain.
|
||||
|
||||
I've manipulated hostapd to test this, by having it change its
|
||||
advertised bandwidth roughly ever 150ms. At the same time, I'm
|
||||
running a flood ping between the client and the AP, which causes
|
||||
this race of update vs. get_rate/status to easily happen on the
|
||||
client. With this change, the system survives this test.
|
||||
|
||||
Reported-by: Sven Eckelmann <sven@open-mesh.com>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rate.c
|
||||
+++ b/net/mac80211/rate.c
|
||||
@@ -683,7 +683,13 @@ void rate_control_get_rate(struct ieee80
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
|
||||
return;
|
||||
|
||||
- ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
||||
+ if (ista) {
|
||||
+ spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
+ ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
||||
+ spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
+ } else {
|
||||
+ ref->ops->get_rate(ref->priv, NULL, NULL, txrc);
|
||||
+ }
|
||||
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
|
||||
return;
|
||||
--- a/net/mac80211/rate.h
|
||||
+++ b/net/mac80211/rate.h
|
||||
@@ -42,10 +42,12 @@ static inline void rate_control_tx_statu
|
||||
if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||
return;
|
||||
|
||||
+ spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
if (ref->ops->tx_status)
|
||||
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||
else
|
||||
ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
|
||||
+ spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -64,7 +66,9 @@ rate_control_tx_status_noskb(struct ieee
|
||||
if (WARN_ON_ONCE(!ref->ops->tx_status_noskb))
|
||||
return;
|
||||
|
||||
+ spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
|
||||
+ spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
}
|
||||
|
||||
static inline void rate_control_rate_init(struct sta_info *sta)
|
||||
@@ -91,8 +95,10 @@ static inline void rate_control_rate_ini
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -115,18 +121,20 @@ static inline void rate_control_rate_upd
|
||||
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);
|
||||
}
|
||||
|
||||
static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
|
||||
- struct ieee80211_sta *sta,
|
||||
- gfp_t gfp)
|
||||
+ struct sta_info *sta, gfp_t gfp)
|
||||
{
|
||||
- return ref->ops->alloc_sta(ref->priv, sta, gfp);
|
||||
+ spin_lock_init(&sta->rate_ctrl_lock);
|
||||
+ return ref->ops->alloc_sta(ref->priv, &sta->sta, gfp);
|
||||
}
|
||||
|
||||
static inline void rate_control_free_sta(struct sta_info *sta)
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -286,7 +286,7 @@ static int sta_prepare_rate_control(stru
|
||||
|
||||
sta->rate_ctrl = local->rate_ctrl;
|
||||
sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
|
||||
- &sta->sta, gfp);
|
||||
+ sta, gfp);
|
||||
if (!sta->rate_ctrl_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -349,6 +349,7 @@ struct sta_info {
|
||||
u8 ptk_idx;
|
||||
struct rate_control_ref *rate_ctrl;
|
||||
void *rate_ctrl_priv;
|
||||
+ spinlock_t rate_ctrl_lock;
|
||||
spinlock_t lock;
|
||||
|
||||
struct work_struct drv_deliver_wk;
|
||||
@ -1,21 +0,0 @@
|
||||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 10 Mar 2015 17:49:29 +0100
|
||||
Subject: [PATCH] ath9k: restart only triggering DFS detector line
|
||||
|
||||
To support HT40 DFS mode, a triggering detector must
|
||||
reset only itself but not other detector lines.
|
||||
|
||||
Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
|
||||
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
|
||||
@@ -289,7 +289,7 @@ dpd_add_pulse(struct dfs_pattern_detecto
|
||||
"count=%d, count_false=%d\n",
|
||||
event->freq, pd->rs->type_id,
|
||||
ps->pri, ps->count, ps->count_falses);
|
||||
- channel_detector_reset(dpd, cd);
|
||||
+ pd->reset(pd, dpd->last_pulse_ts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 14 Jan 2016 03:14:03 +0100
|
||||
Subject: [PATCH] ath9k_hw: add low power tx gain table for AR953x
|
||||
|
||||
Used in some newer TP-Link AR9533 devices.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
|
||||
@@ -698,6 +698,9 @@ static void ar9003_tx_gain_table_mode2(s
|
||||
else if (AR_SREV_9340(ah))
|
||||
INIT_INI_ARRAY(&ah->iniModesTxGain,
|
||||
ar9340Modes_low_ob_db_tx_gain_table_1p0);
|
||||
+ else if (AR_SREV_9531_11(ah))
|
||||
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
|
||||
+ qca953x_1p1_modes_no_xpa_low_power_tx_gain_table);
|
||||
else if (AR_SREV_9485_11_OR_LATER(ah))
|
||||
INIT_INI_ARRAY(&ah->iniModesTxGain,
|
||||
ar9485Modes_low_ob_db_tx_gain_1_1);
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
|
||||
@@ -757,6 +757,71 @@ static const u32 qca953x_1p1_modes_xpa_t
|
||||
{0x00016448, 0x6c927a70},
|
||||
};
|
||||
|
||||
+static const u32 qca953x_1p1_modes_no_xpa_low_power_tx_gain_table[][2] = {
|
||||
+ /* Addr allmodes */
|
||||
+ {0x0000a2dc, 0xfff55592},
|
||||
+ {0x0000a2e0, 0xfff99924},
|
||||
+ {0x0000a2e4, 0xfffe1e00},
|
||||
+ {0x0000a2e8, 0xffffe000},
|
||||
+ {0x0000a410, 0x000050d6},
|
||||
+ {0x0000a500, 0x00000069},
|
||||
+ {0x0000a504, 0x0400006b},
|
||||
+ {0x0000a508, 0x0800006d},
|
||||
+ {0x0000a50c, 0x0c000269},
|
||||
+ {0x0000a510, 0x1000026b},
|
||||
+ {0x0000a514, 0x1400026d},
|
||||
+ {0x0000a518, 0x18000669},
|
||||
+ {0x0000a51c, 0x1c00066b},
|
||||
+ {0x0000a520, 0x1d000a68},
|
||||
+ {0x0000a524, 0x21000a6a},
|
||||
+ {0x0000a528, 0x25000a6c},
|
||||
+ {0x0000a52c, 0x29000a6e},
|
||||
+ {0x0000a530, 0x2d0012a9},
|
||||
+ {0x0000a534, 0x310012ab},
|
||||
+ {0x0000a538, 0x350012ad},
|
||||
+ {0x0000a53c, 0x39001b0a},
|
||||
+ {0x0000a540, 0x3d001b0c},
|
||||
+ {0x0000a544, 0x41001b0e},
|
||||
+ {0x0000a548, 0x43001bae},
|
||||
+ {0x0000a54c, 0x45001914},
|
||||
+ {0x0000a550, 0x47001916},
|
||||
+ {0x0000a554, 0x49001b96},
|
||||
+ {0x0000a558, 0x49001b96},
|
||||
+ {0x0000a55c, 0x49001b96},
|
||||
+ {0x0000a560, 0x49001b96},
|
||||
+ {0x0000a564, 0x49001b96},
|
||||
+ {0x0000a568, 0x49001b96},
|
||||
+ {0x0000a56c, 0x49001b96},
|
||||
+ {0x0000a570, 0x49001b96},
|
||||
+ {0x0000a574, 0x49001b96},
|
||||
+ {0x0000a578, 0x49001b96},
|
||||
+ {0x0000a57c, 0x49001b96},
|
||||
+ {0x0000a600, 0x00000000},
|
||||
+ {0x0000a604, 0x00000000},
|
||||
+ {0x0000a608, 0x00000000},
|
||||
+ {0x0000a60c, 0x00000000},
|
||||
+ {0x0000a610, 0x00000000},
|
||||
+ {0x0000a614, 0x00000000},
|
||||
+ {0x0000a618, 0x00804201},
|
||||
+ {0x0000a61c, 0x01408201},
|
||||
+ {0x0000a620, 0x01408502},
|
||||
+ {0x0000a624, 0x01408502},
|
||||
+ {0x0000a628, 0x01408502},
|
||||
+ {0x0000a62c, 0x01408502},
|
||||
+ {0x0000a630, 0x01408502},
|
||||
+ {0x0000a634, 0x01408502},
|
||||
+ {0x0000a638, 0x01408502},
|
||||
+ {0x0000a63c, 0x01408502},
|
||||
+ {0x0000b2dc, 0xfff55592},
|
||||
+ {0x0000b2e0, 0xfff99924},
|
||||
+ {0x0000b2e4, 0xfffe1e00},
|
||||
+ {0x0000b2e8, 0xffffe000},
|
||||
+ {0x00016044, 0x044922db},
|
||||
+ {0x00016048, 0x6c927a70},
|
||||
+ {0x00016444, 0x044922db},
|
||||
+ {0x00016448, 0x6c927a70},
|
||||
+};
|
||||
+
|
||||
static const u32 qca953x_2p0_baseband_core[][2] = {
|
||||
/* Addr allmodes */
|
||||
{0x00009800, 0xafe68e30},
|
||||
@ -1,76 +0,0 @@
|
||||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 10 Mar 2015 17:49:30 +0100
|
||||
Subject: [PATCH] ath9k: add DFS support for extension channel
|
||||
|
||||
In HT40 modes, pulse events on primary and extension
|
||||
channel are processed individually. If valid, a pulse
|
||||
event will be fed into the detector
|
||||
* for primary frequency, or
|
||||
* for extension frequency (+/-20MHz based on HT40-mode)
|
||||
* or both
|
||||
|
||||
With that, a 40MHz radar will result in two individual
|
||||
radar events.
|
||||
|
||||
Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
@@ -126,8 +126,19 @@ ath9k_postprocess_radar_event(struct ath
|
||||
DFS_STAT_INC(sc, pulses_detected);
|
||||
return true;
|
||||
}
|
||||
-#undef PRI_CH_RADAR_FOUND
|
||||
-#undef EXT_CH_RADAR_FOUND
|
||||
+
|
||||
+static void
|
||||
+ath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe)
|
||||
+{
|
||||
+ struct dfs_pattern_detector *pd = sc->dfs_detector;
|
||||
+ DFS_STAT_INC(sc, pulses_processed);
|
||||
+ if (pd == NULL)
|
||||
+ return;
|
||||
+ if (!pd->add_pulse(pd, pe))
|
||||
+ return;
|
||||
+ DFS_STAT_INC(sc, radar_detected);
|
||||
+ ieee80211_radar_detected(sc->hw);
|
||||
+}
|
||||
|
||||
/*
|
||||
* DFS: check PHY-error for radar pulse and feed the detector
|
||||
@@ -176,18 +187,21 @@ void ath9k_dfs_process_phyerr(struct ath
|
||||
ard.pulse_length_pri = vdata_end[-3];
|
||||
pe.freq = ah->curchan->channel;
|
||||
pe.ts = mactime;
|
||||
- if (ath9k_postprocess_radar_event(sc, &ard, &pe)) {
|
||||
- struct dfs_pattern_detector *pd = sc->dfs_detector;
|
||||
- ath_dbg(common, DFS,
|
||||
- "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, "
|
||||
- "width=%d, rssi=%d, delta_ts=%llu\n",
|
||||
- pe.freq, pe.ts, pe.width, pe.rssi,
|
||||
- pe.ts - sc->dfs_prev_pulse_ts);
|
||||
- sc->dfs_prev_pulse_ts = pe.ts;
|
||||
- DFS_STAT_INC(sc, pulses_processed);
|
||||
- if (pd != NULL && pd->add_pulse(pd, &pe)) {
|
||||
- DFS_STAT_INC(sc, radar_detected);
|
||||
- ieee80211_radar_detected(sc->hw);
|
||||
- }
|
||||
+ if (!ath9k_postprocess_radar_event(sc, &ard, &pe))
|
||||
+ return;
|
||||
+
|
||||
+ ath_dbg(common, DFS,
|
||||
+ "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "
|
||||
+ "width=%d, rssi=%d, delta_ts=%llu\n",
|
||||
+ ard.pulse_bw_info, pe.freq, pe.ts, pe.width, pe.rssi,
|
||||
+ pe.ts - sc->dfs_prev_pulse_ts);
|
||||
+ sc->dfs_prev_pulse_ts = pe.ts;
|
||||
+ if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND)
|
||||
+ ath9k_dfs_process_radar_pulse(sc, &pe);
|
||||
+ if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) {
|
||||
+ pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20;
|
||||
+ ath9k_dfs_process_radar_pulse(sc, &pe);
|
||||
}
|
||||
}
|
||||
+#undef PRI_CH_RADAR_FOUND
|
||||
+#undef EXT_CH_RADAR_FOUND
|
||||
@ -0,0 +1,156 @@
|
||||
From: Eli Cooper <elicooper@gmx.com>
|
||||
Date: Thu, 14 Jan 2016 00:07:12 +0800
|
||||
Subject: [PATCH] rt2x00: fix monitor mode regression
|
||||
|
||||
Since commit df1404650ccbfeb76a84f301f22316be0d00a864 monitor mode for rt2x00
|
||||
has been made effectively useless because the hardware filter is configured to
|
||||
drop packets whose intended recipient is not the device, regardless of the
|
||||
presence of monitor mode interfaces.
|
||||
|
||||
This patch fixes this regression by adding explicit monitor mode support, and
|
||||
configuring the hardware filter accordingly.
|
||||
|
||||
Signed-off-by: Eli Cooper <elicooper@gmx.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
|
||||
@@ -273,8 +273,10 @@ static void rt2400pci_config_filter(stru
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
- rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1);
|
||||
+ rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME,
|
||||
+ !rt2x00dev->is_monitoring);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_TODS,
|
||||
+ !rt2x00dev->is_monitoring &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
|
||||
@@ -274,8 +274,10 @@ static void rt2500pci_config_filter(stru
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
- rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1);
|
||||
+ rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME,
|
||||
+ !rt2x00dev->is_monitoring);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_TODS,
|
||||
+ !rt2x00dev->is_monitoring &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_MCAST,
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
|
||||
@@ -437,8 +437,10 @@ static void rt2500usb_config_filter(stru
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
- rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, 1);
|
||||
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME,
|
||||
+ !rt2x00dev->is_monitoring);
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS,
|
||||
+ !rt2x00dev->is_monitoring &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST,
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
|
||||
@@ -1490,7 +1490,8 @@ void rt2800_config_filter(struct rt2x00_
|
||||
!(filter_flags & FIF_FCSFAIL));
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
- rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, 1);
|
||||
+ rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME,
|
||||
+ !rt2x00dev->is_monitoring);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST,
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
|
||||
@@ -844,11 +844,13 @@ struct rt2x00_dev {
|
||||
* - Open sta interface count.
|
||||
* - Association count.
|
||||
* - Beaconing enabled count.
|
||||
+ * - Whether the device is monitoring.
|
||||
*/
|
||||
unsigned int intf_ap_count;
|
||||
unsigned int intf_sta_count;
|
||||
unsigned int intf_associated;
|
||||
unsigned int intf_beaconing;
|
||||
+ bool is_monitoring;
|
||||
|
||||
/*
|
||||
* Interface combinations
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c
|
||||
@@ -244,6 +244,16 @@ void rt2x00lib_config(struct rt2x00_dev
|
||||
(ieee80211_flags & IEEE80211_CONF_CHANGE_PS))
|
||||
cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
|
||||
|
||||
+ if (ieee80211_flags & IEEE80211_CONF_CHANGE_MONITOR) {
|
||||
+ if (conf->flags & IEEE80211_CONF_MONITOR) {
|
||||
+ rt2x00_dbg(rt2x00dev, "Monitor mode is enabled\n");
|
||||
+ rt2x00dev->is_monitoring = true;
|
||||
+ } else {
|
||||
+ rt2x00_dbg(rt2x00dev, "Monitor mode is disabled\n");
|
||||
+ rt2x00dev->is_monitoring = false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Start configuration.
|
||||
*/
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
|
||||
@@ -1204,6 +1204,7 @@ int rt2x00lib_start(struct rt2x00_dev *r
|
||||
rt2x00dev->intf_ap_count = 0;
|
||||
rt2x00dev->intf_sta_count = 0;
|
||||
rt2x00dev->intf_associated = 0;
|
||||
+ rt2x00dev->is_monitoring = false;
|
||||
|
||||
/* Enable the radio */
|
||||
retval = rt2x00lib_enable_radio(rt2x00dev);
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
|
||||
@@ -385,11 +385,6 @@ void rt2x00mac_configure_filter(struct i
|
||||
*total_flags |= FIF_PSPOLL;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * Check if there is any work left for us.
|
||||
- */
|
||||
- if (rt2x00dev->packet_filter == *total_flags)
|
||||
- return;
|
||||
rt2x00dev->packet_filter = *total_flags;
|
||||
|
||||
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
|
||||
@@ -530,8 +530,10 @@ static void rt61pci_config_filter(struct
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
|
||||
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
|
||||
- rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1);
|
||||
+ rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
|
||||
+ !rt2x00dev->is_monitoring);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
|
||||
+ !rt2x00dev->is_monitoring &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
|
||||
@@ -480,8 +480,10 @@ static void rt73usb_config_filter(struct
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
|
||||
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
|
||||
- rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1);
|
||||
+ rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
|
||||
+ !rt2x00dev->is_monitoring);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
|
||||
+ !rt2x00dev->is_monitoring &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
|
||||
@ -1,19 +0,0 @@
|
||||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 10 Mar 2015 17:49:31 +0100
|
||||
Subject: [PATCH] ath9k: allow 40MHz radar detection width
|
||||
|
||||
Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||
@@ -763,7 +763,8 @@ static const struct ieee80211_iface_comb
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||
- BIT(NL80211_CHAN_WIDTH_20),
|
||||
+ BIT(NL80211_CHAN_WIDTH_20) |
|
||||
+ BIT(NL80211_CHAN_WIDTH_40),
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
From: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
Date: Fri, 15 Jan 2016 18:17:17 +0800
|
||||
Subject: [PATCH] ath9k: avoid ANI restart if no trigger
|
||||
|
||||
Fixes commit 54da20d83f0e ("ath9k_hw: improve ANI processing and rx desensitizing parameters")
|
||||
|
||||
Call ath9k_ani_restart() only when the phy error rate reach the
|
||||
ANI immunity threshold. Sync the logic with internal code base.
|
||||
|
||||
Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ani.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ani.c
|
||||
@@ -444,14 +444,16 @@ void ath9k_hw_ani_monitor(struct ath_hw
|
||||
ofdmPhyErrRate < ah->config.ofdm_trig_low) {
|
||||
ath9k_hw_ani_lower_immunity(ah);
|
||||
aniState->ofdmsTurn = !aniState->ofdmsTurn;
|
||||
+ ath9k_ani_restart(ah);
|
||||
} else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) {
|
||||
ath9k_hw_ani_ofdm_err_trigger(ah);
|
||||
aniState->ofdmsTurn = false;
|
||||
+ ath9k_ani_restart(ah);
|
||||
} else if (cckPhyErrRate > ah->config.cck_trig_high) {
|
||||
ath9k_hw_ani_cck_err_trigger(ah);
|
||||
aniState->ofdmsTurn = true;
|
||||
+ ath9k_ani_restart(ah);
|
||||
}
|
||||
- ath9k_ani_restart(ah);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_ani_monitor);
|
||||
@ -1,137 +0,0 @@
|
||||
From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
|
||||
Date: Wed, 4 Mar 2015 05:12:10 +0300
|
||||
Subject: [PATCH] ath5k: channel change fix
|
||||
|
||||
ath5k updates the channel pointer and after that it stops the Rx logic
|
||||
and apply channel to HW. In case of channel switch, such sequence
|
||||
creates a small window when a frame, which is received on the old
|
||||
channel is considered as a frame received on the new one.
|
||||
|
||||
The most notable consequence of this situation occurs during the switch
|
||||
from 2 GHz band (CCK+OFDM) to the 5GHz band (OFDM-only). Frame received
|
||||
with CCK rate, e.g. beacon received at the 1mbps, causes the following
|
||||
warning:
|
||||
|
||||
WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]()
|
||||
invalid hw_rix: 1a
|
||||
[..]
|
||||
Call Trace:
|
||||
[<802656a8>] show_stack+0x48/0x70
|
||||
[<802dd92c>] warn_slowpath_common+0x88/0xbc
|
||||
[<802dd98c>] warn_slowpath_fmt+0x2c/0x38
|
||||
[<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k]
|
||||
[<8028ac64>] tasklet_action+0x8c/0xf0
|
||||
[<80075804>] __do_softirq+0x180/0x32c
|
||||
[<80196ce8>] irq_exit+0x54/0x70
|
||||
[<80041848>] ret_from_irq+0x0/0x4
|
||||
[<80182fdc>] ioread32+0x4/0xc
|
||||
[<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k]
|
||||
[<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k]
|
||||
[<81b50900>] ath5k_reset+0xd4/0x310 [ath5k]
|
||||
[<81b557e8>] ath5k_config+0x4c/0x104 [ath5k]
|
||||
[<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211]
|
||||
[<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211]
|
||||
[<8022c3f4>] process_one_work+0x28c/0x400
|
||||
[<802df8f8>] worker_thread+0x258/0x3c0
|
||||
[<801b5710>] kthread+0xe0/0xec
|
||||
[<800418a8>] ret_from_kernel_thread+0x14/0x1c
|
||||
|
||||
The easiest way to reproduce this warning is to run scan with dualband
|
||||
NIC in noisy environments, when the channel 11 runs multiple APs. In my
|
||||
tests if the APs num >= 12, the warning appears in the first few
|
||||
seconds of scanning.
|
||||
|
||||
In order to fix this, the Rx disable code moved to a higher level and
|
||||
placed before the channel pointer update. This is also makes the code a
|
||||
bit more symmetrical, since we disable and enable the Rx in the same
|
||||
function.
|
||||
|
||||
In fact, at the pointer update time new frames should not appear,
|
||||
because interrupt generation at this point should already be disabled.
|
||||
The next patch should address this issue.
|
||||
|
||||
CC: Jiri Slaby <jirislaby@gmail.com>
|
||||
CC: Nick Kossifidis <mickflemm@gmail.com>
|
||||
CC: Luis R. Rodriguez <mcgrof@do-not-panic.com>
|
||||
Reported-by: Christophe Prevotaux <cprevotaux@nltinc.com>
|
||||
Tested-by: Christophe Prevotaux <cprevotaux@nltinc.com>
|
||||
Tested-by: Eric Bree <ebree@nltinc.com>
|
||||
Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath5k/base.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/base.c
|
||||
@@ -2858,7 +2858,7 @@ ath5k_reset(struct ath5k_hw *ah, struct
|
||||
{
|
||||
struct ath_common *common = ath5k_hw_common(ah);
|
||||
int ret, ani_mode;
|
||||
- bool fast;
|
||||
+ bool fast = chan && modparam_fastchanswitch ? 1 : 0;
|
||||
|
||||
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n");
|
||||
|
||||
@@ -2876,11 +2876,29 @@ ath5k_reset(struct ath5k_hw *ah, struct
|
||||
* so we should also free any remaining
|
||||
* tx buffers */
|
||||
ath5k_drain_tx_buffs(ah);
|
||||
+
|
||||
+ /* Stop PCU */
|
||||
+ ath5k_hw_stop_rx_pcu(ah);
|
||||
+
|
||||
+ /* Stop DMA
|
||||
+ *
|
||||
+ * Note: If DMA didn't stop continue
|
||||
+ * since only a reset will fix it.
|
||||
+ */
|
||||
+ ret = ath5k_hw_dma_stop(ah);
|
||||
+
|
||||
+ /* RF Bus grant won't work if we have pending
|
||||
+ * frames
|
||||
+ */
|
||||
+ if (ret && fast) {
|
||||
+ ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
|
||||
+ "DMA didn't stop, falling back to normal reset\n");
|
||||
+ fast = false;
|
||||
+ }
|
||||
+
|
||||
if (chan)
|
||||
ah->curchan = chan;
|
||||
|
||||
- fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0;
|
||||
-
|
||||
ret = ath5k_hw_reset(ah, ah->opmode, ah->curchan, fast, skip_pcu);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah, "can't reset hardware (%d)\n", ret);
|
||||
--- a/drivers/net/wireless/ath/ath5k/reset.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/reset.c
|
||||
@@ -1169,30 +1169,6 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum
|
||||
if (ah->ah_version == AR5K_AR5212)
|
||||
ath5k_hw_set_sleep_clock(ah, false);
|
||||
|
||||
- /*
|
||||
- * Stop PCU
|
||||
- */
|
||||
- ath5k_hw_stop_rx_pcu(ah);
|
||||
-
|
||||
- /*
|
||||
- * Stop DMA
|
||||
- *
|
||||
- * Note: If DMA didn't stop continue
|
||||
- * since only a reset will fix it.
|
||||
- */
|
||||
- ret = ath5k_hw_dma_stop(ah);
|
||||
-
|
||||
- /* RF Bus grant won't work if we have pending
|
||||
- * frames */
|
||||
- if (ret && fast) {
|
||||
- ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
|
||||
- "DMA didn't stop, falling back to normal reset\n");
|
||||
- fast = false;
|
||||
- /* Non fatal, just continue with
|
||||
- * normal reset */
|
||||
- ret = 0;
|
||||
- }
|
||||
-
|
||||
mode = channel->hw_value;
|
||||
switch (mode) {
|
||||
case AR5K_MODE_11A:
|
||||
@ -0,0 +1,91 @@
|
||||
From: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
Date: Fri, 15 Jan 2016 18:17:18 +0800
|
||||
Subject: [PATCH] ath9k: clean up ANI per-channel pointer checking
|
||||
|
||||
commit c24bd3620c50 ("ath9k: Do not maintain ANI state per-channel")
|
||||
removed per-channel handling, the code to check 'curchan' also
|
||||
should be removed as never used.
|
||||
|
||||
Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ani.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ani.c
|
||||
@@ -126,12 +126,8 @@ static void ath9k_hw_update_mibstats(str
|
||||
|
||||
static void ath9k_ani_restart(struct ath_hw *ah)
|
||||
{
|
||||
- struct ar5416AniState *aniState;
|
||||
-
|
||||
- if (!ah->curchan)
|
||||
- return;
|
||||
+ struct ar5416AniState *aniState = &ah->ani;
|
||||
|
||||
- aniState = &ah->ani;
|
||||
aniState->listenTime = 0;
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
@@ -221,12 +217,7 @@ static void ath9k_hw_set_ofdm_nil(struct
|
||||
|
||||
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
|
||||
{
|
||||
- struct ar5416AniState *aniState;
|
||||
-
|
||||
- if (!ah->curchan)
|
||||
- return;
|
||||
-
|
||||
- aniState = &ah->ani;
|
||||
+ struct ar5416AniState *aniState = &ah->ani;
|
||||
|
||||
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
|
||||
ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
|
||||
@@ -281,12 +272,7 @@ static void ath9k_hw_set_cck_nil(struct
|
||||
|
||||
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
||||
{
|
||||
- struct ar5416AniState *aniState;
|
||||
-
|
||||
- if (!ah->curchan)
|
||||
- return;
|
||||
-
|
||||
- aniState = &ah->ani;
|
||||
+ struct ar5416AniState *aniState = &ah->ani;
|
||||
|
||||
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
|
||||
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
|
||||
@@ -299,9 +285,7 @@ static void ath9k_hw_ani_cck_err_trigger
|
||||
*/
|
||||
static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
|
||||
{
|
||||
- struct ar5416AniState *aniState;
|
||||
-
|
||||
- aniState = &ah->ani;
|
||||
+ struct ar5416AniState *aniState = &ah->ani;
|
||||
|
||||
/* lower OFDM noise immunity */
|
||||
if (aniState->ofdmNoiseImmunityLevel > 0 &&
|
||||
@@ -329,7 +313,7 @@ void ath9k_ani_reset(struct ath_hw *ah,
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int ofdm_nil, cck_nil;
|
||||
|
||||
- if (!ah->curchan)
|
||||
+ if (!chan)
|
||||
return;
|
||||
|
||||
BUG_ON(aniState == NULL);
|
||||
@@ -416,14 +400,10 @@ static bool ath9k_hw_ani_read_counters(s
|
||||
|
||||
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
- struct ar5416AniState *aniState;
|
||||
+ struct ar5416AniState *aniState = &ah->ani;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u32 ofdmPhyErrRate, cckPhyErrRate;
|
||||
|
||||
- if (!ah->curchan)
|
||||
- return;
|
||||
-
|
||||
- aniState = &ah->ani;
|
||||
if (!ath9k_hw_ani_read_counters(ah))
|
||||
return;
|
||||
|
||||
@ -1,96 +0,0 @@
|
||||
From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
|
||||
Date: Wed, 4 Mar 2015 05:12:11 +0300
|
||||
Subject: [PATCH] ath5k: fix reset race
|
||||
|
||||
To prepare for reset ath5k should finish all asynchronous tasks. At
|
||||
first, it disables the interrupt generation, then it waits for the
|
||||
interrupt handler and tasklets completion, and then proceeds to the HW
|
||||
configuration update. But it does not consider that the interrupt
|
||||
handler or tasklet re-enables the interrupt generation. And we fall in a
|
||||
situation when ath5k assumes that interrupts are disabled, but it is
|
||||
not.
|
||||
|
||||
This can lead to different consequences, such as reception of the frame,
|
||||
when we do not expect it. Under certain circumstances, this can lead to
|
||||
the following warning:
|
||||
|
||||
WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]()
|
||||
invalid hw_rix: 1a
|
||||
[..]
|
||||
Call Trace:
|
||||
[<802656a8>] show_stack+0x48/0x70
|
||||
[<802dd92c>] warn_slowpath_common+0x88/0xbc
|
||||
[<802dd98c>] warn_slowpath_fmt+0x2c/0x38
|
||||
[<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k]
|
||||
[<8028ac64>] tasklet_action+0x8c/0xf0
|
||||
[<80075804>] __do_softirq+0x180/0x32c
|
||||
[<80196ce8>] irq_exit+0x54/0x70
|
||||
[<80041848>] ret_from_irq+0x0/0x4
|
||||
[<80182fdc>] ioread32+0x4/0xc
|
||||
[<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k]
|
||||
[<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k]
|
||||
[<81b50900>] ath5k_reset+0xd4/0x310 [ath5k]
|
||||
[<81b557e8>] ath5k_config+0x4c/0x104 [ath5k]
|
||||
[<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211]
|
||||
[<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211]
|
||||
[<8022c3f4>] process_one_work+0x28c/0x400
|
||||
[<802df8f8>] worker_thread+0x258/0x3c0
|
||||
[<801b5710>] kthread+0xe0/0xec
|
||||
[<800418a8>] ret_from_kernel_thread+0x14/0x1c
|
||||
|
||||
Fix this issue by adding a new status flag, which forbids to re-enable
|
||||
the interrupt generation until the HW configuration is completed.
|
||||
|
||||
Note: previous patch, which reorders the Rx disable code helps to avoid
|
||||
the above warning, but not fixes the root cause of unexpected frame
|
||||
receiving.
|
||||
|
||||
CC: Jiri Slaby <jirislaby@gmail.com>
|
||||
CC: Nick Kossifidis <mickflemm@gmail.com>
|
||||
CC: Luis R. Rodriguez <mcgrof@do-not-panic.com>
|
||||
Reported-by: Christophe Prevotaux <cprevotaux@nltinc.com>
|
||||
Tested-by: Christophe Prevotaux <cprevotaux@nltinc.com>
|
||||
Tested-by: Eric Bree <ebree@nltinc.com>
|
||||
Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
|
||||
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
|
||||
@@ -1283,6 +1283,7 @@ struct ath5k_hw {
|
||||
#define ATH_STAT_PROMISC 1
|
||||
#define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */
|
||||
#define ATH_STAT_STARTED 3 /* opened & irqs enabled */
|
||||
+#define ATH_STAT_RESET 4 /* hw reset */
|
||||
|
||||
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
|
||||
unsigned int fif_filter_flags; /* Current FIF_* filter flags */
|
||||
--- a/drivers/net/wireless/ath/ath5k/base.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/base.c
|
||||
@@ -1523,6 +1523,9 @@ ath5k_set_current_imask(struct ath5k_hw
|
||||
enum ath5k_int imask;
|
||||
unsigned long flags;
|
||||
|
||||
+ if (test_bit(ATH_STAT_RESET, ah->status))
|
||||
+ return;
|
||||
+
|
||||
spin_lock_irqsave(&ah->irqlock, flags);
|
||||
imask = ah->imask;
|
||||
if (ah->rx_pending)
|
||||
@@ -2862,6 +2865,8 @@ ath5k_reset(struct ath5k_hw *ah, struct
|
||||
|
||||
ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n");
|
||||
|
||||
+ __set_bit(ATH_STAT_RESET, ah->status);
|
||||
+
|
||||
ath5k_hw_set_imr(ah, 0);
|
||||
synchronize_irq(ah->irq);
|
||||
ath5k_stop_tasklets(ah);
|
||||
@@ -2952,6 +2957,8 @@ ath5k_reset(struct ath5k_hw *ah, struct
|
||||
*/
|
||||
/* ath5k_chan_change(ah, c); */
|
||||
|
||||
+ __clear_bit(ATH_STAT_RESET, ah->status);
|
||||
+
|
||||
ath5k_beacon_config(ah);
|
||||
/* intrs are enabled by ath5k_beacon_config */
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
Date: Fri, 15 Jan 2016 18:17:19 +0800
|
||||
Subject: [PATCH] ath9k: do not reset while BB panic(0x4000409) on ar9561
|
||||
|
||||
BB panic(0x4000409) observed while AP enabling/disabling
|
||||
bursting.
|
||||
|
||||
Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||
@@ -2071,7 +2071,8 @@ void ar9003_hw_attach_phy_ops(struct ath
|
||||
* to be disabled.
|
||||
*
|
||||
* 0x04000409: Packet stuck on receive.
|
||||
- * Full chip reset is required for all chips except AR9340.
|
||||
+ * Full chip reset is required for all chips except
|
||||
+ * AR9340, AR9531 and AR9561.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -2100,7 +2101,7 @@ bool ar9003_hw_bb_watchdog_check(struct
|
||||
case 0x04000b09:
|
||||
return true;
|
||||
case 0x04000409:
|
||||
- if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
|
||||
+ if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
@ -0,0 +1,27 @@
|
||||
From: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
Date: Fri, 15 Jan 2016 18:17:20 +0800
|
||||
Subject: [PATCH] ath9k: fix inconsistent use of tab and space in
|
||||
indentation
|
||||
|
||||
Minor changes for indenting.
|
||||
|
||||
Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
||||
@@ -5485,11 +5485,11 @@ unsigned int ar9003_get_paprd_scale_fact
|
||||
AR9300_PAPRD_SCALE_1);
|
||||
else {
|
||||
if (chan->channel >= 5700)
|
||||
- return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
|
||||
- AR9300_PAPRD_SCALE_1);
|
||||
+ return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
|
||||
+ AR9300_PAPRD_SCALE_1);
|
||||
else if (chan->channel >= 5400)
|
||||
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
|
||||
- AR9300_PAPRD_SCALE_2);
|
||||
+ AR9300_PAPRD_SCALE_2);
|
||||
else
|
||||
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
|
||||
AR9300_PAPRD_SCALE_1);
|
||||
@ -1,76 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 12 Mar 2015 17:10:50 +0100
|
||||
Subject: [PATCH] ath9k: fix tracking of enabled AP beacons
|
||||
|
||||
sc->nbcnvifs tracks assigned beacon slots, not enabled beacons.
|
||||
Therefore, it cannot be used to decide if cur_conf->enable_beacon (bool)
|
||||
should be updated, or if beacons have been enabled already.
|
||||
With the current code (depending on the order of calls), beacons often
|
||||
do not get enabled in an AP+STA setup.
|
||||
To fix tracking of enabled beacons, convert cur_conf->enable_beacon to a
|
||||
bitmask of enabled beacon slots.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
||||
@@ -219,12 +219,15 @@ void ath9k_beacon_remove_slot(struct ath
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
struct ath_buf *bf = avp->av_bcbuf;
|
||||
+ struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
|
||||
|
||||
ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
|
||||
avp->av_bslot);
|
||||
|
||||
tasklet_disable(&sc->bcon_tasklet);
|
||||
|
||||
+ cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
|
||||
+
|
||||
if (bf && bf->bf_mpdu) {
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
||||
@@ -521,8 +524,7 @@ static bool ath9k_allow_beacon_config(st
|
||||
}
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
- if ((vif->type != NL80211_IFTYPE_AP) ||
|
||||
- (sc->nbcnvifs > 1)) {
|
||||
+ if (vif->type != NL80211_IFTYPE_AP) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"An AP interface is already present !\n");
|
||||
return false;
|
||||
@@ -616,12 +618,14 @@ void ath9k_beacon_config(struct ath_soft
|
||||
* enabling/disabling SWBA.
|
||||
*/
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
- if (!bss_conf->enable_beacon &&
|
||||
- (sc->nbcnvifs <= 1)) {
|
||||
- cur_conf->enable_beacon = false;
|
||||
- } else if (bss_conf->enable_beacon) {
|
||||
- cur_conf->enable_beacon = true;
|
||||
- ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
||||
+ bool enabled = cur_conf->enable_beacon;
|
||||
+
|
||||
+ if (!bss_conf->enable_beacon) {
|
||||
+ cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
|
||||
+ } else {
|
||||
+ cur_conf->enable_beacon |= BIT(avp->av_bslot);
|
||||
+ if (!enabled)
|
||||
+ ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/common.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/common.h
|
||||
@@ -54,7 +54,7 @@ struct ath_beacon_config {
|
||||
u16 dtim_period;
|
||||
u16 bmiss_timeout;
|
||||
u8 dtim_count;
|
||||
- bool enable_beacon;
|
||||
+ u8 enable_beacon;
|
||||
bool ibss_creator;
|
||||
u32 nexttbtt;
|
||||
u32 intval;
|
||||
@ -0,0 +1,65 @@
|
||||
From: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
Date: Fri, 15 Jan 2016 18:17:21 +0800
|
||||
Subject: [PATCH] ath9k: fix data bus error on ar9300 and ar9580
|
||||
|
||||
One crash issue be found on ar9300: RTC_RC reg read leads crash, leading
|
||||
the data bus error, due to RTC_RC reg write not happen properly.
|
||||
|
||||
Warm Reset trigger in continuous beacon stuck for one of the customer for
|
||||
other chip, noticed the MAC was stuck in RTC reset. After analysis noticed
|
||||
DMA did not complete when RTC was put in reset.
|
||||
|
||||
So, before resetting the MAC need to make sure there are no pending DMA
|
||||
transactions because this reset does not reset all parts of the chip.
|
||||
|
||||
The 12th and 11th bit of MAC _DMA_CFG register used to do that.
|
||||
12 cfg_halt_ack 0x0
|
||||
0 DMA has not yet halted
|
||||
1 DMA has halted
|
||||
11 cfg_halt_req 0x0
|
||||
0 DMA logic operates normally
|
||||
1 Request DMA logic to stop so software can reset the MAC
|
||||
|
||||
The Bit [12] of this register indicates when the halt has taken effect or
|
||||
not. the DMA halt IS NOT recoverable; once software sets bit [11] to
|
||||
request a DMA halt, software must wait for bit [12] to be set and reset
|
||||
the MAC.
|
||||
|
||||
So, the same thing we implemented for ar9580 chip.
|
||||
|
||||
Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -1368,6 +1368,16 @@ static bool ath9k_hw_set_reset(struct at
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
ar9003_mci_check_gpm_offset(ah);
|
||||
|
||||
+ /* DMA HALT added to resolve ar9300 and ar9580 bus error during
|
||||
+ * RTC_RC reg read
|
||||
+ */
|
||||
+ if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) {
|
||||
+ REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
|
||||
+ ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK,
|
||||
+ 20 * AH_WAIT_TIMEOUT);
|
||||
+ REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
|
||||
+ }
|
||||
+
|
||||
REG_WRITE(ah, AR_RTC_RC, rst_flags);
|
||||
|
||||
REGWRITE_BUFFER_FLUSH(ah);
|
||||
--- a/drivers/net/wireless/ath/ath9k/reg.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/reg.h
|
||||
@@ -34,8 +34,10 @@
|
||||
#define AR_CFG_SWRG 0x00000010
|
||||
#define AR_CFG_AP_ADHOC_INDICATION 0x00000020
|
||||
#define AR_CFG_PHOK 0x00000100
|
||||
-#define AR_CFG_CLK_GATE_DIS 0x00000400
|
||||
#define AR_CFG_EEBS 0x00000200
|
||||
+#define AR_CFG_CLK_GATE_DIS 0x00000400
|
||||
+#define AR_CFG_HALT_REQ 0x00000800
|
||||
+#define AR_CFG_HALT_ACK 0x00001000
|
||||
#define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000
|
||||
#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Fri, 13 Mar 2015 10:49:40 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: fix rounding issue in MCS duration
|
||||
calculation
|
||||
|
||||
On very high MCS bitrates, the calculated duration of rates that are
|
||||
next to each other can be very imprecise, due to the small packet size
|
||||
used as reference (1200 bytes).
|
||||
This is most visible in VHT80 nss=2 MCS8/9, for which minstrel shows the
|
||||
same throughput when the probability is also the same. This leads to a
|
||||
bad rate selection for such rates.
|
||||
|
||||
Fix this issue by introducing an average A-MPDU size factor into the
|
||||
calculation.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -17,10 +17,11 @@
|
||||
#include "rc80211_minstrel.h"
|
||||
#include "rc80211_minstrel_ht.h"
|
||||
|
||||
+#define AVG_AMPDU_SIZE 16
|
||||
#define AVG_PKT_SIZE 1200
|
||||
|
||||
/* Number of bits for an average sized packet */
|
||||
-#define MCS_NBITS (AVG_PKT_SIZE << 3)
|
||||
+#define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3)
|
||||
|
||||
/* Number of symbols for a packet with (bps) bits per symbol */
|
||||
#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps))
|
||||
@@ -33,7 +34,8 @@
|
||||
)
|
||||
|
||||
/* Transmit duration for the raw data part of an average sized packet */
|
||||
-#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
|
||||
+#define MCS_DURATION(streams, sgi, bps) \
|
||||
+ (MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) / AVG_AMPDU_SIZE)
|
||||
|
||||
#define BW_20 0
|
||||
#define BW_40 1
|
||||
@ -0,0 +1,19 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Fri, 15 Jan 2016 15:59:45 +0100
|
||||
Subject: [PATCH] brcmfmac: add missing include
|
||||
|
||||
linux/module.h is required for defining module parameters
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/netdevice.h>
|
||||
+#include <linux/module.h>
|
||||
#include <brcmu_wifi.h>
|
||||
#include <brcmu_utils.h>
|
||||
#include "core.h"
|
||||
@ -0,0 +1,118 @@
|
||||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Tue, 19 Jan 2016 12:39:24 +0100
|
||||
Subject: [PATCH] brcmfmac: fix sdio sg table alloc crash
|
||||
|
||||
With commit 7d34b0560567 ("brcmfmac: Move all module parameters to
|
||||
one place") a bug was introduced causing a null pointer exception.
|
||||
This patch fixes the bug by initializing the sg table till after
|
||||
the settings have been initialized.
|
||||
|
||||
Fixes: 7d34b0560567 ("brcmfmac: Move all module parameters to one place")
|
||||
Reported-by: Marc Zyngier <marc.zyngier@arm.com>
|
||||
Tested-by: Marc Zyngier <marc.zyngier@arm.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>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
||||
@@ -879,11 +879,24 @@ int brcmf_sdiod_abort(struct brcmf_sdio_
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
|
||||
+void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
+ struct sdio_func *func;
|
||||
+ struct mmc_host *host;
|
||||
+ uint max_blocks;
|
||||
uint nents;
|
||||
int err;
|
||||
|
||||
+ func = sdiodev->func[2];
|
||||
+ host = func->card->host;
|
||||
+ sdiodev->sg_support = host->max_segs > 1;
|
||||
+ max_blocks = min_t(uint, host->max_blk_count, 511u);
|
||||
+ sdiodev->max_request_size = min_t(uint, host->max_req_size,
|
||||
+ max_blocks * func->cur_blksize);
|
||||
+ sdiodev->max_segment_count = min_t(uint, host->max_segs,
|
||||
+ SG_MAX_SINGLE_ALLOC);
|
||||
+ sdiodev->max_segment_size = host->max_seg_size;
|
||||
+
|
||||
if (!sdiodev->sg_support)
|
||||
return;
|
||||
|
||||
@@ -1021,9 +1034,6 @@ static void brcmf_sdiod_host_fixup(struc
|
||||
|
||||
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
- struct sdio_func *func;
|
||||
- struct mmc_host *host;
|
||||
- uint max_blocks;
|
||||
int ret = 0;
|
||||
|
||||
sdiodev->num_funcs = 2;
|
||||
@@ -1054,26 +1064,6 @@ static int brcmf_sdiod_probe(struct brcm
|
||||
goto out;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * determine host related variables after brcmf_sdiod_probe()
|
||||
- * as func->cur_blksize is properly set and F2 init has been
|
||||
- * completed successfully.
|
||||
- */
|
||||
- func = sdiodev->func[2];
|
||||
- host = func->card->host;
|
||||
- sdiodev->sg_support = host->max_segs > 1;
|
||||
- max_blocks = min_t(uint, host->max_blk_count, 511u);
|
||||
- sdiodev->max_request_size = min_t(uint, host->max_req_size,
|
||||
- max_blocks * func->cur_blksize);
|
||||
- sdiodev->max_segment_count = min_t(uint, host->max_segs,
|
||||
- SG_MAX_SINGLE_ALLOC);
|
||||
- sdiodev->max_segment_size = host->max_seg_size;
|
||||
-
|
||||
- /* allocate scatter-gather table. sg support
|
||||
- * will be disabled upon allocation failure.
|
||||
- */
|
||||
- brcmf_sdiod_sgtable_alloc(sdiodev);
|
||||
-
|
||||
ret = brcmf_sdiod_freezer_attach(sdiodev);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -1084,7 +1074,7 @@ static int brcmf_sdiod_probe(struct brcm
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
- brcmf_sdiod_host_fixup(host);
|
||||
+ brcmf_sdiod_host_fixup(sdiodev->func[2]->card->host);
|
||||
out:
|
||||
if (ret)
|
||||
brcmf_sdiod_remove(sdiodev);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
@@ -4114,6 +4114,11 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+ /* allocate scatter-gather table. sg support
|
||||
+ * will be disabled upon allocation failure.
|
||||
+ */
|
||||
+ brcmf_sdiod_sgtable_alloc(bus->sdiodev);
|
||||
+
|
||||
/* Query the F2 block size, set roundup accordingly */
|
||||
bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
|
||||
bus->roundup = min(max_roundup, bus->blocksize);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
|
||||
@@ -342,6 +342,7 @@ int brcmf_sdiod_ramrw(struct brcmf_sdio_
|
||||
|
||||
/* Issue an abort to the specified function */
|
||||
int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
|
||||
+void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev);
|
||||
void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
|
||||
enum brcmf_sdiod_state state);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -1,22 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 15 Mar 2015 08:02:37 +0100
|
||||
Subject: [PATCH] ath9k: disable TPC support again (for now)
|
||||
|
||||
TPC support has been observed to cause some tx power fluctuations on
|
||||
some devices with at least AR934x and AR938x chips.
|
||||
Disable it for now until the bugs have been found and fixed
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -424,7 +424,7 @@ static void ath9k_hw_init_defaults(struc
|
||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
||||
ah->htc_reset_init = true;
|
||||
|
||||
- ah->tpc_enabled = true;
|
||||
+ ah->tpc_enabled = false;
|
||||
|
||||
ah->ani_function = ATH9K_ANI_ALL;
|
||||
if (!AR_SREV_9300_20_OR_LATER(ah))
|
||||
@ -0,0 +1,38 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 21 Jan 2016 16:28:44 +0100
|
||||
Subject: [PATCH] ath9k_hw: ignore eeprom magic mismatch on flash based devices
|
||||
|
||||
Many AR913x based devices (maybe others too) do not have a valid EEPROM
|
||||
magic in their calibration data partition.
|
||||
|
||||
Fixes: 6fa658fd5ab2 ("ath9k: Simplify and fix eeprom endianness swapping")
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
|
||||
@@ -150,18 +150,18 @@ int ath9k_hw_nvram_swap_data(struct ath_
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
- if (magic == AR5416_EEPROM_MAGIC) {
|
||||
- *swap_needed = false;
|
||||
- } else if (swab16(magic) == AR5416_EEPROM_MAGIC) {
|
||||
+ *swap_needed = false;
|
||||
+ if (swab16(magic) == AR5416_EEPROM_MAGIC) {
|
||||
if (ah->ah_flags & AH_NO_EEP_SWAP) {
|
||||
ath_info(common,
|
||||
"Ignoring endianness difference in EEPROM magic bytes.\n");
|
||||
-
|
||||
- *swap_needed = false;
|
||||
} else {
|
||||
*swap_needed = true;
|
||||
}
|
||||
- } else {
|
||||
+ } else if (magic != AR5416_EEPROM_MAGIC) {
|
||||
+ if (ath9k_hw_use_flash(ah))
|
||||
+ return 0;
|
||||
+
|
||||
ath_err(common,
|
||||
"Invalid EEPROM Magic (0x%04x).\n", magic);
|
||||
return -EINVAL;
|
||||
@ -1,21 +0,0 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Tue, 24 Feb 2015 00:28:18 +0100
|
||||
Subject: [PATCH] mac80211: don't look up stations for multicast addresses
|
||||
|
||||
Since multicast addresses don't exist as stations, don't attempt
|
||||
to look them up in the hashtable on TX.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1161,7 +1161,7 @@ ieee80211_tx_prepare(struct ieee80211_su
|
||||
tx->sdata->control_port_protocol == tx->skb->protocol) {
|
||||
tx->sta = sta_info_get_bss(sdata, hdr->addr1);
|
||||
}
|
||||
- if (!tx->sta)
|
||||
+ if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
|
||||
tx->sta = sta_info_get(sdata, hdr->addr1);
|
||||
|
||||
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
|
||||
@ -0,0 +1,55 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Fri, 22 Jan 2016 01:05:56 +0100
|
||||
Subject: [PATCH] ath9k: do not limit the number of DFS interfaces to 1
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||
@@ -751,14 +751,6 @@ static const struct ieee80211_iface_comb
|
||||
|
||||
#endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */
|
||||
|
||||
-static const struct ieee80211_iface_limit if_dfs_limits[] = {
|
||||
- { .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
|
||||
-#ifdef CPTCFG_MAC80211_MESH
|
||||
- BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
-#endif
|
||||
- BIT(NL80211_IFTYPE_ADHOC) },
|
||||
-};
|
||||
-
|
||||
static const struct ieee80211_iface_combination if_comb[] = {
|
||||
{
|
||||
.limits = if_limits,
|
||||
@@ -766,6 +758,11 @@ static const struct ieee80211_iface_comb
|
||||
.max_interfaces = 2048,
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
+#ifdef CPTCFG_ATH9K_DFS_CERTIFIED
|
||||
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||
+ BIT(NL80211_CHAN_WIDTH_20) |
|
||||
+ BIT(NL80211_CHAN_WIDTH_40),
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
.limits = wds_limits,
|
||||
@@ -774,18 +771,6 @@ static const struct ieee80211_iface_comb
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
},
|
||||
-#ifdef CPTCFG_ATH9K_DFS_CERTIFIED
|
||||
- {
|
||||
- .limits = if_dfs_limits,
|
||||
- .n_limits = ARRAY_SIZE(if_dfs_limits),
|
||||
- .max_interfaces = 1,
|
||||
- .num_different_channels = 1,
|
||||
- .beacon_int_infra_match = true,
|
||||
- .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||
- BIT(NL80211_CHAN_WIDTH_20) |
|
||||
- BIT(NL80211_CHAN_WIDTH_40),
|
||||
- }
|
||||
-#endif
|
||||
};
|
||||
|
||||
#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
|
||||
@ -1,130 +0,0 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri, 20 Mar 2015 11:41:58 +0100
|
||||
Subject: [PATCH] mac80211: remove drop_unencrypted code
|
||||
|
||||
This mechanism was historic, and only ever used by IBSS, which
|
||||
also doesn't need to have it as it properly manages station's
|
||||
802.1X PAE state (or, with WEP, always has a key.)
|
||||
|
||||
Remove the mechanism to clean up the code.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -274,8 +274,6 @@ void debugfs_hw_add(struct ieee80211_loc
|
||||
#ifdef CPTCFG_MAC80211_DEBUG_COUNTERS
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
|
||||
- DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted,
|
||||
- local->tx_handlers_drop_unencrypted);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
|
||||
local->tx_handlers_drop_fragment);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
|
||||
--- a/net/mac80211/debugfs_netdev.c
|
||||
+++ b/net/mac80211/debugfs_netdev.c
|
||||
@@ -177,7 +177,6 @@ static ssize_t ieee80211_if_write_##name
|
||||
IEEE80211_IF_FILE_R(name)
|
||||
|
||||
/* common attributes */
|
||||
-IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
|
||||
IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
|
||||
HEX);
|
||||
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
|
||||
@@ -562,7 +561,6 @@ IEEE80211_IF_FILE(dot11MeshAwakeWindowDu
|
||||
|
||||
static void add_common_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
- DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
|
||||
--- a/net/mac80211/ibss.c
|
||||
+++ b/net/mac80211/ibss.c
|
||||
@@ -249,8 +249,6 @@ static void __ieee80211_sta_join_ibss(st
|
||||
if (presp)
|
||||
kfree_rcu(presp, rcu_head);
|
||||
|
||||
- sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
||||
-
|
||||
/* make a copy of the chandef, it could be modified below. */
|
||||
chandef = *req_chandef;
|
||||
chan = chandef.chan;
|
||||
@@ -1289,8 +1287,6 @@ static void ieee80211_sta_create_ibss(st
|
||||
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
- else
|
||||
- sdata->drop_unencrypted = 0;
|
||||
|
||||
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
|
||||
&ifibss->chandef, ifibss->basic_rates,
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -842,8 +842,6 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
unsigned long state;
|
||||
|
||||
- int drop_unencrypted;
|
||||
-
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
/* Fragment table for host-based reassembly */
|
||||
@@ -1289,7 +1287,6 @@ struct ieee80211_local {
|
||||
/* TX/RX handler statistics */
|
||||
unsigned int tx_handlers_drop;
|
||||
unsigned int tx_handlers_queued;
|
||||
- unsigned int tx_handlers_drop_unencrypted;
|
||||
unsigned int tx_handlers_drop_fragment;
|
||||
unsigned int tx_handlers_drop_wep;
|
||||
unsigned int tx_handlers_drop_not_assoc;
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1535,7 +1535,6 @@ int ieee80211_if_change_type(struct ieee
|
||||
}
|
||||
|
||||
/* reset some values that shouldn't be kept across type changes */
|
||||
- sdata->drop_unencrypted = 0;
|
||||
if (type == NL80211_IFTYPE_STATION)
|
||||
sdata->u.mgd.use_4addr = false;
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -1897,8 +1897,7 @@ static int ieee80211_drop_unencrypted(st
|
||||
/* Drop unencrypted frames if key is set. */
|
||||
if (unlikely(!ieee80211_has_protected(fc) &&
|
||||
!ieee80211_is_nullfunc(fc) &&
|
||||
- ieee80211_is_data(fc) &&
|
||||
- (rx->key || rx->sdata->drop_unencrypted)))
|
||||
+ ieee80211_is_data(fc) && rx->key))
|
||||
return -EACCES;
|
||||
|
||||
return 0;
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -594,23 +594,8 @@ ieee80211_tx_h_select_key(struct ieee802
|
||||
else if (!is_multicast_ether_addr(hdr->addr1) &&
|
||||
(key = rcu_dereference(tx->sdata->default_unicast_key)))
|
||||
tx->key = key;
|
||||
- else if (info->flags & IEEE80211_TX_CTL_INJECTED)
|
||||
+ else
|
||||
tx->key = NULL;
|
||||
- else if (!tx->sdata->drop_unencrypted)
|
||||
- tx->key = NULL;
|
||||
- else if (tx->skb->protocol == tx->sdata->control_port_protocol)
|
||||
- tx->key = NULL;
|
||||
- else if (ieee80211_is_robust_mgmt_frame(tx->skb) &&
|
||||
- !(ieee80211_is_action(hdr->frame_control) &&
|
||||
- tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
|
||||
- tx->key = NULL;
|
||||
- else if (ieee80211_is_mgmt(hdr->frame_control) &&
|
||||
- !ieee80211_is_robust_mgmt_frame(tx->skb))
|
||||
- tx->key = NULL;
|
||||
- else {
|
||||
- I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
|
||||
- return TX_DROP;
|
||||
- }
|
||||
|
||||
if (tx->key) {
|
||||
bool skip_hw = false;
|
||||
@ -1,71 +0,0 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri, 20 Mar 2015 16:24:21 +0100
|
||||
Subject: [PATCH] mac80211: don't look up destination station twice
|
||||
|
||||
There's no need to look up the destination station twice while
|
||||
building the 802.11 header for a given frame if the frame will
|
||||
actually be transmitted to the station we initially looked up.
|
||||
|
||||
This happens for 4-addr VLAN interfaces and TDLS connections, which
|
||||
both directly send the frame to the station they looked up, though
|
||||
in the case of TDLS some station conditions need to be checked.
|
||||
|
||||
To avoid that, add a variable indicating that we've looked up the
|
||||
station that the frame is going to be transmitted to, and avoid the
|
||||
lookup/flag checking if it already has been done.
|
||||
|
||||
In the TDLS case, also move the authorized/wme_sta flag assignment
|
||||
to the correct place, i.e. only when that station is really used.
|
||||
Before this change, the new lookup should always have succeeded so
|
||||
that the potentially erroneous data would be overwritten.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1894,6 +1894,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
bool wme_sta = false, authorized = false, tdls_auth = false;
|
||||
bool tdls_peer = false, tdls_setup_frame = false;
|
||||
bool multicast;
|
||||
+ bool have_station = false;
|
||||
u16 info_id = 0;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_sub_if_data *ap_sdata;
|
||||
@@ -1918,6 +1919,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
hdrlen = 30;
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
+ have_station = true;
|
||||
}
|
||||
ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
@@ -2034,9 +2036,6 @@ static struct sk_buff *ieee80211_build_h
|
||||
if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
|
||||
sta = sta_info_get(sdata, skb->data);
|
||||
if (sta) {
|
||||
- authorized = test_sta_flag(sta,
|
||||
- WLAN_STA_AUTHORIZED);
|
||||
- wme_sta = sta->sta.wme;
|
||||
tdls_peer = test_sta_flag(sta,
|
||||
WLAN_STA_TDLS_PEER);
|
||||
tdls_auth = test_sta_flag(sta,
|
||||
@@ -2068,6 +2067,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
+ have_station = true;
|
||||
+ authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
+ wme_sta = sta->sta.wme;
|
||||
} else if (sdata->u.mgd.use_4addr &&
|
||||
cpu_to_be16(ethertype) != sdata->control_port_protocol) {
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
|
||||
@@ -2130,7 +2132,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
* in AP mode)
|
||||
*/
|
||||
multicast = is_multicast_ether_addr(hdr.addr1);
|
||||
- if (!multicast) {
|
||||
+ if (!multicast && !have_station) {
|
||||
sta = sta_info_get(sdata, hdr.addr1);
|
||||
if (sta) {
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
@ -0,0 +1,27 @@
|
||||
From: Michal Kazior <michal.kazior@tieto.com>
|
||||
Date: Thu, 21 Jan 2016 14:23:07 +0100
|
||||
Subject: [PATCH] mac80211: fix txq queue related crashes
|
||||
|
||||
The driver can access the queue simultanously
|
||||
while mac80211 tears down the interface. Without
|
||||
spinlock protection this could lead to corrupting
|
||||
sk_buff_head and subsequently to an invalid
|
||||
pointer dereference.
|
||||
|
||||
Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation")
|
||||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -977,7 +977,10 @@ static void ieee80211_do_stop(struct iee
|
||||
if (sdata->vif.txq) {
|
||||
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
|
||||
|
||||
+ spin_lock_bh(&txqi->queue.lock);
|
||||
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
||||
+ spin_unlock_bh(&txqi->queue.lock);
|
||||
+
|
||||
atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri, 20 Mar 2015 16:24:22 +0100
|
||||
Subject: [PATCH] mac80211: drop 4-addr VLAN frames earlier if not
|
||||
connected
|
||||
|
||||
If there's no station on the 4-addr VLAN interface, then frames
|
||||
cannot be transmitted. Drop such frames earlier, before setting
|
||||
up all the information for them.
|
||||
|
||||
We should keep the old check though since that code might be used
|
||||
for other internally-generated frames.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1920,6 +1920,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
have_station = true;
|
||||
+ } else if (sdata->wdev.use_4addr) {
|
||||
+ ret = -ENOLINK;
|
||||
+ goto free;
|
||||
}
|
||||
ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
@ -0,0 +1,57 @@
|
||||
From: Michal Kazior <michal.kazior@tieto.com>
|
||||
Date: Mon, 25 Jan 2016 14:43:24 +0100
|
||||
Subject: [PATCH] mac80211: fix unnecessary frame drops in mesh fwding
|
||||
|
||||
The ieee80211_queue_stopped() expects hw queue
|
||||
number but it was given raw WMM AC number instead.
|
||||
|
||||
This could cause frame drops and problems with
|
||||
traffic in some cases - most notably if driver
|
||||
doesn't map AC numbers to queue numbers 1:1 and
|
||||
uses ieee80211_stop_queues() and
|
||||
ieee80211_wake_queue() only without ever calling
|
||||
ieee80211_wake_queues().
|
||||
|
||||
On ath10k it was possible to hit this problem in
|
||||
the following case:
|
||||
|
||||
1. wlan0 uses queue 0
|
||||
(ath10k maps queues per vif)
|
||||
2. offchannel uses queue 15
|
||||
3. queues 1-14 are unused
|
||||
4. ieee80211_stop_queues()
|
||||
5. ieee80211_wake_queue(q=0)
|
||||
6. ieee80211_wake_queue(q=15)
|
||||
(other queues are not woken up because both
|
||||
driver and mac80211 know other queues are
|
||||
unused)
|
||||
7. ieee80211_rx_h_mesh_fwding()
|
||||
8. ieee80211_select_queue_80211() returns 2
|
||||
9. ieee80211_queue_stopped(q=2) returns true
|
||||
10. frame is dropped (oops!)
|
||||
|
||||
Fixes: d3c1597b8d1b ("mac80211: fix forwarded mesh frame queue mapping")
|
||||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -2235,7 +2235,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
- u16 q, hdrlen;
|
||||
+ u16 ac, q, hdrlen;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
@@ -2304,7 +2304,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
ether_addr_equal(sdata->vif.addr, hdr->addr3))
|
||||
return RX_CONTINUE;
|
||||
|
||||
- q = ieee80211_select_queue_80211(sdata, skb, hdr);
|
||||
+ ac = ieee80211_select_queue_80211(sdata, skb, hdr);
|
||||
+ q = sdata->vif.hw_queue[ac];
|
||||
if (ieee80211_queue_stopped(&local->hw, q)) {
|
||||
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
|
||||
return RX_DROP_MONITOR;
|
||||
@ -0,0 +1,103 @@
|
||||
From: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com>
|
||||
Date: Tue, 12 Jan 2016 14:30:19 +0530
|
||||
Subject: [PATCH] mac80211: Requeue work after scan complete for all VIF
|
||||
types.
|
||||
|
||||
During a sw scan ieee80211_iface_work ignores work items for all vifs.
|
||||
However after the scan complete work is requeued only for STA, ADHOC
|
||||
and MESH iftypes.
|
||||
|
||||
This occasionally results in event processing getting delayed/not
|
||||
processed for iftype AP when it coexists with a STA. This can result
|
||||
in data halt and eventually disconnection on the AP interface.
|
||||
|
||||
Signed-off-by: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com>
|
||||
Cc: linux-wireless@vger.kernel.org
|
||||
Cc: johannes@sipsolutions.net
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ibss.c
|
||||
+++ b/net/mac80211/ibss.c
|
||||
@@ -1731,7 +1731,6 @@ void ieee80211_ibss_notify_scan_complete
|
||||
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
continue;
|
||||
sdata->u.ibss.last_scan_completed = jiffies;
|
||||
- ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
--- a/net/mac80211/mesh.c
|
||||
+++ b/net/mac80211/mesh.c
|
||||
@@ -1369,17 +1369,6 @@ out:
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
-void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
|
||||
-{
|
||||
- struct ieee80211_sub_if_data *sdata;
|
||||
-
|
||||
- rcu_read_lock();
|
||||
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
- if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
- ieee80211_sdata_running(sdata))
|
||||
- ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
- rcu_read_unlock();
|
||||
-}
|
||||
|
||||
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
--- a/net/mac80211/mesh.h
|
||||
+++ b/net/mac80211/mesh.h
|
||||
@@ -362,14 +362,10 @@ static inline bool mesh_path_sel_is_hwmp
|
||||
return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
|
||||
}
|
||||
|
||||
-void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
|
||||
-
|
||||
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211s_stop(void);
|
||||
#else
|
||||
-static inline void
|
||||
-ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
|
||||
static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
|
||||
{ return false; }
|
||||
static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -3978,8 +3978,6 @@ static void ieee80211_restart_sta_timer(
|
||||
if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&sdata->u.mgd.monitor_work);
|
||||
- /* and do all the other regular work too */
|
||||
- ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/net/mac80211/scan.c
|
||||
+++ b/net/mac80211/scan.c
|
||||
@@ -314,6 +314,7 @@ static void __ieee80211_scan_completed(s
|
||||
bool was_scanning = local->scanning;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
+ struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
@@ -373,7 +374,15 @@ static void __ieee80211_scan_completed(s
|
||||
|
||||
ieee80211_mlme_notify_scan_completed(local);
|
||||
ieee80211_ibss_notify_scan_completed(local);
|
||||
- ieee80211_mesh_notify_scan_completed(local);
|
||||
+
|
||||
+ /* Requeue all the work that might have been ignored while
|
||||
+ * the scan was in progress
|
||||
+ */
|
||||
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
+ if (ieee80211_sdata_running(sdata))
|
||||
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
+ }
|
||||
+
|
||||
if (was_scanning)
|
||||
ieee80211_start_next_roc(local);
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri, 20 Mar 2015 16:24:23 +0100
|
||||
Subject: [PATCH] mac80211: mesh: avoid pointless station lookup
|
||||
|
||||
In ieee80211_build_hdr(), the station is looked up to build the
|
||||
header correctly (QoS field) and to check for authorization. For
|
||||
mesh, authorization isn't checked here, and QoS capability is
|
||||
mandatory, so the station lookup can be avoided.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -2130,12 +2130,14 @@ static struct sk_buff *ieee80211_build_h
|
||||
}
|
||||
|
||||
/*
|
||||
- * There's no need to try to look up the destination
|
||||
- * if it is a multicast address (which can only happen
|
||||
- * in AP mode)
|
||||
+ * There's no need to try to look up the destination station
|
||||
+ * if it is a multicast address. In mesh, there's no need to
|
||||
+ * look up the station at all as it always must be QoS capable
|
||||
+ * and mesh mode checks authorization later.
|
||||
*/
|
||||
multicast = is_multicast_ether_addr(hdr.addr1);
|
||||
- if (!multicast && !have_station) {
|
||||
+ if (!multicast && !have_station &&
|
||||
+ !ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
sta = sta_info_get(sdata, hdr.addr1);
|
||||
if (sta) {
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
@ -1,267 +0,0 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri, 20 Mar 2015 14:18:27 +0100
|
||||
Subject: [PATCH] mac80211: avoid duplicate TX path station lookup
|
||||
|
||||
Instead of looking up the destination station twice in the TX path
|
||||
(first to build the header, and then for control processing), save
|
||||
it when building the header and use it later in the TX path.
|
||||
|
||||
To avoid having to look up the station in the many callers, allow
|
||||
those to pass %NULL which keeps the existing lookup.
|
||||
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -3565,7 +3565,7 @@ static int ieee80211_probe_client(struct
|
||||
nullfunc->qos_ctrl = cpu_to_le16(7);
|
||||
|
||||
local_bh_disable();
|
||||
- ieee80211_xmit(sdata, skb);
|
||||
+ ieee80211_xmit(sdata, sta, skb);
|
||||
local_bh_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1775,7 +1775,8 @@ void mac80211_ev_michael_mic_failure(str
|
||||
gfp_t gfp);
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
bool bss_notify);
|
||||
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
|
||||
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
+ struct sta_info *sta, struct sk_buff *skb);
|
||||
|
||||
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid,
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -1279,7 +1279,7 @@ static void ieee80211_send_null_response
|
||||
}
|
||||
|
||||
info->band = chanctx_conf->def.chan->band;
|
||||
- ieee80211_xmit(sdata, skb);
|
||||
+ ieee80211_xmit(sdata, sta, skb);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1110,11 +1110,13 @@ static bool ieee80211_tx_prep_agg(struct
|
||||
|
||||
/*
|
||||
* initialises @tx
|
||||
+ * pass %NULL for the station if unknown, a valid pointer if known
|
||||
+ * or an ERR_PTR() if the station is known not to exist
|
||||
*/
|
||||
static ieee80211_tx_result
|
||||
ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_tx_data *tx,
|
||||
- struct sk_buff *skb)
|
||||
+ struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_hdr *hdr;
|
||||
@@ -1137,17 +1139,22 @@ ieee80211_tx_prepare(struct ieee80211_su
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
|
||||
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||
- tx->sta = rcu_dereference(sdata->u.vlan.sta);
|
||||
- if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
|
||||
- return TX_DROP;
|
||||
- } else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
|
||||
- IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
|
||||
- tx->sdata->control_port_protocol == tx->skb->protocol) {
|
||||
- tx->sta = sta_info_get_bss(sdata, hdr->addr1);
|
||||
+ if (likely(sta)) {
|
||||
+ if (!IS_ERR(sta))
|
||||
+ tx->sta = sta;
|
||||
+ } else {
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||
+ tx->sta = rcu_dereference(sdata->u.vlan.sta);
|
||||
+ if (!tx->sta && sdata->wdev.use_4addr)
|
||||
+ return TX_DROP;
|
||||
+ } else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
|
||||
+ IEEE80211_TX_CTL_INJECTED) ||
|
||||
+ tx->sdata->control_port_protocol == tx->skb->protocol) {
|
||||
+ tx->sta = sta_info_get_bss(sdata, hdr->addr1);
|
||||
+ }
|
||||
+ if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
|
||||
+ tx->sta = sta_info_get(sdata, hdr->addr1);
|
||||
}
|
||||
- if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
|
||||
- tx->sta = sta_info_get(sdata, hdr->addr1);
|
||||
|
||||
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
|
||||
!ieee80211_is_qos_nullfunc(hdr->frame_control) &&
|
||||
@@ -1485,7 +1492,7 @@ bool ieee80211_tx_prepare_skb(struct iee
|
||||
struct ieee80211_tx_data tx;
|
||||
struct sk_buff *skb2;
|
||||
|
||||
- if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP)
|
||||
+ if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
|
||||
return false;
|
||||
|
||||
info->band = band;
|
||||
@@ -1518,7 +1525,8 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
|
||||
* Returns false if the frame couldn't be transmitted but was queued instead.
|
||||
*/
|
||||
static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||
- struct sk_buff *skb, bool txpending)
|
||||
+ struct sta_info *sta, struct sk_buff *skb,
|
||||
+ bool txpending)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_data tx;
|
||||
@@ -1534,7 +1542,7 @@ static bool ieee80211_tx(struct ieee8021
|
||||
|
||||
/* initialises tx */
|
||||
led_len = skb->len;
|
||||
- res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
|
||||
+ res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
|
||||
|
||||
if (unlikely(res_prepare == TX_DROP)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
@@ -1590,7 +1598,8 @@ static int ieee80211_skb_resize(struct i
|
||||
return 0;
|
||||
}
|
||||
|
||||
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
+ struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
@@ -1625,7 +1634,7 @@ void ieee80211_xmit(struct ieee80211_sub
|
||||
}
|
||||
|
||||
ieee80211_set_qos_hdr(sdata, skb);
|
||||
- ieee80211_tx(sdata, skb, false);
|
||||
+ ieee80211_tx(sdata, sta, skb, false);
|
||||
}
|
||||
|
||||
static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
|
||||
@@ -1846,7 +1855,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
goto fail_rcu;
|
||||
|
||||
info->band = chandef->chan->band;
|
||||
- ieee80211_xmit(sdata, skb);
|
||||
+ ieee80211_xmit(sdata, NULL, skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
@@ -1877,7 +1886,8 @@ fail:
|
||||
* Returns: the (possibly reallocated) skb or an ERR_PTR() code
|
||||
*/
|
||||
static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
- struct sk_buff *skb, u32 info_flags)
|
||||
+ struct sk_buff *skb, u32 info_flags,
|
||||
+ struct sta_info **sta_out)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info;
|
||||
@@ -1920,6 +1930,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
have_station = true;
|
||||
+ *sta_out = sta;
|
||||
} else if (sdata->wdev.use_4addr) {
|
||||
ret = -ENOLINK;
|
||||
goto free;
|
||||
@@ -2073,6 +2084,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
have_station = true;
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
+ *sta_out = sta;
|
||||
} else if (sdata->u.mgd.use_4addr &&
|
||||
cpu_to_be16(ethertype) != sdata->control_port_protocol) {
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
|
||||
@@ -2136,13 +2148,18 @@ static struct sk_buff *ieee80211_build_h
|
||||
* and mesh mode checks authorization later.
|
||||
*/
|
||||
multicast = is_multicast_ether_addr(hdr.addr1);
|
||||
- if (!multicast && !have_station &&
|
||||
- !ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
- sta = sta_info_get(sdata, hdr.addr1);
|
||||
+ if (multicast) {
|
||||
+ *sta_out = ERR_PTR(-ENOENT);
|
||||
+ } else if (!have_station && !ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
+ if (sdata->control_port_protocol == skb->protocol)
|
||||
+ sta = sta_info_get_bss(sdata, hdr.addr1);
|
||||
+ else
|
||||
+ sta = sta_info_get(sdata, hdr.addr1);
|
||||
if (sta) {
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
}
|
||||
+ *sta_out = sta ?: ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
/* For mesh, the use of the QoS header is mandatory */
|
||||
@@ -2320,6 +2337,7 @@ void __ieee80211_subif_start_xmit(struct
|
||||
u32 info_flags)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
+ struct sta_info *sta = NULL;
|
||||
|
||||
if (unlikely(skb->len < ETH_HLEN)) {
|
||||
kfree_skb(skb);
|
||||
@@ -2328,7 +2346,7 @@ void __ieee80211_subif_start_xmit(struct
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
- skb = ieee80211_build_hdr(sdata, skb, info_flags);
|
||||
+ skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
@@ -2336,7 +2354,7 @@ void __ieee80211_subif_start_xmit(struct
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
- ieee80211_xmit(sdata, skb);
|
||||
+ ieee80211_xmit(sdata, sta, skb);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
@@ -2364,10 +2382,11 @@ ieee80211_build_data_template(struct iee
|
||||
.local = sdata->local,
|
||||
.sdata = sdata,
|
||||
};
|
||||
+ struct sta_info *sta_ignore;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
- skb = ieee80211_build_hdr(sdata, skb, info_flags);
|
||||
+ skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta_ignore);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
@@ -2425,7 +2444,7 @@ static bool ieee80211_tx_pending_skb(str
|
||||
return true;
|
||||
}
|
||||
info->band = chanctx_conf->def.chan->band;
|
||||
- result = ieee80211_tx(sdata, skb, true);
|
||||
+ result = ieee80211_tx(sdata, NULL, skb, true);
|
||||
} else {
|
||||
struct sk_buff_head skbs;
|
||||
|
||||
@@ -3163,7 +3182,7 @@ ieee80211_get_buffered_bc(struct ieee802
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
|
||||
- if (!ieee80211_tx_prepare(sdata, &tx, skb))
|
||||
+ if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
|
||||
break;
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
@@ -3295,6 +3314,6 @@ void __ieee80211_tx_skb_tid_band(struct
|
||||
*/
|
||||
local_bh_disable();
|
||||
IEEE80211_SKB_CB(skb)->band = band;
|
||||
- ieee80211_xmit(sdata, skb);
|
||||
+ ieee80211_xmit(sdata, NULL, skb);
|
||||
local_bh_enable();
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
From: Sara Sharon <sara.sharon@intel.com>
|
||||
Date: Mon, 25 Jan 2016 15:46:35 +0200
|
||||
Subject: [PATCH] mac80211: fix ibss scan parameters
|
||||
|
||||
When joining IBSS a full scan should be initiated in order to search
|
||||
for existing cell, unless the fixed_channel parameter was set.
|
||||
A default channel to create the IBSS on if no cell was found is
|
||||
provided as well.
|
||||
However - a scan is initiated only on the default channel provided
|
||||
regardless of whether ifibss->fixed_channel is set or not, with the
|
||||
obvious result of the cell not joining existing IBSS cell that is
|
||||
on another channel.
|
||||
|
||||
Fixes: 76bed0f43b27 ("mac80211: IBSS fix scan request")
|
||||
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
|
||||
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ibss.c
|
||||
+++ b/net/mac80211/ibss.c
|
||||
@@ -7,6 +7,7 @@
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
+ * Copyright(c) 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
@@ -1483,14 +1484,21 @@ static void ieee80211_sta_find_ibss(stru
|
||||
|
||||
sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
|
||||
|
||||
- num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
|
||||
- &ifibss->chandef,
|
||||
- channels,
|
||||
- ARRAY_SIZE(channels));
|
||||
scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
|
||||
- ieee80211_request_ibss_scan(sdata, ifibss->ssid,
|
||||
- ifibss->ssid_len, channels, num,
|
||||
- scan_width);
|
||||
+
|
||||
+ if (ifibss->fixed_channel) {
|
||||
+ num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
|
||||
+ &ifibss->chandef,
|
||||
+ channels,
|
||||
+ ARRAY_SIZE(channels));
|
||||
+ ieee80211_request_ibss_scan(sdata, ifibss->ssid,
|
||||
+ ifibss->ssid_len, channels,
|
||||
+ num, scan_width);
|
||||
+ } else {
|
||||
+ ieee80211_request_ibss_scan(sdata, ifibss->ssid,
|
||||
+ ifibss->ssid_len, NULL,
|
||||
+ 0, scan_width);
|
||||
+ }
|
||||
} else {
|
||||
int interval = IEEE80211_SCAN_INTERVAL;
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
From: John Linville <linville@tuxdriver.com>
|
||||
Date: Tue, 31 Mar 2015 10:49:14 -0400
|
||||
Subject: [PATCH] mac80211: reduce log spam from ieee80211_handle_pwr_constr
|
||||
|
||||
This changes a couple of messages from sdata_info to sdata_dbg.
|
||||
This should reduce some log spam, as reported here:
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1206468
|
||||
|
||||
Signed-off-by: John W. Linville <linville@tuxdriver.com>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -1347,15 +1347,15 @@ static u32 ieee80211_handle_pwr_constr(s
|
||||
*/
|
||||
if (has_80211h_pwr &&
|
||||
(!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
|
||||
- sdata_info(sdata,
|
||||
- "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
|
||||
- pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
|
||||
- sdata->u.mgd.bssid);
|
||||
+ sdata_dbg(sdata,
|
||||
+ "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
|
||||
+ pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
|
||||
+ sdata->u.mgd.bssid);
|
||||
new_ap_level = pwr_level_80211h;
|
||||
} else { /* has_cisco_pwr is always true here. */
|
||||
- sdata_info(sdata,
|
||||
- "Limiting TX power to %d dBm as advertised by %pM\n",
|
||||
- pwr_level_cisco, sdata->u.mgd.bssid);
|
||||
+ sdata_dbg(sdata,
|
||||
+ "Limiting TX power to %d dBm as advertised by %pM\n",
|
||||
+ pwr_level_cisco, sdata->u.mgd.bssid);
|
||||
new_ap_level = pwr_level_cisco;
|
||||
}
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
From: Chris Bainbridge <chris.bainbridge@gmail.com>
|
||||
Date: Wed, 27 Jan 2016 15:46:18 +0000
|
||||
Subject: [PATCH] net/mac80211/agg-rx.c: fix use of uninitialised values
|
||||
|
||||
Use kzalloc instead of kmalloc for struct tid_ampdu_rx. Fixes:
|
||||
|
||||
[ 7.976605] UBSAN: Undefined behaviour in net/mac80211/rx.c:932:29
|
||||
[ 7.976608] load of value 2 is not a valid value for type '_Bool'
|
||||
[ 7.976611] CPU: 3 PID: 1134 Comm: kworker/u16:7 Not tainted 4.5.0-rc1+ #265
|
||||
[ 7.976613] Hardware name: Apple Inc. MacBookPro10,2/Mac-AFD8A9D944EA4843, BIOS MBP102.88Z.0106.B0A.1509130955 09/13/2015
|
||||
[ 7.976616] Workqueue: phy0 rt2x00usb_work_rxdone
|
||||
[ 7.976619] 0000000000000004 ffff880254a7ba50 ffffffff8181d866 0000000000000007
|
||||
[ 7.976622] ffff880254a7ba78 ffff880254a7ba68 ffffffff8188422d ffffffff8379b500
|
||||
[ 7.976626] ffff880254a7bab8 ffffffff81884747 0000000000000202 0000000348620032
|
||||
[ 7.976629] Call Trace:
|
||||
[ 7.976633] [<ffffffff8181d866>] dump_stack+0x45/0x5f
|
||||
[ 7.976637] [<ffffffff8188422d>] ubsan_epilogue+0xd/0x40
|
||||
[ 7.976642] [<ffffffff81884747>] __ubsan_handle_load_invalid_value+0x67/0x70
|
||||
[ 7.976646] [<ffffffff82227b4d>] ieee80211_sta_reorder_release.isra.16+0x5ed/0x730
|
||||
[ 7.976650] [<ffffffff8222ca14>] ieee80211_prepare_and_rx_handle+0xd04/0x1c00
|
||||
[ 7.976654] [<ffffffff81cb27ce>] ? usb_hcd_map_urb_for_dma+0x65e/0x960
|
||||
[ 7.976659] [<ffffffff8222db03>] __ieee80211_rx_handle_packet+0x1f3/0x750
|
||||
[ 7.976663] [<ffffffff8222e4a7>] ieee80211_rx_napi+0x447/0x990
|
||||
[ 7.976667] [<ffffffff81c5fb85>] rt2x00lib_rxdone+0x305/0xbd0
|
||||
[ 7.976670] [<ffffffff811ac23f>] ? dequeue_task_fair+0x64f/0x1de0
|
||||
[ 7.976674] [<ffffffff811a1516>] ? sched_clock_cpu+0xe6/0x150
|
||||
[ 7.976678] [<ffffffff81c6c45c>] rt2x00usb_work_rxdone+0x7c/0x140
|
||||
[ 7.976682] [<ffffffff8117aef6>] process_one_work+0x226/0x860
|
||||
[ 7.976686] [<ffffffff8117b58c>] worker_thread+0x5c/0x680
|
||||
[ 7.976690] [<ffffffff8117b530>] ? process_one_work+0x860/0x860
|
||||
[ 7.976693] [<ffffffff81184f86>] kthread+0xf6/0x150
|
||||
[ 7.976697] [<ffffffff81184e90>] ? kthread_worker_fn+0x310/0x310
|
||||
[ 7.976700] [<ffffffff822a94df>] ret_from_fork+0x3f/0x70
|
||||
[ 7.976703] [<ffffffff81184e90>] ? kthread_worker_fn+0x310/0x310
|
||||
|
||||
Link: https://lkml.org/lkml/2016/1/26/230
|
||||
Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/agg-rx.c
|
||||
+++ b/net/mac80211/agg-rx.c
|
||||
@@ -327,7 +327,7 @@ void __ieee80211_start_rx_ba_session(str
|
||||
}
|
||||
|
||||
/* prepare A-MPDU MLME for Rx aggregation */
|
||||
- tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
|
||||
+ tid_agg_rx = kzalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
|
||||
if (!tid_agg_rx)
|
||||
goto end;
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Fri, 6 Mar 2015 18:40:41 +0100
|
||||
Subject: [PATCH] brcmfmac: Fix race condition in msgbuf ioctl processing.
|
||||
|
||||
Msgbuf is using a wait_event_timeout to wait for the response on
|
||||
an ioctl. The wakeup routine uses waitqueue_active to see if
|
||||
wait_event_timeout has been called. There is a chance that the
|
||||
response arrives before wait_event_timeout is called, this
|
||||
will result in situation that wait_event_timeout never gets
|
||||
woken again and assumed result will be a timeout. This patch
|
||||
removes that errornous situation by always setting the
|
||||
ctl_completed var before checking for queue active.
|
||||
|
||||
Reviewed-by: Arend Van Spriel <arend@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>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
@@ -481,10 +481,9 @@ static int brcmf_msgbuf_ioctl_resp_wait(
|
||||
|
||||
static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf)
|
||||
{
|
||||
- if (waitqueue_active(&msgbuf->ioctl_resp_wait)) {
|
||||
- msgbuf->ctl_completed = true;
|
||||
+ msgbuf->ctl_completed = true;
|
||||
+ if (waitqueue_active(&msgbuf->ioctl_resp_wait))
|
||||
wake_up(&msgbuf->ioctl_resp_wait);
|
||||
- }
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
From: Konstantin Khlebnikov <koct9i@gmail.com>
|
||||
Date: Fri, 29 Jan 2016 11:35:12 +0300
|
||||
Subject: [PATCH] mac80211: minstrel_ht: fix out-of-bound in
|
||||
minstrel_ht_set_best_prob_rate
|
||||
|
||||
Patch fixes this splat
|
||||
|
||||
BUG: KASAN: slab-out-of-bounds in minstrel_ht_update_stats.isra.7+0x6e1/0x9e0
|
||||
[mac80211] at addr ffff8800cee640f4 Read of size 4 by task swapper/3/0
|
||||
|
||||
Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com>
|
||||
Link: http://lkml.kernel.org/r/CALYGNiNyJhSaVnE35qS6UCGaSb2Dx1_i5HcRavuOX14oTz2P+w@mail.gmail.com
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -414,15 +414,16 @@ minstrel_ht_set_best_prob_rate(struct mi
|
||||
(max_tp_group != MINSTREL_CCK_GROUP))
|
||||
return;
|
||||
|
||||
+ max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
|
||||
+ max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
|
||||
+ max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
|
||||
+
|
||||
if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
|
||||
cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
|
||||
mrs->prob_ewma);
|
||||
if (cur_tp_avg > tmp_tp_avg)
|
||||
mi->max_prob_rate = index;
|
||||
|
||||
- max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
|
||||
- max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
|
||||
- max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
|
||||
max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
|
||||
max_gpr_idx,
|
||||
max_gpr_prob);
|
||||
@@ -431,7 +432,7 @@ minstrel_ht_set_best_prob_rate(struct mi
|
||||
} else {
|
||||
if (mrs->prob_ewma > tmp_prob)
|
||||
mi->max_prob_rate = index;
|
||||
- if (mrs->prob_ewma > mg->rates[mg->max_group_prob_rate].prob_ewma)
|
||||
+ if (mrs->prob_ewma > max_gpr_prob)
|
||||
mg->max_group_prob_rate = index;
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:23 +0100
|
||||
Subject: [PATCH] brcmfmac: Update msgbuf commonring size for improved
|
||||
throughput.
|
||||
|
||||
Reviewed-by: Arend Van Spriel <arend@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>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
#ifdef CPTCFG_BRCMFMAC_PROTO_MSGBUF
|
||||
|
||||
-#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 20
|
||||
-#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 256
|
||||
-#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 20
|
||||
+#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 64
|
||||
+#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 512
|
||||
+#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 64
|
||||
#define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024
|
||||
-#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 256
|
||||
+#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 512
|
||||
#define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512
|
||||
|
||||
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40
|
||||
@ -0,0 +1,35 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Tue, 2 Feb 2016 14:39:08 +0100
|
||||
Subject: [PATCH] mac80211: move A-MSDU skb_linearize call to
|
||||
ieee80211_amsdu_to_8023s
|
||||
|
||||
Prepararation for zero-copy A-MSDU support with page fragment SKBs
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -2203,9 +2203,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
|
||||
skb->dev = dev;
|
||||
__skb_queue_head_init(&frame_list);
|
||||
|
||||
- if (skb_linearize(skb))
|
||||
- return RX_DROP_UNUSABLE;
|
||||
-
|
||||
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
||||
rx->sdata->vif.type,
|
||||
rx->local->hw.extra_tx_headroom, true);
|
||||
--- a/net/wireless/util.c
|
||||
+++ b/net/wireless/util.c
|
||||
@@ -657,6 +657,9 @@ void ieee80211_amsdu_to_8023s(struct sk_
|
||||
int remaining, err;
|
||||
u8 dst[ETH_ALEN], src[ETH_ALEN];
|
||||
|
||||
+ if (skb_linearize(skb))
|
||||
+ goto out;
|
||||
+
|
||||
if (has_80211_header) {
|
||||
err = ieee80211_data_to_8023(skb, addr, iftype);
|
||||
if (err)
|
||||
@ -1,307 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:46 +0100
|
||||
Subject: [PATCH] ath9k_htc: add new WMI_REG_RMW_CMDID command
|
||||
|
||||
Since usb bus add extra delay on each request, a command
|
||||
with read + write requests is too expensive. We can dramtically
|
||||
reduce usb load by moving this command to firmware.
|
||||
|
||||
In my tests, this patch will reduce channel scan time
|
||||
for about 5-10 seconds.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath.h
|
||||
+++ b/drivers/net/wireless/ath/ath.h
|
||||
@@ -131,6 +131,9 @@ struct ath_ops {
|
||||
void (*enable_write_buffer)(void *);
|
||||
void (*write_flush) (void *);
|
||||
u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr);
|
||||
+ void (*enable_rmw_buffer)(void *);
|
||||
+ void (*rmw_flush) (void *);
|
||||
+
|
||||
};
|
||||
|
||||
struct ath_common;
|
||||
--- a/drivers/net/wireless/ath/ath9k/htc.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/htc.h
|
||||
@@ -444,6 +444,10 @@ static inline void ath9k_htc_stop_btcoex
|
||||
#define OP_BT_SCAN BIT(4)
|
||||
#define OP_TSF_RESET BIT(6)
|
||||
|
||||
+enum htc_op_flags {
|
||||
+ HTC_FWFLAG_NO_RMW,
|
||||
+};
|
||||
+
|
||||
struct ath9k_htc_priv {
|
||||
struct device *dev;
|
||||
struct ieee80211_hw *hw;
|
||||
@@ -482,6 +486,7 @@ struct ath9k_htc_priv {
|
||||
bool reconfig_beacon;
|
||||
unsigned int rxfilter;
|
||||
unsigned long op_flags;
|
||||
+ unsigned long fw_flags;
|
||||
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
struct ath_spec_scan_priv spec_priv;
|
||||
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
|
||||
@@ -376,17 +376,139 @@ static void ath9k_regwrite_flush(void *h
|
||||
mutex_unlock(&priv->wmi->multi_write_mutex);
|
||||
}
|
||||
|
||||
-static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
|
||||
+static void ath9k_reg_rmw_buffer(void *hw_priv,
|
||||
+ u32 reg_offset, u32 set, u32 clr)
|
||||
+{
|
||||
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
+ u32 rsp_status;
|
||||
+ int r;
|
||||
+
|
||||
+ mutex_lock(&priv->wmi->multi_rmw_mutex);
|
||||
+
|
||||
+ /* Store the register/value */
|
||||
+ priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].reg =
|
||||
+ cpu_to_be32(reg_offset);
|
||||
+ priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].set =
|
||||
+ cpu_to_be32(set);
|
||||
+ priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].clr =
|
||||
+ cpu_to_be32(clr);
|
||||
+
|
||||
+ priv->wmi->multi_rmw_idx++;
|
||||
+
|
||||
+ /* If the buffer is full, send it out. */
|
||||
+ if (priv->wmi->multi_rmw_idx == MAX_RMW_CMD_NUMBER) {
|
||||
+ r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
|
||||
+ (u8 *) &priv->wmi->multi_rmw,
|
||||
+ sizeof(struct register_write) * priv->wmi->multi_rmw_idx,
|
||||
+ (u8 *) &rsp_status, sizeof(rsp_status),
|
||||
+ 100);
|
||||
+ if (unlikely(r)) {
|
||||
+ ath_dbg(common, WMI,
|
||||
+ "REGISTER RMW FAILED, multi len: %d\n",
|
||||
+ priv->wmi->multi_rmw_idx);
|
||||
+ }
|
||||
+ priv->wmi->multi_rmw_idx = 0;
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&priv->wmi->multi_rmw_mutex);
|
||||
+}
|
||||
+
|
||||
+static void ath9k_reg_rmw_flush(void *hw_priv)
|
||||
{
|
||||
- u32 val;
|
||||
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
+ u32 rsp_status;
|
||||
+ int r;
|
||||
+
|
||||
+ if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
|
||||
+ return;
|
||||
+
|
||||
+ atomic_dec(&priv->wmi->m_rmw_cnt);
|
||||
+
|
||||
+ mutex_lock(&priv->wmi->multi_rmw_mutex);
|
||||
+
|
||||
+ if (priv->wmi->multi_rmw_idx) {
|
||||
+ r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
|
||||
+ (u8 *) &priv->wmi->multi_rmw,
|
||||
+ sizeof(struct register_rmw) * priv->wmi->multi_rmw_idx,
|
||||
+ (u8 *) &rsp_status, sizeof(rsp_status),
|
||||
+ 100);
|
||||
+ if (unlikely(r)) {
|
||||
+ ath_dbg(common, WMI,
|
||||
+ "REGISTER RMW FAILED, multi len: %d\n",
|
||||
+ priv->wmi->multi_rmw_idx);
|
||||
+ }
|
||||
+ priv->wmi->multi_rmw_idx = 0;
|
||||
+ }
|
||||
|
||||
- val = ath9k_regread(hw_priv, reg_offset);
|
||||
- val &= ~clr;
|
||||
- val |= set;
|
||||
- ath9k_regwrite(hw_priv, val, reg_offset);
|
||||
+ mutex_unlock(&priv->wmi->multi_rmw_mutex);
|
||||
+}
|
||||
+
|
||||
+static void ath9k_enable_rmw_buffer(void *hw_priv)
|
||||
+{
|
||||
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
+
|
||||
+ if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
|
||||
+ return;
|
||||
+
|
||||
+ atomic_inc(&priv->wmi->m_rmw_cnt);
|
||||
+}
|
||||
+
|
||||
+static u32 ath9k_reg_rmw_single(void *hw_priv,
|
||||
+ u32 reg_offset, u32 set, u32 clr)
|
||||
+{
|
||||
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
+ struct register_rmw buf, buf_ret;
|
||||
+ int ret;
|
||||
+ u32 val = 0;
|
||||
+
|
||||
+ buf.reg = cpu_to_be32(reg_offset);
|
||||
+ buf.set = cpu_to_be32(set);
|
||||
+ buf.clr = cpu_to_be32(clr);
|
||||
+
|
||||
+ ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
|
||||
+ (u8 *) &buf, sizeof(buf),
|
||||
+ (u8 *) &buf_ret, sizeof(buf_ret),
|
||||
+ 100);
|
||||
+ if (unlikely(ret)) {
|
||||
+ ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n",
|
||||
+ reg_offset, ret);
|
||||
+ }
|
||||
return val;
|
||||
}
|
||||
|
||||
+static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
|
||||
+{
|
||||
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
+
|
||||
+ if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) {
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = REG_READ(ah, reg_offset);
|
||||
+ val &= ~clr;
|
||||
+ val |= set;
|
||||
+ REG_WRITE(ah, reg_offset, val);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (atomic_read(&priv->wmi->m_rmw_cnt))
|
||||
+ ath9k_reg_rmw_buffer(hw_priv, reg_offset, set, clr);
|
||||
+ else
|
||||
+ ath9k_reg_rmw_single(hw_priv, reg_offset, set, clr);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
|
||||
{
|
||||
*csz = L1_CACHE_BYTES >> 2;
|
||||
@@ -501,6 +623,8 @@ static int ath9k_init_priv(struct ath9k_
|
||||
ah->reg_ops.write = ath9k_regwrite;
|
||||
ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
|
||||
ah->reg_ops.write_flush = ath9k_regwrite_flush;
|
||||
+ ah->reg_ops.enable_rmw_buffer = ath9k_enable_rmw_buffer;
|
||||
+ ah->reg_ops.rmw_flush = ath9k_reg_rmw_flush;
|
||||
ah->reg_ops.rmw = ath9k_reg_rmw;
|
||||
priv->ah = ah;
|
||||
|
||||
@@ -686,6 +810,12 @@ static int ath9k_init_firmware_version(s
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ if (priv->fw_version_major == 1 && priv->fw_version_minor < 4)
|
||||
+ set_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags);
|
||||
+
|
||||
+ dev_info(priv->dev, "FW RMW support: %s\n",
|
||||
+ test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags) ? "Off" : "On");
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||
@@ -100,6 +100,18 @@
|
||||
(_ah)->reg_ops.write_flush((_ah)); \
|
||||
} while (0)
|
||||
|
||||
+#define ENABLE_REG_RMW_BUFFER(_ah) \
|
||||
+ do { \
|
||||
+ if ((_ah)->reg_ops.enable_rmw_buffer) \
|
||||
+ (_ah)->reg_ops.enable_rmw_buffer((_ah)); \
|
||||
+ } while (0)
|
||||
+
|
||||
+#define REG_RMW_BUFFER_FLUSH(_ah) \
|
||||
+ do { \
|
||||
+ if ((_ah)->reg_ops.rmw_flush) \
|
||||
+ (_ah)->reg_ops.rmw_flush((_ah)); \
|
||||
+ } while (0)
|
||||
+
|
||||
#define PR_EEP(_s, _val) \
|
||||
do { \
|
||||
len += scnprintf(buf + len, size - len, "%20s : %10d\n",\
|
||||
--- a/drivers/net/wireless/ath/ath9k/wmi.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
|
||||
@@ -61,6 +61,8 @@ static const char *wmi_cmd_to_name(enum
|
||||
return "WMI_REG_READ_CMDID";
|
||||
case WMI_REG_WRITE_CMDID:
|
||||
return "WMI_REG_WRITE_CMDID";
|
||||
+ case WMI_REG_RMW_CMDID:
|
||||
+ return "WMI_REG_RMW_CMDID";
|
||||
case WMI_RC_STATE_CHANGE_CMDID:
|
||||
return "WMI_RC_STATE_CHANGE_CMDID";
|
||||
case WMI_RC_RATE_UPDATE_CMDID:
|
||||
@@ -101,6 +103,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_
|
||||
spin_lock_init(&wmi->event_lock);
|
||||
mutex_init(&wmi->op_mutex);
|
||||
mutex_init(&wmi->multi_write_mutex);
|
||||
+ mutex_init(&wmi->multi_rmw_mutex);
|
||||
init_completion(&wmi->cmd_wait);
|
||||
INIT_LIST_HEAD(&wmi->pending_tx_events);
|
||||
tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
|
||||
--- a/drivers/net/wireless/ath/ath9k/wmi.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
|
||||
@@ -112,6 +112,7 @@ enum wmi_cmd_id {
|
||||
WMI_TX_STATS_CMDID,
|
||||
WMI_RX_STATS_CMDID,
|
||||
WMI_BITRATE_MASK_CMDID,
|
||||
+ WMI_REG_RMW_CMDID,
|
||||
};
|
||||
|
||||
enum wmi_event_id {
|
||||
@@ -125,12 +126,19 @@ enum wmi_event_id {
|
||||
};
|
||||
|
||||
#define MAX_CMD_NUMBER 62
|
||||
+#define MAX_RMW_CMD_NUMBER 15
|
||||
|
||||
struct register_write {
|
||||
__be32 reg;
|
||||
__be32 val;
|
||||
};
|
||||
|
||||
+struct register_rmw {
|
||||
+ __be32 reg;
|
||||
+ __be32 set;
|
||||
+ __be32 clr;
|
||||
+} __packed;
|
||||
+
|
||||
struct ath9k_htc_tx_event {
|
||||
int count;
|
||||
struct __wmi_event_txstatus txs;
|
||||
@@ -156,10 +164,18 @@ struct wmi {
|
||||
|
||||
spinlock_t wmi_lock;
|
||||
|
||||
+ /* multi write section */
|
||||
atomic_t mwrite_cnt;
|
||||
struct register_write multi_write[MAX_CMD_NUMBER];
|
||||
u32 multi_write_idx;
|
||||
struct mutex multi_write_mutex;
|
||||
+
|
||||
+ /* multi rmw section */
|
||||
+ atomic_t m_rmw_cnt;
|
||||
+ struct register_rmw multi_rmw[MAX_RMW_CMD_NUMBER];
|
||||
+ u32 multi_rmw_idx;
|
||||
+ struct mutex multi_rmw_mutex;
|
||||
+
|
||||
};
|
||||
|
||||
struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
|
||||
@ -0,0 +1,186 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Tue, 2 Feb 2016 14:39:09 +0100
|
||||
Subject: [PATCH] cfg80211: add function for 802.3 conversion with separate
|
||||
output buffer
|
||||
|
||||
Use skb_copy_bits in preparation for allowing fragmented skbs
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/util.c
|
||||
+++ b/net/wireless/util.c
|
||||
@@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_s
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
|
||||
|
||||
-unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||||
+static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags)
|
||||
{
|
||||
- int ae = meshhdr->flags & MESH_FLAGS_AE;
|
||||
+ int ae = flags & MESH_FLAGS_AE;
|
||||
/* 802.11-2012, 8.2.4.7.3 */
|
||||
switch (ae) {
|
||||
default:
|
||||
@@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(s
|
||||
return 18;
|
||||
}
|
||||
}
|
||||
+
|
||||
+unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||||
+{
|
||||
+ return __ieee80211_get_mesh_hdrlen(meshhdr->flags);
|
||||
+}
|
||||
EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
|
||||
|
||||
-int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
- enum nl80211_iftype iftype)
|
||||
+static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
+ const u8 *addr, enum nl80211_iftype iftype)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
- u16 hdrlen, ethertype;
|
||||
- u8 *payload;
|
||||
- u8 dst[ETH_ALEN];
|
||||
- u8 src[ETH_ALEN] __aligned(2);
|
||||
+ struct {
|
||||
+ u8 hdr[ETH_ALEN] __aligned(2);
|
||||
+ __be16 proto;
|
||||
+ } payload;
|
||||
+ struct ethhdr tmp;
|
||||
+ u16 hdrlen;
|
||||
+ u8 mesh_flags = 0;
|
||||
|
||||
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
|
||||
return -1;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ if (skb->len < hdrlen + 8)
|
||||
+ return -1;
|
||||
|
||||
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
|
||||
* header
|
||||
@@ -432,8 +442,11 @@ int ieee80211_data_to_8023(struct sk_buf
|
||||
* 1 0 BSSID SA DA n/a
|
||||
* 1 1 RA TA DA SA
|
||||
*/
|
||||
- memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
|
||||
- memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
|
||||
+ memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
|
||||
+ memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
|
||||
+
|
||||
+ if (iftype == NL80211_IFTYPE_MESH_POINT)
|
||||
+ skb_copy_bits(skb, hdrlen, &mesh_flags, 1);
|
||||
|
||||
switch (hdr->frame_control &
|
||||
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
|
||||
@@ -450,44 +463,31 @@ int ieee80211_data_to_8023(struct sk_buf
|
||||
iftype != NL80211_IFTYPE_STATION))
|
||||
return -1;
|
||||
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
||||
- struct ieee80211s_hdr *meshdr =
|
||||
- (struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||||
- /* make sure meshdr->flags is on the linear part */
|
||||
- if (!pskb_may_pull(skb, hdrlen + 1))
|
||||
- return -1;
|
||||
- if (meshdr->flags & MESH_FLAGS_AE_A4)
|
||||
+ if (mesh_flags & MESH_FLAGS_AE_A4)
|
||||
return -1;
|
||||
- if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
|
||||
+ if (mesh_flags & MESH_FLAGS_AE_A5_A6) {
|
||||
skb_copy_bits(skb, hdrlen +
|
||||
offsetof(struct ieee80211s_hdr, eaddr1),
|
||||
- dst, ETH_ALEN);
|
||||
- skb_copy_bits(skb, hdrlen +
|
||||
- offsetof(struct ieee80211s_hdr, eaddr2),
|
||||
- src, ETH_ALEN);
|
||||
+ tmp.h_dest, 2 * ETH_ALEN);
|
||||
}
|
||||
- hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
|
||||
+ hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
|
||||
}
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_FCTL_FROMDS):
|
||||
if ((iftype != NL80211_IFTYPE_STATION &&
|
||||
iftype != NL80211_IFTYPE_P2P_CLIENT &&
|
||||
iftype != NL80211_IFTYPE_MESH_POINT) ||
|
||||
- (is_multicast_ether_addr(dst) &&
|
||||
- ether_addr_equal(src, addr)))
|
||||
+ (is_multicast_ether_addr(tmp.h_dest) &&
|
||||
+ ether_addr_equal(tmp.h_source, addr)))
|
||||
return -1;
|
||||
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
||||
- struct ieee80211s_hdr *meshdr =
|
||||
- (struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||||
- /* make sure meshdr->flags is on the linear part */
|
||||
- if (!pskb_may_pull(skb, hdrlen + 1))
|
||||
- return -1;
|
||||
- if (meshdr->flags & MESH_FLAGS_AE_A5_A6)
|
||||
+ if (mesh_flags & MESH_FLAGS_AE_A5_A6)
|
||||
return -1;
|
||||
- if (meshdr->flags & MESH_FLAGS_AE_A4)
|
||||
+ if (mesh_flags & MESH_FLAGS_AE_A4)
|
||||
skb_copy_bits(skb, hdrlen +
|
||||
offsetof(struct ieee80211s_hdr, eaddr1),
|
||||
- src, ETH_ALEN);
|
||||
- hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
|
||||
+ tmp.h_source, ETH_ALEN);
|
||||
+ hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
|
||||
}
|
||||
break;
|
||||
case cpu_to_le16(0):
|
||||
@@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buf
|
||||
break;
|
||||
}
|
||||
|
||||
- if (!pskb_may_pull(skb, hdrlen + 8))
|
||||
- return -1;
|
||||
-
|
||||
- payload = skb->data + hdrlen;
|
||||
- ethertype = (payload[6] << 8) | payload[7];
|
||||
+ skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
|
||||
+ tmp.h_proto = payload.proto;
|
||||
|
||||
- if (likely((ether_addr_equal(payload, rfc1042_header) &&
|
||||
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
||||
- ether_addr_equal(payload, bridge_tunnel_header))) {
|
||||
+ if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
|
||||
+ tmp.h_proto != htons(ETH_P_AARP) &&
|
||||
+ tmp.h_proto != htons(ETH_P_IPX)) ||
|
||||
+ ether_addr_equal(payload.hdr, bridge_tunnel_header)))
|
||||
/* remove RFC1042 or Bridge-Tunnel encapsulation and
|
||||
* replace EtherType */
|
||||
- skb_pull(skb, hdrlen + 6);
|
||||
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
|
||||
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
|
||||
- } else {
|
||||
- struct ethhdr *ehdr;
|
||||
- __be16 len;
|
||||
+ hdrlen += ETH_ALEN + 2;
|
||||
+ else
|
||||
+ tmp.h_proto = htons(skb->len);
|
||||
|
||||
- skb_pull(skb, hdrlen);
|
||||
- len = htons(skb->len);
|
||||
+ pskb_pull(skb, hdrlen);
|
||||
+
|
||||
+ if (!ehdr)
|
||||
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
|
||||
- memcpy(ehdr->h_dest, dst, ETH_ALEN);
|
||||
- memcpy(ehdr->h_source, src, ETH_ALEN);
|
||||
- ehdr->h_proto = len;
|
||||
- }
|
||||
+ memcpy(ehdr, &tmp, sizeof(tmp));
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
+ enum nl80211_iftype iftype)
|
||||
+{
|
||||
+ return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
|
||||
+}
|
||||
EXPORT_SYMBOL(ieee80211_data_to_8023);
|
||||
|
||||
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
||||
@ -1,89 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:47 +0100
|
||||
Subject: [PATCH] ath9k: ar9271_hw_pa_cal - use defs instead of magin
|
||||
numbers
|
||||
|
||||
This function uses mixed styles for register names/numbers which
|
||||
is make harder reading and optimisation.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
@@ -430,22 +430,22 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
u32 regVal;
|
||||
unsigned int i;
|
||||
u32 regList[][2] = {
|
||||
- { 0x786c, 0 },
|
||||
- { 0x7854, 0 },
|
||||
- { 0x7820, 0 },
|
||||
- { 0x7824, 0 },
|
||||
- { 0x7868, 0 },
|
||||
- { 0x783c, 0 },
|
||||
- { 0x7838, 0 } ,
|
||||
- { 0x7828, 0 } ,
|
||||
+ { AR9285_AN_TOP3, 0 },
|
||||
+ { AR9285_AN_RXTXBB1, 0 },
|
||||
+ { AR9285_AN_RF2G1, 0 },
|
||||
+ { AR9285_AN_RF2G2, 0 },
|
||||
+ { AR9285_AN_TOP2, 0 },
|
||||
+ { AR9285_AN_RF2G8, 0 },
|
||||
+ { AR9285_AN_RF2G7, 0 } ,
|
||||
+ { AR9285_AN_RF2G3, 0 } ,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regList); i++)
|
||||
regList[i][1] = REG_READ(ah, regList[i][0]);
|
||||
|
||||
- regVal = REG_READ(ah, 0x7834);
|
||||
+ regVal = REG_READ(ah, AR9285_AN_RF2G6);
|
||||
regVal &= (~(0x1));
|
||||
- REG_WRITE(ah, 0x7834, regVal);
|
||||
+ REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
|
||||
regVal = REG_READ(ah, 0x9808);
|
||||
regVal |= (0x1 << 27);
|
||||
REG_WRITE(ah, 0x9808, regVal);
|
||||
@@ -477,7 +477,7 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
* does not matter since we turn it off
|
||||
*/
|
||||
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
|
||||
-
|
||||
+ /* 7828, b0-11, ccom=fff */
|
||||
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
|
||||
|
||||
/* Set:
|
||||
@@ -490,15 +490,16 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
|
||||
/* find off_6_1; */
|
||||
for (i = 6; i > 0; i--) {
|
||||
- regVal = REG_READ(ah, 0x7834);
|
||||
+ regVal = REG_READ(ah, AR9285_AN_RF2G6);
|
||||
regVal |= (1 << (20 + i));
|
||||
- REG_WRITE(ah, 0x7834, regVal);
|
||||
+ REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
|
||||
udelay(1);
|
||||
/* regVal = REG_READ(ah, 0x7834); */
|
||||
regVal &= (~(0x1 << (20 + i)));
|
||||
- regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
|
||||
+ regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9),
|
||||
+ AR9285_AN_RXTXBB1_SPARE9)
|
||||
<< (20 + i));
|
||||
- REG_WRITE(ah, 0x7834, regVal);
|
||||
+ REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
|
||||
}
|
||||
|
||||
regVal = (regVal >> 20) & 0x7f;
|
||||
@@ -517,9 +518,9 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
- regVal = REG_READ(ah, 0x7834);
|
||||
+ regVal = REG_READ(ah, AR_AN_RF2G1_CH1);
|
||||
regVal |= 0x1;
|
||||
- REG_WRITE(ah, 0x7834, regVal);
|
||||
+ REG_WRITE(ah, AR_AN_RF2G1_CH1, regVal);
|
||||
regVal = REG_READ(ah, 0x9808);
|
||||
regVal &= (~(0x1 << 27));
|
||||
REG_WRITE(ah, 0x9808, regVal);
|
||||
@ -0,0 +1,159 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Tue, 2 Feb 2016 14:39:10 +0100
|
||||
Subject: [PATCH] cfg80211: add support for non-linear skbs in
|
||||
ieee80211_amsdu_to_8023s
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/util.c
|
||||
+++ b/net/wireless/util.c
|
||||
@@ -644,73 +644,75 @@ int ieee80211_data_from_8023(struct sk_b
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_data_from_8023);
|
||||
|
||||
+static struct sk_buff *
|
||||
+__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
|
||||
+ int offset, int len)
|
||||
+{
|
||||
+ struct sk_buff *frame;
|
||||
+
|
||||
+ if (skb->len - offset < len)
|
||||
+ return NULL;
|
||||
+
|
||||
+ /*
|
||||
+ * Allocate and reserve two bytes more for payload
|
||||
+ * alignment since sizeof(struct ethhdr) is 14.
|
||||
+ */
|
||||
+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len);
|
||||
+
|
||||
+ skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
|
||||
+ skb_copy_bits(skb, offset, skb_put(frame, len), len);
|
||||
+
|
||||
+ return frame;
|
||||
+}
|
||||
|
||||
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
const unsigned int extra_headroom,
|
||||
bool has_80211_header)
|
||||
{
|
||||
+ unsigned int hlen = ALIGN(extra_headroom, 4);
|
||||
struct sk_buff *frame = NULL;
|
||||
u16 ethertype;
|
||||
u8 *payload;
|
||||
- const struct ethhdr *eth;
|
||||
- int remaining, err;
|
||||
- u8 dst[ETH_ALEN], src[ETH_ALEN];
|
||||
-
|
||||
- if (skb_linearize(skb))
|
||||
- goto out;
|
||||
+ int offset = 0, remaining, err;
|
||||
+ struct ethhdr eth;
|
||||
+ bool reuse_skb = true;
|
||||
+ bool last = false;
|
||||
|
||||
if (has_80211_header) {
|
||||
- err = ieee80211_data_to_8023(skb, addr, iftype);
|
||||
+ err = __ieee80211_data_to_8023(skb, ð, addr, iftype);
|
||||
if (err)
|
||||
goto out;
|
||||
-
|
||||
- /* skip the wrapping header */
|
||||
- eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
|
||||
- if (!eth)
|
||||
- goto out;
|
||||
- } else {
|
||||
- eth = (struct ethhdr *) skb->data;
|
||||
}
|
||||
|
||||
- while (skb != frame) {
|
||||
+ while (!last) {
|
||||
+ unsigned int subframe_len;
|
||||
+ int len;
|
||||
u8 padding;
|
||||
- __be16 len = eth->h_proto;
|
||||
- unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
|
||||
-
|
||||
- remaining = skb->len;
|
||||
- memcpy(dst, eth->h_dest, ETH_ALEN);
|
||||
- memcpy(src, eth->h_source, ETH_ALEN);
|
||||
|
||||
+ skb_copy_bits(skb, offset, ð, sizeof(eth));
|
||||
+ len = ntohs(eth.h_proto);
|
||||
+ subframe_len = sizeof(struct ethhdr) + len;
|
||||
padding = (4 - subframe_len) & 0x3;
|
||||
+
|
||||
/* the last MSDU has no padding */
|
||||
+ remaining = skb->len - offset;
|
||||
if (subframe_len > remaining)
|
||||
goto purge;
|
||||
|
||||
- skb_pull(skb, sizeof(struct ethhdr));
|
||||
+ offset += sizeof(struct ethhdr);
|
||||
/* reuse skb for the last subframe */
|
||||
- if (remaining <= subframe_len + padding)
|
||||
+ last = remaining <= subframe_len + padding;
|
||||
+ if (!skb_is_nonlinear(skb) && last) {
|
||||
+ skb_pull(skb, offset);
|
||||
frame = skb;
|
||||
- else {
|
||||
- unsigned int hlen = ALIGN(extra_headroom, 4);
|
||||
- /*
|
||||
- * Allocate and reserve two bytes more for payload
|
||||
- * alignment since sizeof(struct ethhdr) is 14.
|
||||
- */
|
||||
- frame = dev_alloc_skb(hlen + subframe_len + 2);
|
||||
+ reuse_skb = true;
|
||||
+ } else {
|
||||
+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len);
|
||||
if (!frame)
|
||||
goto purge;
|
||||
|
||||
- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
|
||||
- memcpy(skb_put(frame, ntohs(len)), skb->data,
|
||||
- ntohs(len));
|
||||
-
|
||||
- eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
|
||||
- padding);
|
||||
- if (!eth) {
|
||||
- dev_kfree_skb(frame);
|
||||
- goto purge;
|
||||
- }
|
||||
+ offset += len + padding;
|
||||
}
|
||||
|
||||
skb_reset_network_header(frame);
|
||||
@@ -719,24 +721,20 @@ void ieee80211_amsdu_to_8023s(struct sk_
|
||||
|
||||
payload = frame->data;
|
||||
ethertype = (payload[6] << 8) | payload[7];
|
||||
-
|
||||
if (likely((ether_addr_equal(payload, rfc1042_header) &&
|
||||
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
||||
ether_addr_equal(payload, bridge_tunnel_header))) {
|
||||
- /* remove RFC1042 or Bridge-Tunnel
|
||||
- * encapsulation and replace EtherType */
|
||||
- skb_pull(frame, 6);
|
||||
- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
|
||||
- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
|
||||
- } else {
|
||||
- memcpy(skb_push(frame, sizeof(__be16)), &len,
|
||||
- sizeof(__be16));
|
||||
- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
|
||||
- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
|
||||
+ eth.h_proto = htons(ethertype);
|
||||
+ skb_pull(frame, ETH_ALEN + 2);
|
||||
}
|
||||
+
|
||||
+ memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth));
|
||||
__skb_queue_tail(list, frame);
|
||||
}
|
||||
|
||||
+ if (!reuse_skb)
|
||||
+ dev_kfree_skb(skb);
|
||||
+
|
||||
return;
|
||||
|
||||
purge:
|
||||
@ -1,79 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:48 +0100
|
||||
Subject: [PATCH] ath9k: ar9271_hw_pa_cal: use proper makroses.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
@@ -443,33 +443,30 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
for (i = 0; i < ARRAY_SIZE(regList); i++)
|
||||
regList[i][1] = REG_READ(ah, regList[i][0]);
|
||||
|
||||
- regVal = REG_READ(ah, AR9285_AN_RF2G6);
|
||||
- regVal &= (~(0x1));
|
||||
- REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
|
||||
- regVal = REG_READ(ah, 0x9808);
|
||||
- regVal |= (0x1 << 27);
|
||||
- REG_WRITE(ah, 0x9808, regVal);
|
||||
-
|
||||
+ /* 7834, b1=0 */
|
||||
+ REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
|
||||
+ /* 9808, b27=1 */
|
||||
+ REG_SET_BIT(ah, 0x9808, 1 << 27);
|
||||
/* 786c,b23,1, pwddac=1 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
|
||||
+ REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC);
|
||||
/* 7854, b5,1, pdrxtxbb=1 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
|
||||
+ REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1);
|
||||
/* 7854, b7,1, pdv2i=1 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
|
||||
+ REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I);
|
||||
/* 7854, b8,1, pddacinterface=1 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
|
||||
+ REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF);
|
||||
/* 7824,b12,0, offcal=0 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
|
||||
+ REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL);
|
||||
/* 7838, b1,0, pwddb=0 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
|
||||
+ REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB);
|
||||
/* 7820,b11,0, enpacal=0 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
|
||||
+ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL);
|
||||
/* 7820,b25,1, pdpadrv1=0 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
|
||||
+ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1);
|
||||
/* 7820,b24,0, pdpadrv2=0 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
|
||||
+ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2);
|
||||
/* 7820,b23,0, pdpaout=0 */
|
||||
- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
|
||||
+ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT);
|
||||
/* 783c,b14-16,7, padrvgn2tab_0=7 */
|
||||
REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
|
||||
/*
|
||||
@@ -516,15 +513,13 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
ah->pacal_info.prev_offset = regVal;
|
||||
}
|
||||
|
||||
- ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
- regVal = REG_READ(ah, AR_AN_RF2G1_CH1);
|
||||
- regVal |= 0x1;
|
||||
- REG_WRITE(ah, AR_AN_RF2G1_CH1, regVal);
|
||||
- regVal = REG_READ(ah, 0x9808);
|
||||
- regVal &= (~(0x1 << 27));
|
||||
- REG_WRITE(ah, 0x9808, regVal);
|
||||
+ /* 7834, b1=1 */
|
||||
+ REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
|
||||
+ /* 9808, b27=0 */
|
||||
+ REG_CLR_BIT(ah, 0x9808, 1 << 27);
|
||||
|
||||
+ ENABLE_REGWRITE_BUFFER(ah);
|
||||
for (i = 0; i < ARRAY_SIZE(regList); i++)
|
||||
REG_WRITE(ah, regList[i][0], regList[i][1]);
|
||||
|
||||
@ -0,0 +1,155 @@
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Tue, 26 Jan 2016 17:11:13 +0100
|
||||
Subject: [PATCH] mac80211: Parse legacy and HT rate in injected frames
|
||||
|
||||
Drivers/devices without their own rate control algorithm can get the
|
||||
information what rates they should use from either the radiotap header of
|
||||
injected frames or from the rate control algorithm. But the parsing of the
|
||||
legacy rate information from the radiotap header was removed in commit
|
||||
e6a9854b05c1 ("mac80211/drivers: rewrite the rate control API").
|
||||
|
||||
The removal of this feature heavily reduced the usefulness of frame
|
||||
injection when wanting to simulate specific transmission behavior. Having
|
||||
rate parsing together with MCS rates and retry support allows a fine
|
||||
grained selection of the tx behavior of injected frames for these kind of
|
||||
tests.
|
||||
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Cc: Simon Wunderlich <sw@simonwunderlich.de>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -708,12 +708,14 @@ enum mac80211_tx_info_flags {
|
||||
* protocol frame (e.g. EAP)
|
||||
* @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
|
||||
* frame (PS-Poll or uAPSD).
|
||||
+ * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
|
||||
*
|
||||
* These flags are used in tx_info->control.flags.
|
||||
*/
|
||||
enum mac80211_tx_control_flags {
|
||||
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
|
||||
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
|
||||
+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
|
||||
};
|
||||
|
||||
/*
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
|
||||
|
||||
info->control.short_preamble = txrc.short_preamble;
|
||||
|
||||
+ /* don't ask rate control when rate already injected via radiotap */
|
||||
+ if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
|
||||
+ return TX_CONTINUE;
|
||||
+
|
||||
if (tx->sta)
|
||||
assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
|
||||
|
||||
@@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub
|
||||
ieee80211_tx(sdata, sta, skb, false);
|
||||
}
|
||||
|
||||
-static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
|
||||
+static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
|
||||
+ struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_radiotap_iterator iterator;
|
||||
struct ieee80211_radiotap_header *rthdr =
|
||||
(struct ieee80211_radiotap_header *) skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
+ struct ieee80211_supported_band *sband =
|
||||
+ local->hw.wiphy->bands[info->band];
|
||||
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
|
||||
NULL);
|
||||
u16 txflags;
|
||||
+ u16 rate = 0;
|
||||
+ bool rate_found = false;
|
||||
+ u8 rate_retries = 0;
|
||||
+ u16 rate_flags = 0;
|
||||
+ u8 mcs_known, mcs_flags;
|
||||
+ int i;
|
||||
|
||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||
IEEE80211_TX_CTL_DONTFRAG;
|
||||
@@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap(
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
break;
|
||||
|
||||
+ case IEEE80211_RADIOTAP_RATE:
|
||||
+ rate = *iterator.this_arg;
|
||||
+ rate_flags = 0;
|
||||
+ rate_found = true;
|
||||
+ break;
|
||||
+
|
||||
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
|
||||
+ rate_retries = *iterator.this_arg;
|
||||
+ break;
|
||||
+
|
||||
+ case IEEE80211_RADIOTAP_MCS:
|
||||
+ mcs_known = iterator.this_arg[0];
|
||||
+ mcs_flags = iterator.this_arg[1];
|
||||
+ if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
|
||||
+ break;
|
||||
+
|
||||
+ rate_found = true;
|
||||
+ rate = iterator.this_arg[2];
|
||||
+ rate_flags = IEEE80211_TX_RC_MCS;
|
||||
+
|
||||
+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
|
||||
+ mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
|
||||
+ rate_flags |= IEEE80211_TX_RC_SHORT_GI;
|
||||
+
|
||||
+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
|
||||
+ mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40)
|
||||
+ rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
|
||||
+ break;
|
||||
+
|
||||
/*
|
||||
* Please update the file
|
||||
* Documentation/networking/mac80211-injection.txt
|
||||
@@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap(
|
||||
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
|
||||
return false;
|
||||
|
||||
+ if (rate_found) {
|
||||
+ info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
|
||||
+
|
||||
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
+ info->control.rates[i].idx = -1;
|
||||
+ info->control.rates[i].flags = 0;
|
||||
+ info->control.rates[i].count = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (rate_flags & IEEE80211_TX_RC_MCS) {
|
||||
+ info->control.rates[0].idx = rate;
|
||||
+ } else {
|
||||
+ for (i = 0; i < sband->n_bitrates; i++) {
|
||||
+ if (rate * 5 != sband->bitrates[i].bitrate)
|
||||
+ continue;
|
||||
+
|
||||
+ info->control.rates[0].idx = i;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ info->control.rates[0].flags = rate_flags;
|
||||
+ info->control.rates[0].count = min_t(u8, rate_retries + 1,
|
||||
+ local->hw.max_rate_tries);
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* remove the radiotap header
|
||||
* iterator->_max_length was sanity-checked against
|
||||
@@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
IEEE80211_TX_CTL_INJECTED;
|
||||
|
||||
/* process and remove the injection radiotap header */
|
||||
- if (!ieee80211_parse_tx_radiotap(skb))
|
||||
+ if (!ieee80211_parse_tx_radiotap(local, skb))
|
||||
goto fail;
|
||||
|
||||
rcu_read_lock();
|
||||
@ -1,48 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:49 +0100
|
||||
Subject: [PATCH] ath9k: ar9271_hw_pa_cal: use RMW buffer
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
@@ -436,13 +436,14 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
{ AR9285_AN_RF2G2, 0 },
|
||||
{ AR9285_AN_TOP2, 0 },
|
||||
{ AR9285_AN_RF2G8, 0 },
|
||||
- { AR9285_AN_RF2G7, 0 } ,
|
||||
- { AR9285_AN_RF2G3, 0 } ,
|
||||
+ { AR9285_AN_RF2G7, 0 },
|
||||
+ { AR9285_AN_RF2G3, 0 },
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regList); i++)
|
||||
regList[i][1] = REG_READ(ah, regList[i][0]);
|
||||
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
/* 7834, b1=0 */
|
||||
REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
|
||||
/* 9808, b27=1 */
|
||||
@@ -476,6 +477,7 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
|
||||
/* 7828, b0-11, ccom=fff */
|
||||
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
|
||||
/* Set:
|
||||
* localmode=1,bmode=1,bmoderxtx=1,synthon=1,
|
||||
@@ -514,10 +516,12 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
}
|
||||
|
||||
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
/* 7834, b1=1 */
|
||||
REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
|
||||
/* 9808, b27=0 */
|
||||
REG_CLR_BIT(ah, 0x9808, 1 << 27);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
for (i = 0; i < ARRAY_SIZE(regList); i++)
|
||||
@ -0,0 +1,317 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Fri, 5 Feb 2016 01:38:51 +0100
|
||||
Subject: [PATCH] mac80211: add A-MSDU tx support
|
||||
|
||||
Requires software tx queueing support. frag_list support (for zero-copy)
|
||||
is optional.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -709,6 +709,7 @@ enum mac80211_tx_info_flags {
|
||||
* @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
|
||||
* frame (PS-Poll or uAPSD).
|
||||
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
|
||||
+ * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
|
||||
*
|
||||
* These flags are used in tx_info->control.flags.
|
||||
*/
|
||||
@@ -716,6 +717,7 @@ enum mac80211_tx_control_flags {
|
||||
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
|
||||
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
|
||||
IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
|
||||
+ IEEE80211_TX_CTRL_AMSDU = BIT(3),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1728,6 +1730,7 @@ struct ieee80211_sta_rates {
|
||||
* size is min(max_amsdu_len, 7935) bytes.
|
||||
* Both additional HT limits must be enforced by the low level driver.
|
||||
* This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2).
|
||||
+ * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control.
|
||||
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
|
||||
*/
|
||||
struct ieee80211_sta {
|
||||
@@ -1748,6 +1751,7 @@ struct ieee80211_sta {
|
||||
bool mfp;
|
||||
u8 max_amsdu_subframes;
|
||||
u16 max_amsdu_len;
|
||||
+ u16 max_rc_amsdu_len;
|
||||
|
||||
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
|
||||
|
||||
@@ -1961,6 +1965,15 @@ struct ieee80211_txq {
|
||||
* order and does not need to manage its own reorder buffer or BA session
|
||||
* timeout.
|
||||
*
|
||||
+ * @IEEE80211_HW_TX_AMSDU: Hardware (or driver) supports software aggregated
|
||||
+ * A-MSDU frames. Requires software tx queueing and fast-xmit support.
|
||||
+ * When not using minstrel/minstrel_ht rate control, the driver should
|
||||
+ * limit the maximum A-MSDU size based on the current tx rate by setting
|
||||
+ * max_rc_amsdu_len in struct ieee80211_sta.
|
||||
+ *
|
||||
+ * @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list
|
||||
+ * skbs, needed for zero-copy software A-MSDU.
|
||||
+ *
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@@ -1998,6 +2011,8 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_BEACON_TX_STATUS,
|
||||
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
|
||||
IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
|
||||
+ IEEE80211_HW_TX_AMSDU,
|
||||
+ IEEE80211_HW_TX_FRAG_LIST,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
@@ -2070,6 +2085,9 @@ enum ieee80211_hw_flags {
|
||||
* size is smaller (an example is LinkSys WRT120N with FW v1.0.07
|
||||
* build 002 Jun 18 2012).
|
||||
*
|
||||
+ * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum
|
||||
+ * of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list.
|
||||
+ *
|
||||
* @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
|
||||
* (if %IEEE80211_HW_QUEUE_CONTROL is set)
|
||||
*
|
||||
@@ -2124,6 +2142,7 @@ struct ieee80211_hw {
|
||||
u8 max_rate_tries;
|
||||
u8 max_rx_aggregation_subframes;
|
||||
u8 max_tx_aggregation_subframes;
|
||||
+ u8 max_tx_fragments;
|
||||
u8 offchannel_tx_hw_queue;
|
||||
u8 radiotap_mcs_details;
|
||||
u16 radiotap_vht_details;
|
||||
--- a/net/mac80211/agg-tx.c
|
||||
+++ b/net/mac80211/agg-tx.c
|
||||
@@ -935,6 +935,7 @@ void ieee80211_process_addba_resp(struct
|
||||
size_t len)
|
||||
{
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
+ struct ieee80211_txq *txq;
|
||||
u16 capab, tid;
|
||||
u8 buf_size;
|
||||
bool amsdu;
|
||||
@@ -945,6 +946,10 @@ void ieee80211_process_addba_resp(struct
|
||||
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
|
||||
buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
|
||||
|
||||
+ txq = sta->sta.txq[tid];
|
||||
+ if (!amsdu && txq)
|
||||
+ set_bit(IEEE80211_TXQ_NO_AMSDU, &to_txq_info(txq)->flags);
|
||||
+
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -127,6 +127,8 @@ static const char *hw_flag_names[NUM_IEE
|
||||
FLAG(BEACON_TX_STATUS),
|
||||
FLAG(NEEDS_UNIQUE_STA_ADDR),
|
||||
FLAG(SUPPORTS_REORDERING_BUFFER),
|
||||
+ FLAG(TX_AMSDU),
|
||||
+ FLAG(TX_FRAG_LIST),
|
||||
|
||||
/* keep last for the build bug below */
|
||||
(void *)0x1
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -799,6 +799,7 @@ struct mac80211_qos_map {
|
||||
enum txq_info_flags {
|
||||
IEEE80211_TXQ_STOP,
|
||||
IEEE80211_TXQ_AMPDU,
|
||||
+ IEEE80211_TXQ_NO_AMSDU,
|
||||
};
|
||||
|
||||
struct txq_info {
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1318,6 +1318,10 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
out:
|
||||
spin_unlock_bh(&txqi->queue.lock);
|
||||
|
||||
+ if (skb && skb_has_frag_list(skb) &&
|
||||
+ !ieee80211_hw_check(&local->hw, TX_FRAG_LIST))
|
||||
+ skb_linearize(skb);
|
||||
+
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
||||
@@ -2757,6 +2761,163 @@ void ieee80211_clear_fast_xmit(struct st
|
||||
kfree_rcu(fast_tx, rcu_head);
|
||||
}
|
||||
|
||||
+static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local,
|
||||
+ struct sk_buff *skb, int headroom,
|
||||
+ int *subframe_len)
|
||||
+{
|
||||
+ int amsdu_len = *subframe_len + sizeof(struct ethhdr);
|
||||
+ int padding = (4 - amsdu_len) & 3;
|
||||
+
|
||||
+ if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) {
|
||||
+ I802_DEBUG_INC(local->tx_expand_skb_head);
|
||||
+
|
||||
+ if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) {
|
||||
+ wiphy_debug(local->hw.wiphy,
|
||||
+ "failed to reallocate TX buffer\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (padding) {
|
||||
+ *subframe_len += padding;
|
||||
+ memset(skb_put(skb, padding), 0, padding);
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
|
||||
+ struct ieee80211_fast_tx *fast_tx,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ struct ieee80211_local *local = sdata->local;
|
||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
+ struct ieee80211_hdr *hdr;
|
||||
+ struct ethhdr amsdu_hdr;
|
||||
+ int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header);
|
||||
+ int subframe_len = skb->len - hdr_len;
|
||||
+ void *data;
|
||||
+ u8 *qc;
|
||||
+
|
||||
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
|
||||
+ return false;
|
||||
+
|
||||
+ if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
|
||||
+ return true;
|
||||
+
|
||||
+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr),
|
||||
+ &subframe_len))
|
||||
+ return false;
|
||||
+
|
||||
+ amsdu_hdr.h_proto = cpu_to_be16(subframe_len);
|
||||
+ memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN);
|
||||
+ memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN);
|
||||
+
|
||||
+ data = skb_push(skb, sizeof(amsdu_hdr));
|
||||
+ memmove(data, data + sizeof(amsdu_hdr), hdr_len);
|
||||
+ memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr));
|
||||
+
|
||||
+ hdr = data;
|
||||
+ qc = ieee80211_get_qos_ctl(hdr);
|
||||
+ *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
|
||||
+
|
||||
+ info->control.flags |= IEEE80211_TX_CTRL_AMSDU;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
+ struct sta_info *sta,
|
||||
+ struct ieee80211_fast_tx *fast_tx,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ struct ieee80211_local *local = sdata->local;
|
||||
+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
+ struct ieee80211_txq *txq = sta->sta.txq[tid];
|
||||
+ struct txq_info *txqi;
|
||||
+ struct sk_buff **frag_tail, *head;
|
||||
+ int subframe_len = skb->len - ETH_ALEN;
|
||||
+ u8 max_subframes = sta->sta.max_amsdu_subframes;
|
||||
+ int max_frags = local->hw.max_tx_fragments;
|
||||
+ int max_amsdu_len = sta->sta.max_amsdu_len;
|
||||
+ __be16 len;
|
||||
+ void *data;
|
||||
+ bool ret = false;
|
||||
+ int n = 1, nfrags;
|
||||
+
|
||||
+ if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!txq)
|
||||
+ return false;
|
||||
+
|
||||
+ txqi = to_txq_info(txq);
|
||||
+ if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags))
|
||||
+ return false;
|
||||
+
|
||||
+ if (sta->sta.max_rc_amsdu_len)
|
||||
+ max_amsdu_len = min_t(int, max_amsdu_len,
|
||||
+ sta->sta.max_rc_amsdu_len);
|
||||
+
|
||||
+ spin_lock_bh(&txqi->queue.lock);
|
||||
+
|
||||
+ head = skb_peek_tail(&txqi->queue);
|
||||
+ if (!head)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (skb->len + head->len > max_amsdu_len)
|
||||
+ goto out;
|
||||
+
|
||||
+ /*
|
||||
+ * HT A-MPDU limits maximum MPDU size to 4095 bytes. Since aggregation
|
||||
+ * sessions are started/stopped without txq flush, use the limit here
|
||||
+ * to avoid having to de-aggregate later.
|
||||
+ */
|
||||
+ if (skb->len + head->len > 4095 &&
|
||||
+ !sta->sta.vht_cap.vht_supported)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head))
|
||||
+ goto out;
|
||||
+
|
||||
+ nfrags = 1 + skb_shinfo(skb)->nr_frags;
|
||||
+ nfrags += 1 + skb_shinfo(head)->nr_frags;
|
||||
+ frag_tail = &skb_shinfo(head)->frag_list;
|
||||
+ while (*frag_tail) {
|
||||
+ nfrags += 1 + skb_shinfo(*frag_tail)->nr_frags;
|
||||
+ frag_tail = &(*frag_tail)->next;
|
||||
+ n++;
|
||||
+ }
|
||||
+
|
||||
+ if (max_subframes && n > max_subframes)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (max_frags && nfrags > max_frags)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2,
|
||||
+ &subframe_len))
|
||||
+ return false;
|
||||
+
|
||||
+ ret = true;
|
||||
+ data = skb_push(skb, ETH_ALEN + 2);
|
||||
+ memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN);
|
||||
+
|
||||
+ data += 2 * ETH_ALEN;
|
||||
+ len = cpu_to_be16(subframe_len);
|
||||
+ memcpy(data, &len, 2);
|
||||
+ memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header));
|
||||
+
|
||||
+ head->len += skb->len;
|
||||
+ head->data_len += skb->len;
|
||||
+ *frag_tail = skb;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&txqi->queue.lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
||||
struct net_device *dev, struct sta_info *sta,
|
||||
struct ieee80211_fast_tx *fast_tx,
|
||||
@@ -2811,6 +2972,10 @@ static bool ieee80211_xmit_fast(struct i
|
||||
|
||||
ieee80211_tx_stats(dev, skb->len + extra_head);
|
||||
|
||||
+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
|
||||
+ ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
|
||||
+ return true;
|
||||
+
|
||||
/* will not be crypto-handled beyond what we do here, so use false
|
||||
* as the may-encrypt argument for the resize to not account for
|
||||
* more room than we already have in 'extra_head'
|
||||
@ -1,5 +1,5 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Wed, 20 Jan 2016 16:35:12 +0100
|
||||
Date: Wed, 20 Jan 2016 16:46:04 +0100
|
||||
Subject: [PATCH] brcmfmac: fix setting primary channel for 80 MHz width
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
@ -14,13 +14,12 @@ offset in MHz against -2 or 2 which was resulting in picking a wrong
|
||||
primary channel.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
.../brcm80211/brcmfmac/cfg80211.c | 23 ++++++++++------------
|
||||
1 file changed, 10 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -246,7 +246,7 @@ static u16 chandef_to_chanspec(struct br
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -247,7 +247,7 @@ static u16 chandef_to_chanspec(struct br
|
||||
brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
|
||||
ch->chan->center_freq, ch->center_freq1, ch->width);
|
||||
ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
|
||||
@ -29,7 +28,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
switch (ch->width) {
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
@@ -255,24 +255,21 @@ static u16 chandef_to_chanspec(struct br
|
||||
@@ -256,24 +256,21 @@ static u16 chandef_to_chanspec(struct br
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
ch_inf.bw = BRCMU_CHAN_BW_40;
|
||||
@ -0,0 +1,51 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 26 Jan 2016 17:57:01 +0100
|
||||
Subject: [PATCH] brcmfmac: analyze descriptors of current component only
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
So far we were looking for address descriptors without a check for
|
||||
crossing current component border. In case of dealing with unsupported
|
||||
descriptor or descriptor missing at all the code would incorrectly get
|
||||
data from another component.
|
||||
|
||||
Consider this binary-described component from BCM4366 EROM:
|
||||
4bf83b01 TAG==CI CID==0x83b
|
||||
20080201 TAG==CI PORTS==0+1 WRAPPERS==0+1
|
||||
18400035 TAG==ADDR SZ_SZD TYPE_SLAVE
|
||||
00050000
|
||||
18107085 TAG==ADDR SZ_4K TYPE_SWRAP
|
||||
|
||||
Driver was assigning invalid base address to this core:
|
||||
brcmfmac: [6 ] core 0x83b:32 base 0x18109000 wrap 0x18107000
|
||||
which came from totally different component defined in EROM:
|
||||
43b36701 TAG==CI CID==0x367
|
||||
00000201 TAG==CI PORTS==0+1 WRAPPERS==0+0
|
||||
18109005 TAG==ADDR SZ_4K TYPE_SLAVE
|
||||
|
||||
This change will also allow us to support components without wrapper
|
||||
address in the future.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
@@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(st
|
||||
*eromaddr -= 4;
|
||||
return -EFAULT;
|
||||
}
|
||||
- } while (desc != DMP_DESC_ADDRESS);
|
||||
+ } while (desc != DMP_DESC_ADDRESS &&
|
||||
+ desc != DMP_DESC_COMPONENT);
|
||||
+
|
||||
+ /* stop if we crossed current component border */
|
||||
+ if (desc == DMP_DESC_COMPONENT) {
|
||||
+ *eromaddr -= 4;
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
/* skip upper 32-bit address descriptor */
|
||||
if (val & DMP_DESC_ADDRSIZE_GT32)
|
||||
@ -0,0 +1,28 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 26 Jan 2016 17:57:02 +0100
|
||||
Subject: [PATCH] brcmfmac: allow storing PMU core without wrapper address
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Separated PMU core can be found in new devices and should be used for
|
||||
accessing PMU registers (which were routed through ChipCommon so far).
|
||||
This core is one of exceptions that doesn't have or need wrapper address
|
||||
to be still safely accessible.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
@@ -883,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcm
|
||||
rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;
|
||||
|
||||
/* need core with ports */
|
||||
- if (nmw + nsw == 0)
|
||||
+ if (nmw + nsw == 0 &&
|
||||
+ id != BCMA_CORE_PMU)
|
||||
continue;
|
||||
|
||||
/* try to obtain register address info */
|
||||
@ -0,0 +1,43 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 26 Jan 2016 17:57:03 +0100
|
||||
Subject: [PATCH] brcmfmac: read extended capabilities of ChipCommon core
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This is an extra bitfield with info about some present hardware.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
@@ -1025,6 +1025,9 @@ static int brcmf_chip_setup(struct brcmf
|
||||
/* get chipcommon capabilites */
|
||||
pub->cc_caps = chip->ops->read32(chip->ctx,
|
||||
CORE_CC_REG(base, capabilities));
|
||||
+ pub->cc_caps_ext = chip->ops->read32(chip->ctx,
|
||||
+ CORE_CC_REG(base,
|
||||
+ capabilities_ext));
|
||||
|
||||
/* get pmu caps & rev */
|
||||
if (pub->cc_caps & CC_CAP_PMU) {
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
|
||||
@@ -27,6 +27,7 @@
|
||||
* @chip: chip identifier.
|
||||
* @chiprev: chip revision.
|
||||
* @cc_caps: chipcommon core capabilities.
|
||||
+ * @cc_caps_ext: chipcommon core extended capabilities.
|
||||
* @pmucaps: PMU capabilities.
|
||||
* @pmurev: PMU revision.
|
||||
* @rambase: RAM base address (only applicable for ARM CR4 chips).
|
||||
@@ -38,6 +39,7 @@ struct brcmf_chip {
|
||||
u32 chip;
|
||||
u32 chiprev;
|
||||
u32 cc_caps;
|
||||
+ u32 cc_caps_ext;
|
||||
u32 pmucaps;
|
||||
u32 pmurev;
|
||||
u32 rambase;
|
||||
@ -0,0 +1,148 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 26 Jan 2016 17:57:04 +0100
|
||||
Subject: [PATCH] brcmfmac: access PMU registers using standalone PMU core if
|
||||
available
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
On recent Broadcom chipsets PMU is present as separated core and it
|
||||
can't be accessed using ChipCommon anymore as it fails with e.g.:
|
||||
[ 18.198412] Unhandled fault: imprecise external abort (0x1406) at 0xb6da200f
|
||||
|
||||
Add a new helper function that will return a proper core that should be
|
||||
used for accessing PMU registers.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
|
||||
@@ -1014,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf
|
||||
{
|
||||
struct brcmf_chip *pub;
|
||||
struct brcmf_core_priv *cc;
|
||||
+ struct brcmf_core *pmu;
|
||||
u32 base;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
@@ -1030,9 +1031,10 @@ static int brcmf_chip_setup(struct brcmf
|
||||
capabilities_ext));
|
||||
|
||||
/* get pmu caps & rev */
|
||||
+ pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */
|
||||
if (pub->cc_caps & CC_CAP_PMU) {
|
||||
val = chip->ops->read32(chip->ctx,
|
||||
- CORE_CC_REG(base, pmucapabilities));
|
||||
+ CORE_CC_REG(pmu->base, pmucapabilities));
|
||||
pub->pmurev = val & PCAP_REV_MASK;
|
||||
pub->pmucaps = val;
|
||||
}
|
||||
@@ -1131,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipco
|
||||
return &cc->pub;
|
||||
}
|
||||
|
||||
+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub)
|
||||
+{
|
||||
+ struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub);
|
||||
+ struct brcmf_core *pmu;
|
||||
+
|
||||
+ /* See if there is separated PMU core available */
|
||||
+ if (cc->rev >= 35 &&
|
||||
+ pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
|
||||
+ pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU);
|
||||
+ if (pmu)
|
||||
+ return pmu;
|
||||
+ }
|
||||
+
|
||||
+ /* Fallback to ChipCommon core for older hardware */
|
||||
+ return cc;
|
||||
+}
|
||||
+
|
||||
bool brcmf_chip_iscoreup(struct brcmf_core *pub)
|
||||
{
|
||||
struct brcmf_core_priv *core;
|
||||
@@ -1301,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_
|
||||
{
|
||||
u32 base, addr, reg, pmu_cc3_mask = ~0;
|
||||
struct brcmf_chip_priv *chip;
|
||||
+ struct brcmf_core *pmu = brcmf_chip_get_pmu(pub);
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
@@ -1320,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_
|
||||
case BRCM_CC_4335_CHIP_ID:
|
||||
case BRCM_CC_4339_CHIP_ID:
|
||||
/* read PMU chipcontrol register 3 */
|
||||
- addr = CORE_CC_REG(base, chipcontrol_addr);
|
||||
+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
|
||||
chip->ops->write32(chip->ctx, addr, 3);
|
||||
- addr = CORE_CC_REG(base, chipcontrol_data);
|
||||
+ addr = CORE_CC_REG(pmu->base, chipcontrol_data);
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
return (reg & pmu_cc3_mask) != 0;
|
||||
case BRCM_CC_43430_CHIP_ID:
|
||||
@@ -1330,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
return reg != 0;
|
||||
default:
|
||||
- addr = CORE_CC_REG(base, pmucapabilities_ext);
|
||||
+ addr = CORE_CC_REG(pmu->base, pmucapabilities_ext);
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
|
||||
return false;
|
||||
|
||||
- addr = CORE_CC_REG(base, retention_ctl);
|
||||
+ addr = CORE_CC_REG(pmu->base, retention_ctl);
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
|
||||
PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
|
||||
@@ -85,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(voi
|
||||
void brcmf_chip_detach(struct brcmf_chip *chip);
|
||||
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
|
||||
struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
|
||||
+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
|
||||
bool brcmf_chip_iscoreup(struct brcmf_core *core);
|
||||
void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
|
||||
void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
@@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcm
|
||||
const struct sdiod_drive_str *str_tab = NULL;
|
||||
u32 str_mask;
|
||||
u32 str_shift;
|
||||
- u32 base;
|
||||
u32 i;
|
||||
u32 drivestrength_sel = 0;
|
||||
u32 cc_data_temp;
|
||||
@@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcm
|
||||
}
|
||||
|
||||
if (str_tab != NULL) {
|
||||
+ struct brcmf_core *pmu = brcmf_chip_get_pmu(ci);
|
||||
+
|
||||
for (i = 0; str_tab[i].strength != 0; i++) {
|
||||
if (drivestrength >= str_tab[i].strength) {
|
||||
drivestrength_sel = str_tab[i].sel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
- base = brcmf_chip_get_chipcommon(ci)->base;
|
||||
- addr = CORE_CC_REG(base, chipcontrol_addr);
|
||||
+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
|
||||
brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
|
||||
cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
|
||||
cc_data_temp &= ~str_mask;
|
||||
@@ -3835,8 +3835,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
|
||||
goto fail;
|
||||
|
||||
/* set PMUControl so a backplane reset does PMU state reload */
|
||||
- reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
|
||||
- pmucontrol);
|
||||
+ reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol);
|
||||
reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
|
||||
if (err)
|
||||
goto fail;
|
||||
@ -0,0 +1,38 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 26 Jan 2016 17:57:05 +0100
|
||||
Subject: [PATCH] brcmfmac: add support for 14e4:4365 PCI ID with BCM4366
|
||||
chipset
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
On Broadcom ARM routers BCM4366 cards are available with 14e4:4365 ID.
|
||||
Unfortunately this ID was already used by Broadcom for cards with
|
||||
BCM43142, a totally different chipset requiring SoftMAC driver. To avoid
|
||||
a conflict between brcmfmac and bcma use more specific ID entry with
|
||||
subvendor and subdevice specified.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
||||
@@ -1951,6 +1951,9 @@ static const struct dev_pm_ops brcmf_pci
|
||||
|
||||
#define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
|
||||
+#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \
|
||||
+ BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
|
||||
+ subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
|
||||
|
||||
static struct pci_device_id brcmf_pcie_devid_table[] = {
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
|
||||
@@ -1966,6 +1969,7 @@ static struct pci_device_id brcmf_pcie_d
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID),
|
||||
+ BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
|
||||
@ -1,35 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:50 +0100
|
||||
Subject: [PATCH] ath9k: add multi_read to be compatible with ath9k_htc
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||
@@ -141,6 +141,16 @@ static unsigned int ath9k_ioread32(void
|
||||
return val;
|
||||
}
|
||||
|
||||
+static void ath9k_multi_ioread32(void *hw_priv, u32 *addr,
|
||||
+ u32 *val, u16 count)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < count; i++)
|
||||
+ val[i] = ath9k_ioread32(hw_priv, addr[i]);
|
||||
+}
|
||||
+
|
||||
+
|
||||
static unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset,
|
||||
u32 set, u32 clr)
|
||||
{
|
||||
@@ -530,6 +540,7 @@ static int ath9k_init_softc(u16 devid, s
|
||||
ah->hw = sc->hw;
|
||||
ah->hw_version.devid = devid;
|
||||
ah->reg_ops.read = ath9k_ioread32;
|
||||
+ ah->reg_ops.multi_read = ath9k_multi_ioread32;
|
||||
ah->reg_ops.write = ath9k_iowrite32;
|
||||
ah->reg_ops.rmw = ath9k_reg_rmw;
|
||||
pCap = &ah->caps;
|
||||
@ -1,69 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:51 +0100
|
||||
Subject: [PATCH] ath9k: add new function ath9k_hw_read_array
|
||||
|
||||
REG_READ generate most overhead on usb bus. It send and read micro packages
|
||||
and reduce usb bandwidth. To reduce this overhead we should read in batches.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -121,6 +121,36 @@ void ath9k_hw_write_array(struct ath_hw
|
||||
REGWRITE_BUFFER_FLUSH(ah);
|
||||
}
|
||||
|
||||
+void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size)
|
||||
+{
|
||||
+ u32 *tmp_reg_list, *tmp_data;
|
||||
+ int i;
|
||||
+
|
||||
+ tmp_reg_list = kmalloc(size * sizeof(u32), GFP_KERNEL);
|
||||
+ if (!tmp_reg_list) {
|
||||
+ dev_err(ah->dev, "%s: tmp_reg_list: alloc filed\n", __func__);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ tmp_data = kmalloc(size * sizeof(u32), GFP_KERNEL);
|
||||
+ if (!tmp_data) {
|
||||
+ dev_err(ah->dev, "%s tmp_data: alloc filed\n", __func__);
|
||||
+ goto error_tmp_data;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < size; i++)
|
||||
+ tmp_reg_list[i] = array[i][0];
|
||||
+
|
||||
+ REG_READ_MULTI(ah, tmp_reg_list, tmp_data, size);
|
||||
+
|
||||
+ for (i = 0; i < size; i++)
|
||||
+ array[i][1] = tmp_data[i];
|
||||
+
|
||||
+ kfree(tmp_data);
|
||||
+error_tmp_data:
|
||||
+ kfree(tmp_reg_list);
|
||||
+}
|
||||
+
|
||||
u32 ath9k_hw_reverse_bits(u32 val, u32 n)
|
||||
{
|
||||
u32 retval;
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||
@@ -138,6 +138,8 @@
|
||||
|
||||
#define REG_WRITE_ARRAY(iniarray, column, regWr) \
|
||||
ath9k_hw_write_array(ah, iniarray, column, &(regWr))
|
||||
+#define REG_READ_ARRAY(ah, array, size) \
|
||||
+ ath9k_hw_read_array(ah, array, size)
|
||||
|
||||
#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
|
||||
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
|
||||
@@ -1020,6 +1022,7 @@ void ath9k_hw_synth_delay(struct ath_hw
|
||||
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
|
||||
void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
|
||||
int column, unsigned int *writecnt);
|
||||
+void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size);
|
||||
u32 ath9k_hw_reverse_bits(u32 val, u32 n);
|
||||
u16 ath9k_hw_computetxtime(struct ath_hw *ah,
|
||||
u8 phy, int kbps,
|
||||
@ -0,0 +1,32 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Sun, 31 Jan 2016 12:14:34 +0100
|
||||
Subject: [PATCH] brcmfmac: treat NULL character in NVRAM as separator
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Platform NVRAM (stored on a flash partition) has entries separated by a
|
||||
NULL (\0) char. Our parsing code switches from VALUE state to IDLE
|
||||
whenever it meets a NULL (\0). When that happens our IDLE handler should
|
||||
simply consume it and analyze whatever is placed ahead.
|
||||
|
||||
This fixes harmless warnings spamming debugging output:
|
||||
[ 155.165624] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=20: ignoring invalid character
|
||||
[ 155.180806] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=44: ignoring invalid character
|
||||
[ 155.195971] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=63: ignoring invalid character
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
|
||||
@@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvr
|
||||
c = nvp->data[nvp->pos];
|
||||
if (c == '\n')
|
||||
return COMMENT;
|
||||
- if (is_whitespace(c))
|
||||
+ if (is_whitespace(c) || c == '\0')
|
||||
goto proceed;
|
||||
if (c == '#')
|
||||
return COMMENT;
|
||||
@ -1,24 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:52 +0100
|
||||
Subject: [PATCH] ath9k: ar9271_hw_pa_cal: use REG_READ_ARRAY
|
||||
|
||||
insted of reading each register separatly
|
||||
and waste 4ms on each operation, we can
|
||||
use one shot read.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
|
||||
@@ -440,8 +440,7 @@ static void ar9271_hw_pa_cal(struct ath_
|
||||
{ AR9285_AN_RF2G3, 0 },
|
||||
};
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(regList); i++)
|
||||
- regList[i][1] = REG_READ(ah, regList[i][0]);
|
||||
+ REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList));
|
||||
|
||||
ENABLE_REG_RMW_BUFFER(ah);
|
||||
/* 7834, b1=0 */
|
||||
@ -0,0 +1,41 @@
|
||||
From: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
|
||||
Date: Mon, 25 Jan 2016 11:47:29 +0100
|
||||
Subject: [PATCH] brcmfmac: sdio: Increase the default timeouts a bit
|
||||
|
||||
On a Radxa Rock2 board with a Ampak AP6335 (Broadcom 4339 core) it seems
|
||||
the card responds very quickly most of the time, unfortunately during
|
||||
initialisation it sometimes seems to take just a bit over 2 seconds to
|
||||
respond.
|
||||
|
||||
This results intialization failing with message like:
|
||||
brcmf_c_preinit_dcmds: Retreiving cur_etheraddr failed, -52
|
||||
brcmf_bus_start: failed: -52
|
||||
brcmf_sdio_firmware_callback: dongle is not responding
|
||||
|
||||
Increasing the timeout to allow for a bit more headroom allows the
|
||||
card to initialize reliably.
|
||||
|
||||
A quick search online after diagnosing/fixing this showed that Google
|
||||
has a similar patch in their ChromeOS tree, so this doesn't seem
|
||||
specific to the board I'm using.
|
||||
|
||||
Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
|
||||
Reviewed-by: Julian Calaby <julian.calaby@gmail.com>
|
||||
Acked-by: Arend van Spriel <arend@broadcom.com>
|
||||
Reviewed-by: Douglas Anderson <dianders@chromium.org>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
@@ -45,8 +45,8 @@
|
||||
#include "chip.h"
|
||||
#include "firmware.h"
|
||||
|
||||
-#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2000)
|
||||
-#define CTL_DONE_TIMEOUT msecs_to_jiffies(2000)
|
||||
+#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
|
||||
+#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
From: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
Date: Fri, 5 Feb 2016 09:45:50 +0800
|
||||
Subject: [PATCH] ath9k: make NF load complete quickly and reliably
|
||||
|
||||
Make NF load complete quickly and reliably. NF load execution
|
||||
is delayed by HW to end of frame if frame Rx or Tx is ongoing.
|
||||
Increasing timeout to max frame duration. If NF cal is ongoing
|
||||
before NF load, stop it before load, and restart it afterwards.
|
||||
|
||||
Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/calib.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/calib.c
|
||||
@@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
|
||||
+ u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
|
||||
|
||||
if (ah->caldata)
|
||||
h = ah->caldata->nfCalHist;
|
||||
@@ -264,6 +265,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
}
|
||||
|
||||
/*
|
||||
+ * stop NF cal if ongoing to ensure NF load completes immediately
|
||||
+ * (or after end rx/tx frame if ongoing)
|
||||
+ */
|
||||
+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
|
||||
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
* Load software filtered NF value into baseband internal minCCApwr
|
||||
* variable.
|
||||
*/
|
||||
@@ -276,18 +287,33 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
|
||||
/*
|
||||
* Wait for load to complete, should be fast, a few 10s of us.
|
||||
- * The max delay was changed from an original 250us to 10000us
|
||||
- * since 250us often results in NF load timeout and causes deaf
|
||||
- * condition during stress testing 12/12/2009
|
||||
+ * The max delay was changed from an original 250us to 22.2 msec.
|
||||
+ * This would increase timeout to the longest possible frame
|
||||
+ * (11n max length 22.1 msec)
|
||||
*/
|
||||
- for (j = 0; j < 10000; j++) {
|
||||
+ for (j = 0; j < 22200; j++) {
|
||||
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
|
||||
- AR_PHY_AGC_CONTROL_NF) == 0)
|
||||
+ AR_PHY_AGC_CONTROL_NF) == 0)
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/*
|
||||
+ * Restart NF so it can continue.
|
||||
+ */
|
||||
+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF)
|
||||
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
|
||||
+ AR_PHY_AGC_CONTROL_ENABLE_NF);
|
||||
+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF)
|
||||
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
|
||||
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
|
||||
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
* We timed out waiting for the noisefloor to load, probably due to an
|
||||
* in-progress rx. Simply return here and allow the load plenty of time
|
||||
* to complete before the next calibration interval. We need to avoid
|
||||
@@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
* here, the baseband nf cal will just be capped by our present
|
||||
* noisefloor until the next calibration timer.
|
||||
*/
|
||||
- if (j == 10000) {
|
||||
+ if (j == 22200) {
|
||||
ath_dbg(common, ANY,
|
||||
"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
|
||||
REG_READ(ah, AR_PHY_AGC_CONTROL));
|
||||
@ -1,39 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:53 +0100
|
||||
Subject: [PATCH] ath9k: use one shot read in ath9k_hw_update_mibstats
|
||||
|
||||
this will reduce some overhead on usb bus.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ani.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ani.c
|
||||
@@ -107,11 +107,21 @@ static const struct ani_cck_level_entry
|
||||
static void ath9k_hw_update_mibstats(struct ath_hw *ah,
|
||||
struct ath9k_mib_stats *stats)
|
||||
{
|
||||
- stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
|
||||
- stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
|
||||
- stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
|
||||
- stats->rts_good += REG_READ(ah, AR_RTS_OK);
|
||||
- stats->beacons += REG_READ(ah, AR_BEACON_CNT);
|
||||
+ u32 addr[5] = {AR_RTS_OK, AR_RTS_FAIL, AR_ACK_FAIL,
|
||||
+ AR_FCS_FAIL, AR_BEACON_CNT};
|
||||
+ u32 data[5];
|
||||
+
|
||||
+ REG_READ_MULTI(ah, &addr[0], &data[0], 5);
|
||||
+ /* AR_RTS_OK */
|
||||
+ stats->rts_good += data[0];
|
||||
+ /* AR_RTS_FAIL */
|
||||
+ stats->rts_bad += data[1];
|
||||
+ /* AR_ACK_FAIL */
|
||||
+ stats->ackrcv_bad += data[2];
|
||||
+ /* AR_FCS_FAIL */
|
||||
+ stats->fcs_bad += data[3];
|
||||
+ /* AR_BEACON_CNT */
|
||||
+ stats->beacons += data[4];
|
||||
}
|
||||
|
||||
static void ath9k_ani_restart(struct ath_hw *ah)
|
||||
@ -1,71 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:54 +0100
|
||||
Subject: [PATCH] ath9k: ath9k_hw_loadnf: use REG_RMW
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/calib.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/calib.c
|
||||
@@ -238,7 +238,6 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
{
|
||||
struct ath9k_nfcal_hist *h = NULL;
|
||||
unsigned i, j;
|
||||
- int32_t val;
|
||||
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
|
||||
@@ -246,6 +245,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
if (ah->caldata)
|
||||
h = ah->caldata->nfCalHist;
|
||||
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
for (i = 0; i < NUM_NF_READINGS; i++) {
|
||||
if (chainmask & (1 << i)) {
|
||||
s16 nfval;
|
||||
@@ -258,10 +258,8 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
else
|
||||
nfval = default_nf;
|
||||
|
||||
- val = REG_READ(ah, ah->nf_regs[i]);
|
||||
- val &= 0xFFFFFE00;
|
||||
- val |= (((u32) nfval << 1) & 0x1ff);
|
||||
- REG_WRITE(ah, ah->nf_regs[i], val);
|
||||
+ REG_RMW(ah, ah->nf_regs[i],
|
||||
+ (((u32) nfval << 1) & 0x1ff), 0x1ff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +272,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
|
||||
AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
|
||||
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
|
||||
/*
|
||||
* Wait for load to complete, should be fast, a few 10s of us.
|
||||
@@ -309,19 +308,17 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
|
||||
* by the median we just loaded. This will be initial (and max) value
|
||||
* of next noise floor calibration the baseband does.
|
||||
*/
|
||||
- ENABLE_REGWRITE_BUFFER(ah);
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
for (i = 0; i < NUM_NF_READINGS; i++) {
|
||||
if (chainmask & (1 << i)) {
|
||||
if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
|
||||
continue;
|
||||
|
||||
- val = REG_READ(ah, ah->nf_regs[i]);
|
||||
- val &= 0xFFFFFE00;
|
||||
- val |= (((u32) (-50) << 1) & 0x1ff);
|
||||
- REG_WRITE(ah, ah->nf_regs[i], val);
|
||||
+ REG_RMW(ah, ah->nf_regs[i],
|
||||
+ (((u32) (-50) << 1) & 0x1ff), 0x1ff);
|
||||
}
|
||||
}
|
||||
- REGWRITE_BUFFER_FLUSH(ah);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
From: Henning Rogge <hrogge@gmail.com>
|
||||
Date: Wed, 3 Feb 2016 13:58:36 +0100
|
||||
Subject: [PATCH] mac80211: Remove MPP table entries with MPath
|
||||
|
||||
Make the mesh_path_del() function remove all mpp table entries
|
||||
that are proxied by the removed mesh path.
|
||||
|
||||
Acked-by: Bob Copeland <me@bobcopeland.com>
|
||||
Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/mesh_pathtbl.c
|
||||
+++ b/net/mac80211/mesh_pathtbl.c
|
||||
@@ -835,6 +835,29 @@ void mesh_path_flush_by_nexthop(struct s
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
|
||||
+ const u8 *proxy)
|
||||
+{
|
||||
+ struct mesh_table *tbl;
|
||||
+ struct mesh_path *mpp;
|
||||
+ struct mpath_node *node;
|
||||
+ int i;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ read_lock_bh(&pathtbl_resize_lock);
|
||||
+ tbl = resize_dereference_mpp_paths();
|
||||
+ for_each_mesh_entry(tbl, node, i) {
|
||||
+ mpp = node->mpath;
|
||||
+ if (ether_addr_equal(mpp->mpp, proxy)) {
|
||||
+ spin_lock(&tbl->hashwlock[i]);
|
||||
+ __mesh_path_del(tbl, node);
|
||||
+ spin_unlock(&tbl->hashwlock[i]);
|
||||
+ }
|
||||
+ }
|
||||
+ read_unlock_bh(&pathtbl_resize_lock);
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
static void table_flush_by_iface(struct mesh_table *tbl,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
@@ -892,6 +915,9 @@ int mesh_path_del(struct ieee80211_sub_i
|
||||
int hash_idx;
|
||||
int err = 0;
|
||||
|
||||
+ /* flush relevant mpp entries first */
|
||||
+ mpp_flush_by_proxy(sdata, addr);
|
||||
+
|
||||
read_lock_bh(&pathtbl_resize_lock);
|
||||
tbl = resize_dereference_mesh_paths();
|
||||
hash_idx = mesh_table_hash(addr, sdata, tbl);
|
||||
@ -1,27 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:55 +0100
|
||||
Subject: [PATCH] ath9k: write buffer related optimisation in
|
||||
ar5008_hw_set_channel_regs
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
|
||||
@@ -681,12 +681,13 @@ static void ar5008_hw_set_channel_regs(s
|
||||
phymode |= AR_PHY_FC_DYN2040_PRI_CH;
|
||||
|
||||
}
|
||||
+ ENABLE_REGWRITE_BUFFER(ah);
|
||||
REG_WRITE(ah, AR_PHY_TURBO, phymode);
|
||||
|
||||
+ /* This function do only REG_WRITE, so
|
||||
+ * we can include it to REGWRITE_BUFFER. */
|
||||
ath9k_hw_set11nmac2040(ah, chan);
|
||||
|
||||
- ENABLE_REGWRITE_BUFFER(ah);
|
||||
-
|
||||
REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
|
||||
REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
|
||||
|
||||
@ -0,0 +1,104 @@
|
||||
From: Henning Rogge <hrogge@gmail.com>
|
||||
Date: Wed, 3 Feb 2016 13:58:37 +0100
|
||||
Subject: [PATCH] mac80211: let unused MPP table entries timeout
|
||||
|
||||
Remember the last time when a mpp table entry is used for
|
||||
rx or tx and remove them after MESH_PATH_EXPIRE time.
|
||||
|
||||
Acked-by: Bob Copeland <me@bobcopeland.com>
|
||||
Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/mesh_pathtbl.c
|
||||
+++ b/net/mac80211/mesh_pathtbl.c
|
||||
@@ -942,6 +942,46 @@ enddel:
|
||||
}
|
||||
|
||||
/**
|
||||
+ * mpp_path_del - delete a mesh proxy path from the table
|
||||
+ *
|
||||
+ * @addr: addr address (ETH_ALEN length)
|
||||
+ * @sdata: local subif
|
||||
+ *
|
||||
+ * Returns: 0 if successful
|
||||
+ */
|
||||
+static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||
+{
|
||||
+ struct mesh_table *tbl;
|
||||
+ struct mesh_path *mpath;
|
||||
+ struct mpath_node *node;
|
||||
+ struct hlist_head *bucket;
|
||||
+ int hash_idx;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ read_lock_bh(&pathtbl_resize_lock);
|
||||
+ tbl = resize_dereference_mpp_paths();
|
||||
+ hash_idx = mesh_table_hash(addr, sdata, tbl);
|
||||
+ bucket = &tbl->hash_buckets[hash_idx];
|
||||
+
|
||||
+ spin_lock(&tbl->hashwlock[hash_idx]);
|
||||
+ hlist_for_each_entry(node, bucket, list) {
|
||||
+ mpath = node->mpath;
|
||||
+ if (mpath->sdata == sdata &&
|
||||
+ ether_addr_equal(addr, mpath->dst)) {
|
||||
+ __mesh_path_del(tbl, node);
|
||||
+ goto enddel;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ err = -ENXIO;
|
||||
+enddel:
|
||||
+ mesh_paths_generation++;
|
||||
+ spin_unlock(&tbl->hashwlock[hash_idx]);
|
||||
+ read_unlock_bh(&pathtbl_resize_lock);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* mesh_path_tx_pending - sends pending frames in a mesh path queue
|
||||
*
|
||||
* @mpath: mesh path to activate
|
||||
@@ -1157,6 +1197,17 @@ void mesh_path_expire(struct ieee80211_s
|
||||
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
|
||||
mesh_path_del(mpath->sdata, mpath->dst);
|
||||
}
|
||||
+
|
||||
+ tbl = rcu_dereference(mpp_paths);
|
||||
+ for_each_mesh_entry(tbl, node, i) {
|
||||
+ if (node->mpath->sdata != sdata)
|
||||
+ continue;
|
||||
+ mpath = node->mpath;
|
||||
+ if ((!(mpath->flags & MESH_PATH_FIXED)) &&
|
||||
+ time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
|
||||
+ mpp_path_del(mpath->sdata, mpath->dst);
|
||||
+ }
|
||||
+
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -2291,6 +2291,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
spin_lock_bh(&mppath->state_lock);
|
||||
if (!ether_addr_equal(mppath->mpp, mpp_addr))
|
||||
memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
|
||||
+ mppath->exp_time = jiffies;
|
||||
spin_unlock_bh(&mppath->state_lock);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -2171,8 +2171,11 @@ static struct sk_buff *ieee80211_build_h
|
||||
mpp_lookup = true;
|
||||
}
|
||||
|
||||
- if (mpp_lookup)
|
||||
+ if (mpp_lookup) {
|
||||
mppath = mpp_path_lookup(sdata, skb->data);
|
||||
+ if (mppath)
|
||||
+ mppath->exp_time = jiffies;
|
||||
+ }
|
||||
|
||||
if (mppath && mpath)
|
||||
mesh_path_del(mpath->sdata, mpath->dst);
|
||||
@ -1,26 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:56 +0100
|
||||
Subject: [PATCH] ath9k: ath9k_hw_set_4k_power_cal_tabl: use rmw buffer
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
|
||||
@@ -389,6 +389,7 @@ static void ath9k_hw_set_4k_power_cal_ta
|
||||
}
|
||||
}
|
||||
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
|
||||
(numXpdGain - 1) & 0x3);
|
||||
REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
|
||||
@@ -396,6 +397,7 @@ static void ath9k_hw_set_4k_power_cal_ta
|
||||
REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
|
||||
xpdGainValues[1]);
|
||||
REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
|
||||
for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
|
||||
regChainOffset = i * 0x1000;
|
||||
@ -0,0 +1,143 @@
|
||||
From: Henning Rogge <hrogge@gmail.com>
|
||||
Date: Wed, 3 Feb 2016 13:58:38 +0100
|
||||
Subject: [PATCH] mac80211: Unify mesh and mpp path removal function
|
||||
|
||||
mpp_path_del() and mesh_path_del() are mostly the same function.
|
||||
Move common code into a new static function.
|
||||
|
||||
Acked-by: Bob Copeland <me@bobcopeland.com>
|
||||
Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/mesh_pathtbl.c
|
||||
+++ b/net/mac80211/mesh_pathtbl.c
|
||||
@@ -55,16 +55,21 @@ int mpp_paths_generation;
|
||||
static DEFINE_RWLOCK(pathtbl_resize_lock);
|
||||
|
||||
|
||||
+static inline struct mesh_table *resize_dereference_paths(
|
||||
+ struct mesh_table __rcu *table)
|
||||
+{
|
||||
+ return rcu_dereference_protected(table,
|
||||
+ lockdep_is_held(&pathtbl_resize_lock));
|
||||
+}
|
||||
+
|
||||
static inline struct mesh_table *resize_dereference_mesh_paths(void)
|
||||
{
|
||||
- return rcu_dereference_protected(mesh_paths,
|
||||
- lockdep_is_held(&pathtbl_resize_lock));
|
||||
+ return resize_dereference_paths(mesh_paths);
|
||||
}
|
||||
|
||||
static inline struct mesh_table *resize_dereference_mpp_paths(void)
|
||||
{
|
||||
- return rcu_dereference_protected(mpp_paths,
|
||||
- lockdep_is_held(&pathtbl_resize_lock));
|
||||
+ return resize_dereference_paths(mpp_paths);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -899,14 +904,17 @@ void mesh_path_flush_by_iface(struct iee
|
||||
}
|
||||
|
||||
/**
|
||||
- * mesh_path_del - delete a mesh path from the table
|
||||
+ * table_path_del - delete a path from the mesh or mpp table
|
||||
*
|
||||
- * @addr: dst address (ETH_ALEN length)
|
||||
+ * @tbl: mesh or mpp path table
|
||||
* @sdata: local subif
|
||||
+ * @addr: dst address (ETH_ALEN length)
|
||||
*
|
||||
* Returns: 0 if successful
|
||||
*/
|
||||
-int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||
+static int table_path_del(struct mesh_table __rcu *rcu_tbl,
|
||||
+ struct ieee80211_sub_if_data *sdata,
|
||||
+ const u8 *addr)
|
||||
{
|
||||
struct mesh_table *tbl;
|
||||
struct mesh_path *mpath;
|
||||
@@ -915,11 +923,7 @@ int mesh_path_del(struct ieee80211_sub_i
|
||||
int hash_idx;
|
||||
int err = 0;
|
||||
|
||||
- /* flush relevant mpp entries first */
|
||||
- mpp_flush_by_proxy(sdata, addr);
|
||||
-
|
||||
- read_lock_bh(&pathtbl_resize_lock);
|
||||
- tbl = resize_dereference_mesh_paths();
|
||||
+ tbl = resize_dereference_paths(rcu_tbl);
|
||||
hash_idx = mesh_table_hash(addr, sdata, tbl);
|
||||
bucket = &tbl->hash_buckets[hash_idx];
|
||||
|
||||
@@ -935,9 +939,30 @@ int mesh_path_del(struct ieee80211_sub_i
|
||||
|
||||
err = -ENXIO;
|
||||
enddel:
|
||||
- mesh_paths_generation++;
|
||||
spin_unlock(&tbl->hashwlock[hash_idx]);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mesh_path_del - delete a mesh path from the table
|
||||
+ *
|
||||
+ * @addr: dst address (ETH_ALEN length)
|
||||
+ * @sdata: local subif
|
||||
+ *
|
||||
+ * Returns: 0 if successful
|
||||
+ */
|
||||
+int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||
+{
|
||||
+ int err = 0;
|
||||
+
|
||||
+ /* flush relevant mpp entries first */
|
||||
+ mpp_flush_by_proxy(sdata, addr);
|
||||
+
|
||||
+ read_lock_bh(&pathtbl_resize_lock);
|
||||
+ err = table_path_del(mesh_paths, sdata, addr);
|
||||
+ mesh_paths_generation++;
|
||||
read_unlock_bh(&pathtbl_resize_lock);
|
||||
+
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -951,33 +976,13 @@ enddel:
|
||||
*/
|
||||
static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||
{
|
||||
- struct mesh_table *tbl;
|
||||
- struct mesh_path *mpath;
|
||||
- struct mpath_node *node;
|
||||
- struct hlist_head *bucket;
|
||||
- int hash_idx;
|
||||
int err = 0;
|
||||
|
||||
read_lock_bh(&pathtbl_resize_lock);
|
||||
- tbl = resize_dereference_mpp_paths();
|
||||
- hash_idx = mesh_table_hash(addr, sdata, tbl);
|
||||
- bucket = &tbl->hash_buckets[hash_idx];
|
||||
-
|
||||
- spin_lock(&tbl->hashwlock[hash_idx]);
|
||||
- hlist_for_each_entry(node, bucket, list) {
|
||||
- mpath = node->mpath;
|
||||
- if (mpath->sdata == sdata &&
|
||||
- ether_addr_equal(addr, mpath->dst)) {
|
||||
- __mesh_path_del(tbl, node);
|
||||
- goto enddel;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- err = -ENXIO;
|
||||
-enddel:
|
||||
- mesh_paths_generation++;
|
||||
- spin_unlock(&tbl->hashwlock[hash_idx]);
|
||||
+ err = table_path_del(mpp_paths, sdata, addr);
|
||||
+ mpp_paths_generation++;
|
||||
read_unlock_bh(&pathtbl_resize_lock);
|
||||
+
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:57 +0100
|
||||
Subject: [PATCH] ath9k: use rmw buffer in ath9k_hw_set_operating_mode
|
||||
and ath9k_hw_reset
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -1227,6 +1227,7 @@ static void ath9k_hw_set_operating_mode(
|
||||
u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC;
|
||||
u32 set = AR_STA_ID1_KSRCH_MODE;
|
||||
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
switch (opmode) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (!AR_SREV_9340_13(ah)) {
|
||||
@@ -1248,6 +1249,7 @@ static void ath9k_hw_set_operating_mode(
|
||||
break;
|
||||
}
|
||||
REG_RMW(ah, AR_STA_ID1, set, mask);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
}
|
||||
|
||||
void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
|
||||
@@ -1960,6 +1962,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
||||
if (!ath9k_hw_mci_is_enabled(ah))
|
||||
REG_WRITE(ah, AR_OBS, 8);
|
||||
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
if (ah->config.rx_intr_mitigation) {
|
||||
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, ah->config.rimt_last);
|
||||
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, ah->config.rimt_first);
|
||||
@@ -1969,6 +1972,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
||||
REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300);
|
||||
REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750);
|
||||
}
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
|
||||
ath9k_hw_init_bb(ah, chan);
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
From: Sven Eckelmann <sven.eckelmann@open-mesh.com>
|
||||
Date: Tue, 2 Feb 2016 08:12:26 +0100
|
||||
Subject: [PATCH] mac80211: minstrel: Change expected throughput unit back to
|
||||
Kbps
|
||||
|
||||
The change from cur_tp to the function
|
||||
minstrel_get_tp_avg/minstrel_ht_get_tp_avg changed the unit used for the
|
||||
current throughput. For example in minstrel_ht the correct
|
||||
conversion between them would be:
|
||||
|
||||
mrs->cur_tp / 10 == minstrel_ht_get_tp_avg(..).
|
||||
|
||||
This factor 10 must also be included in the calculation of
|
||||
minstrel_get_expected_throughput and minstrel_ht_get_expected_throughput to
|
||||
return values with the unit [Kbps] instead of [10Kbps]. Otherwise routing
|
||||
algorithms like B.A.T.M.A.N. V will make incorrect decision based on these
|
||||
values. Its kernel based implementation expects expected_throughput always
|
||||
to have the unit [Kbps] and not sometimes [10Kbps] and sometimes [Kbps].
|
||||
|
||||
The same requirement has iw or olsrdv2's nl80211 based statistics module
|
||||
which retrieve the same data via NL80211_STA_INFO_TX_BITRATE.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Fixes: 6a27b2c40b48 ("mac80211: restructure per-rate throughput calculation into function")
|
||||
Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel.c
|
||||
+++ b/net/mac80211/rc80211_minstrel.c
|
||||
@@ -711,7 +711,7 @@ static u32 minstrel_get_expected_through
|
||||
* computing cur_tp
|
||||
*/
|
||||
tmp_mrs = &mi->r[idx].stats;
|
||||
- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma);
|
||||
+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10;
|
||||
tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
|
||||
|
||||
return tmp_cur_tp;
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -1335,7 +1335,8 @@ static u32 minstrel_ht_get_expected_thro
|
||||
prob = mi->groups[i].rates[j].prob_ewma;
|
||||
|
||||
/* convert tp_avg from pkt per second in kbps */
|
||||
- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024;
|
||||
+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10;
|
||||
+ tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024;
|
||||
|
||||
return tp_avg;
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:58 +0100
|
||||
Subject: [PATCH] ath9k: ath9k_hw_4k_set_board_values: use rmw buffer
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
|
||||
@@ -1082,6 +1082,7 @@ static void ath9k_hw_4k_set_board_values
|
||||
mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
|
||||
pwrctrl = mask * bb_desired_scale;
|
||||
clr = mask * 0x1f;
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
|
||||
REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
|
||||
REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
|
||||
@@ -1096,6 +1097,7 @@ static void ath9k_hw_4k_set_board_values
|
||||
clr = mask * 0x1f;
|
||||
REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
|
||||
REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,307 @@
|
||||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Sun, 7 Feb 2016 18:08:24 +0100
|
||||
Subject: [PATCH] brcmfmac: Increase nr of supported flowrings.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
New generation devices have firmware which has more than 256 flowrings.
|
||||
E.g. following debugging message comes from 14e4:4365 BCM4366:
|
||||
[ 194.606245] brcmfmac: brcmf_pcie_init_ringbuffers Nr of flowrings is 264
|
||||
|
||||
At various code places (related to flowrings) we were using u8 which
|
||||
could lead to storing wrong number or infinite loops when indexing with
|
||||
this type. This issue was quite easy to spot in brcmf_flowring_detach
|
||||
where it led to infinite loop e.g. on failed initialization.
|
||||
|
||||
This patch switches code to proper types and increases the maximum
|
||||
number of supported flowrings to 512.
|
||||
|
||||
Originally this change was sent in September 2015, but back it was
|
||||
causing a regression on BCM43602 resulting in:
|
||||
Unable to handle kernel NULL pointer dereference at virtual address ...
|
||||
|
||||
The reason for this regression was missing update (s/u8/u16) of struct
|
||||
brcmf_flowring_ring. This problem was handled in 9f64df9 ("brcmfmac: Fix
|
||||
bug in flowring management."). Starting with that it's safe to apply
|
||||
this original patch as it doesn't cause a regression anymore.
|
||||
|
||||
This patch fixes an infinite loop on BCM4366 which is supported since
|
||||
4.4 so it makes sense to apply it to stable 4.4+.
|
||||
|
||||
Cc: <stable@vger.kernel.org> # 4.4+
|
||||
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>
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
|
||||
@@ -32,7 +32,7 @@
|
||||
#define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
|
||||
#define BRCMF_FLOWRING_INVALID_IFIDX 0xff
|
||||
|
||||
-#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16)
|
||||
+#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
|
||||
#define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
|
||||
|
||||
static const u8 brcmf_flowring_prio2fifo[] = {
|
||||
@@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f
|
||||
u8 prio, u8 ifidx)
|
||||
{
|
||||
struct brcmf_flowring_hash *hash;
|
||||
- u8 hash_idx;
|
||||
+ u16 hash_idx;
|
||||
u32 i;
|
||||
bool found;
|
||||
bool sta;
|
||||
@@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f
|
||||
}
|
||||
hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
|
||||
BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
|
||||
+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
|
||||
found = false;
|
||||
hash = flow->hash;
|
||||
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
|
||||
@@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f
|
||||
break;
|
||||
}
|
||||
hash_idx++;
|
||||
+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
|
||||
}
|
||||
if (found)
|
||||
return hash[hash_idx].flowid;
|
||||
@@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_f
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
struct brcmf_flowring_hash *hash;
|
||||
- u8 hash_idx;
|
||||
+ u16 hash_idx;
|
||||
u32 i;
|
||||
bool found;
|
||||
u8 fifo;
|
||||
@@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_f
|
||||
}
|
||||
hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
|
||||
BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
|
||||
+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
|
||||
found = false;
|
||||
hash = flow->hash;
|
||||
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
|
||||
@@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_f
|
||||
break;
|
||||
}
|
||||
hash_idx++;
|
||||
+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
|
||||
}
|
||||
if (found) {
|
||||
for (i = 0; i < flow->nrofrings; i++) {
|
||||
@@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_f
|
||||
}
|
||||
|
||||
|
||||
-u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
|
||||
+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
|
||||
@@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowr
|
||||
}
|
||||
|
||||
|
||||
-static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
|
||||
+static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
|
||||
bool blocked)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
@@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct
|
||||
}
|
||||
|
||||
|
||||
-void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
|
||||
+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
- u8 hash_idx;
|
||||
+ u16 hash_idx;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ring = flow->rings[flowid];
|
||||
@@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_
|
||||
}
|
||||
|
||||
|
||||
-u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
|
||||
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
@@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_
|
||||
}
|
||||
|
||||
|
||||
-struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
|
||||
+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
struct sk_buff *skb;
|
||||
@@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(s
|
||||
}
|
||||
|
||||
|
||||
-void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
|
||||
+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
@@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcm
|
||||
}
|
||||
|
||||
|
||||
-u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
|
||||
+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
|
||||
@@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flo
|
||||
}
|
||||
|
||||
|
||||
-void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
|
||||
+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
|
||||
@@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_fl
|
||||
}
|
||||
|
||||
|
||||
-u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid)
|
||||
+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
- u8 hash_idx;
|
||||
+ u16 hash_idx;
|
||||
|
||||
ring = flow->rings[flowid];
|
||||
hash_idx = ring->hash_id;
|
||||
@@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_
|
||||
struct brcmf_pub *drvr = bus_if->drvr;
|
||||
struct brcmf_flowring_tdls_entry *search;
|
||||
struct brcmf_flowring_tdls_entry *remove;
|
||||
- u8 flowid;
|
||||
+ u16 flowid;
|
||||
|
||||
for (flowid = 0; flowid < flow->nrofrings; flowid++) {
|
||||
if (flow->rings[flowid])
|
||||
@@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode(
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
|
||||
struct brcmf_pub *drvr = bus_if->drvr;
|
||||
u32 i;
|
||||
- u8 flowid;
|
||||
+ u16 flowid;
|
||||
|
||||
if (flow->addr_mode[ifidx] != addr_mode) {
|
||||
for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
|
||||
@@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct b
|
||||
struct brcmf_flowring_tdls_entry *prev;
|
||||
struct brcmf_flowring_tdls_entry *search;
|
||||
u32 i;
|
||||
- u8 flowid;
|
||||
+ u16 flowid;
|
||||
bool sta;
|
||||
|
||||
sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
|
||||
@@ -16,7 +16,7 @@
|
||||
#define BRCMFMAC_FLOWRING_H
|
||||
|
||||
|
||||
-#define BRCMF_FLOWRING_HASHSIZE 256
|
||||
+#define BRCMF_FLOWRING_HASHSIZE 512 /* has to be 2^x */
|
||||
#define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ struct brcmf_flowring_hash {
|
||||
u8 mac[ETH_ALEN];
|
||||
u8 fifo;
|
||||
u8 ifidx;
|
||||
- u8 flowid;
|
||||
+ u16 flowid;
|
||||
};
|
||||
|
||||
enum ring_status {
|
||||
@@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_f
|
||||
u8 prio, u8 ifidx);
|
||||
u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
|
||||
u8 prio, u8 ifidx);
|
||||
-void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
|
||||
-void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
|
||||
-u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
|
||||
-u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
|
||||
+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid);
|
||||
+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid);
|
||||
+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid);
|
||||
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
|
||||
struct sk_buff *skb);
|
||||
-struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
|
||||
-void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
|
||||
+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid);
|
||||
+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
|
||||
struct sk_buff *skb);
|
||||
-u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid);
|
||||
-u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid);
|
||||
+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid);
|
||||
+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid);
|
||||
struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings);
|
||||
void brcmf_flowring_detach(struct brcmf_flowring *flow);
|
||||
void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
|
||||
@@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create(
|
||||
}
|
||||
|
||||
|
||||
-static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
|
||||
+static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)
|
||||
{
|
||||
struct brcmf_flowring *flow = msgbuf->flow;
|
||||
struct brcmf_commonring *commonring;
|
||||
@@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct
|
||||
}
|
||||
|
||||
|
||||
-void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid)
|
||||
+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
|
||||
{
|
||||
struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
|
||||
struct msgbuf_tx_flowring_delete_req *delete;
|
||||
@@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brc
|
||||
u32 count;
|
||||
|
||||
if_msgbuf = drvr->bus_if->msgbuf;
|
||||
+
|
||||
+ if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) {
|
||||
+ brcmf_err("driver not configured for this many flowrings %d\n",
|
||||
+ if_msgbuf->nrof_flowrings);
|
||||
+ if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1;
|
||||
+ }
|
||||
+
|
||||
msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL);
|
||||
if (!msgbuf)
|
||||
goto fail;
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
|
||||
int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
|
||||
-void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
|
||||
+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid);
|
||||
int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
|
||||
void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
|
||||
#else
|
||||
@ -1,27 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:29:59 +0100
|
||||
Subject: [PATCH] ath9k: ath9k_hw_analog_shift_rmw: use REG_RMW
|
||||
|
||||
use REG_RMW in ath9k_hw_analog_shift_rmw.
|
||||
It will double execution speed on usb bus.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
|
||||
@@ -27,12 +27,7 @@ void ath9k_hw_analog_shift_regwrite(stru
|
||||
void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
|
||||
u32 shift, u32 val)
|
||||
{
|
||||
- u32 regVal;
|
||||
-
|
||||
- regVal = REG_READ(ah, reg) & ~mask;
|
||||
- regVal |= (val << shift) & mask;
|
||||
-
|
||||
- REG_WRITE(ah, reg, regVal);
|
||||
+ REG_RMW(ah, reg, ((val << shift) & mask), mask);
|
||||
|
||||
if (ah->config.analog_shiftreg)
|
||||
udelay(100);
|
||||
@ -0,0 +1,22 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 8 Feb 2016 14:24:36 +0100
|
||||
Subject: [PATCH] cfg80211: fix faulty variable initialization in
|
||||
ieee80211_amsdu_to_8023s
|
||||
|
||||
reuse_skb is set to true if the code decides to use the last segment.
|
||||
Fixes a memory leak
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/wireless/util.c
|
||||
+++ b/net/wireless/util.c
|
||||
@@ -676,7 +676,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
|
||||
u8 *payload;
|
||||
int offset = 0, remaining, err;
|
||||
struct ethhdr eth;
|
||||
- bool reuse_skb = true;
|
||||
+ bool reuse_skb = false;
|
||||
bool last = false;
|
||||
|
||||
if (has_80211_header) {
|
||||
@ -1,47 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:30:01 +0100
|
||||
Subject: [PATCH] ath9k: use REG_RMW and rmw buffer in
|
||||
ath9k_hw_4k_set_gain
|
||||
|
||||
it is possible to reduce time needed for this function
|
||||
by rplacing REG_WRITE with REG_RMW (plus dummy 0) and putt all commands
|
||||
in same buffer.
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
|
||||
@@ -772,15 +772,14 @@ static void ath9k_hw_4k_set_gain(struct
|
||||
struct ar5416_eeprom_4k *eep,
|
||||
u8 txRxAttenLocal)
|
||||
{
|
||||
- REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0,
|
||||
- pModal->antCtrlChain[0]);
|
||||
-
|
||||
- REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0),
|
||||
- (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
|
||||
- ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
|
||||
- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
|
||||
- SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
|
||||
- SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
+ REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0,
|
||||
+ pModal->antCtrlChain[0], 0);
|
||||
+
|
||||
+ REG_RMW(ah, AR_PHY_TIMING_CTRL4(0),
|
||||
+ SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
|
||||
+ SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF),
|
||||
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF);
|
||||
|
||||
if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
|
||||
AR5416_EEP_MINOR_VER_3) {
|
||||
@@ -819,6 +818,7 @@ static void ath9k_hw_4k_set_gain(struct
|
||||
AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
|
||||
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
|
||||
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -0,0 +1,132 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 8 Feb 2016 14:33:19 +0100
|
||||
Subject: [PATCH] cfg80211: reuse existing page fragments in A-MSDU rx
|
||||
|
||||
This massively reduces data copying and thus improves rx performance
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/wireless/util.c
|
||||
+++ b/net/wireless/util.c
|
||||
@@ -644,23 +644,93 @@ int ieee80211_data_from_8023(struct sk_b
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_data_from_8023);
|
||||
|
||||
+static void
|
||||
+__frame_add_frag(struct sk_buff *skb, struct page *page,
|
||||
+ void *ptr, int len, int size)
|
||||
+{
|
||||
+ struct skb_shared_info *sh = skb_shinfo(skb);
|
||||
+ int page_offset;
|
||||
+
|
||||
+ atomic_inc(&page->_count);
|
||||
+ page_offset = ptr - page_address(page);
|
||||
+ skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
|
||||
+ int offset, int len)
|
||||
+{
|
||||
+ struct skb_shared_info *sh = skb_shinfo(skb);
|
||||
+ const skb_frag_t *frag = &sh->frags[-1];
|
||||
+ struct page *frag_page;
|
||||
+ void *frag_ptr;
|
||||
+ int frag_len, frag_size;
|
||||
+ int head_size = skb->len - skb->data_len;
|
||||
+ int cur_len;
|
||||
+
|
||||
+ frag_page = virt_to_head_page(skb->head);
|
||||
+ frag_ptr = skb->data;
|
||||
+ frag_size = head_size;
|
||||
+
|
||||
+ while (offset >= frag_size) {
|
||||
+ offset -= frag_size;
|
||||
+ frag++;
|
||||
+ frag_page = skb_frag_page(frag);
|
||||
+ frag_ptr = skb_frag_address(frag);
|
||||
+ frag_size = skb_frag_size(frag);
|
||||
+ }
|
||||
+
|
||||
+ frag_ptr += offset;
|
||||
+ frag_len = frag_size - offset;
|
||||
+
|
||||
+ cur_len = min(len, frag_len);
|
||||
+
|
||||
+ __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
|
||||
+ len -= cur_len;
|
||||
+
|
||||
+ while (len > 0) {
|
||||
+ frag++;
|
||||
+ frag_len = skb_frag_size(frag);
|
||||
+ cur_len = min(len, frag_len);
|
||||
+ __frame_add_frag(frame, skb_frag_page(frag),
|
||||
+ skb_frag_address(frag), cur_len, frag_len);
|
||||
+ len -= cur_len;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static struct sk_buff *
|
||||
__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
|
||||
- int offset, int len)
|
||||
+ int offset, int len, bool reuse_frag)
|
||||
{
|
||||
struct sk_buff *frame;
|
||||
+ int cur_len = len;
|
||||
|
||||
if (skb->len - offset < len)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
+ * When reusing framents, copy some data to the head to simplify
|
||||
+ * ethernet header handling and speed up protocol header processing
|
||||
+ * in the stack later.
|
||||
+ */
|
||||
+ if (reuse_frag)
|
||||
+ cur_len = min_t(int, len, 32);
|
||||
+
|
||||
+ /*
|
||||
* Allocate and reserve two bytes more for payload
|
||||
* alignment since sizeof(struct ethhdr) is 14.
|
||||
*/
|
||||
- frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len);
|
||||
+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
|
||||
|
||||
skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
|
||||
- skb_copy_bits(skb, offset, skb_put(frame, len), len);
|
||||
+ skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
|
||||
+
|
||||
+ len -= cur_len;
|
||||
+ if (!len)
|
||||
+ return frame;
|
||||
+
|
||||
+ offset += cur_len;
|
||||
+ __ieee80211_amsdu_copy_frag(skb, frame, offset, len);
|
||||
|
||||
return frame;
|
||||
}
|
||||
@@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
|
||||
u8 *payload;
|
||||
int offset = 0, remaining, err;
|
||||
struct ethhdr eth;
|
||||
+ bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
|
||||
bool reuse_skb = false;
|
||||
bool last = false;
|
||||
|
||||
@@ -703,12 +774,13 @@ void ieee80211_amsdu_to_8023s(struct sk_
|
||||
offset += sizeof(struct ethhdr);
|
||||
/* reuse skb for the last subframe */
|
||||
last = remaining <= subframe_len + padding;
|
||||
- if (!skb_is_nonlinear(skb) && last) {
|
||||
+ if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
|
||||
skb_pull(skb, offset);
|
||||
frame = skb;
|
||||
reuse_skb = true;
|
||||
} else {
|
||||
- frame = __ieee80211_amsdu_copy(skb, hlen, offset, len);
|
||||
+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
|
||||
+ reuse_frag);
|
||||
if (!frame)
|
||||
goto purge;
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
From: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Date: Sun, 22 Mar 2015 19:30:03 +0100
|
||||
Subject: [PATCH] ath9k: use REG_RMW and rmw buffer in
|
||||
ath9k_hw_def_set_gain
|
||||
|
||||
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
|
||||
@@ -466,6 +466,7 @@ static void ath9k_hw_def_set_gain(struct
|
||||
struct ar5416_eeprom_def *eep,
|
||||
u8 txRxAttenLocal, int regChainOffset, int i)
|
||||
{
|
||||
+ ENABLE_REG_RMW_BUFFER(ah);
|
||||
if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
|
||||
txRxAttenLocal = pModal->txRxAttenCh[i];
|
||||
|
||||
@@ -483,16 +484,12 @@ static void ath9k_hw_def_set_gain(struct
|
||||
AR_PHY_GAIN_2GHZ_XATTEN2_DB,
|
||||
pModal->xatten2Db[i]);
|
||||
} else {
|
||||
- REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
|
||||
- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
|
||||
- ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
|
||||
- | SM(pModal-> bswMargin[i],
|
||||
- AR_PHY_GAIN_2GHZ_BSW_MARGIN));
|
||||
- REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
|
||||
- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
|
||||
- ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
|
||||
- | SM(pModal->bswAtten[i],
|
||||
- AR_PHY_GAIN_2GHZ_BSW_ATTEN));
|
||||
+ REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
|
||||
+ SM(pModal-> bswMargin[i], AR_PHY_GAIN_2GHZ_BSW_MARGIN),
|
||||
+ AR_PHY_GAIN_2GHZ_BSW_MARGIN);
|
||||
+ REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
|
||||
+ SM(pModal->bswAtten[i], AR_PHY_GAIN_2GHZ_BSW_ATTEN),
|
||||
+ AR_PHY_GAIN_2GHZ_BSW_ATTEN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,17 +501,14 @@ static void ath9k_hw_def_set_gain(struct
|
||||
AR_PHY_RXGAIN + regChainOffset,
|
||||
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]);
|
||||
} else {
|
||||
- REG_WRITE(ah,
|
||||
- AR_PHY_RXGAIN + regChainOffset,
|
||||
- (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) &
|
||||
- ~AR_PHY_RXGAIN_TXRX_ATTEN)
|
||||
- | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN));
|
||||
- REG_WRITE(ah,
|
||||
- AR_PHY_GAIN_2GHZ + regChainOffset,
|
||||
- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
|
||||
- ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
|
||||
- SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
|
||||
+ REG_RMW(ah, AR_PHY_RXGAIN + regChainOffset,
|
||||
+ SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN),
|
||||
+ AR_PHY_RXGAIN_TXRX_ATTEN);
|
||||
+ REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
|
||||
+ SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN),
|
||||
+ AR_PHY_GAIN_2GHZ_RXTX_MARGIN);
|
||||
}
|
||||
+ REG_RMW_BUFFER_FLUSH(ah);
|
||||
}
|
||||
|
||||
static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
|
||||
@ -0,0 +1,36 @@
|
||||
From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
|
||||
Date: Wed, 10 Feb 2016 16:08:17 +0100
|
||||
Subject: [PATCH] mac80211: fix wiphy supported_band access
|
||||
|
||||
Fix wiphy supported_band access in tx radiotap parsing. In particular,
|
||||
info->band is always set to 0 (IEEE80211_BAND_2GHZ) since it has not
|
||||
assigned yet. This cause a kernel crash on 5GHz only devices.
|
||||
Move ieee80211_parse_tx_radiotap() after info->band assignment
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1890,10 +1890,6 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
|
||||
IEEE80211_TX_CTL_INJECTED;
|
||||
|
||||
- /* process and remove the injection radiotap header */
|
||||
- if (!ieee80211_parse_tx_radiotap(local, skb))
|
||||
- goto fail;
|
||||
-
|
||||
rcu_read_lock();
|
||||
|
||||
/*
|
||||
@@ -1955,6 +1951,10 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
goto fail_rcu;
|
||||
|
||||
info->band = chandef->chan->band;
|
||||
+ /* process and remove the injection radiotap header */
|
||||
+ if (!ieee80211_parse_tx_radiotap(local, skb))
|
||||
+ goto fail_rcu;
|
||||
+
|
||||
ieee80211_xmit(sdata, NULL, skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Fri, 6 Mar 2015 18:40:38 +0100
|
||||
Subject: [PATCH] brcmfmac: Fix oops when SDIO device is removed.
|
||||
|
||||
On removal of SDIO card both functions of card will be getting
|
||||
a remove call. When the first is hanging in ctrl frame xmit then
|
||||
the second will cause oops. This patch fixes the xmit ctrl
|
||||
handling in case of serious errors and also limits the handling
|
||||
for remove to function 1 only.
|
||||
|
||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Signed-off-by: Hante Meuleman <meuleman@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/bcmsdh.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
@@ -1194,7 +1194,7 @@ static void brcmf_ops_sdio_remove(struct
|
||||
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
|
||||
brcmf_dbg(SDIO, "Function: %d\n", func->num);
|
||||
|
||||
- if (func->num != 1 && func->num != 2)
|
||||
+ if (func->num != 1)
|
||||
return;
|
||||
|
||||
bus_if = dev_get_drvdata(&func->dev);
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -2740,6 +2740,11 @@ static void brcmf_sdio_dpc(struct brcmf_
|
||||
if ((bus->sdiodev->state != BRCMF_SDIOD_DATA) || (err != 0)) {
|
||||
brcmf_err("failed backplane access over SDIO, halting operation\n");
|
||||
atomic_set(&bus->intstatus, 0);
|
||||
+ if (bus->ctrl_frame_stat) {
|
||||
+ bus->ctrl_frame_err = -ENODEV;
|
||||
+ bus->ctrl_frame_stat = false;
|
||||
+ brcmf_sdio_wait_event_wakeup(bus);
|
||||
+ }
|
||||
} else if (atomic_read(&bus->intstatus) ||
|
||||
atomic_read(&bus->ipend) > 0 ||
|
||||
(!atomic_read(&bus->fcstate) &&
|
||||
@ -1,157 +0,0 @@
|
||||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Fri, 6 Mar 2015 18:40:39 +0100
|
||||
Subject: [PATCH] brcmfmac: Simplify watchdog sleep.
|
||||
|
||||
The watchdog thread is used to put the SDIO bus to sleep when the
|
||||
system is idling. This patch simplifies the way it is determined
|
||||
when sleep can be entered.
|
||||
|
||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Signed-off-by: Hante Meuleman <meuleman@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/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -485,10 +485,9 @@ struct brcmf_sdio {
|
||||
#endif /* DEBUG */
|
||||
|
||||
uint clkstate; /* State of sd and backplane clock(s) */
|
||||
- bool activity; /* Activity flag for clock down */
|
||||
s32 idletime; /* Control for activity timeout */
|
||||
- s32 idlecount; /* Activity timeout counter */
|
||||
- s32 idleclock; /* How to set bus driver when idle */
|
||||
+ s32 idlecount; /* Activity timeout counter */
|
||||
+ s32 idleclock; /* How to set bus driver when idle */
|
||||
bool rxflow_mode; /* Rx flow control mode */
|
||||
bool rxflow; /* Is rx flow control on */
|
||||
bool alp_only; /* Don't use HT clock (ALP only) */
|
||||
@@ -511,6 +510,7 @@ struct brcmf_sdio {
|
||||
struct workqueue_struct *brcmf_wq;
|
||||
struct work_struct datawork;
|
||||
atomic_t dpc_tskcnt;
|
||||
+ atomic_t dpc_running;
|
||||
|
||||
bool txoff; /* Transmit flow-controlled */
|
||||
struct brcmf_sdio_count sdcnt;
|
||||
@@ -959,13 +959,8 @@ static int brcmf_sdio_clkctl(struct brcm
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
/* Early exit if we're already there */
|
||||
- if (bus->clkstate == target) {
|
||||
- if (target == CLK_AVAIL) {
|
||||
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
|
||||
- bus->activity = true;
|
||||
- }
|
||||
+ if (bus->clkstate == target)
|
||||
return 0;
|
||||
- }
|
||||
|
||||
switch (target) {
|
||||
case CLK_AVAIL:
|
||||
@@ -975,7 +970,6 @@ static int brcmf_sdio_clkctl(struct brcm
|
||||
/* Now request HT Avail on the backplane */
|
||||
brcmf_sdio_htclk(bus, true, pendok);
|
||||
brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
|
||||
- bus->activity = true;
|
||||
break;
|
||||
|
||||
case CLK_SDONLY:
|
||||
@@ -1024,17 +1018,6 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *
|
||||
|
||||
/* Going to sleep */
|
||||
if (sleep) {
|
||||
- /* Don't sleep if something is pending */
|
||||
- if (atomic_read(&bus->intstatus) ||
|
||||
- atomic_read(&bus->ipend) > 0 ||
|
||||
- bus->ctrl_frame_stat ||
|
||||
- (!atomic_read(&bus->fcstate) &&
|
||||
- brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
|
||||
- data_ok(bus))) {
|
||||
- err = -EBUSY;
|
||||
- goto done;
|
||||
- }
|
||||
-
|
||||
clkcsr = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_CHIPCLKCSR,
|
||||
&err);
|
||||
@@ -1045,11 +1028,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *
|
||||
SBSDIO_ALP_AVAIL_REQ, &err);
|
||||
}
|
||||
err = brcmf_sdio_kso_control(bus, false);
|
||||
- /* disable watchdog */
|
||||
- if (!err)
|
||||
- brcmf_sdio_wd_timer(bus, 0);
|
||||
} else {
|
||||
- bus->idlecount = 0;
|
||||
err = brcmf_sdio_kso_control(bus, true);
|
||||
}
|
||||
if (err) {
|
||||
@@ -3566,7 +3545,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *b
|
||||
queue_work(bus->brcmf_wq, &bus->datawork);
|
||||
}
|
||||
|
||||
-static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
|
||||
+static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
|
||||
{
|
||||
brcmf_dbg(TIMER, "Enter\n");
|
||||
|
||||
@@ -3627,22 +3606,21 @@ static bool brcmf_sdio_bus_watchdog(stru
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* On idle timeout clear activity flag and/or turn off clock */
|
||||
- if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
|
||||
- if (++bus->idlecount >= bus->idletime) {
|
||||
+ if ((atomic_read(&bus->dpc_tskcnt) == 0) &&
|
||||
+ (atomic_read(&bus->dpc_running) == 0) &&
|
||||
+ (bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
|
||||
+ bus->idlecount++;
|
||||
+ if (bus->idlecount > bus->idletime) {
|
||||
+ brcmf_dbg(SDIO, "idle\n");
|
||||
+ sdio_claim_host(bus->sdiodev->func[1]);
|
||||
+ brcmf_sdio_wd_timer(bus, 0);
|
||||
bus->idlecount = 0;
|
||||
- if (bus->activity) {
|
||||
- bus->activity = false;
|
||||
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
|
||||
- } else {
|
||||
- brcmf_dbg(SDIO, "idle\n");
|
||||
- sdio_claim_host(bus->sdiodev->func[1]);
|
||||
- brcmf_sdio_bus_sleep(bus, true, false);
|
||||
- sdio_release_host(bus->sdiodev->func[1]);
|
||||
- }
|
||||
+ brcmf_sdio_bus_sleep(bus, true, false);
|
||||
+ sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
||||
+ } else {
|
||||
+ bus->idlecount = 0;
|
||||
}
|
||||
-
|
||||
- return (atomic_read(&bus->ipend) > 0);
|
||||
}
|
||||
|
||||
static void brcmf_sdio_dataworker(struct work_struct *work)
|
||||
@@ -3651,8 +3629,11 @@ static void brcmf_sdio_dataworker(struct
|
||||
datawork);
|
||||
|
||||
while (atomic_read(&bus->dpc_tskcnt)) {
|
||||
+ atomic_set(&bus->dpc_running, 1);
|
||||
atomic_set(&bus->dpc_tskcnt, 0);
|
||||
brcmf_sdio_dpc(bus);
|
||||
+ bus->idlecount = 0;
|
||||
+ atomic_set(&bus->dpc_running, 0);
|
||||
}
|
||||
if (brcmf_sdiod_freezing(bus->sdiodev)) {
|
||||
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN);
|
||||
@@ -4154,6 +4135,7 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
|
||||
}
|
||||
/* Initialize DPC thread */
|
||||
atomic_set(&bus->dpc_tskcnt, 0);
|
||||
+ atomic_set(&bus->dpc_running, 0);
|
||||
|
||||
/* Assign bus interface call back */
|
||||
bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
|
||||
@ -1,83 +0,0 @@
|
||||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Fri, 6 Mar 2015 18:40:40 +0100
|
||||
Subject: [PATCH] brcmfmac: Fix possible race-condition.
|
||||
|
||||
SDIO is using a "shared" variable to handoff ctl frames to DPC
|
||||
and to see when they are done. In a timeout situation this can
|
||||
lead to erroneous situation where DPC started to handle the ctl
|
||||
frame while the timeout expired. This patch will fix this by
|
||||
adding locking around the shared variable.
|
||||
|
||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Signed-off-by: Hante Meuleman <meuleman@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/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -2700,11 +2700,13 @@ static void brcmf_sdio_dpc(struct brcmf_
|
||||
if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
|
||||
data_ok(bus)) {
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
- err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
|
||||
- bus->ctrl_frame_len);
|
||||
+ if (bus->ctrl_frame_stat) {
|
||||
+ err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
|
||||
+ bus->ctrl_frame_len);
|
||||
+ bus->ctrl_frame_err = err;
|
||||
+ bus->ctrl_frame_stat = false;
|
||||
+ }
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
- bus->ctrl_frame_err = err;
|
||||
- bus->ctrl_frame_stat = false;
|
||||
brcmf_sdio_wait_event_wakeup(bus);
|
||||
}
|
||||
/* Send queued frames (limit 1 if rx may still be pending) */
|
||||
@@ -2720,9 +2722,13 @@ static void brcmf_sdio_dpc(struct brcmf_
|
||||
brcmf_err("failed backplane access over SDIO, halting operation\n");
|
||||
atomic_set(&bus->intstatus, 0);
|
||||
if (bus->ctrl_frame_stat) {
|
||||
- bus->ctrl_frame_err = -ENODEV;
|
||||
- bus->ctrl_frame_stat = false;
|
||||
- brcmf_sdio_wait_event_wakeup(bus);
|
||||
+ sdio_claim_host(bus->sdiodev->func[1]);
|
||||
+ if (bus->ctrl_frame_stat) {
|
||||
+ bus->ctrl_frame_err = -ENODEV;
|
||||
+ bus->ctrl_frame_stat = false;
|
||||
+ brcmf_sdio_wait_event_wakeup(bus);
|
||||
+ }
|
||||
+ sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
||||
} else if (atomic_read(&bus->intstatus) ||
|
||||
atomic_read(&bus->ipend) > 0 ||
|
||||
@@ -2930,15 +2936,20 @@ brcmf_sdio_bus_txctl(struct device *dev,
|
||||
brcmf_sdio_trigger_dpc(bus);
|
||||
wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
|
||||
msecs_to_jiffies(CTL_DONE_TIMEOUT));
|
||||
-
|
||||
- if (!bus->ctrl_frame_stat) {
|
||||
+ ret = 0;
|
||||
+ if (bus->ctrl_frame_stat) {
|
||||
+ sdio_claim_host(bus->sdiodev->func[1]);
|
||||
+ if (bus->ctrl_frame_stat) {
|
||||
+ brcmf_dbg(SDIO, "ctrl_frame timeout\n");
|
||||
+ bus->ctrl_frame_stat = false;
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ }
|
||||
+ sdio_release_host(bus->sdiodev->func[1]);
|
||||
+ }
|
||||
+ if (!ret) {
|
||||
brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
|
||||
bus->ctrl_frame_err);
|
||||
ret = bus->ctrl_frame_err;
|
||||
- } else {
|
||||
- brcmf_dbg(SDIO, "ctrl_frame timeout\n");
|
||||
- bus->ctrl_frame_stat = false;
|
||||
- ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
@ -1,86 +0,0 @@
|
||||
From: Syed Asifful Dayyan <syedd@broadcom.com>
|
||||
Date: Fri, 6 Mar 2015 18:40:42 +0100
|
||||
Subject: [PATCH] brcmfmac: Add support for BCM4345 SDIO chipset.
|
||||
|
||||
These changes add support for BCM4345 SDIO chipset.
|
||||
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Signed-off-by: Syed Asifful Dayyan <syedd@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/bcmsdh.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
@@ -1096,6 +1096,7 @@ static const struct sdio_device_id brcmf
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
|
||||
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
|
||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
@@ -491,6 +491,10 @@ static void brcmf_chip_get_raminfo(struc
|
||||
case BRCM_CC_43362_CHIP_ID:
|
||||
ci->pub.ramsize = 0x3c000;
|
||||
break;
|
||||
+ case BRCM_CC_4345_CHIP_ID:
|
||||
+ ci->pub.ramsize = 0xc8000;
|
||||
+ ci->pub.rambase = 0x198000;
|
||||
+ break;
|
||||
case BRCM_CC_4339_CHIP_ID:
|
||||
case BRCM_CC_4354_CHIP_ID:
|
||||
case BRCM_CC_4356_CHIP_ID:
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -617,6 +617,8 @@ static const struct sdiod_drive_str sdio
|
||||
#define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt"
|
||||
#define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin"
|
||||
#define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt"
|
||||
+#define BCM4345_FIRMWARE_NAME "brcm/brcmfmac4345-sdio.bin"
|
||||
+#define BCM4345_NVRAM_NAME "brcm/brcmfmac4345-sdio.txt"
|
||||
#define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin"
|
||||
#define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt"
|
||||
|
||||
@@ -640,6 +642,8 @@ MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM43362_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
|
||||
+MODULE_FIRMWARE(BCM4345_FIRMWARE_NAME);
|
||||
+MODULE_FIRMWARE(BCM4345_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM4354_NVRAM_NAME);
|
||||
|
||||
@@ -669,6 +673,7 @@ static const struct brcmf_firmware_names
|
||||
{ BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
|
||||
{ BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
|
||||
{ BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
|
||||
+ { BRCM_CC_4345_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4345) },
|
||||
{ BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) }
|
||||
};
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
|
||||
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
|
||||
@@ -37,6 +37,7 @@
|
||||
#define BRCM_CC_43362_CHIP_ID 43362
|
||||
#define BRCM_CC_4335_CHIP_ID 0x4335
|
||||
#define BRCM_CC_4339_CHIP_ID 0x4339
|
||||
+#define BRCM_CC_4345_CHIP_ID 0x4345
|
||||
#define BRCM_CC_4354_CHIP_ID 0x4354
|
||||
#define BRCM_CC_4356_CHIP_ID 0x4356
|
||||
#define BRCM_CC_43566_CHIP_ID 43566
|
||||
--- a/include/linux/mmc/sdio_ids.h
|
||||
+++ b/include/linux/mmc/sdio_ids.h
|
||||
@@ -33,6 +33,7 @@
|
||||
#define SDIO_DEVICE_ID_BROADCOM_43341 0xa94d
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335
|
||||
#define SDIO_DEVICE_ID_BROADCOM_43362 0xa962
|
||||
+#define SDIO_DEVICE_ID_BROADCOM_4345 0x4345
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4354 0x4354
|
||||
|
||||
#define SDIO_VENDOR_ID_INTEL 0x0089
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user