mirror of https://github.com/hak5/openwrt.git
mac80211: update to version 2015-06-22
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 46198lede-17.01
parent
32549f52cb
commit
b30e092de6
|
@ -10,11 +10,11 @@ include $(INCLUDE_DIR)/kernel.mk
|
|||
|
||||
PKG_NAME:=mac80211
|
||||
|
||||
PKG_VERSION:=2015-03-09
|
||||
PKG_RELEASE:=3
|
||||
PKG_VERSION:=2015-06-22
|
||||
PKG_RELEASE:=1
|
||||
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
|
||||
PKG_BACKPORT_VERSION:=
|
||||
PKG_MD5SUM:=6d4b04e4ce8a1f54dabfb04f4709453c
|
||||
PKG_MD5SUM:=352b2b46d36a72aadc96161a3cefdb1c
|
||||
|
||||
PKG_SOURCE:=compat-wireless-$(PKG_VERSION)$(PKG_BACKPORT_VERSION).tar.bz2
|
||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
|
||||
|
|
|
@ -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,8 +1,8 @@
|
|||
--- a/backport-include/linux/debugfs.h
|
||||
+++ b/backport-include/linux/debugfs.h
|
||||
@@ -3,6 +3,7 @@
|
||||
#include_next <linux/debugfs.h>
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/device.h>
|
||||
#include <generated/utsrelease.h>
|
||||
+#include <linux/device.h>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1858,6 +1858,13 @@ void ieee80211_remove_interfaces(struct
|
||||
@@ -1916,6 +1916,13 @@ void ieee80211_remove_interfaces(struct
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
unregister_netdevice_many(&unreg_list);
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
--- a/backport-include/asm/barrier.h
|
||||
+++ b/backport-include/asm/barrier.h
|
||||
@@ -1,9 +1,9 @@
|
||||
-#ifndef __BACKPORT_ASM_GENERIC_BARRIER_H
|
||||
-#define __BACKPORT_ASM_GENERIC_BARRIER_H
|
||||
+#ifndef __BACKPORT_ASM_BARRIER_H
|
||||
+#define __BACKPORT_ASM_BARRIER_H
|
||||
#include_next <asm/barrier.h>
|
||||
|
||||
#ifndef dma_rmb
|
||||
#define dma_rmb() rmb()
|
||||
#endif
|
||||
|
||||
-#endif /* __BACKPORT_ASM_GENERIC_BARRIER_H */
|
||||
+#endif /* __BACKPORT_ASM_BARRIER_H */
|
|
@ -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,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/.local-symbols
|
||||
+++ b/.local-symbols
|
||||
@@ -344,40 +344,3 @@ USB_CDC_PHONET=
|
||||
@@ -448,43 +448,6 @@ USB_CDC_PHONET=
|
||||
USB_IPHETH=
|
||||
USB_SIERRA_NET=
|
||||
USB_VL600=
|
||||
|
@ -32,26 +32,18 @@
|
|||
-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/
|
||||
NFC=
|
||||
NFC_DIGITAL=
|
||||
NFC_NCI=
|
||||
--- a/drivers/net/wireless/b43/main.c
|
||||
+++ b/drivers/net/wireless/b43/main.c
|
||||
@@ -2866,7 +2866,7 @@ static struct ssb_device *b43_ssb_gpio_d
|
||||
|
@ -63,7 +55,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. */
|
||||
|
@ -116,12 +108,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,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,374 @@
|
|||
--- a/net/mac80211/Makefile
|
||||
+++ b/net/mac80211/Makefile
|
||||
@@ -15,9 +15,7 @@ mac80211-y := \
|
||||
michael.o \
|
||||
tkip.o \
|
||||
aes_ccm.o \
|
||||
- aes_gcm.o \
|
||||
aes_cmac.o \
|
||||
- aes_gmac.o \
|
||||
cfg.o \
|
||||
ethtool.o \
|
||||
rx.o \
|
||||
--- a/net/mac80211/aes_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/aes_ccm.c
|
||||
+++ b/net/mac80211/aes_ccm.c
|
||||
@@ -19,86 +19,126 @@
|
||||
#include "key.h"
|
||||
#include "aes_ccm.h"
|
||||
|
||||
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0,
|
||||
+ u8 *a, u8 *b)
|
||||
+{
|
||||
+ 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);
|
||||
+
|
||||
+ /* Mask out bits from auth-only-b_0 */
|
||||
+ b_0[0] &= 0x07;
|
||||
+
|
||||
+ /* S_0 is used to encrypt T (= MIC) */
|
||||
+ b_0[14] = 0;
|
||||
+ b_0[15] = 0;
|
||||
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+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)
|
||||
{
|
||||
- struct scatterlist assoc, pt, ct[2];
|
||||
+ 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];
|
||||
+ }
|
||||
|
||||
- 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;
|
||||
-
|
||||
- memset(aead_req, 0, sizeof(aead_req_data));
|
||||
-
|
||||
- sg_init_one(&pt, data, data_len);
|
||||
- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
- sg_init_table(ct, 2);
|
||||
- sg_set_buf(&ct[0], data, data_len);
|
||||
- sg_set_buf(&ct[1], mic, mic_len);
|
||||
-
|
||||
- aead_request_set_tfm(aead_req, tfm);
|
||||
- aead_request_set_assoc(aead_req, &assoc, assoc.length);
|
||||
- aead_request_set_crypt(aead_req, &pt, ct, data_len, b_0);
|
||||
-
|
||||
- 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 assoc, pt, ct[2];
|
||||
- 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_one(&pt, data, data_len);
|
||||
- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
|
||||
- sg_init_table(ct, 2);
|
||||
- sg_set_buf(&ct[0], data, data_len);
|
||||
- sg_set_buf(&ct[1], mic, mic_len);
|
||||
-
|
||||
- aead_request_set_tfm(aead_req, tfm);
|
||||
- aead_request_set_assoc(aead_req, &assoc, assoc.length);
|
||||
- aead_request_set_crypt(aead_req, ct, &pt, data_len + mic_len, b_0);
|
||||
+ 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/key.h
|
||||
+++ b/net/mac80211/key.h
|
||||
@@ -84,7 +84,7 @@ struct ieee80211_key {
|
||||
* Management frames.
|
||||
*/
|
||||
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
|
||||
- struct crypto_aead *tfm;
|
||||
+ struct crypto_cipher *tfm;
|
||||
u32 replays; /* dot11RSNAStatsCCMPReplays */
|
||||
} ccmp;
|
||||
struct {
|
||||
--- a/net/mac80211/wpa.c
|
||||
+++ b/net/mac80211/wpa.c
|
||||
@@ -304,7 +304,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
|
||||
}
|
||||
|
||||
|
||||
-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
|
||||
+static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
|
||||
+ u16 data_len)
|
||||
{
|
||||
__le16 mask_fc;
|
||||
int a4_included, mgmt;
|
||||
@@ -334,14 +335,8 @@ static void ccmp_special_blocks(struct s
|
||||
else
|
||||
qos_tid = 0;
|
||||
|
||||
- /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
|
||||
- * mode authentication are not allowed to collide, yet both are derived
|
||||
- * from this vector b_0. We only set L := 1 here to indicate that the
|
||||
- * data size can be represented in (L+1) bytes. The CCM layer will take
|
||||
- * care of storing the data length in the top (L+1) bytes and setting
|
||||
- * and clearing the other bits as is required to derive the two IVs.
|
||||
- */
|
||||
- b_0[0] = 0x1;
|
||||
+ /* First block, b_0 */
|
||||
+ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
|
||||
|
||||
/* Nonce: Nonce Flags | A2 | PN
|
||||
* Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
|
||||
@@ -349,6 +344,8 @@ static void ccmp_special_blocks(struct s
|
||||
b_0[1] = qos_tid | (mgmt << 4);
|
||||
memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
|
||||
memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
|
||||
+ /* l(m) */
|
||||
+ put_unaligned_be16(data_len, &b_0[14]);
|
||||
|
||||
/* AAD (extra authenticate-only data) / masked 802.11 header
|
||||
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
|
||||
@@ -460,7 +457,7 @@ static int ccmp_encrypt_skb(struct ieee8
|
||||
return 0;
|
||||
|
||||
pos += IEEE80211_CCMP_HDR_LEN;
|
||||
- ccmp_special_blocks(skb, pn, b_0, aad);
|
||||
+ ccmp_special_blocks(skb, pn, b_0, aad, len);
|
||||
ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
|
||||
skb_put(skb, mic_len), mic_len);
|
||||
|
||||
@@ -531,7 +528,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
|
||||
u8 aad[2 * AES_BLOCK_SIZE];
|
||||
u8 b_0[AES_BLOCK_SIZE];
|
||||
/* hardware didn't decrypt/verify MIC */
|
||||
- ccmp_special_blocks(skb, pn, b_0, aad);
|
||||
+ ccmp_special_blocks(skb, pn, b_0, aad, data_len);
|
||||
|
||||
if (ieee80211_aes_ccm_decrypt(
|
||||
key->u.ccmp.tfm, b_0, aad,
|
||||
--- 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/Kconfig
|
||||
+++ b/net/mac80211/Kconfig
|
||||
@@ -5,8 +5,6 @@ config MAC80211
|
||||
depends on CRYPTO
|
||||
depends on CRYPTO_ARC4
|
||||
depends on CRYPTO_AES
|
||||
- select BPAUTO_CRYPTO_CCM
|
||||
- depends on CRYPTO_GCM
|
||||
depends on CRC32
|
||||
select BPAUTO_AVERAGE
|
||||
---help---
|
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
|
||||
@@ -886,7 +886,6 @@ static int ieee80211_stop_ap(struct wiph
|
||||
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
|
||||
|
||||
__sta_info_flush(sdata, true);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
static int ieee80211_ifa6_changed(struct notifier_block *nb,
|
||||
unsigned long data, void *arg)
|
||||
{
|
||||
@@ -1057,14 +1057,14 @@ int ieee80211_register_hw(struct ieee802
|
||||
@@ -1086,14 +1086,14 @@ int ieee80211_register_hw(struct ieee802
|
||||
if (result)
|
||||
goto fail_pm_qos;
|
||||
|
||||
|
@ -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
|
||||
@@ -1102,13 +1102,13 @@ int ieee80211_register_hw(struct ieee802
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
|||
fail_ifa:
|
||||
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
|
||||
&local->network_latency_notifier);
|
||||
@@ -1124,10 +1124,10 @@ void ieee80211_unregister_hw(struct ieee
|
||||
@@ -1141,10 +1141,10 @@ void ieee80211_unregister_hw(struct ieee
|
||||
|
||||
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
|
||||
&local->network_latency_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 *
|
||||
@@ -2008,7 +2008,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)
|
|
@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
|||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -278,6 +278,7 @@ static void ath9k_hw_read_revisions(stru
|
||||
@@ -279,6 +279,7 @@ static void ath9k_hw_read_revisions(stru
|
||||
return;
|
||||
case AR9300_DEVID_QCA956X:
|
||||
ah->hw_version.macVersion = AR_SREV_VERSION_9561;
|
|
@ -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;
|
|
@ -0,0 +1,35 @@
|
|||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 16 Jun 2015 10:34:03 +0200
|
||||
Subject: [PATCH] ath: DFS - limit number of potential PRI sequences
|
||||
|
||||
In the PRI detector, after the current radar pulse
|
||||
has been checked agains existing PRI sequences, it
|
||||
is considered as part of a new potential sequence.
|
||||
|
||||
Previously, the condition to accept a new sequence
|
||||
was to have at least the same number of pulses as
|
||||
the longest matching sequence. This was wrong,
|
||||
since it led to duplicates of PRI sequences.
|
||||
|
||||
This patch changes the acceptance criteria for new
|
||||
potential sequences from 'at least' to 'more than'
|
||||
the longest existing.
|
||||
|
||||
Detection performance remains unaffected, while
|
||||
the number of PRI sequences accounted at runtime
|
||||
(and with it CPU load) is reduced by up to 50%.
|
||||
|
||||
Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
|
||||
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
|
||||
@@ -273,7 +273,7 @@ static bool pseq_handler_create_sequence
|
||||
tmp_false_count++;
|
||||
}
|
||||
}
|
||||
- if (ps.count < min_count)
|
||||
+ if (ps.count <= min_count)
|
||||
/* did not reach minimum count, drop sequence */
|
||||
continue;
|
||||
|
|
@ -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,25 @@
|
|||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 16 Jun 2015 11:46:42 +0200
|
||||
Subject: [PATCH] ath9k: DFS - consider ext_channel pulses only in HT40
|
||||
mode
|
||||
|
||||
The chip reports radar pulses on extension channel
|
||||
even if operating in HT20 mode. This patch adds a
|
||||
sanity check for HT40 mode before it feeds pulses
|
||||
on extension channel to the pattern detector.
|
||||
|
||||
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
|
||||
@@ -198,7 +198,8 @@ void ath9k_dfs_process_phyerr(struct ath
|
||||
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) {
|
||||
+ if (IS_CHAN_HT40(ah->curchan) &&
|
||||
+ ard.pulse_bw_info & EXT_CH_RADAR_FOUND) {
|
||||
pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20;
|
||||
ath9k_dfs_process_radar_pulse(sc, &pe);
|
||||
}
|
|
@ -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,211 @@
|
|||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 16 Jun 2015 12:52:16 +0200
|
||||
Subject: [PATCH] ath9k: DFS - add pulse chirp detection for FCC
|
||||
|
||||
FCC long pulse radar (type 5) requires pulses to be
|
||||
checked for chirping. This patch implements chirp
|
||||
detection based on the FFT data provided for long
|
||||
pulses.
|
||||
|
||||
A chirp is detected when a set of criteria defined
|
||||
by FCC pulse characteristics is met, including
|
||||
* have at least 4 FFT samples
|
||||
* max_bin index moves equidistantly between samples
|
||||
* the gradient is within defined range
|
||||
|
||||
The chirp detection has been tested with reference
|
||||
radar generating devices and proved to work reliably.
|
||||
|
||||
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
|
||||
@@ -30,6 +30,157 @@ struct ath_radar_data {
|
||||
u8 pulse_length_pri;
|
||||
};
|
||||
|
||||
+/**** begin: CHIRP ************************************************************/
|
||||
+
|
||||
+/* min and max gradients for defined FCC chirping pulses, given by
|
||||
+ * - 20MHz chirp width over a pulse width of 50us
|
||||
+ * - 5MHz chirp width over a pulse width of 100us
|
||||
+ */
|
||||
+static const int BIN_DELTA_MIN = 1;
|
||||
+static const int BIN_DELTA_MAX = 10;
|
||||
+
|
||||
+/* we need at least 3 deltas / 4 samples for a reliable chirp detection */
|
||||
+#define NUM_DIFFS 3
|
||||
+static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1);
|
||||
+
|
||||
+/* Threshold for difference of delta peaks */
|
||||
+static const int MAX_DIFF = 2;
|
||||
+
|
||||
+/* width range to be checked for chirping */
|
||||
+static const int MIN_CHIRP_PULSE_WIDTH = 20;
|
||||
+static const int MAX_CHIRP_PULSE_WIDTH = 110;
|
||||
+
|
||||
+struct ath9k_dfs_fft_20 {
|
||||
+ u8 bin[28];
|
||||
+ u8 lower_bins[3];
|
||||
+} __packed;
|
||||
+struct ath9k_dfs_fft_40 {
|
||||
+ u8 bin[64];
|
||||
+ u8 lower_bins[3];
|
||||
+ u8 upper_bins[3];
|
||||
+} __packed;
|
||||
+
|
||||
+static inline int fft_max_index(u8 *bins)
|
||||
+{
|
||||
+ return (bins[2] & 0xfc) >> 2;
|
||||
+}
|
||||
+static inline int fft_max_magnitude(u8 *bins)
|
||||
+{
|
||||
+ return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10;
|
||||
+}
|
||||
+static inline u8 fft_bitmap_weight(u8 *bins)
|
||||
+{
|
||||
+ return bins[0] & 0x3f;
|
||||
+}
|
||||
+
|
||||
+static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft,
|
||||
+ bool is_ctl, bool is_ext)
|
||||
+{
|
||||
+ const int DFS_UPPER_BIN_OFFSET = 64;
|
||||
+ /* if detected radar on both channels, select the significant one */
|
||||
+ if (is_ctl && is_ext) {
|
||||
+ /* first check wether channels have 'strong' bins */
|
||||
+ is_ctl = fft_bitmap_weight(fft->lower_bins) != 0;
|
||||
+ is_ext = fft_bitmap_weight(fft->upper_bins) != 0;
|
||||
+
|
||||
+ /* if still unclear, take higher magnitude */
|
||||
+ if (is_ctl && is_ext) {
|
||||
+ int mag_lower = fft_max_magnitude(fft->lower_bins);
|
||||
+ int mag_upper = fft_max_magnitude(fft->upper_bins);
|
||||
+ if (mag_upper > mag_lower)
|
||||
+ is_ctl = false;
|
||||
+ else
|
||||
+ is_ext = false;
|
||||
+ }
|
||||
+ }
|
||||
+ if (is_ctl)
|
||||
+ return fft_max_index(fft->lower_bins);
|
||||
+ return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET;
|
||||
+}
|
||||
+static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
|
||||
+ int datalen, bool is_ctl, bool is_ext)
|
||||
+{
|
||||
+ int i;
|
||||
+ int max_bin[FFT_NUM_SAMPLES];
|
||||
+ struct ath_hw *ah = sc->sc_ah;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+ int prev_delta;
|
||||
+
|
||||
+ if (IS_CHAN_HT40(ah->curchan)) {
|
||||
+ struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data;
|
||||
+ int num_fft_packets = datalen / sizeof(*fft);
|
||||
+ if (num_fft_packets == 0)
|
||||
+ return false;
|
||||
+
|
||||
+ ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n",
|
||||
+ datalen, num_fft_packets);
|
||||
+ if (num_fft_packets < (FFT_NUM_SAMPLES)) {
|
||||
+ ath_dbg(common, DFS, "not enough packets for chirp\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+ /* HW sometimes adds 2 garbage bytes in front of FFT samples */
|
||||
+ if ((datalen % sizeof(*fft)) == 2) {
|
||||
+ fft = (struct ath9k_dfs_fft_40 *) (data + 2);
|
||||
+ ath_dbg(common, DFS, "fixing datalen by 2\n");
|
||||
+ }
|
||||
+ if (IS_CHAN_HT40MINUS(ah->curchan)) {
|
||||
+ int temp = is_ctl;
|
||||
+ is_ctl = is_ext;
|
||||
+ is_ext = temp;
|
||||
+ }
|
||||
+ for (i = 0; i < FFT_NUM_SAMPLES; i++)
|
||||
+ max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
|
||||
+ is_ext);
|
||||
+ } else {
|
||||
+ struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data;
|
||||
+ int num_fft_packets = datalen / sizeof(*fft);
|
||||
+ if (num_fft_packets == 0)
|
||||
+ return false;
|
||||
+ ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n",
|
||||
+ datalen, num_fft_packets);
|
||||
+ if (num_fft_packets < (FFT_NUM_SAMPLES)) {
|
||||
+ ath_dbg(common, DFS, "not enough packets for chirp\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+ /* in ht20, this is a 6-bit signed number => shift it to 0 */
|
||||
+ for (i = 0; i < FFT_NUM_SAMPLES; i++)
|
||||
+ max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20;
|
||||
+ }
|
||||
+ ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n",
|
||||
+ max_bin[0], max_bin[1], max_bin[2], max_bin[3]);
|
||||
+
|
||||
+ /* Check for chirp attributes within specs
|
||||
+ * a) delta of adjacent max_bins is within range
|
||||
+ * b) delta of adjacent deltas are within tolerance
|
||||
+ */
|
||||
+ prev_delta = 0;
|
||||
+ for (i = 0; i < NUM_DIFFS; i++) {
|
||||
+ int ddelta = -1;
|
||||
+ int delta = max_bin[i + 1] - max_bin[i];
|
||||
+
|
||||
+ /* ensure gradient is within valid range */
|
||||
+ if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) {
|
||||
+ ath_dbg(common, DFS, "CHIRP: invalid delta %d "
|
||||
+ "in sample %d\n", delta, i);
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (i == 0)
|
||||
+ goto done;
|
||||
+ ddelta = delta - prev_delta;
|
||||
+ if (abs(ddelta) > MAX_DIFF) {
|
||||
+ ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n",
|
||||
+ ddelta);
|
||||
+ return false;
|
||||
+ }
|
||||
+done:
|
||||
+ ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n",
|
||||
+ i, delta, ddelta);
|
||||
+ prev_delta = delta;
|
||||
+ }
|
||||
+ return true;
|
||||
+}
|
||||
+/**** end: CHIRP **************************************************************/
|
||||
+
|
||||
/* convert pulse duration to usecs, considering clock mode */
|
||||
static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)
|
||||
{
|
||||
@@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath
|
||||
return false;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * TODO: check chirping pulses
|
||||
- * checks for chirping are dependent on the DFS regulatory domain
|
||||
- * used, which is yet TBD
|
||||
- */
|
||||
-
|
||||
/* convert duration to usecs */
|
||||
pe->width = dur_to_usecs(sc->sc_ah, dur);
|
||||
pe->rssi = rssi;
|
||||
@@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath
|
||||
if (!ath9k_postprocess_radar_event(sc, &ard, &pe))
|
||||
return;
|
||||
|
||||
+ if (pe.width > MIN_CHIRP_PULSE_WIDTH &&
|
||||
+ pe.width < MAX_CHIRP_PULSE_WIDTH) {
|
||||
+ bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND);
|
||||
+ bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND);
|
||||
+ int clen = datalen - 3;
|
||||
+ pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext);
|
||||
+ } else {
|
||||
+ pe.chirp = false;
|
||||
+ }
|
||||
+
|
||||
ath_dbg(common, DFS,
|
||||
"ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "
|
||||
"width=%d, rssi=%d, delta_ts=%llu\n",
|
|
@ -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
|
||||
};
|
|
@ -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:
|
|
@ -42,7 +42,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
|||
|
||||
--- a/drivers/net/wireless/ath/ath9k/recv.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/recv.c
|
||||
@@ -496,10 +496,9 @@ bool ath_stoprecv(struct ath_softc *sc)
|
||||
@@ -491,10 +491,9 @@ bool ath_stoprecv(struct ath_softc *sc)
|
||||
|
||||
if (!(ah->ah_flags & AH_UNPLUGGED) &&
|
||||
unlikely(!stopped)) {
|
||||
|
@ -58,7 +58,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
|||
}
|
||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
@@ -1896,8 +1896,11 @@ bool ath_drain_all_txq(struct ath_softc
|
||||
@@ -1883,8 +1883,11 @@ bool ath_drain_all_txq(struct ath_softc
|
||||
npend |= BIT(i);
|
||||
}
|
||||
|
|
@ -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,121 @@
|
|||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 2 Jul 2015 15:20:56 +0200
|
||||
Subject: [PATCH] ath9k: limit retries for powersave response frames
|
||||
|
||||
In some cases, the channel might be busy enough that an ath9k AP's
|
||||
response to PS-Poll frames might be too slow and the station has already
|
||||
gone to sleep. To avoid wasting too much airtime on this, limit the
|
||||
number of retries on such frames and ensure that no sample rate gets
|
||||
used.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
@@ -147,10 +147,25 @@ static void ath_send_bar(struct ath_atx_
|
||||
}
|
||||
|
||||
static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
- struct ath_buf *bf)
|
||||
+ struct ath_buf *bf, bool ps)
|
||||
{
|
||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
|
||||
+
|
||||
+ if (ps) {
|
||||
+ /* Clear the first rate to avoid using a sample rate for PS frames */
|
||||
+ info->control.rates[0].idx = -1;
|
||||
+ info->control.rates[0].count = 0;
|
||||
+ }
|
||||
+
|
||||
ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
|
||||
ARRAY_SIZE(bf->rates));
|
||||
+ if (!ps)
|
||||
+ return;
|
||||
+
|
||||
+ if (bf->rates[0].count > 2)
|
||||
+ bf->rates[0].count = 2;
|
||||
+
|
||||
+ bf->rates[1].idx = -1;
|
||||
}
|
||||
|
||||
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
||||
@@ -1430,7 +1445,7 @@ ath_tx_form_burst(struct ath_softc *sc,
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
break;
|
||||
|
||||
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
@@ -1461,7 +1476,7 @@ static bool ath_tx_sched_aggr(struct ath
|
||||
return false;
|
||||
}
|
||||
|
||||
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
||||
if (aggr)
|
||||
last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
|
||||
tid_q, &aggr_len);
|
||||
@@ -1653,7 +1668,7 @@ void ath9k_release_buffered_frames(struc
|
||||
|
||||
__skb_unlink(bf->bf_mpdu, tid_q);
|
||||
list_add_tail(&bf->list, &bf_q);
|
||||
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
||||
if (bf_isampdu(bf)) {
|
||||
ath_tx_addto_baw(sc, tid, bf);
|
||||
bf->bf_state.bf_type &= ~BUF_AGGR;
|
||||
@@ -2318,7 +2333,7 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||||
struct ath_txq *txq = txctl->txq;
|
||||
struct ath_atx_tid *tid = NULL;
|
||||
struct ath_buf *bf;
|
||||
- bool queue, skip_uapsd = false, ps_resp;
|
||||
+ bool queue, ps_resp;
|
||||
int q, ret;
|
||||
|
||||
if (vif)
|
||||
@@ -2365,13 +2380,13 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||||
if (!txctl->an)
|
||||
txctl->an = &avp->mcast_node;
|
||||
queue = true;
|
||||
- skip_uapsd = true;
|
||||
+ ps_resp = false;
|
||||
}
|
||||
|
||||
if (txctl->an && queue)
|
||||
tid = ath_get_skb_tid(sc, txctl->an, skb);
|
||||
|
||||
- if (!skip_uapsd && ps_resp) {
|
||||
+ if (ps_resp) {
|
||||
ath_txq_unlock(sc, txq);
|
||||
txq = sc->tx.uapsdq;
|
||||
ath_txq_lock(sc, txq);
|
||||
@@ -2409,7 +2424,7 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||||
if (txctl->paprd)
|
||||
bf->bf_state.bfs_paprd_timestamp = jiffies;
|
||||
|
||||
- ath_set_rates(vif, sta, bf);
|
||||
+ ath_set_rates(vif, sta, bf, ps_resp);
|
||||
ath_tx_send_normal(sc, txq, tid, skb);
|
||||
|
||||
out:
|
||||
@@ -2448,7 +2463,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
|
||||
break;
|
||||
|
||||
bf->bf_lastbf = bf;
|
||||
- ath_set_rates(vif, NULL, bf);
|
||||
+ ath_set_rates(vif, NULL, bf, false);
|
||||
ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
|
||||
duration += info.rates[0].PktDuration;
|
||||
if (bf_tail)
|
||||
@@ -2968,7 +2983,7 @@ int ath9k_tx99_send(struct ath_softc *sc
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- ath_set_rates(sc->tx99_vif, NULL, bf);
|
||||
+ ath_set_rates(sc->tx99_vif, NULL, bf, false);
|
||||
|
||||
ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
|
||||
ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
|
|
@ -0,0 +1,56 @@
|
|||
From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
|
||||
Date: Fri, 3 Jul 2015 11:45:42 +0530
|
||||
Subject: [PATCH] ath10k: Delay device access after cold reset
|
||||
|
||||
It is observed that during cold reset pcie access right
|
||||
after a write operation to SOC_GLOBAL_RESET_ADDRESS causes
|
||||
Data Bus Error and system hard lockup. The reason
|
||||
for bus error is that pcie needs some time to get
|
||||
back to stable state for any transaction during cold reset. Add
|
||||
delay of 20 msecs after write of SOC_GLOBAL_RESET_ADDRESS
|
||||
to fix this issue.
|
||||
|
||||
Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath10k/pci.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/pci.c
|
||||
@@ -2602,7 +2602,6 @@ static int ath10k_pci_wait_for_target_in
|
||||
|
||||
static int ath10k_pci_cold_reset(struct ath10k *ar)
|
||||
{
|
||||
- int i;
|
||||
u32 val;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
|
||||
@@ -2618,23 +2617,18 @@ static int ath10k_pci_cold_reset(struct
|
||||
val |= 1;
|
||||
ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
|
||||
|
||||
- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
|
||||
- if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
|
||||
- RTC_STATE_COLD_RESET_MASK)
|
||||
- break;
|
||||
- msleep(1);
|
||||
- }
|
||||
+ /* After writing into SOC_GLOBAL_RESET to put device into
|
||||
+ * reset and pulling out of reset pcie may not be stable
|
||||
+ * for any immediate pcie register access and cause bus error,
|
||||
+ * add delay before any pcie access request to fix this issue.
|
||||
+ */
|
||||
+ msleep(20);
|
||||
|
||||
/* Pull Target, including PCIe, out of RESET. */
|
||||
val &= ~1;
|
||||
ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
|
||||
|
||||
- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
|
||||
- if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
|
||||
- RTC_STATE_COLD_RESET_MASK))
|
||||
- break;
|
||||
- msleep(1);
|
||||
- }
|
||||
+ msleep(20);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
|
||||
|
|
@ -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;
|
|
@ -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
|
|
@ -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))
|
|
@ -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) &&
|
|
@ -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);
|
|
@ -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);
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
- }
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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);
|
|
@ -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);
|
|
@ -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]);
|
||||
|
|
@ -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++)
|
|
@ -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,
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
@ -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;
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
|
@ -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,
|
|
@ -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
|
|
@ -1,48 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 11 Mar 2015 16:11:27 +0100
|
||||
Subject: [PATCH] brcmfmac: remove duplication of ramsize info
|
||||
|
||||
Removing the ramsize from the brcmf_sdio structure to avoid
|
||||
duplication. The information is available in brcmf_chip
|
||||
structure.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -432,8 +432,6 @@ struct brcmf_sdio {
|
||||
struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
|
||||
struct brcmf_chip *ci; /* Chip info struct */
|
||||
|
||||
- u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
|
||||
-
|
||||
u32 hostintmask; /* Copy of Host Interrupt Mask */
|
||||
atomic_t intstatus; /* Intstatus bits (events) pending */
|
||||
atomic_t fcstate; /* State of dongle flow-control */
|
||||
@@ -1075,7 +1073,7 @@ static int brcmf_sdio_readshared(struct
|
||||
struct sdpcm_shared_le sh_le;
|
||||
__le32 addr_le;
|
||||
|
||||
- shaddr = bus->ci->rambase + bus->ramsize - 4;
|
||||
+ shaddr = bus->ci->rambase + bus->ci->ramsize - 4;
|
||||
|
||||
/*
|
||||
* Read last word in socram to determine
|
||||
@@ -3871,13 +3869,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdi
|
||||
drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
|
||||
brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
|
||||
|
||||
- /* Get info on the SOCRAM cores... */
|
||||
- bus->ramsize = bus->ci->ramsize;
|
||||
- if (!(bus->ramsize)) {
|
||||
- brcmf_err("failed to find SOCRAM memory!\n");
|
||||
- goto fail;
|
||||
- }
|
||||
-
|
||||
/* Set card control so an SDIO card reset does a WLAN backplane reset */
|
||||
reg_val = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SDIO_CCCR_BRCM_CARDCTRL, &err);
|
|
@ -1,74 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 11 Mar 2015 16:11:28 +0100
|
||||
Subject: [PATCH] brcmfmac: always perform cores checks
|
||||
|
||||
Instead of checking the cores in the chip only if CONFIG_BRCMDBG
|
||||
is selected perform the check always and extend it with more sanity
|
||||
checking.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
@@ -419,13 +419,13 @@ static struct brcmf_core *brcmf_chip_add
|
||||
return &core->pub;
|
||||
}
|
||||
|
||||
-#ifdef DEBUG
|
||||
/* safety check for chipinfo */
|
||||
static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci)
|
||||
{
|
||||
struct brcmf_core_priv *core;
|
||||
bool need_socram = false;
|
||||
bool has_socram = false;
|
||||
+ bool cpu_found = false;
|
||||
int idx = 1;
|
||||
|
||||
list_for_each_entry(core, &ci->cores, list) {
|
||||
@@ -435,12 +435,14 @@ static int brcmf_chip_cores_check(struct
|
||||
|
||||
switch (core->pub.id) {
|
||||
case BCMA_CORE_ARM_CM3:
|
||||
+ cpu_found = true;
|
||||
need_socram = true;
|
||||
break;
|
||||
case BCMA_CORE_INTERNAL_MEM:
|
||||
has_socram = true;
|
||||
break;
|
||||
case BCMA_CORE_ARM_CR4:
|
||||
+ cpu_found = true;
|
||||
if (ci->pub.rambase == 0) {
|
||||
brcmf_err("RAM base not provided with ARM CR4 core\n");
|
||||
return -ENOMEM;
|
||||
@@ -451,19 +453,21 @@ static int brcmf_chip_cores_check(struct
|
||||
}
|
||||
}
|
||||
|
||||
+ if (!cpu_found) {
|
||||
+ brcmf_err("CPU core not detected\n");
|
||||
+ return -ENXIO;
|
||||
+ }
|
||||
/* check RAM core presence for ARM CM3 core */
|
||||
if (need_socram && !has_socram) {
|
||||
brcmf_err("RAM core not provided with ARM CM3 core\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
+ if (!ci->pub.ramsize) {
|
||||
+ brcmf_err("RAM size is undetermined\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
return 0;
|
||||
}
|
||||
-#else /* DEBUG */
|
||||
-static inline int brcmf_chip_cores_check(struct brcmf_chip_priv *ci)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
-#endif
|
||||
|
||||
static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
|
||||
{
|
|
@ -1,240 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 11 Mar 2015 16:11:29 +0100
|
||||
Subject: [PATCH] brcmfmac: rename chip download functions
|
||||
|
||||
The functions brcmf_chip_[enter/exit]_download() are not exclusively
|
||||
used for firmware download so rename these more appropriate.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
@@ -807,7 +807,7 @@ struct brcmf_chip *brcmf_chip_attach(voi
|
||||
err = -EINVAL;
|
||||
if (WARN_ON(!ops->prepare))
|
||||
err = -EINVAL;
|
||||
- if (WARN_ON(!ops->exit_dl))
|
||||
+ if (WARN_ON(!ops->activate))
|
||||
err = -EINVAL;
|
||||
if (err < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@@ -905,7 +905,7 @@ void brcmf_chip_resetcore(struct brcmf_c
|
||||
}
|
||||
|
||||
static void
|
||||
-brcmf_chip_cm3_enterdl(struct brcmf_chip_priv *chip)
|
||||
+brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip)
|
||||
{
|
||||
struct brcmf_core *core;
|
||||
|
||||
@@ -919,7 +919,7 @@ brcmf_chip_cm3_enterdl(struct brcmf_chip
|
||||
brcmf_chip_resetcore(core, 0, 0, 0);
|
||||
}
|
||||
|
||||
-static bool brcmf_chip_cm3_exitdl(struct brcmf_chip_priv *chip)
|
||||
+static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip)
|
||||
{
|
||||
struct brcmf_core *core;
|
||||
|
||||
@@ -929,7 +929,7 @@ static bool brcmf_chip_cm3_exitdl(struct
|
||||
return false;
|
||||
}
|
||||
|
||||
- chip->ops->exit_dl(chip->ctx, &chip->pub, 0);
|
||||
+ chip->ops->activate(chip->ctx, &chip->pub, 0);
|
||||
|
||||
core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CM3);
|
||||
brcmf_chip_resetcore(core, 0, 0, 0);
|
||||
@@ -938,7 +938,7 @@ static bool brcmf_chip_cm3_exitdl(struct
|
||||
}
|
||||
|
||||
static inline void
|
||||
-brcmf_chip_cr4_enterdl(struct brcmf_chip_priv *chip)
|
||||
+brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip)
|
||||
{
|
||||
struct brcmf_core *core;
|
||||
|
||||
@@ -951,11 +951,11 @@ brcmf_chip_cr4_enterdl(struct brcmf_chip
|
||||
D11_BCMA_IOCTL_PHYCLOCKEN);
|
||||
}
|
||||
|
||||
-static bool brcmf_chip_cr4_exitdl(struct brcmf_chip_priv *chip, u32 rstvec)
|
||||
+static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec)
|
||||
{
|
||||
struct brcmf_core *core;
|
||||
|
||||
- chip->ops->exit_dl(chip->ctx, &chip->pub, rstvec);
|
||||
+ chip->ops->activate(chip->ctx, &chip->pub, rstvec);
|
||||
|
||||
/* restore ARM */
|
||||
core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CR4);
|
||||
@@ -964,7 +964,7 @@ static bool brcmf_chip_cr4_exitdl(struct
|
||||
return true;
|
||||
}
|
||||
|
||||
-void brcmf_chip_enter_download(struct brcmf_chip *pub)
|
||||
+void brcmf_chip_set_passive(struct brcmf_chip *pub)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
struct brcmf_core *arm;
|
||||
@@ -974,14 +974,14 @@ void brcmf_chip_enter_download(struct br
|
||||
chip = container_of(pub, struct brcmf_chip_priv, pub);
|
||||
arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
|
||||
if (arm) {
|
||||
- brcmf_chip_cr4_enterdl(chip);
|
||||
+ brcmf_chip_cr4_set_passive(chip);
|
||||
return;
|
||||
}
|
||||
|
||||
- brcmf_chip_cm3_enterdl(chip);
|
||||
+ brcmf_chip_cm3_set_passive(chip);
|
||||
}
|
||||
|
||||
-bool brcmf_chip_exit_download(struct brcmf_chip *pub, u32 rstvec)
|
||||
+bool brcmf_chip_set_active(struct brcmf_chip *pub, u32 rstvec)
|
||||
{
|
||||
struct brcmf_chip_priv *chip;
|
||||
struct brcmf_core *arm;
|
||||
@@ -991,9 +991,9 @@ bool brcmf_chip_exit_download(struct brc
|
||||
chip = container_of(pub, struct brcmf_chip_priv, pub);
|
||||
arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
|
||||
if (arm)
|
||||
- return brcmf_chip_cr4_exitdl(chip, rstvec);
|
||||
+ return brcmf_chip_cr4_set_active(chip, rstvec);
|
||||
|
||||
- return brcmf_chip_cm3_exitdl(chip);
|
||||
+ return brcmf_chip_cm3_set_active(chip);
|
||||
}
|
||||
|
||||
bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h
|
||||
@@ -64,7 +64,7 @@ struct brcmf_core {
|
||||
* @write32: write 32-bit value over bus.
|
||||
* @prepare: prepare bus for core configuration.
|
||||
* @setup: bus-specific core setup.
|
||||
- * @exit_dl: exit download state.
|
||||
+ * @active: chip becomes active.
|
||||
* The callback should use the provided @rstvec when non-zero.
|
||||
*/
|
||||
struct brcmf_buscore_ops {
|
||||
@@ -72,7 +72,7 @@ struct brcmf_buscore_ops {
|
||||
void (*write32)(void *ctx, u32 addr, u32 value);
|
||||
int (*prepare)(void *ctx);
|
||||
int (*setup)(void *ctx, struct brcmf_chip *chip);
|
||||
- void (*exit_dl)(void *ctx, struct brcmf_chip *chip, u32 rstvec);
|
||||
+ void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec);
|
||||
};
|
||||
|
||||
struct brcmf_chip *brcmf_chip_attach(void *ctx,
|
||||
@@ -84,8 +84,8 @@ bool brcmf_chip_iscoreup(struct brcmf_co
|
||||
void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
|
||||
void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
|
||||
u32 postreset);
|
||||
-void brcmf_chip_enter_download(struct brcmf_chip *ci);
|
||||
-bool brcmf_chip_exit_download(struct brcmf_chip *ci, u32 rstvec);
|
||||
+void brcmf_chip_set_passive(struct brcmf_chip *ci);
|
||||
+bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec);
|
||||
bool brcmf_chip_sr_capable(struct brcmf_chip *pub);
|
||||
|
||||
#endif /* BRCMF_AXIDMP_H */
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -509,7 +509,7 @@ static void brcmf_pcie_attach(struct brc
|
||||
|
||||
static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo)
|
||||
{
|
||||
- brcmf_chip_enter_download(devinfo->ci);
|
||||
+ brcmf_chip_set_passive(devinfo->ci);
|
||||
|
||||
if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) {
|
||||
brcmf_pcie_select_core(devinfo, BCMA_CORE_ARM_CR4);
|
||||
@@ -536,7 +536,7 @@ static int brcmf_pcie_exit_download_stat
|
||||
brcmf_chip_resetcore(core, 0, 0, 0);
|
||||
}
|
||||
|
||||
- return !brcmf_chip_exit_download(devinfo->ci, resetintr);
|
||||
+ return !brcmf_chip_set_active(devinfo->ci, resetintr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1566,8 +1566,8 @@ static int brcmf_pcie_buscoreprep(void *
|
||||
}
|
||||
|
||||
|
||||
-static void brcmf_pcie_buscore_exitdl(void *ctx, struct brcmf_chip *chip,
|
||||
- u32 rstvec)
|
||||
+static void brcmf_pcie_buscore_activate(void *ctx, struct brcmf_chip *chip,
|
||||
+ u32 rstvec)
|
||||
{
|
||||
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx;
|
||||
|
||||
@@ -1577,7 +1577,7 @@ static void brcmf_pcie_buscore_exitdl(vo
|
||||
|
||||
static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = {
|
||||
.prepare = brcmf_pcie_buscoreprep,
|
||||
- .exit_dl = brcmf_pcie_buscore_exitdl,
|
||||
+ .activate = brcmf_pcie_buscore_activate,
|
||||
.read32 = brcmf_pcie_buscore_read32,
|
||||
.write32 = brcmf_pcie_buscore_write32,
|
||||
};
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -3357,7 +3357,7 @@ static int brcmf_sdio_download_firmware(
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
|
||||
|
||||
/* Keep arm in reset */
|
||||
- brcmf_chip_enter_download(bus->ci);
|
||||
+ brcmf_chip_set_passive(bus->ci);
|
||||
|
||||
rstvec = get_unaligned_le32(fw->data);
|
||||
brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec);
|
||||
@@ -3378,7 +3378,7 @@ static int brcmf_sdio_download_firmware(
|
||||
}
|
||||
|
||||
/* Take arm out of reset */
|
||||
- if (!brcmf_chip_exit_download(bus->ci, rstvec)) {
|
||||
+ if (!brcmf_chip_set_active(bus->ci, rstvec)) {
|
||||
brcmf_err("error getting out of ARM core reset\n");
|
||||
goto err;
|
||||
}
|
||||
@@ -3771,8 +3771,8 @@ static int brcmf_sdio_buscoreprep(void *
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip,
|
||||
- u32 rstvec)
|
||||
+static void brcmf_sdio_buscore_activate(void *ctx, struct brcmf_chip *chip,
|
||||
+ u32 rstvec)
|
||||
{
|
||||
struct brcmf_sdio_dev *sdiodev = ctx;
|
||||
struct brcmf_core *core;
|
||||
@@ -3815,7 +3815,7 @@ static void brcmf_sdio_buscore_write32(v
|
||||
|
||||
static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
|
||||
.prepare = brcmf_sdio_buscoreprep,
|
||||
- .exit_dl = brcmf_sdio_buscore_exitdl,
|
||||
+ .activate = brcmf_sdio_buscore_activate,
|
||||
.read32 = brcmf_sdio_buscore_read32,
|
||||
.write32 = brcmf_sdio_buscore_write32,
|
||||
};
|
||||
@@ -4239,12 +4239,11 @@ void brcmf_sdio_remove(struct brcmf_sdio
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
|
||||
/* Leave the device in state where it is
|
||||
- * 'quiet'. This is done by putting it in
|
||||
- * download_state which essentially resets
|
||||
- * all necessary cores.
|
||||
+ * 'passive'. This is done by resetting all
|
||||
+ * necessary cores.
|
||||
*/
|
||||
msleep(20);
|
||||
- brcmf_chip_enter_download(bus->ci);
|
||||
+ brcmf_chip_set_passive(bus->ci);
|
||||
brcmf_sdio_clkctl(bus, CLK_NONE, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 11 Mar 2015 16:11:30 +0100
|
||||
Subject: [PATCH] brcmfmac: assure device is ready for download after
|
||||
brcmf_chip_attach()
|
||||
|
||||
Make the brcmf_chip_attach() function responsible for putting the
|
||||
device in a state where it is accessible for firmware download.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
@@ -786,12 +786,6 @@ static int brcmf_chip_setup(struct brcmf
|
||||
if (chip->ops->setup)
|
||||
ret = chip->ops->setup(chip->ctx, pub);
|
||||
|
||||
- /*
|
||||
- * Make sure any on-chip ARM is off (in case strapping is wrong),
|
||||
- * or downloaded code was already running.
|
||||
- */
|
||||
- brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3);
|
||||
- brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -833,6 +827,8 @@ struct brcmf_chip *brcmf_chip_attach(voi
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
+ /* assure chip is passive for download */
|
||||
+ brcmf_chip_set_passive(&chip->pub);
|
||||
return &chip->pub;
|
||||
|
||||
fail:
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -509,8 +509,6 @@ static void brcmf_pcie_attach(struct brc
|
||||
|
||||
static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo)
|
||||
{
|
||||
- brcmf_chip_set_passive(devinfo->ci);
|
||||
-
|
||||
if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) {
|
||||
brcmf_pcie_select_core(devinfo, BCMA_CORE_ARM_CR4);
|
||||
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKIDX,
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -3356,9 +3356,6 @@ static int brcmf_sdio_download_firmware(
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
|
||||
|
||||
- /* Keep arm in reset */
|
||||
- brcmf_chip_set_passive(bus->ci);
|
||||
-
|
||||
rstvec = get_unaligned_le32(fw->data);
|
||||
brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec);
|
||||
|
|
@ -1,367 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 11 Mar 2015 16:11:31 +0100
|
||||
Subject: [PATCH] brcmfmac: extract ram size info from internal memory
|
||||
registers
|
||||
|
||||
Instead of hard-coded memory sizes it is possible to obtain that
|
||||
information from the internal memory registers.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
@@ -100,9 +100,6 @@
|
||||
#define BCM4329_CORE_SOCRAM_BASE 0x18003000
|
||||
/* ARM Cortex M3 core, ID 0x82a */
|
||||
#define BCM4329_CORE_ARM_BASE 0x18002000
|
||||
-#define BCM4329_RAMSIZE 0x48000
|
||||
-/* bcm43143 */
|
||||
-#define BCM43143_RAMSIZE 0x70000
|
||||
|
||||
#define CORE_SB(base, field) \
|
||||
(base + SBCONFIGOFF + offsetof(struct sbconfig, field))
|
||||
@@ -150,6 +147,78 @@ struct sbconfig {
|
||||
u32 sbidhigh; /* identification */
|
||||
};
|
||||
|
||||
+/* bankidx and bankinfo reg defines corerev >= 8 */
|
||||
+#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000
|
||||
+#define SOCRAM_BANKINFO_SZMASK 0x0000007f
|
||||
+#define SOCRAM_BANKIDX_ROM_MASK 0x00000100
|
||||
+
|
||||
+#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8
|
||||
+/* socram bankinfo memtype */
|
||||
+#define SOCRAM_MEMTYPE_RAM 0
|
||||
+#define SOCRAM_MEMTYPE_R0M 1
|
||||
+#define SOCRAM_MEMTYPE_DEVRAM 2
|
||||
+
|
||||
+#define SOCRAM_BANKINFO_SZBASE 8192
|
||||
+#define SRCI_LSS_MASK 0x00f00000
|
||||
+#define SRCI_LSS_SHIFT 20
|
||||
+#define SRCI_SRNB_MASK 0xf0
|
||||
+#define SRCI_SRNB_SHIFT 4
|
||||
+#define SRCI_SRBSZ_MASK 0xf
|
||||
+#define SRCI_SRBSZ_SHIFT 0
|
||||
+#define SR_BSZ_BASE 14
|
||||
+
|
||||
+struct sbsocramregs {
|
||||
+ u32 coreinfo;
|
||||
+ u32 bwalloc;
|
||||
+ u32 extracoreinfo;
|
||||
+ u32 biststat;
|
||||
+ u32 bankidx;
|
||||
+ u32 standbyctrl;
|
||||
+
|
||||
+ u32 errlogstatus; /* rev 6 */
|
||||
+ u32 errlogaddr; /* rev 6 */
|
||||
+ /* used for patching rev 3 & 5 */
|
||||
+ u32 cambankidx;
|
||||
+ u32 cambankstandbyctrl;
|
||||
+ u32 cambankpatchctrl;
|
||||
+ u32 cambankpatchtblbaseaddr;
|
||||
+ u32 cambankcmdreg;
|
||||
+ u32 cambankdatareg;
|
||||
+ u32 cambankmaskreg;
|
||||
+ u32 PAD[1];
|
||||
+ u32 bankinfo; /* corev 8 */
|
||||
+ u32 bankpda;
|
||||
+ u32 PAD[14];
|
||||
+ u32 extmemconfig;
|
||||
+ u32 extmemparitycsr;
|
||||
+ u32 extmemparityerrdata;
|
||||
+ u32 extmemparityerrcnt;
|
||||
+ u32 extmemwrctrlandsize;
|
||||
+ u32 PAD[84];
|
||||
+ u32 workaround;
|
||||
+ u32 pwrctl; /* corerev >= 2 */
|
||||
+ u32 PAD[133];
|
||||
+ u32 sr_control; /* corerev >= 15 */
|
||||
+ u32 sr_status; /* corerev >= 15 */
|
||||
+ u32 sr_address; /* corerev >= 15 */
|
||||
+ u32 sr_data; /* corerev >= 15 */
|
||||
+};
|
||||
+
|
||||
+#define SOCRAMREGOFFS(_f) offsetof(struct sbsocramregs, _f)
|
||||
+
|
||||
+#define ARMCR4_CAP (0x04)
|
||||
+#define ARMCR4_BANKIDX (0x40)
|
||||
+#define ARMCR4_BANKINFO (0x44)
|
||||
+#define ARMCR4_BANKPDA (0x4C)
|
||||
+
|
||||
+#define ARMCR4_TCBBNB_MASK 0xf0
|
||||
+#define ARMCR4_TCBBNB_SHIFT 4
|
||||
+#define ARMCR4_TCBANB_MASK 0xf
|
||||
+#define ARMCR4_TCBANB_SHIFT 0
|
||||
+
|
||||
+#define ARMCR4_BSZ_MASK 0x3f
|
||||
+#define ARMCR4_BSZ_MULT 8192
|
||||
+
|
||||
struct brcmf_core_priv {
|
||||
struct brcmf_core pub;
|
||||
u32 wrapbase;
|
||||
@@ -443,10 +512,6 @@ static int brcmf_chip_cores_check(struct
|
||||
break;
|
||||
case BCMA_CORE_ARM_CR4:
|
||||
cpu_found = true;
|
||||
- if (ci->pub.rambase == 0) {
|
||||
- brcmf_err("RAM base not provided with ARM CR4 core\n");
|
||||
- return -ENOMEM;
|
||||
- }
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -462,60 +527,160 @@ static int brcmf_chip_cores_check(struct
|
||||
brcmf_err("RAM core not provided with ARM CM3 core\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
- if (!ci->pub.ramsize) {
|
||||
- brcmf_err("RAM size is undetermined\n");
|
||||
- return -ENOMEM;
|
||||
- }
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
|
||||
+static u32 brcmf_chip_core_read32(struct brcmf_core_priv *core, u16 reg)
|
||||
{
|
||||
- switch (ci->pub.chip) {
|
||||
- case BRCM_CC_4329_CHIP_ID:
|
||||
- ci->pub.ramsize = BCM4329_RAMSIZE;
|
||||
- break;
|
||||
- case BRCM_CC_43143_CHIP_ID:
|
||||
- ci->pub.ramsize = BCM43143_RAMSIZE;
|
||||
- break;
|
||||
- case BRCM_CC_43241_CHIP_ID:
|
||||
- ci->pub.ramsize = 0x90000;
|
||||
- break;
|
||||
- case BRCM_CC_4330_CHIP_ID:
|
||||
- ci->pub.ramsize = 0x48000;
|
||||
- break;
|
||||
+ return core->chip->ops->read32(core->chip->ctx, core->pub.base + reg);
|
||||
+}
|
||||
+
|
||||
+static void brcmf_chip_core_write32(struct brcmf_core_priv *core,
|
||||
+ u16 reg, u32 val)
|
||||
+{
|
||||
+ core->chip->ops->write32(core->chip->ctx, core->pub.base + reg, val);
|
||||
+}
|
||||
+
|
||||
+static bool brcmf_chip_socram_banksize(struct brcmf_core_priv *core, u8 idx,
|
||||
+ u32 *banksize)
|
||||
+{
|
||||
+ u32 bankinfo;
|
||||
+ u32 bankidx = (SOCRAM_MEMTYPE_RAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
|
||||
+
|
||||
+ bankidx |= idx;
|
||||
+ brcmf_chip_core_write32(core, SOCRAMREGOFFS(bankidx), bankidx);
|
||||
+ bankinfo = brcmf_chip_core_read32(core, SOCRAMREGOFFS(bankinfo));
|
||||
+ *banksize = (bankinfo & SOCRAM_BANKINFO_SZMASK) + 1;
|
||||
+ *banksize *= SOCRAM_BANKINFO_SZBASE;
|
||||
+ return !!(bankinfo & SOCRAM_BANKINFO_RETNTRAM_MASK);
|
||||
+}
|
||||
+
|
||||
+static void brcmf_chip_socram_ramsize(struct brcmf_core_priv *sr, u32 *ramsize,
|
||||
+ u32 *srsize)
|
||||
+{
|
||||
+ u32 coreinfo;
|
||||
+ uint nb, banksize, lss;
|
||||
+ bool retent;
|
||||
+ int i;
|
||||
+
|
||||
+ *ramsize = 0;
|
||||
+ *srsize = 0;
|
||||
+
|
||||
+ if (WARN_ON(sr->pub.rev < 4))
|
||||
+ return;
|
||||
+
|
||||
+ if (!brcmf_chip_iscoreup(&sr->pub))
|
||||
+ brcmf_chip_resetcore(&sr->pub, 0, 0, 0);
|
||||
+
|
||||
+ /* Get info for determining size */
|
||||
+ coreinfo = brcmf_chip_core_read32(sr, SOCRAMREGOFFS(coreinfo));
|
||||
+ nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
|
||||
+
|
||||
+ if ((sr->pub.rev <= 7) || (sr->pub.rev == 12)) {
|
||||
+ banksize = (coreinfo & SRCI_SRBSZ_MASK);
|
||||
+ lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
|
||||
+ if (lss != 0)
|
||||
+ nb--;
|
||||
+ *ramsize = nb * (1 << (banksize + SR_BSZ_BASE));
|
||||
+ if (lss != 0)
|
||||
+ *ramsize += (1 << ((lss - 1) + SR_BSZ_BASE));
|
||||
+ } else {
|
||||
+ nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
|
||||
+ for (i = 0; i < nb; i++) {
|
||||
+ retent = brcmf_chip_socram_banksize(sr, i, &banksize);
|
||||
+ *ramsize += banksize;
|
||||
+ if (retent)
|
||||
+ *srsize += banksize;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* hardcoded save&restore memory sizes */
|
||||
+ switch (sr->chip->pub.chip) {
|
||||
case BRCM_CC_4334_CHIP_ID:
|
||||
- case BRCM_CC_43340_CHIP_ID:
|
||||
- ci->pub.ramsize = 0x80000;
|
||||
+ if (sr->chip->pub.chiprev < 2)
|
||||
+ *srsize = (32 * 1024);
|
||||
break;
|
||||
- case BRCM_CC_4335_CHIP_ID:
|
||||
- ci->pub.ramsize = 0xc0000;
|
||||
- ci->pub.rambase = 0x180000;
|
||||
- break;
|
||||
- case BRCM_CC_43362_CHIP_ID:
|
||||
- ci->pub.ramsize = 0x3c000;
|
||||
+ default:
|
||||
break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/** Return the TCM-RAM size of the ARMCR4 core. */
|
||||
+static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)
|
||||
+{
|
||||
+ u32 corecap;
|
||||
+ u32 memsize = 0;
|
||||
+ u32 nab;
|
||||
+ u32 nbb;
|
||||
+ u32 totb;
|
||||
+ u32 bxinfo;
|
||||
+ u32 idx;
|
||||
+
|
||||
+ corecap = brcmf_chip_core_read32(cr4, ARMCR4_CAP);
|
||||
+
|
||||
+ nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT;
|
||||
+ nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT;
|
||||
+ totb = nab + nbb;
|
||||
+
|
||||
+ for (idx = 0; idx < totb; idx++) {
|
||||
+ brcmf_chip_core_write32(cr4, ARMCR4_BANKIDX, idx);
|
||||
+ bxinfo = brcmf_chip_core_read32(cr4, ARMCR4_BANKINFO);
|
||||
+ memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT;
|
||||
+ }
|
||||
+
|
||||
+ return memsize;
|
||||
+}
|
||||
+
|
||||
+static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
|
||||
+{
|
||||
+ switch (ci->pub.chip) {
|
||||
case BRCM_CC_4345_CHIP_ID:
|
||||
- ci->pub.ramsize = 0xc8000;
|
||||
- ci->pub.rambase = 0x198000;
|
||||
- break;
|
||||
+ return 0x198000;
|
||||
+ case BRCM_CC_4335_CHIP_ID:
|
||||
case BRCM_CC_4339_CHIP_ID:
|
||||
case BRCM_CC_4354_CHIP_ID:
|
||||
case BRCM_CC_4356_CHIP_ID:
|
||||
case BRCM_CC_43567_CHIP_ID:
|
||||
case BRCM_CC_43569_CHIP_ID:
|
||||
case BRCM_CC_43570_CHIP_ID:
|
||||
- ci->pub.ramsize = 0xc0000;
|
||||
- ci->pub.rambase = 0x180000;
|
||||
- break;
|
||||
case BRCM_CC_43602_CHIP_ID:
|
||||
- ci->pub.ramsize = 0xf0000;
|
||||
- ci->pub.rambase = 0x180000;
|
||||
- break;
|
||||
+ return 0x180000;
|
||||
default:
|
||||
brcmf_err("unknown chip: %s\n", ci->pub.name);
|
||||
break;
|
||||
}
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
|
||||
+{
|
||||
+ struct brcmf_core_priv *mem_core;
|
||||
+ struct brcmf_core *mem;
|
||||
+
|
||||
+ mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_ARM_CR4);
|
||||
+ if (mem) {
|
||||
+ mem_core = container_of(mem, struct brcmf_core_priv, pub);
|
||||
+ ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core);
|
||||
+ ci->pub.rambase = brcmf_chip_tcm_rambase(ci);
|
||||
+ if (!ci->pub.rambase) {
|
||||
+ brcmf_err("RAM base not provided with ARM CR4 core\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ } else {
|
||||
+ mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_INTERNAL_MEM);
|
||||
+ mem_core = container_of(mem, struct brcmf_core_priv, pub);
|
||||
+ brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize,
|
||||
+ &ci->pub.srsize);
|
||||
+ }
|
||||
+ brcmf_dbg(INFO, "RAM: base=0x%x size=%d (0x%x) sr=%d (0x%x)\n",
|
||||
+ ci->pub.rambase, ci->pub.ramsize, ci->pub.ramsize,
|
||||
+ ci->pub.srsize, ci->pub.srsize);
|
||||
+
|
||||
+ if (!ci->pub.ramsize) {
|
||||
+ brcmf_err("RAM size is undetermined\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static u32 brcmf_chip_dmp_get_desc(struct brcmf_chip_priv *ci, u32 *eromaddr,
|
||||
@@ -668,6 +833,7 @@ static int brcmf_chip_recognition(struct
|
||||
struct brcmf_core *core;
|
||||
u32 regdata;
|
||||
u32 socitype;
|
||||
+ int ret;
|
||||
|
||||
/* Get CC core rev
|
||||
* Chipid is assume to be at offset 0 from SI_ENUM_BASE
|
||||
@@ -720,9 +886,13 @@ static int brcmf_chip_recognition(struct
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
- brcmf_chip_get_raminfo(ci);
|
||||
-
|
||||
- return brcmf_chip_cores_check(ci);
|
||||
+ ret = brcmf_chip_cores_check(ci);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* assure chip is passive for core access */
|
||||
+ brcmf_chip_set_passive(&ci->pub);
|
||||
+ return brcmf_chip_get_raminfo(ci);
|
||||
}
|
||||
|
||||
static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
|
||||
@@ -827,8 +997,6 @@ struct brcmf_chip *brcmf_chip_attach(voi
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
- /* assure chip is passive for download */
|
||||
- brcmf_chip_set_passive(&chip->pub);
|
||||
return &chip->pub;
|
||||
|
||||
fail:
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h
|
||||
@@ -30,7 +30,8 @@
|
||||
* @pmucaps: PMU capabilities.
|
||||
* @pmurev: PMU revision.
|
||||
* @rambase: RAM base address (only applicable for ARM CR4 chips).
|
||||
- * @ramsize: amount of RAM on chip.
|
||||
+ * @ramsize: amount of RAM on chip including retention.
|
||||
+ * @srsize: amount of retention RAM on chip.
|
||||
* @name: string representation of the chip identifier.
|
||||
*/
|
||||
struct brcmf_chip {
|
||||
@@ -41,6 +42,7 @@ struct brcmf_chip {
|
||||
u32 pmurev;
|
||||
u32 rambase;
|
||||
u32 ramsize;
|
||||
+ u32 srsize;
|
||||
char name[8];
|
||||
};
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 11 Mar 2015 16:11:32 +0100
|
||||
Subject: [PATCH] brcmfmac: take save&restore memory into account for SDIO
|
||||
shared info
|
||||
|
||||
The firmware provides pointer to SDIO shared information at end of
|
||||
RAM during firmware initialization. End of RAM is obviously determined
|
||||
by the actual ram size, but part of that may be used for save&restore
|
||||
memory. In that case another location in RAM will hold the pointer.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -1067,44 +1067,47 @@ static inline bool brcmf_sdio_valid_shar
|
||||
static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
|
||||
struct sdpcm_shared *sh)
|
||||
{
|
||||
- u32 addr;
|
||||
+ u32 addr = 0;
|
||||
int rv;
|
||||
u32 shaddr = 0;
|
||||
struct sdpcm_shared_le sh_le;
|
||||
__le32 addr_le;
|
||||
|
||||
- shaddr = bus->ci->rambase + bus->ci->ramsize - 4;
|
||||
+ sdio_claim_host(bus->sdiodev->func[1]);
|
||||
+ brcmf_sdio_bus_sleep(bus, false, false);
|
||||
|
||||
/*
|
||||
* Read last word in socram to determine
|
||||
* address of sdpcm_shared structure
|
||||
*/
|
||||
- sdio_claim_host(bus->sdiodev->func[1]);
|
||||
- brcmf_sdio_bus_sleep(bus, false, false);
|
||||
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
|
||||
- sdio_release_host(bus->sdiodev->func[1]);
|
||||
+ shaddr = bus->ci->rambase + bus->ci->ramsize - 4;
|
||||
+ if (!bus->ci->rambase && brcmf_chip_sr_capable(bus->ci))
|
||||
+ shaddr -= bus->ci->srsize;
|
||||
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr,
|
||||
+ (u8 *)&addr_le, 4);
|
||||
if (rv < 0)
|
||||
- return rv;
|
||||
-
|
||||
- addr = le32_to_cpu(addr_le);
|
||||
-
|
||||
- brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
|
||||
+ goto fail;
|
||||
|
||||
/*
|
||||
* Check if addr is valid.
|
||||
* NVRAM length at the end of memory should have been overwritten.
|
||||
*/
|
||||
+ addr = le32_to_cpu(addr_le);
|
||||
if (!brcmf_sdio_valid_shared_address(addr)) {
|
||||
- brcmf_err("invalid sdpcm_shared address 0x%08X\n",
|
||||
- addr);
|
||||
- return -EINVAL;
|
||||
+ brcmf_err("invalid sdpcm_shared address 0x%08X\n", addr);
|
||||
+ rv = -EINVAL;
|
||||
+ goto fail;
|
||||
}
|
||||
|
||||
+ brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
|
||||
+
|
||||
/* Read hndrte_shared structure */
|
||||
rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
|
||||
sizeof(struct sdpcm_shared_le));
|
||||
if (rv < 0)
|
||||
- return rv;
|
||||
+ goto fail;
|
||||
+
|
||||
+ sdio_release_host(bus->sdiodev->func[1]);
|
||||
|
||||
/* Endianness */
|
||||
sh->flags = le32_to_cpu(sh_le.flags);
|
||||
@@ -1121,8 +1124,13 @@ static int brcmf_sdio_readshared(struct
|
||||
sh->flags & SDPCM_SHARED_VERSION_MASK);
|
||||
return -EPROTO;
|
||||
}
|
||||
-
|
||||
return 0;
|
||||
+
|
||||
+fail:
|
||||
+ brcmf_err("unable to obtain sdpcm_shared info: rv=%d (addr=0x%x)\n",
|
||||
+ rv, addr);
|
||||
+ sdio_release_host(bus->sdiodev->func[1]);
|
||||
+ return rv;
|
||||
}
|
||||
|
||||
static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
|
|
@ -1,59 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 11 Mar 2015 16:11:33 +0100
|
||||
Subject: [PATCH] brcmfmac: fix watchdog timer regression
|
||||
|
||||
The watchdog timer is used to put the device in a low-power mode when
|
||||
it is idle for some time. This timer is stopped during that mode and
|
||||
should be restarted upon activity. This has been broken by commit
|
||||
d4150fced0365 ("brcmfmac: Simplify watchdog sleep."). This patch
|
||||
restores the behaviour as it was before that commit.
|
||||
|
||||
Reported-by: Pontus Fuchs <pontusf@broadcom.com>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -972,7 +972,6 @@ static int brcmf_sdio_clkctl(struct brcm
|
||||
brcmf_sdio_sdclk(bus, true);
|
||||
/* Now request HT Avail on the backplane */
|
||||
brcmf_sdio_htclk(bus, true, pendok);
|
||||
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
|
||||
break;
|
||||
|
||||
case CLK_SDONLY:
|
||||
@@ -984,7 +983,6 @@ static int brcmf_sdio_clkctl(struct brcm
|
||||
else
|
||||
brcmf_err("request for %d -> %d\n",
|
||||
bus->clkstate, target);
|
||||
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
|
||||
break;
|
||||
|
||||
case CLK_NONE:
|
||||
@@ -993,7 +991,6 @@ static int brcmf_sdio_clkctl(struct brcm
|
||||
brcmf_sdio_htclk(bus, false, false);
|
||||
/* Now remove the SD clock */
|
||||
brcmf_sdio_sdclk(bus, false);
|
||||
- brcmf_sdio_wd_timer(bus, 0);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
@@ -1048,6 +1045,7 @@ end:
|
||||
brcmf_sdio_clkctl(bus, CLK_NONE, pendok);
|
||||
} else {
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
|
||||
+ brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
|
||||
}
|
||||
bus->sleeping = sleep;
|
||||
brcmf_dbg(SDIO, "new state %s\n",
|
||||
@@ -4242,6 +4240,7 @@ void brcmf_sdio_remove(struct brcmf_sdio
|
||||
if (bus->ci) {
|
||||
if (bus->sdiodev->state != BRCMF_SDIOD_NOMEDIUM) {
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
+ brcmf_sdio_wd_timer(bus, 0);
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
|
||||
/* Leave the device in state where it is
|
||||
* 'passive'. This is done by resetting all
|
|
@ -1,44 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:21 +0100
|
||||
Subject: [PATCH] brcmfmac: avoid runtime-pm for sdio host controller
|
||||
|
||||
Several host controllers supporting runtime-pm are causing issues
|
||||
with our sdio wireless cards because they disable the sdio interrupt
|
||||
upon going into runtime suspend. This patch avoids that by doing
|
||||
a pm_runtime_forbid() call during the probe. Tested with Sony Vaio
|
||||
Duo 13 which uses sdhci-acpi host controller.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/brcmfmac-sdio.h>
|
||||
+#include <linux/pm_runtime.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
@@ -1006,6 +1007,7 @@ static int brcmf_sdiod_remove(struct brc
|
||||
sg_free_table(&sdiodev->sgtable);
|
||||
sdiodev->sbwad = 0;
|
||||
|
||||
+ pm_runtime_allow(sdiodev->func[1]->card->host->parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1074,7 +1076,7 @@ static int brcmf_sdiod_probe(struct brcm
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
-
|
||||
+ pm_runtime_forbid(host->parent);
|
||||
out:
|
||||
if (ret)
|
||||
brcmf_sdiod_remove(sdiodev);
|
|
@ -1,171 +0,0 @@
|
|||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:22 +0100
|
||||
Subject: [PATCH] brcmfmac: Add necessary memory barriers for SDIO.
|
||||
|
||||
SDIO uses a thread to handle all communication with the device,
|
||||
for this data is exchanged between threads. This data needs proper
|
||||
memory barriers to make sure that data "exchange" is going correct.
|
||||
|
||||
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
|
||||
@@ -507,8 +507,8 @@ struct brcmf_sdio {
|
||||
|
||||
struct workqueue_struct *brcmf_wq;
|
||||
struct work_struct datawork;
|
||||
- atomic_t dpc_tskcnt;
|
||||
- atomic_t dpc_running;
|
||||
+ bool dpc_triggered;
|
||||
+ bool dpc_running;
|
||||
|
||||
bool txoff; /* Transmit flow-controlled */
|
||||
struct brcmf_sdio_count sdcnt;
|
||||
@@ -2713,6 +2713,7 @@ static void brcmf_sdio_dpc(struct brcmf_
|
||||
err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
|
||||
bus->ctrl_frame_len);
|
||||
bus->ctrl_frame_err = err;
|
||||
+ wmb();
|
||||
bus->ctrl_frame_stat = false;
|
||||
}
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
@@ -2734,6 +2735,7 @@ static void brcmf_sdio_dpc(struct brcmf_
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
if (bus->ctrl_frame_stat) {
|
||||
bus->ctrl_frame_err = -ENODEV;
|
||||
+ wmb();
|
||||
bus->ctrl_frame_stat = false;
|
||||
brcmf_sdio_wait_event_wakeup(bus);
|
||||
}
|
||||
@@ -2744,7 +2746,7 @@ static void brcmf_sdio_dpc(struct brcmf_
|
||||
(!atomic_read(&bus->fcstate) &&
|
||||
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
|
||||
data_ok(bus))) {
|
||||
- atomic_inc(&bus->dpc_tskcnt);
|
||||
+ bus->dpc_triggered = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2940,6 +2942,7 @@ brcmf_sdio_bus_txctl(struct device *dev,
|
||||
/* Send from dpc */
|
||||
bus->ctrl_frame_buf = msg;
|
||||
bus->ctrl_frame_len = msglen;
|
||||
+ wmb();
|
||||
bus->ctrl_frame_stat = true;
|
||||
|
||||
brcmf_sdio_trigger_dpc(bus);
|
||||
@@ -2958,6 +2961,7 @@ brcmf_sdio_bus_txctl(struct device *dev,
|
||||
if (!ret) {
|
||||
brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
|
||||
bus->ctrl_frame_err);
|
||||
+ rmb();
|
||||
ret = bus->ctrl_frame_err;
|
||||
}
|
||||
|
||||
@@ -3526,8 +3530,8 @@ done:
|
||||
|
||||
void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus)
|
||||
{
|
||||
- if (atomic_read(&bus->dpc_tskcnt) == 0) {
|
||||
- atomic_inc(&bus->dpc_tskcnt);
|
||||
+ if (!bus->dpc_triggered) {
|
||||
+ bus->dpc_triggered = true;
|
||||
queue_work(bus->brcmf_wq, &bus->datawork);
|
||||
}
|
||||
}
|
||||
@@ -3558,7 +3562,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *b
|
||||
if (!bus->intr)
|
||||
brcmf_err("isr w/o interrupt configured!\n");
|
||||
|
||||
- atomic_inc(&bus->dpc_tskcnt);
|
||||
+ bus->dpc_triggered = true;
|
||||
queue_work(bus->brcmf_wq, &bus->datawork);
|
||||
}
|
||||
|
||||
@@ -3578,7 +3582,7 @@ static void brcmf_sdio_bus_watchdog(stru
|
||||
if (!bus->intr ||
|
||||
(bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
|
||||
|
||||
- if (atomic_read(&bus->dpc_tskcnt) == 0) {
|
||||
+ if (!bus->dpc_triggered) {
|
||||
u8 devpend;
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
@@ -3596,7 +3600,7 @@ static void brcmf_sdio_bus_watchdog(stru
|
||||
bus->sdcnt.pollcnt++;
|
||||
atomic_set(&bus->ipend, 1);
|
||||
|
||||
- atomic_inc(&bus->dpc_tskcnt);
|
||||
+ bus->dpc_triggered = true;
|
||||
queue_work(bus->brcmf_wq, &bus->datawork);
|
||||
}
|
||||
}
|
||||
@@ -3623,17 +3627,21 @@ static void brcmf_sdio_bus_watchdog(stru
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* On idle timeout clear activity flag and/or turn off clock */
|
||||
- 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);
|
||||
+ if (!bus->dpc_triggered) {
|
||||
+ rmb();
|
||||
+ if ((!bus->dpc_running) && (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;
|
||||
+ brcmf_sdio_bus_sleep(bus, true, false);
|
||||
+ sdio_release_host(bus->sdiodev->func[1]);
|
||||
+ }
|
||||
+ } else {
|
||||
bus->idlecount = 0;
|
||||
- brcmf_sdio_bus_sleep(bus, true, false);
|
||||
- sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
||||
} else {
|
||||
bus->idlecount = 0;
|
||||
@@ -3645,13 +3653,14 @@ static void brcmf_sdio_dataworker(struct
|
||||
struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio,
|
||||
datawork);
|
||||
|
||||
- while (atomic_read(&bus->dpc_tskcnt)) {
|
||||
- atomic_set(&bus->dpc_running, 1);
|
||||
- atomic_set(&bus->dpc_tskcnt, 0);
|
||||
+ bus->dpc_running = true;
|
||||
+ wmb();
|
||||
+ while (ACCESS_ONCE(bus->dpc_triggered)) {
|
||||
+ bus->dpc_triggered = false;
|
||||
brcmf_sdio_dpc(bus);
|
||||
bus->idlecount = 0;
|
||||
- atomic_set(&bus->dpc_running, 0);
|
||||
}
|
||||
+ bus->dpc_running = false;
|
||||
if (brcmf_sdiod_freezing(bus->sdiodev)) {
|
||||
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN);
|
||||
brcmf_sdiod_try_freeze(bus->sdiodev);
|
||||
@@ -4144,8 +4153,8 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
|
||||
bus->watchdog_tsk = NULL;
|
||||
}
|
||||
/* Initialize DPC thread */
|
||||
- atomic_set(&bus->dpc_tskcnt, 0);
|
||||
- atomic_set(&bus->dpc_running, 0);
|
||||
+ bus->dpc_triggered = false;
|
||||
+ bus->dpc_running = false;
|
||||
|
||||
/* Assign bus interface call back */
|
||||
bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
|
|
@ -1,26 +0,0 @@
|
|||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:24 +0100
|
||||
Subject: [PATCH] brcmfmac: Remove unnecessary new-line in pcie console
|
||||
logging.
|
||||
|
||||
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/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -651,10 +651,9 @@ static void brcmf_pcie_bus_console_read(
|
||||
console->log_str[console->log_idx] = ch;
|
||||
console->log_idx++;
|
||||
}
|
||||
-
|
||||
if (ch == '\n') {
|
||||
console->log_str[console->log_idx] = 0;
|
||||
- brcmf_dbg(PCIE, "CONSOLE: %s\n", console->log_str);
|
||||
+ brcmf_dbg(PCIE, "CONSOLE: %s", console->log_str);
|
||||
console->log_idx = 0;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:25 +0100
|
||||
Subject: [PATCH] brcmfmac: add MODULE_FIRMWARE() macros for bcm4356 PCIe
|
||||
device
|
||||
|
||||
The BCM4356 PCIe wireless device was added recently but overlooked
|
||||
the fact that the MODULE_FIRMWARE() macros were missing for the
|
||||
firmwares needed by this device.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -189,6 +189,8 @@ MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_4354_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_4354_NVRAM_NAME);
|
||||
+MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME);
|
||||
+MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME);
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:26 +0100
|
||||
Subject: [PATCH] brcmfmac: add support for BCM43430 SDIO chipset
|
||||
|
||||
This patch added support for the BCM43430 802.11n SDIO chipset.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
@@ -1098,6 +1098,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_43430),
|
||||
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
|
||||
@@ -600,6 +600,12 @@ static void brcmf_chip_socram_ramsize(st
|
||||
if (sr->chip->pub.chiprev < 2)
|
||||
*srsize = (32 * 1024);
|
||||
break;
|
||||
+ case BRCM_CC_43430_CHIP_ID:
|
||||
+ /* assume sr for now as we can not check
|
||||
+ * firmware sr capability at this point.
|
||||
+ */
|
||||
+ *srsize = (64 * 1024);
|
||||
+ break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1072,6 +1078,7 @@ static void
|
||||
brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip)
|
||||
{
|
||||
struct brcmf_core *core;
|
||||
+ struct brcmf_core_priv *sr;
|
||||
|
||||
brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3);
|
||||
core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
|
||||
@@ -1081,6 +1088,13 @@ brcmf_chip_cm3_set_passive(struct brcmf_
|
||||
D11_BCMA_IOCTL_PHYCLOCKEN);
|
||||
core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM);
|
||||
brcmf_chip_resetcore(core, 0, 0, 0);
|
||||
+
|
||||
+ /* disable bank #3 remap for this device */
|
||||
+ if (chip->pub.chip == BRCM_CC_43430_CHIP_ID) {
|
||||
+ sr = container_of(core, struct brcmf_core_priv, pub);
|
||||
+ brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankidx), 3);
|
||||
+ brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankpda), 0);
|
||||
+ }
|
||||
}
|
||||
|
||||
static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip)
|
||||
@@ -1188,6 +1202,10 @@ bool brcmf_chip_sr_capable(struct brcmf_
|
||||
addr = CORE_CC_REG(base, chipcontrol_data);
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
return (reg & pmu_cc3_mask) != 0;
|
||||
+ case BRCM_CC_43430_CHIP_ID:
|
||||
+ addr = CORE_CC_REG(base, sr_control1);
|
||||
+ reg = chip->ops->read32(chip->ctx, addr);
|
||||
+ return reg != 0;
|
||||
default:
|
||||
addr = CORE_CC_REG(base, pmucapabilities_ext);
|
||||
reg = chip->ops->read32(chip->ctx, addr);
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -615,6 +615,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 BCM43430_FIRMWARE_NAME "brcm/brcmfmac43430-sdio.bin"
|
||||
+#define BCM43430_NVRAM_NAME "brcm/brcmfmac43430-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"
|
||||
@@ -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(BCM43430_FIRMWARE_NAME);
|
||||
+MODULE_FIRMWARE(BCM43430_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM4345_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM4345_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME);
|
||||
@@ -671,6 +675,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_43430_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43430) },
|
||||
{ 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_43430_CHIP_ID 43430
|
||||
#define BRCM_CC_4345_CHIP_ID 0x4345
|
||||
#define BRCM_CC_4354_CHIP_ID 0x4354
|
||||
#define BRCM_CC_4356_CHIP_ID 0x4356
|
||||
--- a/drivers/net/wireless/brcm80211/include/chipcommon.h
|
||||
+++ b/drivers/net/wireless/brcm80211/include/chipcommon.h
|
||||
@@ -183,7 +183,14 @@ struct chipcregs {
|
||||
u8 uart1lsr;
|
||||
u8 uart1msr;
|
||||
u8 uart1scratch;
|
||||
- u32 PAD[126];
|
||||
+ u32 PAD[62];
|
||||
+
|
||||
+ /* save/restore, corerev >= 48 */
|
||||
+ u32 sr_capability; /* 0x500 */
|
||||
+ u32 sr_control0; /* 0x504 */
|
||||
+ u32 sr_control1; /* 0x508 */
|
||||
+ u32 gpio_control; /* 0x50C */
|
||||
+ u32 PAD[60];
|
||||
|
||||
/* PMU registers (corerev >= 20) */
|
||||
u32 pmucontrol; /* 0x600 */
|
||||
--- 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_43430 0xa9a6
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4345 0x4345
|
||||
#define SDIO_DEVICE_ID_BROADCOM_4354 0x4354
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:27 +0100
|
||||
Subject: [PATCH] brcmfmac: only support the BCM43455/7 device
|
||||
|
||||
Recently support was added for the BCM4345 SDIO chipset by
|
||||
commit 9c51026509d7 ("brcmfmac: Add support for BCM4345 SDIO chipset")
|
||||
however this was verified using a BCM43455 device, which is
|
||||
a more recent revision of the chip. This patch assure that
|
||||
older revisions are not probed as they would fail.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Syed Asifful Dayyan <syedd@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -617,8 +617,8 @@ static const struct sdiod_drive_str sdio
|
||||
#define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt"
|
||||
#define BCM43430_FIRMWARE_NAME "brcm/brcmfmac43430-sdio.bin"
|
||||
#define BCM43430_NVRAM_NAME "brcm/brcmfmac43430-sdio.txt"
|
||||
-#define BCM4345_FIRMWARE_NAME "brcm/brcmfmac4345-sdio.bin"
|
||||
-#define BCM4345_NVRAM_NAME "brcm/brcmfmac4345-sdio.txt"
|
||||
+#define BCM43455_FIRMWARE_NAME "brcm/brcmfmac43455-sdio.bin"
|
||||
+#define BCM43455_NVRAM_NAME "brcm/brcmfmac43455-sdio.txt"
|
||||
#define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin"
|
||||
#define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt"
|
||||
|
||||
@@ -644,8 +644,8 @@ MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM43430_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM43430_NVRAM_NAME);
|
||||
-MODULE_FIRMWARE(BCM4345_FIRMWARE_NAME);
|
||||
-MODULE_FIRMWARE(BCM4345_NVRAM_NAME);
|
||||
+MODULE_FIRMWARE(BCM43455_FIRMWARE_NAME);
|
||||
+MODULE_FIRMWARE(BCM43455_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM4354_NVRAM_NAME);
|
||||
|
||||
@@ -676,7 +676,7 @@ static const struct brcmf_firmware_names
|
||||
{ BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
|
||||
{ BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
|
||||
{ BRCM_CC_43430_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43430) },
|
||||
- { BRCM_CC_4345_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4345) },
|
||||
+ { BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, BRCMF_FIRMWARE_NVRAM(BCM43455) },
|
||||
{ BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) }
|
||||
};
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 18 Mar 2015 13:25:28 +0100
|
||||
Subject: [PATCH] brcmfmac: remove support for unreleased BCM4354 PCIe
|
||||
|
||||
There are no known BCM4354 PCIe devices released so removing
|
||||
support from the driver until proven otherwise.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -47,8 +47,6 @@ enum brcmf_pcie_state {
|
||||
|
||||
#define BRCMF_PCIE_43602_FW_NAME "brcm/brcmfmac43602-pcie.bin"
|
||||
#define BRCMF_PCIE_43602_NVRAM_NAME "brcm/brcmfmac43602-pcie.txt"
|
||||
-#define BRCMF_PCIE_4354_FW_NAME "brcm/brcmfmac4354-pcie.bin"
|
||||
-#define BRCMF_PCIE_4354_NVRAM_NAME "brcm/brcmfmac4354-pcie.txt"
|
||||
#define BRCMF_PCIE_4356_FW_NAME "brcm/brcmfmac4356-pcie.bin"
|
||||
#define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt"
|
||||
#define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin"
|
||||
@@ -187,8 +185,6 @@ enum brcmf_pcie_state {
|
||||
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME);
|
||||
-MODULE_FIRMWARE(BRCMF_PCIE_4354_FW_NAME);
|
||||
-MODULE_FIRMWARE(BRCMF_PCIE_4354_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME);
|
||||
@@ -1327,10 +1323,6 @@ static int brcmf_pcie_get_fwnames(struct
|
||||
fw_name = BRCMF_PCIE_43602_FW_NAME;
|
||||
nvram_name = BRCMF_PCIE_43602_NVRAM_NAME;
|
||||
break;
|
||||
- case BRCM_CC_4354_CHIP_ID:
|
||||
- fw_name = BRCMF_PCIE_4354_FW_NAME;
|
||||
- nvram_name = BRCMF_PCIE_4354_NVRAM_NAME;
|
||||
- break;
|
||||
case BRCM_CC_4356_CHIP_ID:
|
||||
fw_name = BRCMF_PCIE_4356_FW_NAME;
|
||||
nvram_name = BRCMF_PCIE_4356_NVRAM_NAME;
|
||||
@@ -1855,7 +1847,6 @@ cleanup:
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
|
||||
|
||||
static struct pci_device_id brcmf_pcie_devid_table[] = {
|
||||
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
|
|
@ -1,28 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Fri, 20 Mar 2015 22:18:17 +0100
|
||||
Subject: [PATCH] brcmfmac: disable MBSS feature for BCM43362
|
||||
|
||||
The BCM43362 firmware falsely reports it is capable of providing
|
||||
MBSS. As a result AP mode no longer works for this device. Therefor
|
||||
disable MBSS in the driver for this chipset.
|
||||
|
||||
Cc: stable@vger.kernel.org # 3.19.y
|
||||
Reported-by: Jorg Krause <jkrause@posteo.de>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
|
||||
@@ -126,7 +126,8 @@ void brcmf_feat_attach(struct brcmf_pub
|
||||
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
|
||||
if (drvr->bus_if->wowl_supported)
|
||||
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
|
||||
- brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
|
||||
+ if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
|
||||
+ brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
|
||||
|
||||
/* set chip related quirks */
|
||||
switch (drvr->bus_if->chip) {
|
|
@ -1,300 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:24 +0200
|
||||
Subject: [PATCH] brcmfmac: use static superset of channels for wiphy
|
||||
bands
|
||||
|
||||
The driver was constructing a list of channels per wiphy band
|
||||
by querying the device. This list is not what the hardware is
|
||||
able to do as it is already filtered by the country setting in
|
||||
the device. As user-space may change the country this would
|
||||
require updating the channel list which is not recommended [1].
|
||||
This patch introduces a superset of channels. The individual
|
||||
channels are disabled appropriately by querying the device.
|
||||
|
||||
[1] http://mid.gmane.org/1426706320.3001.21.camel@sipsolutions.net
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -129,13 +129,47 @@ static struct ieee80211_rate __wl_rates[
|
||||
RATETAB_ENT(BRCM_RATE_54M, 0),
|
||||
};
|
||||
|
||||
-#define wl_a_rates (__wl_rates + 4)
|
||||
-#define wl_a_rates_size 8
|
||||
#define wl_g_rates (__wl_rates + 0)
|
||||
-#define wl_g_rates_size 12
|
||||
+#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
|
||||
+#define wl_a_rates (__wl_rates + 4)
|
||||
+#define wl_a_rates_size (wl_g_rates_size - 4)
|
||||
+
|
||||
+#define CHAN2G(_channel, _freq) { \
|
||||
+ .band = IEEE80211_BAND_2GHZ, \
|
||||
+ .center_freq = (_freq), \
|
||||
+ .hw_value = (_channel), \
|
||||
+ .flags = IEEE80211_CHAN_DISABLED, \
|
||||
+ .max_antenna_gain = 0, \
|
||||
+ .max_power = 30, \
|
||||
+}
|
||||
+
|
||||
+#define CHAN5G(_channel) { \
|
||||
+ .band = IEEE80211_BAND_5GHZ, \
|
||||
+ .center_freq = 5000 + (5 * (_channel)), \
|
||||
+ .hw_value = (_channel), \
|
||||
+ .flags = IEEE80211_CHAN_DISABLED, \
|
||||
+ .max_antenna_gain = 0, \
|
||||
+ .max_power = 30, \
|
||||
+}
|
||||
+
|
||||
+static struct ieee80211_channel __wl_2ghz_channels[] = {
|
||||
+ CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
|
||||
+ CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
|
||||
+ CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
|
||||
+ CHAN2G(13, 2472), CHAN2G(14, 2484)
|
||||
+};
|
||||
+
|
||||
+static struct ieee80211_channel __wl_5ghz_channels[] = {
|
||||
+ CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
|
||||
+ CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
|
||||
+ CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
|
||||
+ CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
|
||||
+ CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
|
||||
+ CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
|
||||
+};
|
||||
|
||||
/* Band templates duplicated per wiphy. The channel info
|
||||
- * is filled in after querying the device.
|
||||
+ * above is added to the band during setup.
|
||||
*/
|
||||
static const struct ieee80211_supported_band __wl_band_2ghz = {
|
||||
.band = IEEE80211_BAND_2GHZ,
|
||||
@@ -143,7 +177,7 @@ static const struct ieee80211_supported_
|
||||
.n_bitrates = wl_g_rates_size,
|
||||
};
|
||||
|
||||
-static const struct ieee80211_supported_band __wl_band_5ghz_a = {
|
||||
+static const struct ieee80211_supported_band __wl_band_5ghz = {
|
||||
.band = IEEE80211_BAND_5GHZ,
|
||||
.bitrates = wl_a_rates,
|
||||
.n_bitrates = wl_a_rates_size,
|
||||
@@ -5252,40 +5286,6 @@ dongle_scantime_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
-/* Filter the list of channels received from firmware counting only
|
||||
- * the 20MHz channels. The wiphy band data only needs those which get
|
||||
- * flagged to indicate if they can take part in higher bandwidth.
|
||||
- */
|
||||
-static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
|
||||
- struct brcmf_chanspec_list *chlist,
|
||||
- u32 chcnt[])
|
||||
-{
|
||||
- u32 total = le32_to_cpu(chlist->count);
|
||||
- struct brcmu_chan ch;
|
||||
- int i;
|
||||
-
|
||||
- for (i = 0; i < total; i++) {
|
||||
- ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
|
||||
- cfg->d11inf.decchspec(&ch);
|
||||
-
|
||||
- /* Firmware gives a ordered list. We skip non-20MHz
|
||||
- * channels is 2G. For 5G we can abort upon reaching
|
||||
- * a non-20MHz channel in the list.
|
||||
- */
|
||||
- if (ch.bw != BRCMU_CHAN_BW_20) {
|
||||
- if (ch.band == BRCMU_CHAN_BAND_5G)
|
||||
- break;
|
||||
- else
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- if (ch.band == BRCMU_CHAN_BAND_2G)
|
||||
- chcnt[0] += 1;
|
||||
- else if (ch.band == BRCMU_CHAN_BAND_5G)
|
||||
- chcnt[1] += 1;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
|
||||
struct brcmu_chan *ch)
|
||||
{
|
||||
@@ -5321,7 +5321,6 @@ static int brcmf_construct_chaninfo(stru
|
||||
u32 i, j;
|
||||
u32 total;
|
||||
u32 chaninfo;
|
||||
- u32 chcnt[2] = { 0, 0 };
|
||||
u32 index;
|
||||
|
||||
pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
|
||||
@@ -5338,42 +5337,15 @@ static int brcmf_construct_chaninfo(stru
|
||||
goto fail_pbuf;
|
||||
}
|
||||
|
||||
- brcmf_count_20mhz_channels(cfg, list, chcnt);
|
||||
wiphy = cfg_to_wiphy(cfg);
|
||||
- if (chcnt[0]) {
|
||||
- band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
|
||||
- GFP_KERNEL);
|
||||
- if (band == NULL) {
|
||||
- err = -ENOMEM;
|
||||
- goto fail_pbuf;
|
||||
- }
|
||||
- band->channels = kcalloc(chcnt[0], sizeof(*channel),
|
||||
- GFP_KERNEL);
|
||||
- if (band->channels == NULL) {
|
||||
- kfree(band);
|
||||
- err = -ENOMEM;
|
||||
- goto fail_pbuf;
|
||||
- }
|
||||
- band->n_channels = 0;
|
||||
- wiphy->bands[IEEE80211_BAND_2GHZ] = band;
|
||||
- }
|
||||
- if (chcnt[1]) {
|
||||
- band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
|
||||
- GFP_KERNEL);
|
||||
- if (band == NULL) {
|
||||
- err = -ENOMEM;
|
||||
- goto fail_band2g;
|
||||
- }
|
||||
- band->channels = kcalloc(chcnt[1], sizeof(*channel),
|
||||
- GFP_KERNEL);
|
||||
- if (band->channels == NULL) {
|
||||
- kfree(band);
|
||||
- err = -ENOMEM;
|
||||
- goto fail_band2g;
|
||||
- }
|
||||
- band->n_channels = 0;
|
||||
- wiphy->bands[IEEE80211_BAND_5GHZ] = band;
|
||||
- }
|
||||
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
|
||||
+ if (band)
|
||||
+ for (i = 0; i < band->n_channels; i++)
|
||||
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
|
||||
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
|
||||
+ if (band)
|
||||
+ for (i = 0; i < band->n_channels; i++)
|
||||
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
|
||||
|
||||
total = le32_to_cpu(list->count);
|
||||
for (i = 0; i < total; i++) {
|
||||
@@ -5388,6 +5360,8 @@ static int brcmf_construct_chaninfo(stru
|
||||
brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
|
||||
continue;
|
||||
}
|
||||
+ if (!band)
|
||||
+ continue;
|
||||
if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
|
||||
ch.bw == BRCMU_CHAN_BW_40)
|
||||
continue;
|
||||
@@ -5415,9 +5389,9 @@ static int brcmf_construct_chaninfo(stru
|
||||
} else if (ch.bw == BRCMU_CHAN_BW_40) {
|
||||
brcmf_update_bw40_channel_flag(&channel[index], &ch);
|
||||
} else {
|
||||
- /* disable other bandwidths for now as mentioned
|
||||
- * order assure they are enabled for subsequent
|
||||
- * chanspecs.
|
||||
+ /* enable the channel and disable other bandwidths
|
||||
+ * for now as mentioned order assure they are enabled
|
||||
+ * for subsequent chanspecs.
|
||||
*/
|
||||
channel[index].flags = IEEE80211_CHAN_NO_HT40 |
|
||||
IEEE80211_CHAN_NO_80MHZ;
|
||||
@@ -5436,16 +5410,8 @@ static int brcmf_construct_chaninfo(stru
|
||||
IEEE80211_CHAN_NO_IR;
|
||||
}
|
||||
}
|
||||
- if (index == band->n_channels)
|
||||
- band->n_channels++;
|
||||
}
|
||||
- kfree(pbuf);
|
||||
- return 0;
|
||||
|
||||
-fail_band2g:
|
||||
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
|
||||
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
|
||||
- wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
|
||||
fail_pbuf:
|
||||
kfree(pbuf);
|
||||
return err;
|
||||
@@ -5778,7 +5744,12 @@ static void brcmf_wiphy_wowl_params(stru
|
||||
|
||||
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
||||
{
|
||||
+ struct ieee80211_supported_band *band;
|
||||
struct ieee80211_iface_combination ifc_combo;
|
||||
+ __le32 bandlist[3];
|
||||
+ u32 n_bands;
|
||||
+ int err, i;
|
||||
+
|
||||
wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
|
||||
wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
|
||||
wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
|
||||
@@ -5820,7 +5791,52 @@ static int brcmf_setup_wiphy(struct wiph
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
|
||||
brcmf_wiphy_wowl_params(wiphy);
|
||||
|
||||
- return brcmf_setup_wiphybands(wiphy);
|
||||
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
|
||||
+ sizeof(bandlist));
|
||||
+ if (err) {
|
||||
+ brcmf_err("could not obtain band info: err=%d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+ /* first entry in bandlist is number of bands */
|
||||
+ n_bands = le32_to_cpu(bandlist[0]);
|
||||
+ for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
|
||||
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
|
||||
+ band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!band)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ band->channels = kmemdup(&__wl_2ghz_channels,
|
||||
+ sizeof(__wl_2ghz_channels),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!band->channels) {
|
||||
+ kfree(band);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
|
||||
+ wiphy->bands[IEEE80211_BAND_2GHZ] = band;
|
||||
+ }
|
||||
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
|
||||
+ band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!band)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ band->channels = kmemdup(&__wl_5ghz_channels,
|
||||
+ sizeof(__wl_5ghz_channels),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!band->channels) {
|
||||
+ kfree(band);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
|
||||
+ wiphy->bands[IEEE80211_BAND_5GHZ] = band;
|
||||
+ }
|
||||
+ }
|
||||
+ err = brcmf_setup_wiphybands(wiphy);
|
||||
+ return err;
|
||||
}
|
||||
|
||||
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
|
||||
@@ -6011,6 +6027,9 @@ static void brcmf_cfg80211_reg_notifier(
|
||||
|
||||
static void brcmf_free_wiphy(struct wiphy *wiphy)
|
||||
{
|
||||
+ if (!wiphy)
|
||||
+ return;
|
||||
+
|
||||
kfree(wiphy->iface_combinations);
|
||||
if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
|
||||
kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
|
|
@ -1,29 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:25 +0200
|
||||
Subject: [PATCH] brcmfmac: update wiphy band information upon updating
|
||||
regulatory domain
|
||||
|
||||
When change the country code the available channels may change. So
|
||||
the wiphy bands should be updated accordingly.
|
||||
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -6022,7 +6022,11 @@ static void brcmf_cfg80211_reg_notifier(
|
||||
memset(&ccreq, 0, sizeof(ccreq));
|
||||
ccreq.rev = cpu_to_le32(-1);
|
||||
memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
|
||||
- brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
|
||||
+ if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
|
||||
+ brcmf_err("firmware rejected country setting\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ brcmf_setup_wiphybands(wiphy);
|
||||
}
|
||||
|
||||
static void brcmf_free_wiphy(struct wiphy *wiphy)
|
|
@ -1,24 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:26 +0200
|
||||
Subject: [PATCH] brcmfmac: add description for feature flags
|
||||
|
||||
Some feature flags were not described in the header file. Adding
|
||||
the description.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
|
||||
@@ -19,7 +19,9 @@
|
||||
/*
|
||||
* Features:
|
||||
*
|
||||
+ * MBSS: multiple BSSID support (eg. guest network in AP mode).
|
||||
* MCHAN: multi-channel for concurrent P2P.
|
||||
+ * WOWL: Wake-On-WLAN.
|
||||
*/
|
||||
#define BRCMF_FEAT_LIST \
|
||||
BRCMF_FEAT_DEF(MBSS) \
|
|
@ -1,51 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:27 +0200
|
||||
Subject: [PATCH] brcmfmac: make scheduled scan support conditional
|
||||
|
||||
The scheduled scan support depends on firmware supporting the PNO
|
||||
feature. This feature is optional so add a feature flag for this
|
||||
in the driver and announce scheduled scan support accordingly.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -5782,7 +5782,8 @@ static int brcmf_setup_wiphy(struct wiph
|
||||
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
|
||||
wiphy->mgmt_stypes = brcmf_txrx_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
- brcmf_wiphy_pno_params(wiphy);
|
||||
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
|
||||
+ brcmf_wiphy_pno_params(wiphy);
|
||||
|
||||
/* vendor commands/events support */
|
||||
wiphy->vendor_commands = brcmf_vendor_cmds;
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
|
||||
@@ -124,6 +124,7 @@ void brcmf_feat_attach(struct brcmf_pub
|
||||
struct brcmf_if *ifp = drvr->iflist[0];
|
||||
|
||||
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
|
||||
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
|
||||
if (drvr->bus_if->wowl_supported)
|
||||
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
|
||||
if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
|
||||
@@ -21,11 +21,13 @@
|
||||
*
|
||||
* MBSS: multiple BSSID support (eg. guest network in AP mode).
|
||||
* MCHAN: multi-channel for concurrent P2P.
|
||||
+ * PNO: preferred network offload.
|
||||
* WOWL: Wake-On-WLAN.
|
||||
*/
|
||||
#define BRCMF_FEAT_LIST \
|
||||
BRCMF_FEAT_DEF(MBSS) \
|
||||
BRCMF_FEAT_DEF(MCHAN) \
|
||||
+ BRCMF_FEAT_DEF(PNO) \
|
||||
BRCMF_FEAT_DEF(WOWL)
|
||||
/*
|
||||
* Quirks:
|
|
@ -1,43 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:28 +0200
|
||||
Subject: [PATCH] brcmfmac: add support for BCM4324 rev B5 chipset
|
||||
|
||||
This patch adds support for the BCM4324 B5 revision. This device
|
||||
is similar to BCM43241 from driver and firmware perspective. It
|
||||
is known to be used in Lenovo Thinkpad Tablet devices.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -601,6 +601,8 @@ static const struct sdiod_drive_str sdio
|
||||
#define BCM43241B0_NVRAM_NAME "brcm/brcmfmac43241b0-sdio.txt"
|
||||
#define BCM43241B4_FIRMWARE_NAME "brcm/brcmfmac43241b4-sdio.bin"
|
||||
#define BCM43241B4_NVRAM_NAME "brcm/brcmfmac43241b4-sdio.txt"
|
||||
+#define BCM43241B5_FIRMWARE_NAME "brcm/brcmfmac43241b5-sdio.bin"
|
||||
+#define BCM43241B5_NVRAM_NAME "brcm/brcmfmac43241b5-sdio.txt"
|
||||
#define BCM4329_FIRMWARE_NAME "brcm/brcmfmac4329-sdio.bin"
|
||||
#define BCM4329_NVRAM_NAME "brcm/brcmfmac4329-sdio.txt"
|
||||
#define BCM4330_FIRMWARE_NAME "brcm/brcmfmac4330-sdio.bin"
|
||||
@@ -628,6 +630,8 @@ MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME
|
||||
MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME);
|
||||
+MODULE_FIRMWARE(BCM43241B5_FIRMWARE_NAME);
|
||||
+MODULE_FIRMWARE(BCM43241B5_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME);
|
||||
MODULE_FIRMWARE(BCM4329_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME);
|
||||
@@ -667,7 +671,8 @@ enum brcmf_firmware_type {
|
||||
static const struct brcmf_firmware_names brcmf_fwname_data[] = {
|
||||
{ BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
|
||||
{ BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
|
||||
- { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
|
||||
+ { BRCM_CC_43241_CHIP_ID, 0x00000020, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
|
||||
+ { BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, BRCMF_FIRMWARE_NVRAM(BCM43241B5) },
|
||||
{ BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
|
||||
{ BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
|
||||
{ BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
|
|
@ -1,27 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:29 +0200
|
||||
Subject: [PATCH] brcmfmac: process interrupt regardless sdiod state
|
||||
|
||||
When the sdio bus state is not ready to process we abort the
|
||||
interrupt service routine. This is not wanted as it keeps the
|
||||
interrupt source active. Better clear the interrupt source.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
|
||||
@@ -3555,10 +3555,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *b
|
||||
return;
|
||||
}
|
||||
|
||||
- if (bus->sdiodev->state != BRCMF_SDIOD_DATA) {
|
||||
- brcmf_err("bus is down. we have nothing to do\n");
|
||||
- return;
|
||||
- }
|
||||
/* Count the interrupt call */
|
||||
bus->sdcnt.intrcount++;
|
||||
if (in_interrupt())
|
|
@ -1,68 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:30 +0200
|
||||
Subject: [PATCH] brcmfmac: fix sdio suspend and resume
|
||||
|
||||
commit 330b4e4be937 ("brcmfmac: Add wowl support for SDIO devices.")
|
||||
changed the behaviour by removing the MMC_PM_KEEP_POWER flag for
|
||||
non-wowl scenario, which needs to be restored. Another necessary
|
||||
change is to mark the card as being non-removable. With this in place
|
||||
the suspend resume test passes successfully doing:
|
||||
|
||||
# echo devices > /sys/power/pm_test
|
||||
# echo mem > /sys/power/state
|
||||
|
||||
Note that power may still be switched off when system is going
|
||||
in S3 state.
|
||||
|
||||
Reported-by: Fu, Zhonghui <<zhonghui.fu@linux.intel.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
|
||||
@@ -1011,6 +1011,14 @@ static int brcmf_sdiod_remove(struct brc
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void brcmf_sdiod_host_fixup(struct mmc_host *host)
|
||||
+{
|
||||
+ /* runtime-pm powers off the device */
|
||||
+ pm_runtime_forbid(host->parent);
|
||||
+ /* avoid removal detection upon resume */
|
||||
+ host->caps |= MMC_CAP_NONREMOVABLE;
|
||||
+}
|
||||
+
|
||||
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
struct sdio_func *func;
|
||||
@@ -1076,7 +1084,7 @@ static int brcmf_sdiod_probe(struct brcm
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
- pm_runtime_forbid(host->parent);
|
||||
+ brcmf_sdiod_host_fixup(host);
|
||||
out:
|
||||
if (ret)
|
||||
brcmf_sdiod_remove(sdiodev);
|
||||
@@ -1246,15 +1254,15 @@ static int brcmf_ops_sdio_suspend(struct
|
||||
brcmf_sdiod_freezer_on(sdiodev);
|
||||
brcmf_sdio_wd_timer(sdiodev->bus, 0);
|
||||
|
||||
+ sdio_flags = MMC_PM_KEEP_POWER;
|
||||
if (sdiodev->wowl_enabled) {
|
||||
- sdio_flags = MMC_PM_KEEP_POWER;
|
||||
if (sdiodev->pdata->oob_irq_supported)
|
||||
enable_irq_wake(sdiodev->pdata->oob_irq_nr);
|
||||
else
|
||||
- sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
|
||||
- if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
|
||||
- brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
|
||||
+ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
|
||||
}
|
||||
+ if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
|
||||
+ brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:31 +0200
|
||||
Subject: [PATCH] brcmfmac: add support for BCM4358 PCIe device
|
||||
|
||||
This patch adds support for the BCM4358 2x2 11ac device.
|
||||
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
|
||||
@@ -649,6 +649,7 @@ static u32 brcmf_chip_tcm_rambase(struct
|
||||
case BRCM_CC_43567_CHIP_ID:
|
||||
case BRCM_CC_43569_CHIP_ID:
|
||||
case BRCM_CC_43570_CHIP_ID:
|
||||
+ case BRCM_CC_4358_CHIP_ID:
|
||||
case BRCM_CC_43602_CHIP_ID:
|
||||
return 0x180000;
|
||||
default:
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -51,6 +51,8 @@ enum brcmf_pcie_state {
|
||||
#define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt"
|
||||
#define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin"
|
||||
#define BRCMF_PCIE_43570_NVRAM_NAME "brcm/brcmfmac43570-pcie.txt"
|
||||
+#define BRCMF_PCIE_4358_FW_NAME "brcm/brcmfmac4358-pcie.bin"
|
||||
+#define BRCMF_PCIE_4358_NVRAM_NAME "brcm/brcmfmac4358-pcie.txt"
|
||||
|
||||
#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
|
||||
|
||||
@@ -189,6 +191,8 @@ MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME)
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME);
|
||||
MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME);
|
||||
+MODULE_FIRMWARE(BRCMF_PCIE_4358_FW_NAME);
|
||||
+MODULE_FIRMWARE(BRCMF_PCIE_4358_NVRAM_NAME);
|
||||
|
||||
|
||||
struct brcmf_pcie_console {
|
||||
@@ -1333,6 +1337,10 @@ static int brcmf_pcie_get_fwnames(struct
|
||||
fw_name = BRCMF_PCIE_43570_FW_NAME;
|
||||
nvram_name = BRCMF_PCIE_43570_NVRAM_NAME;
|
||||
break;
|
||||
+ case BRCM_CC_4358_CHIP_ID:
|
||||
+ fw_name = BRCMF_PCIE_4358_FW_NAME;
|
||||
+ nvram_name = BRCMF_PCIE_4358_NVRAM_NAME;
|
||||
+ break;
|
||||
default:
|
||||
brcmf_err("Unsupported chip 0x%04x\n", devinfo->ci->chip);
|
||||
return -ENODEV;
|
||||
@@ -1850,6 +1858,7 @@ static struct pci_device_id brcmf_pcie_d
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
|
||||
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
|
||||
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
|
||||
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
|
||||
@@ -45,6 +45,7 @@
|
||||
#define BRCM_CC_43567_CHIP_ID 43567
|
||||
#define BRCM_CC_43569_CHIP_ID 43569
|
||||
#define BRCM_CC_43570_CHIP_ID 43570
|
||||
+#define BRCM_CC_4358_CHIP_ID 0x4358
|
||||
#define BRCM_CC_43602_CHIP_ID 43602
|
||||
|
||||
/* USB Device IDs */
|
||||
@@ -59,6 +60,7 @@
|
||||
#define BRCM_PCIE_4356_DEVICE_ID 0x43ec
|
||||
#define BRCM_PCIE_43567_DEVICE_ID 0x43d3
|
||||
#define BRCM_PCIE_43570_DEVICE_ID 0x43d9
|
||||
+#define BRCM_PCIE_4358_DEVICE_ID 0x43e9
|
||||
#define BRCM_PCIE_43602_DEVICE_ID 0x43ba
|
||||
#define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb
|
||||
#define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc
|
|
@ -1,30 +0,0 @@
|
|||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:32 +0200
|
||||
Subject: [PATCH] brcmfmac: add additional 43602 pcie device id.
|
||||
|
||||
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>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -1862,6 +1862,7 @@ static struct pci_device_id brcmf_pcie_d
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
|
||||
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
|
||||
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID),
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
|
||||
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
|
||||
@@ -64,6 +64,7 @@
|
||||
#define BRCM_PCIE_43602_DEVICE_ID 0x43ba
|
||||
#define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb
|
||||
#define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc
|
||||
+#define BRCM_PCIE_43602_RAW_DEVICE_ID 43602
|
||||
|
||||
/* brcmsmac IDs */
|
||||
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
|
|
@ -1,351 +0,0 @@
|
|||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:33 +0200
|
||||
Subject: [PATCH] brcmfmac: Add support for multiple PCIE devices in
|
||||
nvram.
|
||||
|
||||
With PCIE it is possible to support multiple devices with the
|
||||
same device type. They all load the same nvram file. In order to
|
||||
support this the nvram can specify which part of the nvram is
|
||||
for which pcie device. This patch adds support for these new
|
||||
types of nvram files.
|
||||
|
||||
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>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
@@ -23,6 +23,10 @@
|
||||
#include "debug.h"
|
||||
#include "firmware.h"
|
||||
|
||||
+#define BRCMF_FW_MAX_NVRAM_SIZE 64000
|
||||
+#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
|
||||
+#define BRCMF_FW_NVRAM_PCIEDEV_LEN 9 /* pcie/1/4/ */
|
||||
+
|
||||
char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
|
||||
module_param_string(firmware_path, brcmf_firmware_path,
|
||||
BRCMF_FW_PATH_LEN, 0440);
|
||||
@@ -46,6 +50,8 @@ enum nvram_parser_state {
|
||||
* @column: current column in line.
|
||||
* @pos: byte offset in input buffer.
|
||||
* @entry: start position of key,value entry.
|
||||
+ * @multi_dev_v1: detect pcie multi device v1 (compressed).
|
||||
+ * @multi_dev_v2: detect pcie multi device v2.
|
||||
*/
|
||||
struct nvram_parser {
|
||||
enum nvram_parser_state state;
|
||||
@@ -56,6 +62,8 @@ struct nvram_parser {
|
||||
u32 column;
|
||||
u32 pos;
|
||||
u32 entry;
|
||||
+ bool multi_dev_v1;
|
||||
+ bool multi_dev_v2;
|
||||
};
|
||||
|
||||
static bool is_nvram_char(char c)
|
||||
@@ -108,6 +116,10 @@ static enum nvram_parser_state brcmf_nvr
|
||||
st = COMMENT;
|
||||
else
|
||||
st = VALUE;
|
||||
+ if (strncmp(&nvp->fwnv->data[nvp->entry], "devpath", 7) == 0)
|
||||
+ nvp->multi_dev_v1 = true;
|
||||
+ if (strncmp(&nvp->fwnv->data[nvp->entry], "pcie/", 5) == 0)
|
||||
+ nvp->multi_dev_v2 = true;
|
||||
} else if (!is_nvram_char(c)) {
|
||||
brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
|
||||
nvp->line, nvp->column);
|
||||
@@ -133,6 +145,8 @@ brcmf_nvram_handle_value(struct nvram_pa
|
||||
ekv = (u8 *)&nvp->fwnv->data[nvp->pos];
|
||||
skv = (u8 *)&nvp->fwnv->data[nvp->entry];
|
||||
cplen = ekv - skv;
|
||||
+ if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE)
|
||||
+ return END;
|
||||
/* copy to output buffer */
|
||||
memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
|
||||
nvp->nvram_len += cplen;
|
||||
@@ -180,10 +194,18 @@ static enum nvram_parser_state
|
||||
static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
|
||||
const struct firmware *nv)
|
||||
{
|
||||
+ size_t size;
|
||||
+
|
||||
memset(nvp, 0, sizeof(*nvp));
|
||||
nvp->fwnv = nv;
|
||||
+ /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */
|
||||
+ if (nv->size > BRCMF_FW_MAX_NVRAM_SIZE)
|
||||
+ size = BRCMF_FW_MAX_NVRAM_SIZE;
|
||||
+ else
|
||||
+ size = nv->size;
|
||||
/* Alloc for extra 0 byte + roundup by 4 + length field */
|
||||
- nvp->nvram = kzalloc(nv->size + 1 + 3 + sizeof(u32), GFP_KERNEL);
|
||||
+ size += 1 + 3 + sizeof(u32);
|
||||
+ nvp->nvram = kzalloc(size, GFP_KERNEL);
|
||||
if (!nvp->nvram)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -192,12 +214,136 @@ static int brcmf_init_nvram_parser(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple
|
||||
+ * devices. Strip it down for one device, use domain_nr/bus_nr to determine
|
||||
+ * which data is to be returned. v1 is the version where nvram is stored
|
||||
+ * compressed and "devpath" maps to index for valid entries.
|
||||
+ */
|
||||
+static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
|
||||
+ u16 bus_nr)
|
||||
+{
|
||||
+ u32 i, j;
|
||||
+ bool found;
|
||||
+ u8 *nvram;
|
||||
+ u8 id;
|
||||
+
|
||||
+ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
|
||||
+ if (!nvram)
|
||||
+ goto fail;
|
||||
+
|
||||
+ /* min length: devpath0=pcie/1/4/ + 0:x=y */
|
||||
+ if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6)
|
||||
+ goto fail;
|
||||
+
|
||||
+ /* First search for the devpathX and see if it is the configuration
|
||||
+ * for domain_nr/bus_nr. Search complete nvp
|
||||
+ */
|
||||
+ found = false;
|
||||
+ i = 0;
|
||||
+ while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
|
||||
+ /* Format: devpathX=pcie/Y/Z/
|
||||
+ * Y = domain_nr, Z = bus_nr, X = virtual ID
|
||||
+ */
|
||||
+ if ((strncmp(&nvp->nvram[i], "devpath", 7) == 0) &&
|
||||
+ (strncmp(&nvp->nvram[i + 8], "=pcie/", 6) == 0)) {
|
||||
+ if (((nvp->nvram[i + 14] - '0') == domain_nr) &&
|
||||
+ ((nvp->nvram[i + 16] - '0') == bus_nr)) {
|
||||
+ id = nvp->nvram[i + 7] - '0';
|
||||
+ found = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ while (nvp->nvram[i] != 0)
|
||||
+ i++;
|
||||
+ i++;
|
||||
+ }
|
||||
+ if (!found)
|
||||
+ goto fail;
|
||||
+
|
||||
+ /* Now copy all valid entries, release old nvram and assign new one */
|
||||
+ i = 0;
|
||||
+ j = 0;
|
||||
+ while (i < nvp->nvram_len) {
|
||||
+ if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
|
||||
+ i += 2;
|
||||
+ while (nvp->nvram[i] != 0) {
|
||||
+ nvram[j] = nvp->nvram[i];
|
||||
+ i++;
|
||||
+ j++;
|
||||
+ }
|
||||
+ nvram[j] = 0;
|
||||
+ j++;
|
||||
+ }
|
||||
+ while (nvp->nvram[i] != 0)
|
||||
+ i++;
|
||||
+ i++;
|
||||
+ }
|
||||
+ kfree(nvp->nvram);
|
||||
+ nvp->nvram = nvram;
|
||||
+ nvp->nvram_len = j;
|
||||
+ return;
|
||||
+
|
||||
+fail:
|
||||
+ kfree(nvram);
|
||||
+ nvp->nvram_len = 0;
|
||||
+}
|
||||
+
|
||||
+/* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple
|
||||
+ * devices. Strip it down for one device, use domain_nr/bus_nr to determine
|
||||
+ * which data is to be returned. v2 is the version where nvram is stored
|
||||
+ * uncompressed, all relevant valid entries are identified by
|
||||
+ * pcie/domain_nr/bus_nr:
|
||||
+ */
|
||||
+static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
|
||||
+ u16 bus_nr)
|
||||
+{
|
||||
+ u32 i, j;
|
||||
+ u8 *nvram;
|
||||
+
|
||||
+ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
|
||||
+ if (!nvram)
|
||||
+ goto fail;
|
||||
+
|
||||
+ /* Copy all valid entries, release old nvram and assign new one.
|
||||
+ * Valid entries are of type pcie/X/Y/ where X = domain_nr and
|
||||
+ * Y = bus_nr.
|
||||
+ */
|
||||
+ i = 0;
|
||||
+ j = 0;
|
||||
+ while (i < nvp->nvram_len - BRCMF_FW_NVRAM_PCIEDEV_LEN) {
|
||||
+ if ((strncmp(&nvp->nvram[i], "pcie/", 5) == 0) &&
|
||||
+ (nvp->nvram[i + 6] == '/') && (nvp->nvram[i + 8] == '/') &&
|
||||
+ ((nvp->nvram[i + 5] - '0') == domain_nr) &&
|
||||
+ ((nvp->nvram[i + 7] - '0') == bus_nr)) {
|
||||
+ i += BRCMF_FW_NVRAM_PCIEDEV_LEN;
|
||||
+ while (nvp->nvram[i] != 0) {
|
||||
+ nvram[j] = nvp->nvram[i];
|
||||
+ i++;
|
||||
+ j++;
|
||||
+ }
|
||||
+ nvram[j] = 0;
|
||||
+ j++;
|
||||
+ }
|
||||
+ while (nvp->nvram[i] != 0)
|
||||
+ i++;
|
||||
+ i++;
|
||||
+ }
|
||||
+ kfree(nvp->nvram);
|
||||
+ nvp->nvram = nvram;
|
||||
+ nvp->nvram_len = j;
|
||||
+ return;
|
||||
+fail:
|
||||
+ kfree(nvram);
|
||||
+ nvp->nvram_len = 0;
|
||||
+}
|
||||
+
|
||||
/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
|
||||
* and ending in a NUL. Removes carriage returns, empty lines, comment lines,
|
||||
* and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
|
||||
* End of buffer is completed with token identifying length of buffer.
|
||||
*/
|
||||
-static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length)
|
||||
+static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length,
|
||||
+ u16 domain_nr, u16 bus_nr)
|
||||
{
|
||||
struct nvram_parser nvp;
|
||||
u32 pad;
|
||||
@@ -212,6 +358,16 @@ static void *brcmf_fw_nvram_strip(const
|
||||
if (nvp.state == END)
|
||||
break;
|
||||
}
|
||||
+ if (nvp.multi_dev_v1)
|
||||
+ brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
|
||||
+ else if (nvp.multi_dev_v2)
|
||||
+ brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
|
||||
+
|
||||
+ if (nvp.nvram_len == 0) {
|
||||
+ kfree(nvp.nvram);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
pad = nvp.nvram_len;
|
||||
*new_length = roundup(nvp.nvram_len + 1, 4);
|
||||
while (pad != *new_length) {
|
||||
@@ -239,6 +395,8 @@ struct brcmf_fw {
|
||||
u16 flags;
|
||||
const struct firmware *code;
|
||||
const char *nvram_name;
|
||||
+ u16 domain_nr;
|
||||
+ u16 bus_nr;
|
||||
void (*done)(struct device *dev, const struct firmware *fw,
|
||||
void *nvram_image, u32 nvram_len);
|
||||
};
|
||||
@@ -254,7 +412,8 @@ static void brcmf_fw_request_nvram_done(
|
||||
goto fail;
|
||||
|
||||
if (fw) {
|
||||
- nvram = brcmf_fw_nvram_strip(fw, &nvram_length);
|
||||
+ nvram = brcmf_fw_nvram_strip(fw, &nvram_length,
|
||||
+ fwctx->domain_nr, fwctx->bus_nr);
|
||||
release_firmware(fw);
|
||||
if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
|
||||
goto fail;
|
||||
@@ -309,11 +468,12 @@ fail:
|
||||
kfree(fwctx);
|
||||
}
|
||||
|
||||
-int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
|
||||
- const char *code, const char *nvram,
|
||||
- void (*fw_cb)(struct device *dev,
|
||||
- const struct firmware *fw,
|
||||
- void *nvram_image, u32 nvram_len))
|
||||
+int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
|
||||
+ const char *code, const char *nvram,
|
||||
+ void (*fw_cb)(struct device *dev,
|
||||
+ const struct firmware *fw,
|
||||
+ void *nvram_image, u32 nvram_len),
|
||||
+ u16 domain_nr, u16 bus_nr)
|
||||
{
|
||||
struct brcmf_fw *fwctx;
|
||||
|
||||
@@ -333,8 +493,21 @@ int brcmf_fw_get_firmwares(struct device
|
||||
fwctx->done = fw_cb;
|
||||
if (flags & BRCMF_FW_REQUEST_NVRAM)
|
||||
fwctx->nvram_name = nvram;
|
||||
+ fwctx->domain_nr = domain_nr;
|
||||
+ fwctx->bus_nr = bus_nr;
|
||||
|
||||
return request_firmware_nowait(THIS_MODULE, true, code, dev,
|
||||
GFP_KERNEL, fwctx,
|
||||
brcmf_fw_request_code_done);
|
||||
}
|
||||
+
|
||||
+int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
|
||||
+ const char *code, const char *nvram,
|
||||
+ void (*fw_cb)(struct device *dev,
|
||||
+ const struct firmware *fw,
|
||||
+ void *nvram_image, u32 nvram_len))
|
||||
+{
|
||||
+ return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
|
||||
+ 0);
|
||||
+}
|
||||
+
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
|
||||
@@ -32,6 +32,12 @@ void brcmf_fw_nvram_free(void *nvram);
|
||||
* fails it will not use the callback, but call device_release_driver()
|
||||
* instead which will call the driver .remove() callback.
|
||||
*/
|
||||
+int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
|
||||
+ const char *code, const char *nvram,
|
||||
+ void (*fw_cb)(struct device *dev,
|
||||
+ const struct firmware *fw,
|
||||
+ void *nvram_image, u32 nvram_len),
|
||||
+ u16 domain_nr, u16 bus_nr);
|
||||
int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
|
||||
const char *code, const char *nvram,
|
||||
void (*fw_cb)(struct device *dev,
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -1649,8 +1649,13 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
|
||||
struct brcmf_pciedev_info *devinfo;
|
||||
struct brcmf_pciedev *pcie_bus_dev;
|
||||
struct brcmf_bus *bus;
|
||||
+ u16 domain_nr;
|
||||
+ u16 bus_nr;
|
||||
|
||||
- brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
|
||||
+ domain_nr = pci_domain_nr(pdev->bus) + 1;
|
||||
+ bus_nr = pdev->bus->number;
|
||||
+ brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device,
|
||||
+ domain_nr, bus_nr);
|
||||
|
||||
ret = -ENOMEM;
|
||||
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
|
||||
@@ -1699,10 +1704,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
|
||||
if (ret)
|
||||
goto fail_bus;
|
||||
|
||||
- ret = brcmf_fw_get_firmwares(bus->dev, BRCMF_FW_REQUEST_NVRAM |
|
||||
- BRCMF_FW_REQ_NV_OPTIONAL,
|
||||
- devinfo->fw_name, devinfo->nvram_name,
|
||||
- brcmf_pcie_setup);
|
||||
+ ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM |
|
||||
+ BRCMF_FW_REQ_NV_OPTIONAL,
|
||||
+ devinfo->fw_name, devinfo->nvram_name,
|
||||
+ brcmf_pcie_setup, domain_nr, bus_nr);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
fail_bus:
|
|
@ -1,23 +0,0 @@
|
|||
From: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Date: Thu, 7 May 2015 12:59:19 +0300
|
||||
Subject: [PATCH] brcmfmac: cleanup a sizeof()
|
||||
|
||||
"flowrings" and "*flowrings" are both pointers so this always returns
|
||||
sizeof(void *) and the current code works fine. But "*flowrings" is
|
||||
intended here and static checkers complain, so lets change it.
|
||||
|
||||
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -1617,7 +1617,7 @@ static void brcmf_pcie_setup(struct devi
|
||||
bus->msgbuf->commonrings[i] =
|
||||
&devinfo->shared.commonrings[i]->commonring;
|
||||
|
||||
- flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(flowrings),
|
||||
+ flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*flowrings),
|
||||
GFP_KERNEL);
|
||||
if (!flowrings)
|
||||
goto fail;
|
|
@ -1,33 +0,0 @@
|
|||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Thu, 7 May 2015 14:13:03 +0200
|
||||
Subject: [PATCH] brcmfmac: check result of USB firmware request
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This prevents silence failures with driver waiting (infinitely) for a
|
||||
callback.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Acked-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
|
||||
@@ -1270,8 +1270,13 @@ static int brcmf_usb_probe_cb(struct brc
|
||||
bus->chiprev = bus_pub->chiprev;
|
||||
|
||||
/* request firmware here */
|
||||
- brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), NULL,
|
||||
- brcmf_usb_probe_phase2);
|
||||
+ ret = brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo),
|
||||
+ NULL, brcmf_usb_probe_phase2);
|
||||
+ if (ret) {
|
||||
+ brcmf_err("firmware request failed: %d\n", ret);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
fail:
|
|
@ -1,47 +0,0 @@
|
|||
From: "Fu, Zhonghui" <zhonghui.fu@linux.intel.com>
|
||||
Date: Mon, 11 May 2015 10:41:32 +0800
|
||||
Subject: [PATCH] brcmfmac: prohibit ACPI power management for brcmfmac driver
|
||||
|
||||
ACPI will manage WiFi chip's power state during suspend/resume
|
||||
process on some tablet platforms(such as ASUS T100TA). This is
|
||||
not supported by brcmfmac driver now, and the context of WiFi
|
||||
chip will be damaged after resume. This patch informs ACPI not
|
||||
to manage WiFi chip's power state.
|
||||
|
||||
Signed-off-by: Zhonghui Fu <zhonghui.fu@linux.intel.com>
|
||||
Acked-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
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/acpi.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#include <defs.h>
|
||||
@@ -1122,6 +1123,8 @@ static int brcmf_ops_sdio_probe(struct s
|
||||
int err;
|
||||
struct brcmf_sdio_dev *sdiodev;
|
||||
struct brcmf_bus *bus_if;
|
||||
+ struct device *dev;
|
||||
+ struct acpi_device *adev;
|
||||
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
brcmf_dbg(SDIO, "Class=%x\n", func->class);
|
||||
@@ -1129,6 +1132,12 @@ static int brcmf_ops_sdio_probe(struct s
|
||||
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
|
||||
brcmf_dbg(SDIO, "Function#: %d\n", func->num);
|
||||
|
||||
+ /* prohibit ACPI power management for this device */
|
||||
+ dev = &func->dev;
|
||||
+ adev = ACPI_COMPANION(dev);
|
||||
+ if (adev)
|
||||
+ adev->flags.power_manageable = 0;
|
||||
+
|
||||
/* Consume func num 1 but dont do anything with it. */
|
||||
if (func->num == 1)
|
||||
return 0;
|
|
@ -1,30 +0,0 @@
|
|||
From: Arnd Bergmann <arnd@arndb.de>
|
||||
Date: Tue, 12 May 2015 23:54:25 +0200
|
||||
Subject: [PATCH] brcmfmac: avoid gcc-5.1 warning
|
||||
|
||||
gcc-5.0 gained a new warning in the fwsignal portion of the brcmfmac
|
||||
driver:
|
||||
|
||||
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c: In function 'brcmf_fws_txs_process':
|
||||
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c:1478:8: warning: 'skb' may be used uninitialized in this function [-Wmaybe-uninitialized]
|
||||
|
||||
This is a false positive, and marking the brcmf_fws_hanger_poppkt function
|
||||
as 'static inline' makes the warning go away. I have checked the object
|
||||
file output and while a little code gets moved around, the size of
|
||||
the binary remains identical.
|
||||
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
|
||||
@@ -635,7 +635,7 @@ static int brcmf_fws_hanger_pushpkt(stru
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
|
||||
+static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
|
||||
u32 slot_id, struct sk_buff **pktout,
|
||||
bool remove_item)
|
||||
{
|
|
@ -1,45 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 20 May 2015 14:09:47 +0200
|
||||
Subject: [PATCH] brcmfmac: allow device tree node without 'interrupts'
|
||||
property
|
||||
|
||||
As described in the device tree bindings for 'brcm,bcm4329-fmac'
|
||||
nodes, the interrupts property is optional. So adding a check
|
||||
for the presence of this property before attempting to parse
|
||||
and map the interrupt. If not present or parsing fails return
|
||||
and fallback to in-band sdio interrupt.
|
||||
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/of.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/of.c
|
||||
@@ -39,10 +39,16 @@ void brcmf_of_probe(struct brcmf_sdio_de
|
||||
if (!sdiodev->pdata)
|
||||
return;
|
||||
|
||||
+ if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
|
||||
+ sdiodev->pdata->drive_strength = val;
|
||||
+
|
||||
+ /* make sure there are interrupts defined in the node */
|
||||
+ if (!of_find_property(np, "interrupts", NULL))
|
||||
+ return;
|
||||
+
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq) {
|
||||
brcmf_err("interrupt could not be mapped\n");
|
||||
- devm_kfree(dev, sdiodev->pdata);
|
||||
return;
|
||||
}
|
||||
irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
|
||||
@@ -50,7 +56,4 @@ void brcmf_of_probe(struct brcmf_sdio_de
|
||||
sdiodev->pdata->oob_irq_supported = true;
|
||||
sdiodev->pdata->oob_irq_nr = irq;
|
||||
sdiodev->pdata->oob_irq_flags = irqf;
|
||||
-
|
||||
- if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
|
||||
- sdiodev->pdata->drive_strength = val;
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Wed, 20 May 2015 14:09:48 +0200
|
||||
Subject: [PATCH] brcmfmac: Improve throughput by scheduling msbug flow worker.
|
||||
|
||||
The tx flow worker in msgbuf gets scheduled at tx till a certain
|
||||
threshold has been reached. Then the tx completes will take over
|
||||
the scheduling. When amsdu and ampdu is used the frames are
|
||||
transferred wireless in a very bulky fashion, in combination
|
||||
with this scheduling algorithm and buffer limiters in the stack
|
||||
this can result in limited throughput. This change causes the
|
||||
flow worker to be scheduled more frequently from tx.
|
||||
|
||||
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/flowring.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
|
||||
@@ -249,8 +249,8 @@ void brcmf_flowring_delete(struct brcmf_
|
||||
}
|
||||
|
||||
|
||||
-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
|
||||
- struct sk_buff *skb)
|
||||
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
|
||||
+ struct sk_buff *skb)
|
||||
{
|
||||
struct brcmf_flowring_ring *ring;
|
||||
|
||||
@@ -271,6 +271,7 @@ void brcmf_flowring_enqueue(struct brcmf
|
||||
if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
|
||||
brcmf_flowring_block(flow, flowid, false);
|
||||
}
|
||||
+ return skb_queue_len(&ring->skblist);
|
||||
}
|
||||
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
|
||||
@@ -64,8 +64,8 @@ u32 brcmf_flowring_create(struct brcmf_f
|
||||
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);
|
||||
-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
|
||||
- struct sk_buff *skb);
|
||||
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 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 *skb);
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
@@ -73,7 +73,7 @@
|
||||
#define BRCMF_MSGBUF_TX_FLUSH_CNT1 32
|
||||
#define BRCMF_MSGBUF_TX_FLUSH_CNT2 96
|
||||
|
||||
-#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64
|
||||
+#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 96
|
||||
#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32
|
||||
|
||||
struct msgbuf_common_hdr {
|
||||
@@ -797,6 +797,8 @@ static int brcmf_msgbuf_txdata(struct br
|
||||
struct brcmf_flowring *flow = msgbuf->flow;
|
||||
struct ethhdr *eh = (struct ethhdr *)(skb->data);
|
||||
u32 flowid;
|
||||
+ u32 queue_count;
|
||||
+ bool force;
|
||||
|
||||
flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);
|
||||
if (flowid == BRCMF_FLOWRING_INVALID_ID) {
|
||||
@@ -804,8 +806,9 @@ static int brcmf_msgbuf_txdata(struct br
|
||||
if (flowid == BRCMF_FLOWRING_INVALID_ID)
|
||||
return -ENOMEM;
|
||||
}
|
||||
- brcmf_flowring_enqueue(flow, flowid, skb);
|
||||
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false);
|
||||
+ queue_count = brcmf_flowring_enqueue(flow, flowid, skb);
|
||||
+ force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);
|
||||
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, force);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
From: Franky Lin <frankyl@broadcom.com>
|
||||
Date: Wed, 20 May 2015 14:09:49 +0200
|
||||
Subject: [PATCH] brcmfmac: remove pci shared structure rev4 support
|
||||
|
||||
All pcie full dongle chips supported by fmac are using rev 5+ shared
|
||||
structure. This patch removes the rev4 related code.
|
||||
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Franky Lin <frankyl@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -112,10 +112,9 @@ enum brcmf_pcie_state {
|
||||
BRCMF_PCIE_MB_INT_D2H3_DB0 | \
|
||||
BRCMF_PCIE_MB_INT_D2H3_DB1)
|
||||
|
||||
-#define BRCMF_PCIE_MIN_SHARED_VERSION 4
|
||||
+#define BRCMF_PCIE_MIN_SHARED_VERSION 5
|
||||
#define BRCMF_PCIE_MAX_SHARED_VERSION 5
|
||||
#define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF
|
||||
-#define BRCMF_PCIE_SHARED_TXPUSH_SUPPORT 0x4000
|
||||
|
||||
#define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000
|
||||
#define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000
|
||||
@@ -1280,11 +1279,6 @@ brcmf_pcie_init_share_ram_info(struct br
|
||||
brcmf_err("Unsupported PCIE version %d\n", version);
|
||||
return -EINVAL;
|
||||
}
|
||||
- if (shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT) {
|
||||
- brcmf_err("Unsupported legacy TX mode 0x%x\n",
|
||||
- shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
|
||||
addr = sharedram_addr + BRCMF_SHARED_MAX_RXBUFPOST_OFFSET;
|
||||
shared->max_rxbufpost = brcmf_pcie_read_tcm16(devinfo, addr);
|
|
@ -1,120 +0,0 @@
|
|||
From: Franky Lin <frankyl@broadcom.com>
|
||||
Date: Wed, 20 May 2015 14:09:50 +0200
|
||||
Subject: [PATCH] brcmfmac: remove dummy cache flush/invalidate function
|
||||
|
||||
brcmf_dma_flush and brcmf_dma_invalidate_cache are not necessary and
|
||||
have never been implemented.
|
||||
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Franky Lin <frankyl@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
|
||||
@@ -22,17 +22,6 @@
|
||||
#include "core.h"
|
||||
#include "commonring.h"
|
||||
|
||||
-
|
||||
-/* dma flushing needs implementation for mips and arm platforms. Should
|
||||
- * be put in util. Note, this is not real flushing. It is virtual non
|
||||
- * cached memory. Only write buffers should have to be drained. Though
|
||||
- * this may be different depending on platform......
|
||||
- * SEE ALSO msgbuf.c
|
||||
- */
|
||||
-#define brcmf_dma_flush(addr, len)
|
||||
-#define brcmf_dma_invalidate_cache(addr, len)
|
||||
-
|
||||
-
|
||||
void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
|
||||
int (*cr_ring_bell)(void *ctx),
|
||||
int (*cr_update_rptr)(void *ctx),
|
||||
@@ -206,14 +195,9 @@ int brcmf_commonring_write_complete(stru
|
||||
address = commonring->buf_addr;
|
||||
address += (commonring->f_ptr * commonring->item_len);
|
||||
if (commonring->f_ptr > commonring->w_ptr) {
|
||||
- brcmf_dma_flush(address,
|
||||
- (commonring->depth - commonring->f_ptr) *
|
||||
- commonring->item_len);
|
||||
address = commonring->buf_addr;
|
||||
commonring->f_ptr = 0;
|
||||
}
|
||||
- brcmf_dma_flush(address, (commonring->w_ptr - commonring->f_ptr) *
|
||||
- commonring->item_len);
|
||||
|
||||
commonring->f_ptr = commonring->w_ptr;
|
||||
|
||||
@@ -258,8 +242,6 @@ void *brcmf_commonring_get_read_ptr(stru
|
||||
if (commonring->r_ptr == commonring->depth)
|
||||
commonring->r_ptr = 0;
|
||||
|
||||
- brcmf_dma_invalidate_cache(ret_addr, *n_ items * commonring->item_len);
|
||||
-
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
@@ -278,16 +278,6 @@ struct brcmf_msgbuf_pktids {
|
||||
struct brcmf_msgbuf_pktid *array;
|
||||
};
|
||||
|
||||
-
|
||||
-/* dma flushing needs implementation for mips and arm platforms. Should
|
||||
- * be put in util. Note, this is not real flushing. It is virtual non
|
||||
- * cached memory. Only write buffers should have to be drained. Though
|
||||
- * this may be different depending on platform......
|
||||
- */
|
||||
-#define brcmf_dma_flush(addr, len)
|
||||
-#define brcmf_dma_invalidate_cache(addr, len)
|
||||
-
|
||||
-
|
||||
static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf);
|
||||
|
||||
|
||||
@@ -462,7 +452,6 @@ static int brcmf_msgbuf_tx_ioctl(struct
|
||||
memcpy(msgbuf->ioctbuf, buf, buf_len);
|
||||
else
|
||||
memset(msgbuf->ioctbuf, 0, buf_len);
|
||||
- brcmf_dma_flush(ioctl_buf, buf_len);
|
||||
|
||||
err = brcmf_commonring_write_complete(commonring);
|
||||
brcmf_commonring_unlock(commonring);
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -276,15 +276,6 @@ static const u32 brcmf_ring_itemsize[BRC
|
||||
};
|
||||
|
||||
|
||||
-/* dma flushing needs implementation for mips and arm platforms. Should
|
||||
- * be put in util. Note, this is not real flushing. It is virtual non
|
||||
- * cached memory. Only write buffers should have to be drained. Though
|
||||
- * this may be different depending on platform......
|
||||
- */
|
||||
-#define brcmf_dma_flush(addr, len)
|
||||
-#define brcmf_dma_invalidate_cache(addr, len)
|
||||
-
|
||||
-
|
||||
static u32
|
||||
brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
|
||||
{
|
||||
@@ -1174,7 +1165,6 @@ static int brcmf_pcie_init_scratchbuffer
|
||||
goto fail;
|
||||
|
||||
memset(devinfo->shared.scratch, 0, BRCMF_DMA_D2H_SCRATCH_BUF_LEN);
|
||||
- brcmf_dma_flush(devinfo->shared.scratch, BRCMF_DMA_D2H_SCRATCH_BUF_LEN);
|
||||
|
||||
addr = devinfo->shared.tcm_base_address +
|
||||
BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET;
|
||||
@@ -1192,7 +1182,6 @@ static int brcmf_pcie_init_scratchbuffer
|
||||
goto fail;
|
||||
|
||||
memset(devinfo->shared.ringupd, 0, BRCMF_DMA_D2H_RINGUPD_BUF_LEN);
|
||||
- brcmf_dma_flush(devinfo->shared.ringupd, BRCMF_DMA_D2H_RINGUPD_BUF_LEN);
|
||||
|
||||
addr = devinfo->shared.tcm_base_address +
|
||||
BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET;
|
|
@ -1,270 +0,0 @@
|
|||
From: Franky Lin <frankyl@broadcom.com>
|
||||
Date: Wed, 20 May 2015 14:09:51 +0200
|
||||
Subject: [PATCH] brcmfmac: add support for dma indices feature
|
||||
|
||||
PCIe full dongle firmware can support a dma indices feature with which
|
||||
firmware can update/fetch the read/write indices of message buffer
|
||||
rings on both host to dongle and dongle to host directions. The support is
|
||||
announced by firmware through shared flags.
|
||||
|
||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Franky Lin <frankyl@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
|
||||
@@ -115,6 +115,8 @@ enum brcmf_pcie_state {
|
||||
#define BRCMF_PCIE_MIN_SHARED_VERSION 5
|
||||
#define BRCMF_PCIE_MAX_SHARED_VERSION 5
|
||||
#define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF
|
||||
+#define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000
|
||||
+#define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000
|
||||
|
||||
#define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000
|
||||
#define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000
|
||||
@@ -146,6 +148,10 @@ enum brcmf_pcie_state {
|
||||
#define BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET 8
|
||||
#define BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET 12
|
||||
#define BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET 16
|
||||
+#define BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET 20
|
||||
+#define BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET 28
|
||||
+#define BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET 36
|
||||
+#define BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET 44
|
||||
#define BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET 0
|
||||
#define BRCMF_SHARED_RING_MAX_SUB_QUEUES 52
|
||||
|
||||
@@ -247,6 +253,13 @@ struct brcmf_pciedev_info {
|
||||
bool mbdata_completed;
|
||||
bool irq_allocated;
|
||||
bool wowl_enabled;
|
||||
+ u8 dma_idx_sz;
|
||||
+ void *idxbuf;
|
||||
+ u32 idxbuf_sz;
|
||||
+ dma_addr_t idxbuf_dmahandle;
|
||||
+ u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset);
|
||||
+ void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
|
||||
+ u16 value);
|
||||
};
|
||||
|
||||
struct brcmf_pcie_ringbuf {
|
||||
@@ -323,6 +336,25 @@ brcmf_pcie_write_tcm16(struct brcmf_pcie
|
||||
}
|
||||
|
||||
|
||||
+static u16
|
||||
+brcmf_pcie_read_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset)
|
||||
+{
|
||||
+ u16 *address = devinfo->idxbuf + mem_offset;
|
||||
+
|
||||
+ return (*(address));
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void
|
||||
+brcmf_pcie_write_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
|
||||
+ u16 value)
|
||||
+{
|
||||
+ u16 *address = devinfo->idxbuf + mem_offset;
|
||||
+
|
||||
+ *(address) = value;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static u32
|
||||
brcmf_pcie_read_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset)
|
||||
{
|
||||
@@ -868,7 +900,7 @@ static int brcmf_pcie_ring_mb_write_rptr
|
||||
brcmf_dbg(PCIE, "W r_ptr %d (%d), ring %d\n", commonring->r_ptr,
|
||||
commonring->w_ptr, ring->id);
|
||||
|
||||
- brcmf_pcie_write_tcm16(devinfo, ring->r_idx_addr, commonring->r_ptr);
|
||||
+ devinfo->write_ptr(devinfo, ring->r_idx_addr, commonring->r_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -886,7 +918,7 @@ static int brcmf_pcie_ring_mb_write_wptr
|
||||
brcmf_dbg(PCIE, "W w_ptr %d (%d), ring %d\n", commonring->w_ptr,
|
||||
commonring->r_ptr, ring->id);
|
||||
|
||||
- brcmf_pcie_write_tcm16(devinfo, ring->w_idx_addr, commonring->w_ptr);
|
||||
+ devinfo->write_ptr(devinfo, ring->w_idx_addr, commonring->w_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -915,7 +947,7 @@ static int brcmf_pcie_ring_mb_update_rpt
|
||||
if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
|
||||
return -EIO;
|
||||
|
||||
- commonring->r_ptr = brcmf_pcie_read_tcm16(devinfo, ring->r_idx_addr);
|
||||
+ commonring->r_ptr = devinfo->read_ptr(devinfo, ring->r_idx_addr);
|
||||
|
||||
brcmf_dbg(PCIE, "R r_ptr %d (%d), ring %d\n", commonring->r_ptr,
|
||||
commonring->w_ptr, ring->id);
|
||||
@@ -933,7 +965,7 @@ static int brcmf_pcie_ring_mb_update_wpt
|
||||
if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
|
||||
return -EIO;
|
||||
|
||||
- commonring->w_ptr = brcmf_pcie_read_tcm16(devinfo, ring->w_idx_addr);
|
||||
+ commonring->w_ptr = devinfo->read_ptr(devinfo, ring->w_idx_addr);
|
||||
|
||||
brcmf_dbg(PCIE, "R w_ptr %d (%d), ring %d\n", commonring->w_ptr,
|
||||
commonring->r_ptr, ring->id);
|
||||
@@ -1038,6 +1070,13 @@ static void brcmf_pcie_release_ringbuffe
|
||||
}
|
||||
kfree(devinfo->shared.flowrings);
|
||||
devinfo->shared.flowrings = NULL;
|
||||
+ if (devinfo->idxbuf) {
|
||||
+ dma_free_coherent(&devinfo->pdev->dev,
|
||||
+ devinfo->idxbuf_sz,
|
||||
+ devinfo->idxbuf,
|
||||
+ devinfo->idxbuf_dmahandle);
|
||||
+ devinfo->idxbuf = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
@@ -1053,19 +1092,72 @@ static int brcmf_pcie_init_ringbuffers(s
|
||||
u32 addr;
|
||||
u32 ring_mem_ptr;
|
||||
u32 i;
|
||||
+ u64 address;
|
||||
+ u32 bufsz;
|
||||
u16 max_sub_queues;
|
||||
+ u8 idx_offset;
|
||||
|
||||
ring_addr = devinfo->shared.ring_info_addr;
|
||||
brcmf_dbg(PCIE, "Base ring addr = 0x%08x\n", ring_addr);
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES;
|
||||
+ max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr);
|
||||
|
||||
- addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET;
|
||||
- d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
- addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET;
|
||||
- d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
- addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET;
|
||||
- h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
- addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET;
|
||||
- h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
+ if (devinfo->dma_idx_sz != 0) {
|
||||
+ bufsz = (BRCMF_NROF_D2H_COMMON_MSGRINGS + max_sub_queues) *
|
||||
+ devinfo->dma_idx_sz * 2;
|
||||
+ devinfo->idxbuf = dma_alloc_coherent(&devinfo->pdev->dev, bufsz,
|
||||
+ &devinfo->idxbuf_dmahandle,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!devinfo->idxbuf)
|
||||
+ devinfo->dma_idx_sz = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (devinfo->dma_idx_sz == 0) {
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET;
|
||||
+ d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET;
|
||||
+ d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET;
|
||||
+ h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET;
|
||||
+ h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
+ idx_offset = sizeof(u32);
|
||||
+ devinfo->write_ptr = brcmf_pcie_write_tcm16;
|
||||
+ devinfo->read_ptr = brcmf_pcie_read_tcm16;
|
||||
+ brcmf_dbg(PCIE, "Using TCM indices\n");
|
||||
+ } else {
|
||||
+ memset(devinfo->idxbuf, 0, bufsz);
|
||||
+ devinfo->idxbuf_sz = bufsz;
|
||||
+ idx_offset = devinfo->dma_idx_sz;
|
||||
+ devinfo->write_ptr = brcmf_pcie_write_idx;
|
||||
+ devinfo->read_ptr = brcmf_pcie_read_idx;
|
||||
+
|
||||
+ h2d_w_idx_ptr = 0;
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET;
|
||||
+ address = (u64)devinfo->idxbuf_dmahandle;
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
|
||||
+
|
||||
+ h2d_r_idx_ptr = h2d_w_idx_ptr + max_sub_queues * idx_offset;
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET;
|
||||
+ address += max_sub_queues * idx_offset;
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
|
||||
+
|
||||
+ d2h_w_idx_ptr = h2d_r_idx_ptr + max_sub_queues * idx_offset;
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET;
|
||||
+ address += max_sub_queues * idx_offset;
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
|
||||
+
|
||||
+ d2h_r_idx_ptr = d2h_w_idx_ptr +
|
||||
+ BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset;
|
||||
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET;
|
||||
+ address += BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset;
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
|
||||
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
|
||||
+ brcmf_dbg(PCIE, "Using host memory indices\n");
|
||||
+ }
|
||||
|
||||
addr = ring_addr + BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET;
|
||||
ring_mem_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
|
||||
@@ -1079,8 +1171,8 @@ static int brcmf_pcie_init_ringbuffers(s
|
||||
ring->id = i;
|
||||
devinfo->shared.commonrings[i] = ring;
|
||||
|
||||
- h2d_w_idx_ptr += sizeof(u32);
|
||||
- h2d_r_idx_ptr += sizeof(u32);
|
||||
+ h2d_w_idx_ptr += idx_offset;
|
||||
+ h2d_r_idx_ptr += idx_offset;
|
||||
ring_mem_ptr += BRCMF_RING_MEM_SZ;
|
||||
}
|
||||
|
||||
@@ -1094,13 +1186,11 @@ static int brcmf_pcie_init_ringbuffers(s
|
||||
ring->id = i;
|
||||
devinfo->shared.commonrings[i] = ring;
|
||||
|
||||
- d2h_w_idx_ptr += sizeof(u32);
|
||||
- d2h_r_idx_ptr += sizeof(u32);
|
||||
+ d2h_w_idx_ptr += idx_offset;
|
||||
+ d2h_r_idx_ptr += idx_offset;
|
||||
ring_mem_ptr += BRCMF_RING_MEM_SZ;
|
||||
}
|
||||
|
||||
- addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES;
|
||||
- max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr);
|
||||
devinfo->shared.nrof_flowrings =
|
||||
max_sub_queues - BRCMF_NROF_H2D_COMMON_MSGRINGS;
|
||||
rings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*ring),
|
||||
@@ -1124,15 +1214,15 @@ static int brcmf_pcie_init_ringbuffers(s
|
||||
ring);
|
||||
ring->w_idx_addr = h2d_w_idx_ptr;
|
||||
ring->r_idx_addr = h2d_r_idx_ptr;
|
||||
- h2d_w_idx_ptr += sizeof(u32);
|
||||
- h2d_r_idx_ptr += sizeof(u32);
|
||||
+ h2d_w_idx_ptr += idx_offset;
|
||||
+ h2d_r_idx_ptr += idx_offset;
|
||||
}
|
||||
devinfo->shared.flowrings = rings;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
- brcmf_err("Allocating commonring buffers failed\n");
|
||||
+ brcmf_err("Allocating ring buffers failed\n");
|
||||
brcmf_pcie_release_ringbuffers(devinfo);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -1269,6 +1359,14 @@ brcmf_pcie_init_share_ram_info(struct br
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ /* check firmware support dma indicies */
|
||||
+ if (shared->flags & BRCMF_PCIE_SHARED_DMA_INDEX) {
|
||||
+ if (shared->flags & BRCMF_PCIE_SHARED_DMA_2B_IDX)
|
||||
+ devinfo->dma_idx_sz = sizeof(u16);
|
||||
+ else
|
||||
+ devinfo->dma_idx_sz = sizeof(u32);
|
||||
+ }
|
||||
+
|
||||
addr = sharedram_addr + BRCMF_SHARED_MAX_RXBUFPOST_OFFSET;
|
||||
shared->max_rxbufpost = brcmf_pcie_read_tcm16(devinfo, addr);
|
||||
if (shared->max_rxbufpost == 0)
|
|
@ -1,102 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Tue, 26 May 2015 13:19:46 +0200
|
||||
Subject: [PATCH] brcmfmac: avoid null pointer access when
|
||||
brcmf_msgbuf_get_pktid() fails
|
||||
|
||||
The function brcmf_msgbuf_get_pktid() may return a NULL pointer so
|
||||
the callers should check the return pointer before accessing it to
|
||||
avoid the crash below (see [1]):
|
||||
|
||||
brcmfmac: brcmf_msgbuf_get_pktid: Invalid packet id 273 (not in use)
|
||||
BUG: unable to handle kernel NULL pointer dereference at 0000000000000080
|
||||
IP: [<ffffffff8145b225>] skb_pull+0x5/0x50
|
||||
PGD 0
|
||||
Oops: 0000 [#1] PREEMPT SMP
|
||||
Modules linked in: pci_stub vboxpci(O) vboxnetflt(O) vboxnetadp(O) vboxdrv(O)
|
||||
snd_hda_codec_hdmi bnep mousedev hid_generic ushwmon msr ext4 crc16 mbcache
|
||||
jbd2 sd_mod uas usb_storage ahci libahci libata scsi_mod xhci_pci xhci_hcd
|
||||
usbcore usb_common
|
||||
CPU: 0 PID: 1661 Comm: irq/61-brcmf_pc Tainted: G O 4.0.1-MacbookPro-ARCH #1
|
||||
Hardware name: Apple Inc. MacBookPro12,1/Mac-E43C1C25D4880AD6,
|
||||
BIOS MBP121.88Z.0167.B02.1503241251 03/24/2015
|
||||
task: ffff880264203cc0 ti: ffff88025ffe4000 task.ti: ffff88025ffe4000
|
||||
RIP: 0010:[<ffffffff8145b225>] [<ffffffff8145b225>] skb_pull+0x5/0x50
|
||||
RSP: 0018:ffff88025ffe7d40 EFLAGS: 00010202
|
||||
RAX: 0000000000000000 RBX: ffff88008a33c000 RCX: 0000000000000044
|
||||
RDX: 0000000000000000 RSI: 000000000000004a RDI: 0000000000000000
|
||||
RBP: ffff88025ffe7da8 R08: 0000000000000096 R09: 000000000000004a
|
||||
R10: 0000000000000000 R11: 000000000000048e R12: ffff88025ff14f00
|
||||
R13: 0000000000000000 R14: ffff880263b48200 R15: ffff88008a33c000
|
||||
FS: 0000000000000000(0000) GS:ffff88026ec00000(0000) knlGS:0000000000000000
|
||||
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
CR2: 0000000000000080 CR3: 000000000180b000 CR4: 00000000003407f0
|
||||
Stack:
|
||||
ffffffffa06aed74 ffff88025ffe7dc8 ffff880263b48270 ffff880263b48278
|
||||
05ea88020000004a 0002ffff81014635 000000001720b2f6 ffff88026ec116c0
|
||||
ffff880263b48200 0000000000010000 ffff880263b4ae00 ffff880264203cc0
|
||||
Call Trace:
|
||||
[<ffffffffa06aed74>] ? brcmf_msgbuf_process_rx+0x404/0x480 [brcmfmac]
|
||||
[<ffffffff810cea60>] ? irq_finalize_oneshot.part.30+0xf0/0xf0
|
||||
[<ffffffffa06afb55>] brcmf_proto_msgbuf_rx_trigger+0x35/0xf0 [brcmfmac]
|
||||
[<ffffffffa06baf2a>] brcmf_pcie_isr_thread_v2+0x8a/0x130 [brcmfmac]
|
||||
[<ffffffff810cea80>] irq_thread_fn+0x20/0x50
|
||||
[<ffffffff810ceddf>] irq_thread+0x13f/0x170
|
||||
[<ffffffff810cebf0>] ? wake_threads_waitq+0x30/0x30
|
||||
[<ffffffff810ceca0>] ? irq_thread_dtor+0xb0/0xb0
|
||||
[<ffffffff81092a08>] kthread+0xd8/0xf0
|
||||
[<ffffffff81092930>] ? kthread_create_on_node+0x1c0/0x1c0
|
||||
[<ffffffff8156d898>] ret_from_fork+0x58/0x90
|
||||
[<ffffffff81092930>] ? kthread_create_on_node+0x1c0/0x1c0
|
||||
Code: 01 83 e2 f7 88 50 01 48 83 c4 08 5b 5d f3 c3 0f 1f 80 00 00 00 00 83 e2
|
||||
f7 88 50 01 c3 66 0f 1f 84 00 00 00 00 00 0f 1f
|
||||
RIP [<ffffffff8145b225>] skb_pull+0x5/0x50
|
||||
RSP <ffff88025ffe7d40>
|
||||
CR2: 0000000000000080
|
||||
---[ end trace b074c0f90e7c997d ]---
|
||||
|
||||
[1] http://mid.gmane.org/20150430193259.GA5630@googlemail.com
|
||||
|
||||
Cc: <stable@vger.kernel.org> # v3.18, v3.19, v4.0, v4.1
|
||||
Reported-by: Michael Hornung <mhornung.linux@gmail.com>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
|
||||
@@ -500,11 +500,9 @@ static int brcmf_msgbuf_query_dcmd(struc
|
||||
msgbuf->rx_pktids,
|
||||
msgbuf->ioctl_resp_pktid);
|
||||
if (msgbuf->ioctl_resp_ret_len != 0) {
|
||||
- if (!skb) {
|
||||
- brcmf_err("Invalid packet id idx recv'd %d\n",
|
||||
- msgbuf->ioctl_resp_pktid);
|
||||
+ if (!skb)
|
||||
return -EBADF;
|
||||
- }
|
||||
+
|
||||
memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ?
|
||||
len : msgbuf->ioctl_resp_ret_len);
|
||||
}
|
||||
@@ -866,10 +864,8 @@ brcmf_msgbuf_process_txstatus(struct brc
|
||||
flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS;
|
||||
skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
|
||||
msgbuf->tx_pktids, idx);
|
||||
- if (!skb) {
|
||||
- brcmf_err("Invalid packet id idx recv'd %d\n", idx);
|
||||
+ if (!skb)
|
||||
return;
|
||||
- }
|
||||
|
||||
set_bit(flowid, msgbuf->txstatus_done_map);
|
||||
commonring = msgbuf->flowrings[flowid];
|
||||
@@ -1148,6 +1144,8 @@ brcmf_msgbuf_process_rx_complete(struct
|
||||
|
||||
skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
|
||||
msgbuf->rx_pktids, idx);
|
||||
+ if (!skb)
|
||||
+ return;
|
||||
|
||||
if (data_offset)
|
||||
skb_pull(skb, data_offset);
|
|
@ -1,63 +0,0 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
Date: Wed, 27 May 2015 19:31:41 +0200
|
||||
Subject: [PATCH] brcmfmac: fix invalid access to struct acpi_device fields
|
||||
|
||||
The fields of struct acpi_device are only known when CONFIG_ACPI is
|
||||
defined. Fix this by using a helper function. This will resolve the
|
||||
issue found in linux-next:
|
||||
|
||||
../brcmfmac/bcmsdh.c: In function 'brcmf_ops_sdio_probe':
|
||||
../brcmfmac/bcmsdh.c:1139:7: error: dereferencing pointer to incomplete type
|
||||
adev->flags.power_manageable = 0;
|
||||
^
|
||||
|
||||
Fixes: f0992ace680c ("brcmfmac: prohibit ACPI power management ...")
|
||||
Cc: Fu, Zhonghui <zhonghui.fu@linux.intel.com>
|
||||
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
|
||||
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
|
||||
@@ -1117,6 +1117,18 @@ MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_id
|
||||
static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
|
||||
|
||||
|
||||
+static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev,
|
||||
+ int val)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_ACPI)
|
||||
+ struct acpi_device *adev;
|
||||
+
|
||||
+ adev = ACPI_COMPANION(dev);
|
||||
+ if (adev)
|
||||
+ adev->flags.power_manageable = 0;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static int brcmf_ops_sdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
@@ -1124,7 +1136,6 @@ static int brcmf_ops_sdio_probe(struct s
|
||||
struct brcmf_sdio_dev *sdiodev;
|
||||
struct brcmf_bus *bus_if;
|
||||
struct device *dev;
|
||||
- struct acpi_device *adev;
|
||||
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
brcmf_dbg(SDIO, "Class=%x\n", func->class);
|
||||
@@ -1132,11 +1143,9 @@ static int brcmf_ops_sdio_probe(struct s
|
||||
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
|
||||
brcmf_dbg(SDIO, "Function#: %d\n", func->num);
|
||||
|
||||
- /* prohibit ACPI power management for this device */
|
||||
dev = &func->dev;
|
||||
- adev = ACPI_COMPANION(dev);
|
||||
- if (adev)
|
||||
- adev->flags.power_manageable = 0;
|
||||
+ /* prohibit ACPI power management for this device */
|
||||
+ brcmf_sdiod_acpi_set_power_manageable(dev, 0);
|
||||
|
||||
/* Consume func num 1 but dont do anything with it. */
|
||||
if (func->num == 1)
|
|
@ -1,56 +0,0 @@
|
|||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Wed, 20 May 2015 09:34:21 +0200
|
||||
Subject: [PATCH] brcmfmac: simplify check stripping v2 NVRAM
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Comparing NVRAM entry with a full filtering string is simpler than
|
||||
comparing it with a short prefix and then checking random chars at magic
|
||||
offsets. The cost of snprintf relatively low, we execute it just once.
|
||||
Tested on BCM43602 with NVRAM hacked to use V2 format.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#define BRCMF_FW_MAX_NVRAM_SIZE 64000
|
||||
#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
|
||||
-#define BRCMF_FW_NVRAM_PCIEDEV_LEN 9 /* pcie/1/4/ */
|
||||
+#define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
|
||||
|
||||
char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
|
||||
module_param_string(firmware_path, brcmf_firmware_path,
|
||||
@@ -297,6 +297,8 @@ fail:
|
||||
static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
|
||||
u16 bus_nr)
|
||||
{
|
||||
+ char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN];
|
||||
+ size_t len;
|
||||
u32 i, j;
|
||||
u8 *nvram;
|
||||
|
||||
@@ -308,14 +310,13 @@ static void brcmf_fw_strip_multi_v2(stru
|
||||
* Valid entries are of type pcie/X/Y/ where X = domain_nr and
|
||||
* Y = bus_nr.
|
||||
*/
|
||||
+ snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr);
|
||||
+ len = strlen(prefix);
|
||||
i = 0;
|
||||
j = 0;
|
||||
- while (i < nvp->nvram_len - BRCMF_FW_NVRAM_PCIEDEV_LEN) {
|
||||
- if ((strncmp(&nvp->nvram[i], "pcie/", 5) == 0) &&
|
||||
- (nvp->nvram[i + 6] == '/') && (nvp->nvram[i + 8] == '/') &&
|
||||
- ((nvp->nvram[i + 5] - '0') == domain_nr) &&
|
||||
- ((nvp->nvram[i + 7] - '0') == bus_nr)) {
|
||||
- i += BRCMF_FW_NVRAM_PCIEDEV_LEN;
|
||||
+ while (i < nvp->nvram_len - len) {
|
||||
+ if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
|
||||
+ i += len;
|
||||
while (nvp->nvram[i] != 0) {
|
||||
nvram[j] = nvp->nvram[i];
|
||||
i++;
|
|
@ -1,57 +0,0 @@
|
|||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Wed, 20 May 2015 11:01:08 +0200
|
||||
Subject: [PATCH] brcmfmac: simplify check finding NVRAM v1 device path
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
With a simple use of snprintf and small buffer we can compare NVRAM
|
||||
entry value with a full string. This way we avoid checking random chars
|
||||
at magic offsets.
|
||||
Tested on BCM43602 with NVRAM hacked to use v1 format.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
@@ -222,6 +222,10 @@ static int brcmf_init_nvram_parser(struc
|
||||
static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
|
||||
u16 bus_nr)
|
||||
{
|
||||
+ /* Device path with a leading '=' key-value separator */
|
||||
+ char pcie_path[] = "=pcie/?/?";
|
||||
+ size_t pcie_len;
|
||||
+
|
||||
u32 i, j;
|
||||
bool found;
|
||||
u8 *nvram;
|
||||
@@ -238,6 +242,9 @@ static void brcmf_fw_strip_multi_v1(stru
|
||||
/* First search for the devpathX and see if it is the configuration
|
||||
* for domain_nr/bus_nr. Search complete nvp
|
||||
*/
|
||||
+ snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr,
|
||||
+ bus_nr);
|
||||
+ pcie_len = strlen(pcie_path);
|
||||
found = false;
|
||||
i = 0;
|
||||
while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
|
||||
@@ -245,13 +252,10 @@ static void brcmf_fw_strip_multi_v1(stru
|
||||
* Y = domain_nr, Z = bus_nr, X = virtual ID
|
||||
*/
|
||||
if ((strncmp(&nvp->nvram[i], "devpath", 7) == 0) &&
|
||||
- (strncmp(&nvp->nvram[i + 8], "=pcie/", 6) == 0)) {
|
||||
- if (((nvp->nvram[i + 14] - '0') == domain_nr) &&
|
||||
- ((nvp->nvram[i + 16] - '0') == bus_nr)) {
|
||||
- id = nvp->nvram[i + 7] - '0';
|
||||
- found = true;
|
||||
- break;
|
||||
- }
|
||||
+ (strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len) == 0)) {
|
||||
+ id = nvp->nvram[i + 7] - '0';
|
||||
+ found = true;
|
||||
+ break;
|
||||
}
|
||||
while (nvp->nvram[i] != 0)
|
||||
i++;
|
|
@ -1,45 +0,0 @@
|
|||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Wed, 20 May 2015 13:59:54 +0200
|
||||
Subject: [PATCH] brcmfmac: treat \0 as end of comment when parsing NVRAM
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This fixes brcmfmac dealing with NVRAM coming from platform e.g. from a
|
||||
flash MTD partition. In such cases entries are separated by \0 instead
|
||||
of \n which caused ignoring whole content after the first "comment".
|
||||
While platform NVRAM doesn't usually contain comments, we switch to
|
||||
COMMENT state after e.g. finding an unexpected char in key name.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
|
||||
@@ -162,17 +162,20 @@ brcmf_nvram_handle_value(struct nvram_pa
|
||||
static enum nvram_parser_state
|
||||
brcmf_nvram_handle_comment(struct nvram_parser *nvp)
|
||||
{
|
||||
- char *eol, *sol;
|
||||
+ char *eoc, *sol;
|
||||
|
||||
sol = (char *)&nvp->fwnv->data[nvp->pos];
|
||||
- eol = strchr(sol, '\n');
|
||||
- if (eol == NULL)
|
||||
- return END;
|
||||
+ eoc = strchr(sol, '\n');
|
||||
+ if (!eoc) {
|
||||
+ eoc = strchr(sol, '\0');
|
||||
+ if (!eoc)
|
||||
+ return END;
|
||||
+ }
|
||||
|
||||
/* eat all moving to next line */
|
||||
nvp->line++;
|
||||
nvp->column = 1;
|
||||
- nvp->pos += (eol - sol) + 1;
|
||||
+ nvp->pos += (eoc - sol) + 1;
|
||||
return IDLE;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue