Based on patch by Bryan Forbes <bryan@reigndropsfall.net> Also update mt76 to update for API changes Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 44655master
parent
ee1e8c2f2d
commit
1e5b7c17b0
@ -0,0 +1,10 @@ |
||||
--- a/backport-include/linux/debugfs.h
|
||||
+++ b/backport-include/linux/debugfs.h
|
||||
@@ -3,6 +3,7 @@
|
||||
#include_next <linux/debugfs.h>
|
||||
#include <linux/version.h>
|
||||
#include <generated/utsrelease.h>
|
||||
+#include <linux/device.h>
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name,
|
@ -1,318 +0,0 @@ |
||||
--- a/drivers/bcma/bcma_private.h
|
||||
+++ b/drivers/bcma/bcma_private.h
|
||||
@@ -41,6 +41,7 @@ int __init bcma_bus_scan_early(struct bc
|
||||
struct bcma_device_id *match,
|
||||
struct bcma_device *core);
|
||||
void bcma_init_bus(struct bcma_bus *bus);
|
||||
+void bcma_unregister_cores(struct bcma_bus *bus);
|
||||
|
||||
/* sprom.c */
|
||||
int bcma_sprom_get(struct bcma_bus *bus);
|
||||
@@ -105,6 +106,11 @@ static inline void __exit bcma_host_soc_
|
||||
|
||||
/* driver_pci.c */
|
||||
u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
|
||||
+void bcma_core_pci_up(struct bcma_drv_pci *pc);
|
||||
+void bcma_core_pci_down(struct bcma_drv_pci *pc);
|
||||
+
|
||||
+/* driver_pcie2.c */
|
||||
+void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2);
|
||||
|
||||
extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
|
||||
|
||||
--- a/drivers/bcma/driver_gpio.c
|
||||
+++ b/drivers/bcma/driver_gpio.c
|
||||
@@ -76,7 +76,7 @@ static void bcma_gpio_free(struct gpio_c
|
||||
bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
|
||||
}
|
||||
|
||||
-#if IS_BUILTIN(CONFIG_BCM47XX)
|
||||
+#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
|
||||
static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
|
||||
@@ -215,7 +215,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
||||
chip->set = bcma_gpio_set_value;
|
||||
chip->direction_input = bcma_gpio_direction_input;
|
||||
chip->direction_output = bcma_gpio_direction_output;
|
||||
-#if IS_BUILTIN(CONFIG_BCM47XX)
|
||||
+#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
|
||||
chip->to_irq = bcma_gpio_to_irq;
|
||||
#endif
|
||||
#if IS_BUILTIN(CONFIG_OF)
|
||||
--- a/drivers/bcma/driver_pci.c
|
||||
+++ b/drivers/bcma/driver_pci.c
|
||||
@@ -262,21 +262,21 @@ void bcma_core_pci_power_save(struct bcm
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
|
||||
|
||||
-int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
|
||||
+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 (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
||||
+ 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 = pc->core->bus->host_pci;
|
||||
+ pdev = bus->host_pci;
|
||||
|
||||
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
if (err)
|
||||
@@ -308,28 +308,12 @@ static void bcma_core_pci_extend_L1timer
|
||||
bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
|
||||
}
|
||||
|
||||
-void bcma_core_pci_up(struct bcma_bus *bus)
|
||||
+void bcma_core_pci_up(struct bcma_drv_pci *pc)
|
||||
{
|
||||
- struct bcma_drv_pci *pc;
|
||||
-
|
||||
- if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
||||
- return;
|
||||
-
|
||||
- pc = &bus->drv_pci[0];
|
||||
-
|
||||
bcma_core_pci_extend_L1timer(pc, true);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(bcma_core_pci_up);
|
||||
|
||||
-void bcma_core_pci_down(struct bcma_bus *bus)
|
||||
+void bcma_core_pci_down(struct bcma_drv_pci *pc)
|
||||
{
|
||||
- struct bcma_drv_pci *pc;
|
||||
-
|
||||
- if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
||||
- return;
|
||||
-
|
||||
- pc = &bus->drv_pci[0];
|
||||
-
|
||||
bcma_core_pci_extend_L1timer(pc, false);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(bcma_core_pci_down);
|
||||
--- a/drivers/bcma/driver_pci_host.c
|
||||
+++ b/drivers/bcma/driver_pci_host.c
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/pci.h>
|
||||
+#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <asm/paccess.h>
|
||||
--- a/drivers/bcma/driver_pcie2.c
|
||||
+++ b/drivers/bcma/driver_pcie2.c
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
+#include <linux/pci.h>
|
||||
|
||||
/**************************************************
|
||||
* R/W ops.
|
||||
@@ -156,14 +157,23 @@ static void pciedev_reg_pm_clk_period(st
|
||||
|
||||
void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
|
||||
{
|
||||
- struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo;
|
||||
+ struct bcma_bus *bus = pcie2->core->bus;
|
||||
+ struct bcma_chipinfo *ci = &bus->chipinfo;
|
||||
u32 tmp;
|
||||
|
||||
tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54));
|
||||
if ((tmp & 0xe) >> 1 == 2)
|
||||
bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17);
|
||||
|
||||
- /* TODO: Do we need pcie_reqsize? */
|
||||
+ switch (bus->chipinfo.id) {
|
||||
+ case BCMA_CHIP_ID_BCM4360:
|
||||
+ case BCMA_CHIP_ID_BCM4352:
|
||||
+ pcie2->reqsize = 1024;
|
||||
+ break;
|
||||
+ default:
|
||||
+ pcie2->reqsize = 128;
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3)
|
||||
bcma_core_pcie2_war_delay_perst_enab(pcie2, true);
|
||||
@@ -173,3 +183,18 @@ void bcma_core_pcie2_init(struct bcma_dr
|
||||
pciedev_crwlpciegen2_180(pcie2);
|
||||
pciedev_crwlpciegen2_182(pcie2);
|
||||
}
|
||||
+
|
||||
+/**************************************************
|
||||
+ * Runtime ops.
|
||||
+ **************************************************/
|
||||
+
|
||||
+void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2)
|
||||
+{
|
||||
+ struct bcma_bus *bus = pcie2->core->bus;
|
||||
+ struct pci_dev *dev = bus->host_pci;
|
||||
+ int err;
|
||||
+
|
||||
+ err = pcie_set_readrq(dev, pcie2->reqsize);
|
||||
+ if (err)
|
||||
+ bcma_err(bus, "Error setting PCI_EXP_DEVCTL_READRQ: %d\n", err);
|
||||
+}
|
||||
--- a/drivers/bcma/host_pci.c
|
||||
+++ b/drivers/bcma/host_pci.c
|
||||
@@ -211,16 +211,26 @@ static int bcma_host_pci_probe(struct pc
|
||||
/* Initialize struct, detect chip */
|
||||
bcma_init_bus(bus);
|
||||
|
||||
+ /* Scan bus to find out generation of PCIe core */
|
||||
+ err = bcma_bus_scan(bus);
|
||||
+ if (err)
|
||||
+ goto err_pci_unmap_mmio;
|
||||
+
|
||||
+ if (bcma_find_core(bus, BCMA_CORE_PCIE2))
|
||||
+ bus->host_is_pcie2 = true;
|
||||
+
|
||||
/* Register */
|
||||
err = bcma_bus_register(bus);
|
||||
if (err)
|
||||
- goto err_pci_unmap_mmio;
|
||||
+ goto err_unregister_cores;
|
||||
|
||||
pci_set_drvdata(dev, bus);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
+err_unregister_cores:
|
||||
+ bcma_unregister_cores(bus);
|
||||
err_pci_unmap_mmio:
|
||||
pci_iounmap(dev, bus->mmio);
|
||||
err_pci_release_regions:
|
||||
@@ -281,9 +291,12 @@ static const struct pci_device_id bcma_p
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
|
||||
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
|
||||
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
|
||||
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43b1) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xa8db, BCM43217 (sic!) */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) }, /* 0xa8dc */
|
||||
@@ -308,3 +321,31 @@ void __exit bcma_host_pci_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&bcma_pci_bridge_driver);
|
||||
}
|
||||
+
|
||||
+/**************************************************
|
||||
+ * Runtime ops for drivers.
|
||||
+ **************************************************/
|
||||
+
|
||||
+/* See also pcicore_up */
|
||||
+void bcma_host_pci_up(struct bcma_bus *bus)
|
||||
+{
|
||||
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
||||
+ return;
|
||||
+
|
||||
+ if (bus->host_is_pcie2)
|
||||
+ bcma_core_pcie2_up(&bus->drv_pcie2);
|
||||
+ else
|
||||
+ bcma_core_pci_up(&bus->drv_pci[0]);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcma_host_pci_up);
|
||||
+
|
||||
+/* See also pcicore_down */
|
||||
+void bcma_host_pci_down(struct bcma_bus *bus)
|
||||
+{
|
||||
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
||||
+ return;
|
||||
+
|
||||
+ if (!bus->host_is_pcie2)
|
||||
+ bcma_core_pci_down(&bus->drv_pci[0]);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcma_host_pci_down);
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -288,7 +288,7 @@ static int bcma_register_devices(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void bcma_unregister_cores(struct bcma_bus *bus)
|
||||
+void bcma_unregister_cores(struct bcma_bus *bus)
|
||||
{
|
||||
struct bcma_device *core, *tmp;
|
||||
|
||||
--- a/drivers/net/wireless/b43/main.c
|
||||
+++ b/drivers/net/wireless/b43/main.c
|
||||
@@ -4770,7 +4770,7 @@ static void b43_wireless_core_exit(struc
|
||||
switch (dev->dev->bus_type) {
|
||||
#ifdef CPTCFG_B43_BCMA
|
||||
case B43_BUS_BCMA:
|
||||
- bcma_core_pci_down(dev->dev->bdev->bus);
|
||||
+ bcma_host_pci_down(dev->dev->bdev->bus);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CPTCFG_B43_SSB
|
||||
@@ -4817,9 +4817,9 @@ 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->drv_pci[0],
|
||||
+ bcma_core_pci_irq_ctl(dev->dev->bdev->bus,
|
||||
dev->dev->bdev, true);
|
||||
- bcma_core_pci_up(dev->dev->bdev->bus);
|
||||
+ bcma_host_pci_up(dev->dev->bdev->bus);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CPTCFG_B43_SSB
|
||||
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
|
||||
@@ -4669,7 +4669,7 @@ static int brcms_b_attach(struct brcms_c
|
||||
brcms_c_coredisable(wlc_hw);
|
||||
|
||||
/* Match driver "down" state */
|
||||
- bcma_core_pci_down(wlc_hw->d11core->bus);
|
||||
+ bcma_host_pci_down(wlc_hw->d11core->bus);
|
||||
|
||||
/* turn off pll and xtal to match driver "down" state */
|
||||
brcms_b_xtal(wlc_hw, OFF);
|
||||
@@ -4960,7 +4960,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->drv_pci[0], wlc_hw->d11core,
|
||||
+ bcma_core_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
|
||||
true);
|
||||
|
||||
/*
|
||||
@@ -4970,12 +4970,12 @@ static int brcms_b_up_prep(struct brcms_
|
||||
*/
|
||||
if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
|
||||
/* put SB PCI in down state again */
|
||||
- bcma_core_pci_down(wlc_hw->d11core->bus);
|
||||
+ bcma_host_pci_down(wlc_hw->d11core->bus);
|
||||
brcms_b_xtal(wlc_hw, OFF);
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
- bcma_core_pci_up(wlc_hw->d11core->bus);
|
||||
+ bcma_host_pci_up(wlc_hw->d11core->bus);
|
||||
|
||||
/* reset the d11 core */
|
||||
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
|
||||
@@ -5172,7 +5172,7 @@ static int brcms_b_down_finish(struct br
|
||||
|
||||
/* turn off primary xtal and pll */
|
||||
if (!wlc_hw->noreset) {
|
||||
- bcma_core_pci_down(wlc_hw->d11core->bus);
|
||||
+ bcma_host_pci_down(wlc_hw->d11core->bus);
|
||||
brcms_b_xtal(wlc_hw, OFF);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,347 +0,0 @@ |
||||
--- a/net/mac80211/Kconfig
|
||||
+++ b/net/mac80211/Kconfig
|
||||
@@ -5,7 +5,6 @@ config MAC80211
|
||||
depends on CRYPTO
|
||||
depends on CRYPTO_ARC4
|
||||
depends on CRYPTO_AES
|
||||
- select BACKPORT_CRYPTO_CCM
|
||||
depends on CRC32
|
||||
select BACKPORT_AVERAGE
|
||||
---help---
|
||||
--- a/net/mac80211/aes_ccm.c
|
||||
+++ b/net/mac80211/aes_ccm.c
|
||||
@@ -2,8 +2,6 @@
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
*
|
||||
- * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
|
||||
- *
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
@@ -19,76 +17,134 @@
|
||||
#include "key.h"
|
||||
#include "aes_ccm.h"
|
||||
|
||||
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
- u8 *data, size_t data_len, u8 *mic)
|
||||
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a)
|
||||
+{
|
||||
+ int i;
|
||||
+ u8 *b_0, *aad, *b, *s_0;
|
||||
+
|
||||
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
|
||||
+ aad = scratch + 4 * AES_BLOCK_SIZE;
|
||||
+ b = scratch;
|
||||
+ s_0 = scratch + AES_BLOCK_SIZE;
|
||||
+
|
||||
+ crypto_cipher_encrypt_one(tfm, b, b_0);
|
||||
+
|
||||
+ /* Extra Authenticate-only data (always two AES blocks) */
|
||||
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||
+ aad[i] ^= b[i];
|
||||
+ crypto_cipher_encrypt_one(tfm, b, aad);
|
||||
+
|
||||
+ aad += AES_BLOCK_SIZE;
|
||||
+
|
||||
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||
+ aad[i] ^= b[i];
|
||||
+ crypto_cipher_encrypt_one(tfm, a, aad);
|
||||
+
|
||||
+ /* Mask out bits from auth-only-b_0 */
|
||||
+ b_0[0] &= 0x07;
|
||||
+
|
||||
+ /* S_0 is used to encrypt T (= MIC) */
|
||||
+ b_0[14] = 0;
|
||||
+ b_0[15] = 0;
|
||||
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
+ u8 *data, size_t data_len,
|
||||
+ u8 *cdata, u8 *mic)
|
||||
{
|
||||
- struct scatterlist assoc, pt, ct[2];
|
||||
+ int i, j, last_len, num_blocks;
|
||||
+ u8 *pos, *cpos, *b, *s_0, *e, *b_0;
|
||||
|
||||
- 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, IEEE80211_CCMP_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);
|
||||
+ b = scratch;
|
||||
+ s_0 = scratch + AES_BLOCK_SIZE;
|
||||
+ e = scratch + 2 * AES_BLOCK_SIZE;
|
||||
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
|
||||
+
|
||||
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
||||
+ last_len = data_len % AES_BLOCK_SIZE;
|
||||
+ aes_ccm_prepare(tfm, scratch, b);
|
||||
+
|
||||
+ /* Process payload blocks */
|
||||
+ pos = data;
|
||||
+ cpos = cdata;
|
||||
+ for (j = 1; j <= num_blocks; j++) {
|
||||
+ int blen = (j == num_blocks && last_len) ?
|
||||
+ last_len : AES_BLOCK_SIZE;
|
||||
+
|
||||
+ /* Authentication followed by encryption */
|
||||
+ for (i = 0; i < blen; i++)
|
||||
+ b[i] ^= pos[i];
|
||||
+ crypto_cipher_encrypt_one(tfm, b, b);
|
||||
+
|
||||
+ b_0[14] = (j >> 8) & 0xff;
|
||||
+ b_0[15] = j & 0xff;
|
||||
+ crypto_cipher_encrypt_one(tfm, e, b_0);
|
||||
+ for (i = 0; i < blen; i++)
|
||||
+ *cpos++ = *pos++ ^ e[i];
|
||||
+ }
|
||||
|
||||
- crypto_aead_encrypt(aead_req);
|
||||
+ for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++)
|
||||
+ mic[i] = b[i] ^ s_0[i];
|
||||
}
|
||||
|
||||
-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
- u8 *data, size_t data_len, u8 *mic)
|
||||
+
|
||||
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
+ u8 *cdata, size_t data_len, u8 *mic, u8 *data)
|
||||
{
|
||||
- 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;
|
||||
-
|
||||
- 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, IEEE80211_CCMP_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 + IEEE80211_CCMP_MIC_LEN, b_0);
|
||||
+ int i, j, last_len, num_blocks;
|
||||
+ u8 *pos, *cpos, *b, *s_0, *a, *b_0;
|
||||
+
|
||||
+ b = scratch;
|
||||
+ s_0 = scratch + AES_BLOCK_SIZE;
|
||||
+ a = scratch + 2 * AES_BLOCK_SIZE;
|
||||
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
|
||||
+
|
||||
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
||||
+ last_len = data_len % AES_BLOCK_SIZE;
|
||||
+ aes_ccm_prepare(tfm, scratch, a);
|
||||
+
|
||||
+ /* Process payload blocks */
|
||||
+ cpos = cdata;
|
||||
+ pos = data;
|
||||
+ for (j = 1; j <= num_blocks; j++) {
|
||||
+ int blen = (j == num_blocks && last_len) ?
|
||||
+ last_len : AES_BLOCK_SIZE;
|
||||
+
|
||||
+ /* Decryption followed by authentication */
|
||||
+ b_0[14] = (j >> 8) & 0xff;
|
||||
+ b_0[15] = j & 0xff;
|
||||
+ crypto_cipher_encrypt_one(tfm, b, b_0);
|
||||
+ for (i = 0; i < blen; i++) {
|
||||
+ *pos = *cpos++ ^ b[i];
|
||||
+ a[i] ^= *pos++;
|
||||
+ }
|
||||
+ crypto_cipher_encrypt_one(tfm, a, a);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) {
|
||||
+ if ((mic[i] ^ s_0[i]) != a[i])
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
- return crypto_aead_decrypt(aead_req);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[])
|
||||
+
|
||||
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
|
||||
{
|
||||
- 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, WLAN_KEY_LEN_CCMP);
|
||||
- if (!err)
|
||||
- err = crypto_aead_setauthsize(tfm, IEEE80211_CCMP_MIC_LEN);
|
||||
- if (!err)
|
||||
- return tfm;
|
||||
+ tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
||||
+ if (!IS_ERR(tfm))
|
||||
+ crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP);
|
||||
|
||||
- crypto_free_aead(tfm);
|
||||
- return ERR_PTR(err);
|
||||
+ return tfm;
|
||||
}
|
||||
|
||||
-void ieee80211_aes_key_free(struct crypto_aead *tfm)
|
||||
+
|
||||
+void ieee80211_aes_key_free(struct crypto_cipher *tfm)
|
||||
{
|
||||
- crypto_free_aead(tfm);
|
||||
+ crypto_free_cipher(tfm);
|
||||
}
|
||||
--- a/net/mac80211/aes_ccm.h
|
||||
+++ b/net/mac80211/aes_ccm.h
|
||||
@@ -12,11 +12,13 @@
|
||||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]);
|
||||
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
- u8 *data, size_t data_len, u8 *mic);
|
||||
-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
- u8 *data, size_t data_len, u8 *mic);
|
||||
-void ieee80211_aes_key_free(struct crypto_aead *tfm);
|
||||
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
|
||||
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
+ u8 *data, size_t data_len,
|
||||
+ u8 *cdata, u8 *mic);
|
||||
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
|
||||
+ u8 *cdata, size_t data_len,
|
||||
+ u8 *mic, u8 *data);
|
||||
+void ieee80211_aes_key_free(struct crypto_cipher *tfm);
|
||||
|
||||
#endif /* AES_CCM_H */
|
||||
--- a/net/mac80211/key.h
|
||||
+++ b/net/mac80211/key.h
|
||||
@@ -84,7 +84,7 @@ struct ieee80211_key {
|
||||
* Management frames.
|
||||
*/
|
||||
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
|
||||
- struct crypto_aead *tfm;
|
||||
+ struct crypto_cipher *tfm;
|
||||
u32 replays; /* dot11RSNAStatsCCMPReplays */
|
||||
} ccmp;
|
||||
struct {
|
||||
--- a/net/mac80211/wpa.c
|
||||
+++ b/net/mac80211/wpa.c
|
||||
@@ -302,15 +302,22 @@ ieee80211_crypto_tkip_decrypt(struct iee
|
||||
}
|
||||
|
||||
|
||||
-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
|
||||
+static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
|
||||
+ int encrypted)
|
||||
{
|
||||
__le16 mask_fc;
|
||||
int a4_included, mgmt;
|
||||
u8 qos_tid;
|
||||
- u16 len_a;
|
||||
+ u8 *b_0, *aad;
|
||||
+ u16 data_len, len_a;
|
||||
unsigned int hdrlen;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
+ memset(scratch, 0, 6 * AES_BLOCK_SIZE);
|
||||
+
|
||||
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
|
||||
+ aad = scratch + 4 * AES_BLOCK_SIZE;
|
||||
+
|
||||
/*
|
||||
* Mask FC: zero subtype b4 b5 b6 (if not mgmt)
|
||||
* Retry, PwrMgt, MoreData; set Protected
|
||||
@@ -332,21 +339,20 @@ static void ccmp_special_blocks(struct s
|
||||
else
|
||||
qos_tid = 0;
|
||||
|
||||
- /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
|
||||
- * mode authentication are not allowed to collide, yet both are derived
|
||||
- * from this vector b_0. We only set L := 1 here to indicate that the
|
||||
- * data size can be represented in (L+1) bytes. The CCM layer will take
|
||||
- * care of storing the data length in the top (L+1) bytes and setting
|
||||
- * and clearing the other bits as is required to derive the two IVs.
|
||||
- */
|
||||
- b_0[0] = 0x1;
|
||||
+ data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN;
|
||||
+ if (encrypted)
|
||||
+ data_len -= IEEE80211_CCMP_MIC_LEN;
|
||||
|
||||
+ /* First block, b_0 */
|
||||
+ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
|
||||
/* Nonce: Nonce Flags | A2 | PN
|
||||
* Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
|
||||
*/
|
||||
b_0[1] = qos_tid | (mgmt << 4);
|
||||
memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
|
||||
memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
|
||||
+ /* l(m) */
|
||||
+ put_unaligned_be16(data_len, &b_0[14]);
|
||||
|
||||
/* AAD (extra authenticate-only data) / masked 802.11 header
|
||||
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
|
||||
@@ -402,8 +408,7 @@ static int ccmp_encrypt_skb(struct ieee8
|
||||
u8 *pos;
|
||||
u8 pn[6];
|
||||
u64 pn64;
|
||||
- u8 aad[2 * AES_BLOCK_SIZE];
|
||||
- u8 b_0[AES_BLOCK_SIZE];
|
||||
+ u8 scratch[6 * AES_BLOCK_SIZE];
|
||||
|
||||
if (info->control.hw_key &&
|
||||
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
|
||||
@@ -457,9 +462,9 @@ static int ccmp_encrypt_skb(struct ieee8
|
||||
return 0;
|
||||
|
||||
pos += IEEE80211_CCMP_HDR_LEN;
|
||||
- ccmp_special_blocks(skb, pn, b_0, aad);
|
||||
- ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
|
||||
- skb_put(skb, IEEE80211_CCMP_MIC_LEN));
|
||||
+ ccmp_special_blocks(skb, pn, scratch, 0);
|
||||
+ ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len,
|
||||
+ pos, skb_put(skb, IEEE80211_CCMP_MIC_LEN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -522,16 +527,16 @@ ieee80211_crypto_ccmp_decrypt(struct iee
|
||||
}
|
||||
|
||||
if (!(status->flag & RX_FLAG_DECRYPTED)) {
|
||||
- u8 aad[2 * AES_BLOCK_SIZE];
|
||||
- u8 b_0[AES_BLOCK_SIZE];
|
||||
+ u8 scratch[6 * AES_BLOCK_SIZE];
|
||||
/* hardware didn't decrypt/verify MIC */
|
||||
- ccmp_special_blocks(skb, pn, b_0, aad);
|
||||
+ ccmp_special_blocks(skb, pn, scratch, 1);
|
||||
|
||||
if (ieee80211_aes_ccm_decrypt(
|
||||
- key->u.ccmp.tfm, b_0, aad,
|
||||
+ key->u.ccmp.tfm, scratch,
|
||||
skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
|
||||
data_len,
|
||||
- skb->data + skb->len - IEEE80211_CCMP_MIC_LEN))
|
||||
+ skb->data + skb->len - IEEE80211_CCMP_MIC_LEN,
|
||||
+ skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN))
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
@ -1,395 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 27 Sep 2014 15:57:09 +0200
|
||||
Subject: [PATCH] Revert "ath5k: Remove AHB bus support"
|
||||
|
||||
This reverts commit 093ec3c5337434f40d77c1af06c139da3e5ba6dc.
|
||||
---
|
||||
create mode 100644 drivers/net/wireless/ath/ath5k/ahb.c
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath5k/Kconfig
|
||||
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
|
||||
@@ -1,13 +1,14 @@
|
||||
config ATH5K
|
||||
tristate "Atheros 5xxx wireless cards support"
|
||||
depends on m
|
||||
- depends on PCI && MAC80211
|
||||
+ depends on (PCI || ATHEROS_AR231X) && MAC80211
|
||||
select ATH_COMMON
|
||||
select MAC80211_LEDS
|
||||
select BACKPORT_LEDS_CLASS
|
||||
select BACKPORT_NEW_LEDS
|
||||
select BACKPORT_AVERAGE
|
||||
- select ATH5K_PCI
|
||||
+ select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
|
||||
+ select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros 5xxx chipset.
|
||||
@@ -52,9 +53,16 @@ config ATH5K_TRACER
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
+config ATH5K_AHB
|
||||
+ bool "Atheros 5xxx AHB bus support"
|
||||
+ depends on (ATHEROS_AR231X && !PCI)
|
||||
+ ---help---
|
||||
+ This adds support for WiSoC type chipsets of the 5xxx Atheros
|
||||
+ family.
|
||||
+
|
||||
config ATH5K_PCI
|
||||
bool "Atheros 5xxx PCI bus support"
|
||||
- depends on PCI
|
||||
+ depends on (!ATHEROS_AR231X && PCI)
|
||||
---help---
|
||||
This adds support for PCI type chipsets of the 5xxx Atheros
|
||||
family.
|
||||
--- a/drivers/net/wireless/ath/ath5k/Makefile
|
||||
+++ b/drivers/net/wireless/ath/ath5k/Makefile
|
||||
@@ -17,5 +17,6 @@ ath5k-y += ani.o
|
||||
ath5k-y += sysfs.o
|
||||
ath5k-y += mac80211-ops.o
|
||||
ath5k-$(CPTCFG_ATH5K_DEBUG) += debug.o
|
||||
+ath5k-$(CPTCFG_ATH5K_AHB) += ahb.o
|
||||
ath5k-$(CPTCFG_ATH5K_PCI) += pci.o
|
||||
obj-$(CPTCFG_ATH5K) += ath5k.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
|
||||
@@ -0,0 +1,234 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
|
||||
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
|
||||
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
|
||||
+ *
|
||||
+ * Permission to use, copy, modify, and/or distribute this software for any
|
||||
+ * purpose with or without fee is hereby granted, provided that the above
|
||||
+ * copyright notice and this permission notice appear in all copies.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/nl80211.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/etherdevice.h>
|
||||
+#include <linux/export.h>
|
||||
+#include <ar231x_platform.h>
|
||||
+#include "ath5k.h"
|
||||
+#include "debug.h"
|
||||
+#include "base.h"
|
||||
+#include "reg.h"
|
||||
+
|
||||
+/* return bus cachesize in 4B word units */
|
||||
+static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
|
||||
+{
|
||||
+ *csz = L1_CACHE_BYTES >> 2;
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
|
||||
+{
|
||||
+ struct ath5k_hw *ah = common->priv;
|
||||
+ struct platform_device *pdev = to_platform_device(ah->dev);
|
||||
+ struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
|
||||
+ u16 *eeprom, *eeprom_end;
|
||||
+
|
||||
+ eeprom = (u16 *) bcfg->radio;
|
||||
+ eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
|
||||
+
|
||||
+ eeprom += off;
|
||||
+ if (eeprom > eeprom_end)
|
||||
+ return false;
|
||||
+
|
||||
+ *data = *eeprom;
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+int ath5k_hw_read_srev(struct ath5k_hw *ah)
|
||||
+{
|
||||
+ struct platform_device *pdev = to_platform_device(ah->dev);
|
||||
+ struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
|
||||
+ ah->ah_mac_srev = bcfg->devid;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
|
||||
+{
|
||||
+ struct platform_device *pdev = to_platform_device(ah->dev);
|
||||
+ struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
|
||||
+ u8 *cfg_mac;
|
||||
+
|
||||
+ if (to_platform_device(ah->dev)->id == 0)
|
||||
+ cfg_mac = bcfg->config->wlan0_mac;
|
||||
+ else
|
||||
+ cfg_mac = bcfg->config->wlan1_mac;
|
||||
+
|
||||
+ memcpy(mac, cfg_mac, ETH_ALEN);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct ath_bus_ops ath_ahb_bus_ops = {
|
||||
+ .ath_bus_type = ATH_AHB,
|
||||
+ .read_cachesize = ath5k_ahb_read_cachesize,
|
||||
+ .eeprom_read = ath5k_ahb_eeprom_read,
|
||||
+ .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
|
||||
+};
|
||||
+
|
||||
+/*Initialization*/
|
||||
+static int ath_ahb_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
|
||||
+ struct ath5k_hw *ah;
|
||||
+ struct ieee80211_hw *hw;
|
||||
+ struct resource *res;
|
||||
+ void __iomem *mem;
|
||||
+ int irq;
|
||||
+ int ret = 0;
|
||||
+ u32 reg;
|
||||
+
|
||||
+ if (!dev_get_platdata(&pdev->dev)) {
|
||||
+ dev_err(&pdev->dev, "no platform data specified\n");
|
||||
+ ret = -EINVAL;
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (res == NULL) {
|
||||
+ dev_err(&pdev->dev, "no memory resource found\n");
|
||||
+ ret = -ENXIO;
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+
|
||||
+ mem = ioremap_nocache(res->start, resource_size(res));
|
||||
+ if (mem == NULL) {
|
||||
+ dev_err(&pdev->dev, "ioremap failed\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
+ if (res == NULL) {
|
||||
+ dev_err(&pdev->dev, "no IRQ resource found\n");
|
||||
+ ret = -ENXIO;
|
||||
+ goto err_iounmap;
|
||||
+ }
|
||||
+
|
||||
+ irq = res->start;
|
||||
+
|
||||
+ hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops);
|
||||
+ if (hw == NULL) {
|
||||
+ dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_iounmap;
|
||||
+ }
|
||||
+
|
||||
+ ah = hw->priv;
|
||||
+ ah->hw = hw;
|
||||
+ ah->dev = &pdev->dev;
|
||||
+ ah->iobase = mem;
|
||||
+ ah->irq = irq;
|
||||
+ ah->devid = bcfg->devid;
|
||||
+
|
||||
+ if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
|
||||
+ /* Enable WMAC AHB arbitration */
|
||||
+ reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
|
||||
+ reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
|
||||
+ iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
|
||||
+
|
||||
+ /* Enable global WMAC swapping */
|
||||
+ reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
|
||||
+ reg |= AR5K_AR2315_BYTESWAP_WMAC;
|
||||
+ iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
|
||||
+ } else {
|
||||
+ /* Enable WMAC DMA access (assuming 5312 or 231x*/
|
||||
+ /* TODO: check other platforms */
|
||||
+ reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
|
||||
+ if (to_platform_device(ah->dev)->id == 0)
|
||||
+ reg |= AR5K_AR5312_ENABLE_WLAN0;
|
||||
+ else
|
||||
+ reg |= AR5K_AR5312_ENABLE_WLAN1;
|
||||
+ iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
|
||||
+
|
||||
+ /*
|
||||
+ * On a dual-band AR5312, the multiband radio is only
|
||||
+ * used as pass-through. Disable 2 GHz support in the
|
||||
+ * driver for it
|
||||
+ */
|
||||
+ if (to_platform_device(ah->dev)->id == 0 &&
|
||||
+ (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
|
||||
+ (BD_WLAN1 | BD_WLAN0))
|
||||
+ ah->ah_capabilities.cap_needs_2GHz_ovr = true;
|
||||
+ else
|
||||
+ ah->ah_capabilities.cap_needs_2GHz_ovr = false;
|
||||
+ }
|
||||
+
|
||||
+ ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
|
||||
+ if (ret != 0) {
|
||||
+ dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_free_hw;
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, hw);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+ err_free_hw:
|
||||
+ ieee80211_free_hw(hw);
|
||||
+ err_iounmap:
|
||||
+ iounmap(mem);
|
||||
+ err_out:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int ath_ahb_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
|
||||
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
|
||||
+ struct ath5k_hw *ah;
|
||||
+ u32 reg;
|
||||
+
|
||||
+ if (!hw)
|
||||
+ return 0;
|
||||
+
|
||||
+ ah = hw->priv;
|
||||
+
|
||||
+ if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
|
||||
+ /* Disable WMAC AHB arbitration */
|
||||
+ reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
|
||||
+ reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
|
||||
+ iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
|
||||
+ } else {
|
||||
+ /*Stop DMA access */
|
||||
+ reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
|
||||
+ if (to_platform_device(ah->dev)->id == 0)
|
||||
+ reg &= ~AR5K_AR5312_ENABLE_WLAN0;
|
||||
+ else
|
||||
+ reg &= ~AR5K_AR5312_ENABLE_WLAN1;
|
||||
+ iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
|
||||
+ }
|
||||
+
|
||||
+ ath5k_deinit_ah(ah);
|
||||
+ iounmap(ah->iobase);
|
||||
+ ieee80211_free_hw(hw);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver ath_ahb_driver = {
|
||||
+ .probe = ath_ahb_probe,
|
||||
+ .remove = ath_ahb_remove,
|
||||
+ .driver = {
|
||||
+ .name = "ar231x-wmac",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(ath_ahb_driver);
|
||||
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
|
||||
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
|
||||
@@ -1647,6 +1647,32 @@ static inline struct ath_regulatory *ath
|
||||
return &(ath5k_hw_common(ah)->regulatory);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_ATHEROS_AR231X
|
||||
+#define AR5K_AR2315_PCI_BASE ((void __iomem *)0xb0100000)
|
||||
+
|
||||
+static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
|
||||
+{
|
||||
+ /* On AR2315 and AR2317 the PCI clock domain registers
|
||||
+ * are outside of the WMAC register space */
|
||||
+ if (unlikely((reg >= 0x4000) && (reg < 0x5000) &&
|
||||
+ (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
|
||||
+ return AR5K_AR2315_PCI_BASE + reg;
|
||||
+
|
||||
+ return ah->iobase + reg;
|
||||
+}
|
||||
+
|
||||
+static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
|
||||
+{
|
||||
+ return ioread32(ath5k_ahb_reg(ah, reg));
|
||||
+}
|
||||
+
|
||||
+static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
|
||||
+{
|
||||
+ iowrite32(val, ath5k_ahb_reg(ah, reg));
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+
|
||||
static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
|
||||
{
|
||||
return ioread32(ah->iobase + reg);
|
||||
@@ -1657,6 +1683,8 @@ static inline void ath5k_hw_reg_write(st
|
||||
iowrite32(val, ah->iobase + reg);
|
||||
}
|
||||
|
||||
+#endif
|
||||
+
|
||||
static inline enum ath_bus_type ath5k_get_bus_type(struct ath5k_hw *ah)
|
||||
{
|
||||
return ath5k_hw_common(ah)->bus_ops->ath_bus_type;
|
||||
--- a/drivers/net/wireless/ath/ath5k/base.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/base.c
|
||||
@@ -99,6 +99,15 @@ static int ath5k_reset(struct ath5k_hw *
|
||||
|
||||
/* Known SREVs */
|
||||
static const struct ath5k_srev_name srev_names[] = {
|
||||
+#ifdef CONFIG_ATHEROS_AR231X
|
||||
+ { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R2 },
|
||||
+ { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R7 },
|
||||
+ { "2313", AR5K_VERSION_MAC, AR5K_SREV_AR2313_R8 },
|
||||
+ { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R6 },
|
||||
+ { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R7 },
|
||||
+ { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R1 },
|
||||
+ { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R2 },
|
||||
+#else
|
||||
{ "5210", AR5K_VERSION_MAC, AR5K_SREV_AR5210 },
|
||||
{ "5311", AR5K_VERSION_MAC, AR5K_SREV_AR5311 },
|
||||
{ "5311A", AR5K_VERSION_MAC, AR5K_SREV_AR5311A },
|
||||
@@ -117,6 +126,7 @@ static const struct ath5k_srev_name srev
|
||||
{ "5418", AR5K_VERSION_MAC, AR5K_SREV_AR5418 },
|
||||
{ "2425", AR5K_VERSION_MAC, AR5K_SREV_AR2425 },
|
||||
{ "2417", AR5K_VERSION_MAC, AR5K_SREV_AR2417 },
|
||||
+#endif
|
||||
{ "xxxxx", AR5K_VERSION_MAC, AR5K_SREV_UNKNOWN },
|
||||
{ "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 },
|
||||
{ "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 },
|
||||
@@ -132,6 +142,10 @@ static const struct ath5k_srev_name srev
|
||||
{ "5413", AR5K_VERSION_RAD, AR5K_SREV_RAD_5413 },
|
||||
{ "5424", AR5K_VERSION_RAD, AR5K_SREV_RAD_5424 },
|
||||
{ "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 },
|
||||
+#ifdef CONFIG_ATHEROS_AR231X
|
||||
+ { "2316", AR5K_VERSION_RAD, AR5K_SREV_RAD_2316 },
|
||||
+ { "2317", AR5K_VERSION_RAD, AR5K_SREV_RAD_2317 },
|
||||
+#endif
|
||||
{ "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN },
|
||||
};
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath5k/led.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/led.c
|
||||
@@ -163,14 +163,20 @@ int ath5k_init_leds(struct ath5k_hw *ah)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ieee80211_hw *hw = ah->hw;
|
||||
+#ifndef CONFIG_ATHEROS_AR231X
|
||||
struct pci_dev *pdev = ah->pdev;
|
||||
+#endif
|
||||
char name[ATH5K_LED_MAX_NAME_LEN + 1];
|
||||
const struct pci_device_id *match;
|
||||
|
||||
if (!ah->pdev)
|
||||
return 0;
|
||||
|
||||
+#ifdef CONFIG_ATHEROS_AR231X
|
||||
+ match = NULL;
|
||||
+#else
|
||||
match = pci_match_id(&ath5k_led_devices[0], pdev);
|
||||
+#endif
|
||||
if (match) {
|
||||
__set_bit(ATH_STAT_LEDSOFT, ah->status);
|
||||
ah->led_pin = ATH_PIN(match->driver_data);
|
@ -1,37 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 27 Sep 2014 15:58:51 +0200
|
||||
Subject: [PATCH] ath5k: fix AHB kconfig dependency
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath5k/Kconfig
|
||||
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
|
||||
@@ -7,8 +7,8 @@ config ATH5K
|
||||
select BACKPORT_LEDS_CLASS
|
||||
select BACKPORT_NEW_LEDS
|
||||
select BACKPORT_AVERAGE
|
||||
- select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
|
||||
- select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
|
||||
+ select ATH5K_AHB if ATHEROS_AR231X
|
||||
+ select ATH5K_PCI if !ATHEROS_AR231X
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros 5xxx chipset.
|
||||
@@ -55,14 +55,14 @@ config ATH5K_TRACER
|
||||
|
||||
config ATH5K_AHB
|
||||
bool "Atheros 5xxx AHB bus support"
|
||||
- depends on (ATHEROS_AR231X && !PCI)
|
||||
+ depends on ATHEROS_AR231X
|
||||
---help---
|
||||
This adds support for WiSoC type chipsets of the 5xxx Atheros
|
||||
family.
|
||||
|
||||
config ATH5K_PCI
|
||||
bool "Atheros 5xxx PCI bus support"
|
||||
- depends on (!ATHEROS_AR231X && PCI)
|
||||
+ depends on !ATHEROS_AR231X
|
||||
---help---
|
||||
This adds support for PCI type chipsets of the 5xxx Atheros
|
||||
family.
|
@ -0,0 +1,125 @@ |
||||
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
|
||||
@@ -280,7 +280,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
|
||||
@@ -348,6 +348,7 @@ struct sta_info {
|
||||
u8 ptk_idx;
|
||||
struct rate_control_ref *rate_ctrl;
|
||||
void *rate_ctrl_priv;
|
||||
+ spinlock_t rate_ctrl_lock;
|
||||
spinlock_t lock;
|
||||
|
||||
struct work_struct drv_deliver_wk;
|
@ -1,118 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Wed, 22 Oct 2014 18:18:04 +0200
|
||||
Subject: [PATCH] ath9k: add support for reporting tx power to mac80211
|
||||
|
||||
Track it per channel context instead of in the softc
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
@@ -347,6 +347,7 @@ struct ath_chanctx {
|
||||
|
||||
int flush_timeout;
|
||||
u16 txpower;
|
||||
+ u16 cur_txpower;
|
||||
bool offchannel;
|
||||
bool stopped;
|
||||
bool active;
|
||||
@@ -987,7 +988,6 @@ struct ath_softc {
|
||||
u8 gtt_cnt;
|
||||
u32 intrstatus;
|
||||
u16 ps_flags; /* PS_* */
|
||||
- u16 curtxpow;
|
||||
bool ps_enabled;
|
||||
bool ps_idle;
|
||||
short nbcnvifs;
|
||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||
@@ -172,17 +172,20 @@ static void ath9k_reg_notifier(struct wi
|
||||
ath_reg_notifier_apply(wiphy, request, reg);
|
||||
|
||||
/* Set tx power */
|
||||
- if (ah->curchan) {
|
||||
- sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power;
|
||||
- ath9k_ps_wakeup(sc);
|
||||
- ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
|
||||
- sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
|
||||
- /* synchronize DFS detector if regulatory domain changed */
|
||||
- if (sc->dfs_detector != NULL)
|
||||
- sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
|
||||
- request->dfs_region);
|
||||
- ath9k_ps_restore(sc);
|
||||
- }
|
||||
+ if (!ah->curchan)
|
||||
+ return;
|
||||
+
|
||||
+ sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power;
|
||||
+ ath9k_ps_wakeup(sc);
|
||||
+ ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
|
||||
+ ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
|
||||
+ sc->cur_chan->txpower,
|
||||
+ &sc->cur_chan->cur_txpower);
|
||||
+ /* synchronize DFS detector if regulatory domain changed */
|
||||
+ if (sc->dfs_detector != NULL)
|
||||
+ sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
|
||||
+ request->dfs_region);
|
||||
+ ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -233,8 +233,9 @@ static bool ath_complete_reset(struct at
|
||||
|
||||
ath9k_calculate_summary_state(sc, sc->cur_chan);
|
||||
ath_startrecv(sc);
|
||||
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||
- sc->cur_chan->txpower, &sc->curtxpow);
|
||||
+ ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
|
||||
+ sc->cur_chan->txpower,
|
||||
+ &sc->cur_chan->cur_txpower);
|
||||
clear_bit(ATH_OP_HW_RESET, &common->op_flags);
|
||||
|
||||
if (!sc->cur_chan->offchannel && start) {
|
||||
@@ -1471,8 +1472,9 @@ static int ath9k_config(struct ieee80211
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
||||
ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
|
||||
sc->cur_chan->txpower = 2 * conf->power_level;
|
||||
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||
- sc->cur_chan->txpower, &sc->curtxpow);
|
||||
+ ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
|
||||
+ sc->cur_chan->txpower,
|
||||
+ &sc->cur_chan->cur_txpower);
|
||||
}
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
@@ -2594,6 +2596,24 @@ void ath9k_fill_chanctx_ops(void)
|
||||
|
||||
#endif
|
||||
|
||||
+static int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
+ int *dbm)
|
||||
+{
|
||||
+ struct ath_softc *sc = hw->priv;
|
||||
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
+
|
||||
+ mutex_lock(&sc->mutex);
|
||||
+ if (avp->chanctx)
|
||||
+ *dbm = avp->chanctx->cur_txpower;
|
||||
+ else
|
||||
+ *dbm = sc->cur_chan->cur_txpower;
|
||||
+ mutex_unlock(&sc->mutex);
|
||||
+
|
||||
+ *dbm /= 2;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
struct ieee80211_ops ath9k_ops = {
|
||||
.tx = ath9k_tx,
|
||||
.start = ath9k_start,
|
||||
@@ -2640,4 +2660,5 @@ struct ieee80211_ops ath9k_ops = {
|
||||
#endif
|
||||
.sw_scan_start = ath9k_sw_scan_start,
|
||||
.sw_scan_complete = ath9k_sw_scan_complete,
|
||||
+ .get_txpower = ath9k_get_txpower,
|
||||
};
|
@ -0,0 +1,21 @@ |
||||
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;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Wed, 22 Oct 2014 18:44:03 +0200
|
||||
Subject: [PATCH] ath10k: add SURVEY_INFO_IN_USE for current channel on
|
||||
survey
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
@@ -4044,6 +4044,9 @@ static int ath10k_get_survey(struct ieee
|
||||
|
||||
survey->channel = &sband->channels[idx];
|
||||
|
||||
+ if (ar->rx_channel == survey->channel)
|
||||
+ survey->filled |= SURVEY_INFO_IN_USE;
|
||||
+
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
@ -0,0 +1,76 @@ |
||||
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
|
@ -1,61 +0,0 @@ |
||||
From: Miaoqing Pan <miaoqing@qca.qualcomm.com>
|
||||
Date: Thu, 6 Nov 2014 10:52:23 +0530
|
||||
Subject: [PATCH] ath9k: Fix RTC_DERIVED_CLK usage
|
||||
|
||||
Based on the reference clock, which could be 25MHz or 40MHz,
|
||||
AR_RTC_DERIVED_CLK is programmed differently for AR9340 and AR9550.
|
||||
But, when a chip reset is done, processing the initvals
|
||||
sets the register back to the default value.
|
||||
|
||||
Fix this by moving the code in ath9k_hw_init_pll() to
|
||||
ar9003_hw_override_ini(). Also, do this override for AR9531.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Miaoqing Pan <miaoqing@qca.qualcomm.com>
|
||||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||
@@ -664,6 +664,19 @@ static void ar9003_hw_override_ini(struc
|
||||
ah->enabled_cals |= TX_CL_CAL;
|
||||
else
|
||||
ah->enabled_cals &= ~TX_CL_CAL;
|
||||
+
|
||||
+ if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
|
||||
+ if (ah->is_clk_25mhz) {
|
||||
+ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
|
||||
+ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
|
||||
+ REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
|
||||
+ } else {
|
||||
+ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
|
||||
+ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
|
||||
+ REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
|
||||
+ }
|
||||
+ udelay(100);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void ar9003_hw_prog_ini(struct ath_hw *ah,
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -870,19 +870,6 @@ static void ath9k_hw_init_pll(struct ath
|
||||
udelay(RTC_PLL_SETTLE_DELAY);
|
||||
|
||||
REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
|
||||
-
|
||||
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
|
||||
- if (ah->is_clk_25mhz) {
|
||||
- REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
|
||||
- REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
|
||||
- REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
|
||||
- } else {
|
||||
- REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
|
||||
- REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
|
||||
- REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
|
||||
- }
|
||||
- udelay(100);
|
||||
- }
|
||||
}
|
||||
|
||||
static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
|
@ -0,0 +1,19 @@ |
||||
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,38 +0,0 @@ |
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Wed, 5 Nov 2014 23:31:07 +0100
|
||||
Subject: [PATCH] b43: fix NULL pointer dereference in b43_phy_copy()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
phy_read and phy_write are not set for every phy any more sine this:
|
||||
commit d342b95dd735014a590f9051b1ba227eb54ca8f6
|
||||
Author: Rafał Miłecki <zajec5@gmail.com>
|
||||
Date: Thu Jul 31 21:59:43 2014 +0200
|
||||
|
||||
b43: don't duplicate common PHY read/write ops
|
||||
|
||||
b43_phy_copy() accesses phy_read and phy_write directly and will fail
|
||||
with some phys. This patch fixes the regression by using the
|
||||
b43_phy_read() and b43_phy_write() functions which should be used for
|
||||
read and write access.
|
||||
|
||||
This should fix this bug report:
|
||||
https://bugzilla.kernel.org/show_bug.cgi?id=87731
|
||||
|
||||
Reported-by: Volker Kempter <v.kempter@pe.tu-clausthal.de>
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/b43/phy_common.c
|
||||
+++ b/drivers/net/wireless/b43/phy_common.c
|
||||
@@ -301,8 +301,7 @@ void b43_phy_write(struct b43_wldev *dev
|
||||
void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
|
||||
{
|
||||
assert_mac_suspended(dev);
|
||||
- dev->phy.ops->phy_write(dev, destreg,
|
||||
- dev->phy.ops->phy_read(dev, srcreg));
|
||||
+ b43_phy_write(dev, destreg, b43_phy_read(dev, srcreg));
|
||||
}
|
||||
|
||||
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
|
@ -1,33 +0,0 @@ |
||||
From: Ben Greear <greearb@candelatech.com>
|
||||
Date: Tue, 4 Nov 2014 15:22:49 -0800
|
||||
Subject: [PATCH] ath9k: fix misc debugfs when not using chan context
|
||||
|
||||
When channel-context is not enabled, all vifs belong to
|
||||
the first context, but it is not configured as 'assigned'.
|
||||
|
||||
Fix misc debugfs file to print out info for non-assigned
|
||||
contexts, and also print whether ctx is assigned or not.
|
||||
|
||||
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||||
@@ -828,13 +828,14 @@ static ssize_t read_file_misc(struct fil
|
||||
|
||||
i = 0;
|
||||
ath_for_each_chanctx(sc, ctx) {
|
||||
- if (!ctx->assigned || list_empty(&ctx->vifs))
|
||||
+ if (list_empty(&ctx->vifs))
|
||||
continue;
|
||||
ath9k_calculate_iter_data(sc, ctx, &iter_data);
|
||||
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
- "VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i",
|
||||
- i++, iter_data.naps, iter_data.nstations,
|
||||
+ "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i WDS: %i",
|
||||
+ i++, (int)(ctx->assigned), iter_data.naps,
|
||||
+ iter_data.nstations,
|
||||
iter_data.nmeshes, iter_data.nwds);
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
|
@ -1,70 +0,0 @@ |
||||
From: Ben Greear <greearb@candelatech.com>
|
||||
Date: Tue, 4 Nov 2014 15:22:50 -0800
|
||||
Subject: [PATCH] ath9k: fix regression in bssidmask calculation
|
||||
|
||||
The commit that went into 3.17:
|
||||
|
||||
ath9k: Summarize hw state per channel context
|
||||
|
||||
Group and set hw state (opmode, primary_sta, beacon conf) per
|
||||
channel context instead of whole list of vifs. This would allow
|
||||
each channel context to run in different mode (STA/AP).
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
|
||||
Signed-off-by: John W. Linville <linville@tuxdriver.com>
|
||||
|
||||
broke multi-vif configuration due to not properly calculating
|
||||
the bssid mask.
|
||||
|
||||
The test case that caught this was:
|
||||
|
||||
create wlan0 and sta0-4 (6 total), not sure how much that matters.
|
||||
associate all 6 (works fine)
|
||||
disconnect 5 of them, leaving sta0 up
|
||||
Start trying to bring up the other 5 one at a time. It will
|
||||
fail, with iw events looking like this (in these logs, several
|
||||
sta are trying to come up, but symptom is the same with just one)
|
||||
|
||||
The patch causing the regression made quite a few changes, but
|
||||
the part I think caused this particular problem was not
|
||||
recalculating the bssid mask when adding and removing interfaces.
|
||||
|
||||
Re-adding those calls fixes my test case. Fix bad comment
|
||||
as well.
|
||||
|
||||
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -994,9 +994,8 @@ void ath9k_calculate_iter_data(struct at
|
||||
struct ath_vif *avp;
|
||||
|
||||
/*
|
||||
- * Pick the MAC address of the first interface as the new hardware
|
||||
- * MAC address. The hardware will use it together with the BSSID mask
|
||||
- * when matching addresses.
|
||||
+ * The hardware will use primary station addr together with the
|
||||
+ * BSSID mask when matching addresses.
|
||||
*/
|
||||
memset(iter_data, 0, sizeof(*iter_data));
|
||||
memset(&iter_data->mask, 0xff, ETH_ALEN);
|
||||
@@ -1225,6 +1224,8 @@ static int ath9k_add_interface(struct ie
|
||||
list_add_tail(&avp->list, &avp->chanctx->vifs);
|
||||
}
|
||||
|
||||
+ ath9k_calculate_summary_state(sc, avp->chanctx);
|
||||
+
|
||||
ath9k_assign_hw_queues(hw, vif);
|
||||
|
||||
an->sc = sc;
|
||||
@@ -1294,6 +1295,8 @@ static void ath9k_remove_interface(struc
|
||||
|
||||
ath_tx_node_cleanup(sc, &avp->mcast_node);
|
||||
|
||||
+ ath9k_calculate_summary_state(sc, avp->chanctx);
|
||||
+
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
@ -1,95 +0,0 @@ |
||||
From: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
Date: Sun, 2 Nov 2014 13:38:47 +0100
|
||||
Subject: [PATCH] rt2x00: do not align payload on modern H/W
|
||||
|
||||
RT2800 and newer hardware require padding between header and payload if
|
||||
header length is not multiple of 4.
|
||||
|
||||
For historical reasons we also align payload to to 4 bytes boundary, but
|
||||
such alignment is not needed on modern H/W.
|
||||
|
||||
Patch improve performance on embedded CPUs and _possibly_ fixes
|
||||
skb_under_panic problems reported from time to time:
|
||||
|
||||
https://bugzilla.kernel.org/show_bug.cgi?id=84911
|
||||
https://bugzilla.kernel.org/show_bug.cgi?id=72471
|
||||
http://marc.info/?l=linux-wireless&m=139108549530402&w=2
|
||||
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1087591
|
||||
|
||||
But we can not explain or otherwise confirm the patch fixes this panic
|
||||
issue for sure.
|
||||
|
||||
Originally-From: Helmut Schaa <helmut.schaa@googlemail.com>
|
||||
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
|
||||
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
|
||||
@@ -158,55 +158,29 @@ void rt2x00queue_align_frame(struct sk_b
|
||||
skb_trim(skb, frame_length);
|
||||
}
|
||||
|
||||
-void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
|
||||
+/*
|
||||
+ * H/W needs L2 padding between the header and the paylod if header size
|
||||
+ * is not 4 bytes aligned.
|
||||
+ */
|
||||
+void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int hdr_len)
|
||||
{
|
||||
- unsigned int payload_length = skb->len - header_length;
|
||||
- unsigned int header_align = ALIGN_SIZE(skb, 0);
|
||||
- unsigned int payload_align = ALIGN_SIZE(skb, header_length);
|
||||
- unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
|
||||
+ unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
|
||||
|
||||
- /*
|
||||
- * Adjust the header alignment if the payload needs to be moved more
|
||||
- * than the header.
|
||||
- */
|
||||
- if (payload_align > header_align)
|
||||
- header_align += 4;
|
||||
-
|
||||
- /* There is nothing to do if no alignment is needed */
|
||||
- if (!header_align)
|
||||
+ if (!l2pad)
|
||||
return;
|
||||
|
||||
- /* Reserve the amount of space needed in front of the frame */
|
||||
- skb_push(skb, header_align);
|
||||
-
|
||||
- /*
|
||||
- * Move the header.
|
||||
- */
|
||||
- memmove(skb->data, skb->data + header_align, header_length);
|
||||
-
|
||||
- /* Move the payload, if present and if required */
|
||||
- if (payload_length && payload_align)
|
||||
- memmove(skb->data + header_length + l2pad,
|
||||
- skb->data + header_length + l2pad + payload_align,
|
||||
- payload_length);
|
||||
-
|
||||
- /* Trim the skb to the correct size */
|
||||
- skb_trim(skb, header_length + l2pad + payload_length);
|
||||
+ skb_push(skb, l2pad);
|
||||
+ memmove(skb->data, skb->data + l2pad, hdr_len);
|
||||
}
|
||||
|
||||
-void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
|
||||
+void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int hdr_len)
|
||||
{
|
||||
- /*
|
||||
- * L2 padding is only present if the skb contains more than just the
|
||||
- * IEEE 802.11 header.
|
||||
- */
|
||||
- unsigned int l2pad = (skb->len > header_length) ?
|
||||
- L2PAD_SIZE(header_length) : 0;
|
||||
+ unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
|
||||
|
||||
if (!l2pad)
|
||||
return;
|
||||
|
||||
- memmove(skb->data + l2pad, skb->data, header_length);
|
||||
+ memmove(skb->data + l2pad, skb->data, hdr_len);
|
||||
skb_pull(skb, l2pad);
|
||||
}
|
||||
|
@ -1,38 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 13 Nov 2014 18:27:47 +0100
|
||||
Subject: [PATCH] ath9k: prevent early IRQs from accessing hardware
|
||||
|
||||
IRQs are suppressed if ah == NULL and ATH_OP_INVALID being set in
|
||||
common->op_flags. Close a short time window between those two.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||
@@ -513,10 +513,14 @@ static int ath9k_init_softc(u16 devid, s
|
||||
ah->reg_ops.read = ath9k_ioread32;
|
||||
ah->reg_ops.write = ath9k_iowrite32;
|
||||
ah->reg_ops.rmw = ath9k_reg_rmw;
|
||||
- sc->sc_ah = ah;
|
||||
pCap = &ah->caps;
|
||||
|
||||
common = ath9k_hw_common(ah);
|
||||
+
|
||||
+ /* Will be cleared in ath9k_start() */
|
||||
+ set_bit(ATH_OP_INVALID, &common->op_flags);
|
||||
+
|
||||
+ sc->sc_ah = ah;
|
||||
sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
|
||||
sc->tx99_power = MAX_RATE_POWER + 1;
|
||||
init_waitqueue_head(&sc->tx_wait);
|
||||
@@ -876,9 +880,6 @@ int ath9k_init_device(u16 devid, struct
|
||||
common = ath9k_hw_common(ah);
|
||||
ath9k_set_hw_capab(sc, hw);
|
||||
|
||||
- /* Will be cleared in ath9k_start() */
|
||||
- set_bit(ATH_OP_INVALID, &common->op_flags);
|
||||
-
|
||||
/* Initialize regulatory */
|
||||
error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
|
||||
ath9k_reg_notifier);
|
@ -1,29 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 13 Nov 2014 18:29:00 +0100
|
||||
Subject: [PATCH] ath9k: set ATH_OP_INVALID before disabling hardware
|
||||
|
||||
Closes another small IRQ handler race
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -885,6 +885,9 @@ static void ath9k_stop(struct ieee80211_
|
||||
&sc->cur_chan->chandef);
|
||||
|
||||
ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
|
||||
+
|
||||
+ set_bit(ATH_OP_INVALID, &common->op_flags);
|
||||
+
|
||||
ath9k_hw_phy_disable(ah);
|
||||
|
||||
ath9k_hw_configpcipowersave(ah, true);
|
||||
@@ -893,7 +896,6 @@ static void ath9k_stop(struct ieee80211_
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
- set_bit(ATH_OP_INVALID, &common->op_flags);
|
||||
sc->ps_idle = prev_idle;
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
@ -1,61 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 13 Nov 2014 18:29:26 +0100
|
||||
Subject: [PATCH] ath9k: do not access hardware on IRQs during reset
|
||||
|
||||
Instead of killing interrupts during reset when the first one happens,
|
||||
kill them before issuing the reset.
|
||||
This fixes an easy to reproduce crash with multiple cards sharing the
|
||||
same IRQ.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -512,16 +512,13 @@ irqreturn_t ath_isr(int irq, void *dev)
|
||||
if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
|
||||
return IRQ_NONE;
|
||||
|
||||
- /* shared irq, not for us */
|
||||
+ if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
|
||||
+ return IRQ_NONE;
|
||||
|
||||
+ /* shared irq, not for us */
|
||||
if (!ath9k_hw_intrpend(ah))
|
||||
return IRQ_NONE;
|
||||
|
||||
- if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
|
||||
- ath9k_hw_kill_interrupts(ah);
|
||||
- return IRQ_HANDLED;
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* Figure out the reason(s) for the interrupt. Note
|
||||
* that the hal returns a pseudo-ISR that may include
|
||||
@@ -532,6 +529,9 @@ irqreturn_t ath_isr(int irq, void *dev)
|
||||
ath9k_debug_sync_cause(sc, sync_cause);
|
||||
status &= ah->imask; /* discard unasked-for bits */
|
||||
|
||||
+ if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
|
||||
+ return IRQ_HANDLED;
|
||||
+
|
||||
/*
|
||||
* If there are no status bits set, then this interrupt was not
|
||||
* for me (should have been caught above).
|
||||
@@ -613,6 +613,7 @@ int ath_reset(struct ath_softc *sc, stru
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int r;
|
||||
|
||||
+ ath9k_hw_kill_interrupts(sc->sc_ah);
|
||||
set_bit(ATH_OP_HW_RESET, &common->op_flags);
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
@@ -633,6 +634,7 @@ void ath9k_queue_reset(struct ath_softc
|
||||
#ifdef CPTCFG_ATH9K_DEBUGFS
|
||||
RESET_STAT_INC(sc, type);
|
||||
#endif
|
||||
+ ath9k_hw_kill_interrupts(sc->sc_ah);
|
||||
set_bit(ATH_OP_HW_RESET, &common->op_flags);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
}
|
@ -1,22 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 15 Nov 2014 03:45:56 +0100
|
||||
Subject: [PATCH] mac80211: skip legacy rate mask handling for VHT rates
|
||||
|
||||
The rate mask code currently assumes that a rate is legacy if
|
||||
IEEE80211_TX_RC_MCS is not set. This might be the cause of bogus VHT
|
||||
rates being reported with minstrel_ht.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rate.c
|
||||
+++ b/net/mac80211/rate.c
|
||||
@@ -385,7 +385,7 @@ static void rate_idx_match_mask(struct i
|
||||
*rate = alt_rate;
|
||||
return;
|
||||
}
|
||||
- } else {
|
||||
+ } else if (!(rate->flags & IEEE80211_TX_RC_VHT_MCS)) {
|
||||
/* handle legacy rates */
|
||||
if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask))
|
||||
return;
|
@ -1,33 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 15 Nov 2014 22:13:38 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: add a small optimization to
|
||||
minstrel_aggr_check
|
||||
|
||||
Check the queue mapping earlier, skb->queue_mapping is more likely than
|
||||
skb->data to still be in d-cache.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -690,6 +690,9 @@ minstrel_aggr_check(struct ieee80211_sta
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
u16 tid;
|
||||
|
||||
+ if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
|
||||
+ return;
|
||||
+
|
||||
if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
|
||||
return;
|
||||
|
||||
@@ -700,9 +703,6 @@ minstrel_aggr_check(struct ieee80211_sta
|
||||
if (likely(sta->ampdu_mlme.tid_tx[tid]))
|
||||
return;
|
||||
|
||||
- if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
|
||||
- return;
|
||||
-
|
||||
ieee80211_start_tx_ba_session(pubsta, tid, 5000);
|
||||
}
|
||||
|
@ -1,33 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 15 Nov 2014 22:16:36 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: move aggregation check to
|
||||
.get_rate()
|
||||
|
||||
Preparation for adding a no-skb tx status path
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -782,9 +782,6 @@ minstrel_ht_tx_status(void *priv, struct
|
||||
if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
|
||||
update = true;
|
||||
minstrel_ht_update_stats(mp, mi);
|
||||
- if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
- mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
|
||||
- minstrel_aggr_check(sta, skb);
|
||||
}
|
||||
|
||||
if (update)
|
||||
@@ -1026,6 +1023,10 @@ minstrel_ht_get_rate(void *priv, struct
|
||||
if (!msp->is_ht)
|
||||
return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
|
||||
|
||||
+ if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
+ mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
|
||||
+ minstrel_aggr_check(sta, txrc->skb);
|
||||
+
|
||||
info->flags |= mi->tx_flags;
|
||||
minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
|
||||
|
@ -1,43 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 15 Nov 2014 22:23:44 +0100
|
||||
Subject: [PATCH] mac80211: add tx_status_noskb to rate_control_ops
|
||||
|
||||
This op works like .tx_status, except it does not need access to the
|
||||
skb. This will be used by drivers that cannot match tx status
|
||||
information to specific packets.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -4727,6 +4727,10 @@ struct rate_control_ops {
|
||||
void (*free_sta)(void *priv, struct ieee80211_sta *sta,
|
||||
void *priv_sta);
|
||||
|
||||
+ void (*tx_status_noskb)(void *priv,
|
||||
+ struct ieee80211_supported_band *sband,
|
||||
+ struct ieee80211_sta *sta, void *priv_sta,
|
||||
+ struct ieee80211_tx_info *info);
|
||||
void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb);
|
||||
--- a/net/mac80211/rate.h
|
||||
+++ b/net/mac80211/rate.h
|
||||
@@ -37,11 +37,15 @@ static inline void rate_control_tx_statu
|
||||
struct rate_control_ref *ref = local->rate_ctrl;
|
||||
struct ieee80211_sta *ista = &sta->sta;
|
||||
void *priv_sta = sta->rate_ctrl_priv;
|
||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||
return;
|
||||
|
||||
- ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||
+ 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);
|
||||
}
|
||||
|
||||
|
@ -1,31 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 15 Nov 2014 22:38:07 +0100
|
||||
Subject: [PATCH] mac80211: minstrel: switch to .tx_status_noskb
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel.c
|
||||
+++ b/net/mac80211/rc80211_minstrel.c
|
||||
@@ -223,11 +223,10 @@ minstrel_update_stats(struct minstrel_pr
|
||||
static void
|
||||
minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
- struct sk_buff *skb)
|
||||
+ struct ieee80211_tx_info *info)
|
||||
{
|
||||
struct minstrel_priv *mp = priv;
|
||||
struct minstrel_sta_info *mi = priv_sta;
|
||||
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||
int i, ndx;
|
||||
int success;
|
||||
@@ -674,7 +673,7 @@ static u32 minstrel_get_expected_through
|
||||
|
||||
const struct rate_control_ops mac80211_minstrel = {
|
||||
.name = "minstrel",
|
||||
- .tx_status = minstrel_tx_status,
|
||||
+ .tx_status_noskb = minstrel_tx_status,
|
||||
.get_rate = minstrel_get_rate,
|
||||
.rate_init = minstrel_rate_init,
|
||||
.alloc = minstrel_alloc,
|
@ -1,41 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 15 Nov 2014 22:38:21 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: switch to .tx_status_noskb
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -709,11 +709,10 @@ minstrel_aggr_check(struct ieee80211_sta
|
||||
static void
|
||||
minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
- struct sk_buff *skb)
|
||||
+ struct ieee80211_tx_info *info)
|
||||
{
|
||||
struct minstrel_ht_sta_priv *msp = priv_sta;
|
||||
struct minstrel_ht_sta *mi = &msp->ht;
|
||||
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||
struct minstrel_rate_stats *rate, *rate2;
|
||||
struct minstrel_priv *mp = priv;
|
||||
@@ -721,7 +720,8 @@ minstrel_ht_tx_status(void *priv, struct
|
||||
int i;
|
||||
|
||||
if (!msp->is_ht)
|
||||
- return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
|
||||
+ return mac80211_minstrel.tx_status_noskb(priv, sband, sta,
|
||||
+ &msp->legacy, info);
|
||||
|
||||
/* This packet was aggregated but doesn't carry status info */
|
||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
@@ -1343,7 +1343,7 @@ static u32 minstrel_ht_get_expected_thro
|
||||
|
||||
static const struct rate_control_ops mac80211_minstrel_ht = {
|
||||
.name = "minstrel_ht",
|
||||
- .tx_status = minstrel_ht_tx_status,
|
||||
+ .tx_status_noskb = minstrel_ht_tx_status,
|
||||
.get_rate = minstrel_ht_get_rate,
|
||||
.rate_init = minstrel_ht_rate_init,
|
||||
.rate_update = minstrel_ht_rate_update,
|
@ -1,219 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 15 Nov 2014 23:50:27 +0100
|
||||
Subject: [PATCH] mac80211: add ieee80211_tx_status_noskb
|
||||
|
||||
This can be used by drivers that cannot reliably map tx status
|
||||
information onto specific skbs.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -3517,6 +3517,28 @@ void ieee80211_tx_status(struct ieee8021
|
||||
struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
+ * ieee80211_tx_status_noskb - transmit status callback without skb
|
||||
+ *
|
||||
+ * This function can be used as a replacement for ieee80211_tx_status
|
||||
+ * in drivers that cannot reliably map tx status information back to
|
||||
+ * specific skbs.
|
||||
+ *
|
||||
+ * This function may not be called in IRQ context. Calls to this function
|
||||
+ * for a single hardware must be synchronized against each other. Calls
|
||||
+ * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe()
|
||||
+ * may not be mixed for a single hardware. Must not run concurrently with
|
||||
+ * ieee80211_rx() or ieee80211_rx_ni().
|
||||
+ *
|
||||
+ * @hw: the hardware the frame was transmitted by
|
||||
+ * @sta: the receiver station to which this packet is sent
|
||||
+ * (NULL for multicast packets)
|
||||
+ * @info: tx status information
|
||||
+ */
|
||||
+void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_sta *sta,
|
||||
+ struct ieee80211_tx_info *info);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_tx_status_ni - transmit status callback (in process context)
|
||||
*
|
||||
* Like ieee80211_tx_status() but can be called in process context.
|
||||
--- a/net/mac80211/rate.h
|
||||
+++ b/net/mac80211/rate.h
|
||||
@@ -49,6 +49,23 @@ static inline void rate_control_tx_statu
|
||||
}
|
||||
|
||||
|
||||
+static inline void
|
||||
+rate_control_tx_status_noskb(struct ieee80211_local *local,
|
||||
+ struct ieee80211_supported_band *sband,
|
||||
+ struct sta_info *sta,
|
||||
+ struct ieee80211_tx_info *info)
|
||||
+{
|
||||
+ struct rate_control_ref *ref = local->rate_ctrl;
|
||||
+ struct ieee80211_sta *ista = &sta->sta;
|
||||
+ void *priv_sta = sta->rate_ctrl_priv;
|
||||
+
|
||||
+ if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||
+ return;
|
||||
+
|
||||
+ ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
|
||||
+}
|
||||
+
|
||||
+
|
||||
static inline void rate_control_rate_init(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_local *local = sta->sdata->local;
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -541,10 +541,9 @@ static void ieee80211_tx_latency_end_msr
|
||||
#define STA_LOST_TDLS_PKT_THRESHOLD 10
|
||||
#define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */
|
||||
|
||||
-static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
|
||||
+static void ieee80211_lost_packet(struct sta_info *sta,
|
||||
+ struct ieee80211_tx_info *info)
|
||||
{
|
||||
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
-
|
||||
/* This packet was aggregated but doesn't carry status info */
|
||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
||||
@@ -571,24 +570,13 @@ static void ieee80211_lost_packet(struct
|
||||
sta->lost_packets = 0;
|
||||
}
|
||||
|
||||
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
+static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_tx_info *info,
|
||||
+ int *retry_count)
|
||||
{
|
||||
- struct sk_buff *skb2;
|
||||
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
- struct ieee80211_local *local = hw_to_local(hw);
|
||||
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
- __le16 fc;
|
||||
- struct ieee80211_supported_band *sband;
|
||||
- struct ieee80211_sub_if_data *sdata;
|
||||
- struct net_device *prev_dev = NULL;
|
||||
- struct sta_info *sta, *tmp;
|
||||
- int retry_count = -1, i;
|
||||
int rates_idx = -1;
|
||||
- bool send_to_cooked;
|
||||
- bool acked;
|
||||
- struct ieee80211_bar *bar;
|
||||
- int rtap_len;
|
||||
- int shift = 0;
|
||||
+ int count = -1;
|
||||
+ int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
@@ -606,12 +594,94 @@ void ieee80211_tx_status(struct ieee8021
|
||||
break;
|
||||
}
|
||||
|
||||
- retry_count += info->status.rates[i].count;
|
||||
+ count += info->status.rates[i].count;
|
||||
}
|
||||
rates_idx = i - 1;
|
||||
|
||||
- if (retry_count < 0)
|
||||
- retry_count = 0;
|
||||
+ if (count < 0)
|
||||
+ count = 0;
|
||||
+
|
||||
+ *retry_count = count;
|
||||
+ return rates_idx;
|
||||
+}
|
||||
+
|
||||
+void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_sta *pubsta,
|
||||
+ struct ieee80211_tx_info *info)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct ieee80211_supported_band *sband;
|
||||
+ int retry_count;
|
||||
+ int rates_idx;
|
||||
+ bool acked;
|
||||
+
|
||||
+ rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
|
||||
+
|
||||
+ sband = hw->wiphy->bands[info->band];
|
||||
+
|
||||
+ acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
|
||||
+ if (pubsta) {
|
||||
+ struct sta_info *sta;
|
||||
+
|
||||
+ sta = container_of(pubsta, struct sta_info, sta);
|
||||
+
|
||||
+ if (info->flags & IEEE80211_TX_STATUS_EOSP)
|
||||
+ clear_sta_flag(sta, WLAN_STA_SP);
|
||||
+
|
||||
+ if (!acked)
|
||||
+ sta->tx_retry_failed++;
|
||||
+ sta->tx_retry_count += retry_count;
|
||||
+
|
||||
+ if (acked) {
|
||||
+ sta->last_rx = jiffies;
|
||||
+
|
||||
+ if (sta->lost_packets)
|
||||
+ sta->lost_packets = 0;
|
||||
+
|
||||
+ /* Track when last TDLS packet was ACKed */
|
||||
+ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
|
||||
+ sta->last_tdls_pkt_time = jiffies;
|
||||
+ } else {
|
||||
+ ieee80211_lost_packet(sta, info);
|
||||
+ }
|
||||
+
|
||||
+ rate_control_tx_status_noskb(local, sband, sta, info);
|
||||
+ }
|
||||
+
|
||||
+ if (acked) {
|
||||
+ local->dot11TransmittedFrameCount++;
|
||||
+ if (!pubsta)
|
||||
+ local->dot11MulticastTransmittedFrameCount++;
|
||||
+ if (retry_count > 0)
|
||||
+ local->dot11RetryCount++;
|
||||
+ if (retry_count > 1)
|
||||
+ local->dot11MultipleRetryCount++;
|
||||
+ } else {
|
||||
+ local->dot11FailedCount++;
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_tx_status_noskb);
|
||||
+
|
||||
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct sk_buff *skb2;
|
||||
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
+ __le16 fc;
|
||||
+ struct ieee80211_supported_band *sband;
|
||||
+ struct ieee80211_sub_if_data *sdata;
|
||||
+ struct net_device *prev_dev = NULL;
|
||||
+ struct sta_info *sta, *tmp;
|
||||
+ int retry_count;
|
||||
+ int rates_idx;
|
||||
+ bool send_to_cooked;
|
||||
+ bool acked;
|
||||
+ struct ieee80211_bar *bar;
|
||||
+ int rtap_len;
|
||||
+ int shift = 0;
|
||||
+
|
||||
+ rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
@@ -716,7 +786,7 @@ void ieee80211_tx_status(struct ieee8021
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
|
||||
sta->last_tdls_pkt_time = jiffies;
|
||||
} else {
|
||||
- ieee80211_lost_packet(sta, skb);
|
||||
+ ieee80211_lost_packet(sta, info);
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Tue, 18 Nov 2014 21:43:25 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: fix a crash in rate sorting
|
||||
|
||||
The commit 5935839ad73583781b8bbe8d91412f6826e218a4
|
||||
"mac80211: improve minstrel_ht rate sorting by throughput & probability"
|
||||
|
||||
introduced a crash on rate sorting that occurs when the rate added to
|
||||
the sorting array is faster than all the previous rates. Due to an
|
||||
off-by-one error, it reads the rate index from tp_list[-1], which
|
||||
contains uninitialized stack garbage, and then uses the resulting index
|
||||
for accessing the group rate stats, leading to a crash if the garbage
|
||||
value is big enough.
|
||||
|
||||
Cc: Thomas Huehn <thomas@net.t-labs.tu-berlin.de>
|
||||
Reported-by: Jouni Malinen <j@w1.fi>
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -394,19 +394,16 @@ minstrel_ht_sort_best_tp_rates(struct mi
|
||||
cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp;
|
||||
cur_prob = mi->groups[cur_group].rates[cur_idx].probability;
|
||||
|
||||
- tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
|
||||
- tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
|
||||
- tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
|
||||
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
|
||||
-
|
||||
- while (j > 0 && (cur_thr > tmp_thr ||
|
||||
- (cur_thr == tmp_thr && cur_prob > tmp_prob))) {
|
||||
- j--;
|
||||
+ do {
|
||||
tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
|
||||
tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
|
||||
tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
|
||||
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
|
||||
- }
|
||||
+ if (cur_thr < tmp_thr ||
|
||||
+ (cur_thr == tmp_thr && cur_prob <= tmp_prob))
|
||||
+ break;
|
||||
+ j--;
|
||||
+ } while (j > 0);
|
||||
|
||||
if (j < MAX_THR_RATES - 1) {
|
||||
memmove(&tp_list[j + 1], &tp_list[j], (sizeof(*tp_list) *
|
@ -1,92 +0,0 @@ |
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Tue, 18 Nov 2014 23:26:40 +0100
|
||||
Subject: [PATCH] mac80211: notify drivers on sta rate table changes
|
||||
|
||||
This allows drivers with a firmware or chip-based rate lookup table to
|
||||
use the most recent default rate selection without having to get it from
|
||||
per-packet data or explicit ieee80211_get_tx_rate calls
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2631,6 +2631,9 @@ enum ieee80211_reconfig_type {
|
||||
* uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
|
||||
* otherwise the rate control algorithm is notified directly.
|
||||
* Must be atomic.
|
||||
+ * @sta_rate_tbl_update: Notifies the driver that the rate table changed. This
|
||||
+ * is only used if the configured rate control algorithm actually uses
|
||||
+ * the new rate table API, and is therefore optional. Must be atomic.
|
||||
*
|
||||
* @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
|
||||
* bursting) for a hardware TX queue.
|
||||
@@ -2972,6 +2975,9 @@ struct ieee80211_ops {
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 changed);
|
||||
+ void (*sta_rate_tbl_update)(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_vif *vif,
|
||||
+ struct ieee80211_sta *sta);
|
||||
int (*conf_tx)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, u16 ac,
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -621,6 +621,21 @@ static inline void drv_sta_rc_update(str
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
+static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local,
|
||||
+ struct ieee80211_sub_if_data *sdata,
|
||||
+ struct ieee80211_sta *sta)
|
||||
+{
|
||||
+ sdata = get_bss_sdata(sdata);
|
||||
+ if (!check_sdata_in_driver(sdata))
|
||||
+ return;
|
||||
+
|
||||
+ trace_drv_sta_rate_tbl_update(local, sdata, sta);
|
||||
+ if (local->ops->sta_rate_tbl_update)
|
||||
+ local->ops->sta_rate_tbl_update(&local->hw, &sdata->vif, sta);
|
||||
+
|
||||
+ trace_drv_return_void(local);
|
||||
+}
|
||||
+
|
||||
static inline int drv_conf_tx(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata, u16 ac,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
--- a/net/mac80211/rate.c
|
||||
+++ b/net/mac80211/rate.c
|
||||
@@ -696,6 +696,7 @@ int rate_control_set_rates(struct ieee80
|
||||
struct ieee80211_sta *pubsta,
|
||||
struct ieee80211_sta_rates *rates)
|
||||
{
|
||||
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
struct ieee80211_sta_rates *old;
|
||||
|
||||
/*
|
||||
@@ -709,6 +710,8 @@ int rate_control_set_rates(struct ieee80
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
|
||||
+ drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rate_control_set_rates);
|
||||
--- a/net/mac80211/trace.h
|
||||
+++ b/net/mac80211/trace.h
|
||||
@@ -826,6 +826,13 @@ DEFINE_EVENT(sta_event, drv_sta_pre_rcu_
|
||||
TP_ARGS(local, sdata, sta)
|
||||
);
|
||||
|
||||
+DEFINE_EVENT(sta_event, drv_sta_rate_tbl_update,
|
||||
+ TP_PROTO(struct ieee80211_local *local,
|
||||
+ struct ieee80211_sub_if_data *sdata,
|
||||
+ struct ieee80211_sta *sta),
|
||||
+ TP_ARGS(local, sdata, sta)
|
||||
+);
|
||||
+
|
||||
TRACE_EVENT(drv_conf_tx,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
@ -1,34 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Fri, 21 Nov 2014 23:27:33 +0100
|
||||
Subject: [PATCH] mac80211: add more missing checks for VHT tx rates
|
||||
|
||||
Fixes a crash on attempting to calculate the frame duration for a VHT
|
||||
packet (which needs to be handled by hw/driver instead).
|
||||
|
||||
Reported-by: Jouni Malinen <j@w1.fi>
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rate.c
|
||||
+++ b/net/mac80211/rate.c
|
||||
@@ -446,7 +446,8 @@ static void rate_fixup_ratelist(struct i
|
||||
*
|
||||
* XXX: Should this check all retry rates?
|
||||
*/
|
||||
- if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) {
|
||||
+ if (!(rates[0].flags &
|
||||
+ (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) {
|
||||
u32 basic_rates = vif->bss_conf.basic_rates;
|
||||
s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0;
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -60,7 +60,7 @@ static __le16 ieee80211_duration(struct
|
||||
rcu_read_unlock();
|
||||
|
||||
/* assume HW handles this */
|
||||
- if (tx->rate.flags & IEEE80211_TX_RC_MCS)
|
||||
+ if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
|
||||
return 0;
|
||||
|
||||
/* uh huh? */
|
@ -1,82 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 24 Nov 2014 18:09:03 +0100
|
||||
Subject: [PATCH] mac80211: copy chandef from AP vif to VLANs
|
||||
|
||||
Fixes a crash in nl80211_send_chandef, introduced in
|
||||
|
||||
commit c12bc4885f4b3bab0ed779c69d5d7e3223fa5003
|
||||
"mac80211: return the vif's chandef in ieee80211_cfg_get_channel()"
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/chan.c
|
||||
+++ b/net/mac80211/chan.c
|
||||
@@ -932,6 +932,21 @@ ieee80211_vif_chanctx_reservation_comple
|
||||
}
|
||||
}
|
||||
|
||||
+static void
|
||||
+ieee80211_vif_update_chandef(struct ieee80211_sub_if_data *sdata,
|
||||
+ const struct cfg80211_chan_def *chandef)
|
||||
+{
|
||||
+ struct ieee80211_sub_if_data *vlan;
|
||||
+
|
||||
+ sdata->vif.bss_conf.chandef = *chandef;
|
||||
+
|
||||
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
+ return;
|
||||
+
|
||||
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||
+ vlan->vif.bss_conf.chandef = *chandef;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
@@ -994,7 +1009,7 @@ ieee80211_vif_use_reserved_reassign(stru
|
||||
if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
|
||||
changed = BSS_CHANGED_BANDWIDTH;
|
||||
|
||||
- sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
|
||||
+ ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
|
||||
|
||||
if (changed)
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
@@ -1336,7 +1351,7 @@ static int ieee80211_vif_use_reserved_sw
|
||||
sdata->reserved_chandef.width)
|
||||
changed = BSS_CHANGED_BANDWIDTH;
|
||||
|
||||
- sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
|
||||
+ ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
|
||||
if (changed)
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
changed);
|
||||
@@ -1507,7 +1522,7 @@ int ieee80211_vif_use_channel(struct iee
|
||||
goto out;
|
||||
}
|
||||
|
||||
- sdata->vif.bss_conf.chandef = *chandef;
|
||||
+ ieee80211_vif_update_chandef(sdata, chandef);
|
||||
|
||||
ret = ieee80211_assign_vif_chanctx(sdata, ctx);
|
||||
if (ret) {
|
||||
@@ -1649,7 +1664,7 @@ int ieee80211_vif_change_bandwidth(struc
|
||||
break;
|
||||
}
|
||||
|
||||
- sdata->vif.bss_conf.chandef = *chandef;
|
||||
+ ieee80211_vif_update_chandef(sdata, chandef);
|
||||
|
||||
ieee80211_recalc_chanctx_chantype(local, ctx);
|
||||
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -520,6 +520,7 @@ int ieee80211_do_open(struct wireless_de
|
||||
sdata->vif.cab_queue = master->vif.cab_queue;
|
||||
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
|
||||
sizeof(sdata->vif.hw_queue));
|
||||
+ sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
|
||||
break;
|
||||
}
|
||||
case NL80211_IFTYPE_AP:
|
@ -1,31 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 30 Nov 2014 20:30:46 +0100
|
||||
Subject: [PATCH] ath9k_hw: fix hardware queue allocation
|
||||
|
||||
The driver passes the desired hardware queue index for a WMM data queue
|
||||
in qinfo->tqi_subtype. This was ignored in ath9k_hw_setuptxqueue, which
|
||||
instead relied on the order in which the function is called.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Reported-by: Hubert Feurstein <h.feurstein@gmail.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/mac.c
|
||||
@@ -311,14 +311,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw
|
||||
q = ATH9K_NUM_TX_QUEUES - 3;
|
||||
break;
|
||||
case ATH9K_TX_QUEUE_DATA:
|
||||
- for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++)
|
||||
- if (ah->txq[q].tqi_type ==
|
||||
- ATH9K_TX_QUEUE_INACTIVE)
|
||||
- break;
|
||||
- if (q == ATH9K_NUM_TX_QUEUES) {
|
||||
- ath_err(common, "No available TX queue\n");
|
||||
- return -1;
|
||||
- }
|
||||
+ q = qinfo->tqi_subtype;
|
||||
break;
|
||||
default:
|
||||
ath_err(common, "Invalid TX queue type: %u\n", type);
|
@ -1,24 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 30 Nov 2014 20:34:16 +0100
|
||||
Subject: [PATCH] ath9k: fix BE/BK queue order
|
||||
|
||||
Hardware queues are ordered by priority. Use queue index 0 for BK, which
|
||||
has lower priority than BE.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||
@@ -217,8 +217,8 @@
|
||||
#define AH_WOW_BEACON_MISS BIT(3)
|
||||
|
||||
enum ath_hw_txq_subtype {
|
||||
- ATH_TXQ_AC_BE = 0,
|
||||
- ATH_TXQ_AC_BK = 1,
|
||||
+ ATH_TXQ_AC_BK = 0,
|
||||
+ ATH_TXQ_AC_BE = 1,
|
||||
ATH_TXQ_AC_VI = 2,
|
||||
ATH_TXQ_AC_VO = 3,
|
||||
};
|
@ -1,29 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 30 Nov 2014 21:51:12 +0100
|
||||
Subject: [PATCH] ath5k: fix hardware queue index assignment
|
||||
|
||||
Like with ath9k, ath5k queues also need to be ordered by priority.
|
||||
queue_info->tqi_subtype already contains the correct index, so use it
|
||||
instead of relying on the order of ath5k_hw_setup_tx_queue calls.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath5k/qcu.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
|
||||
@@ -225,13 +225,7 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw
|
||||
} else {
|
||||
switch (queue_type) {
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
- for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
|
||||
- ah->ah_txq[queue].tqi_type !=
|
||||
- AR5K_TX_QUEUE_INACTIVE; queue++) {
|
||||
-
|
||||
- if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
|
||||
- return -EINVAL;
|
||||
- }
|
||||
+ queue = queue_info->tqi_subtype;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_UAPSD:
|
||||
queue = AR5K_TX_QUEUE_ID_UAPSD;
|
@ -1,30 +0,0 @@ |
||||
From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
Date: Tue, 16 Dec 2014 09:52:59 +0100
|
||||
Subject: [PATCH] ath10k: fix low TX rates when IBSS and HT
|
||||
|
||||
This fix TX problem when IBSS used in HT mode.
|
||||
Before we used 6Mbps all the time for TX direction.
|
||||
|
||||
Reported-by: Yeoh Chun-Yeow <yeohchunyeow@gmail.com>
|
||||
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
@@ -1375,9 +1375,16 @@ static void ath10k_peer_assoc_h_qos(stru
|
||||
if (vif->bss_conf.qos)
|
||||
arg->peer_flags |= WMI_PEER_QOS;
|
||||
break;
|
||||
+ case WMI_VDEV_TYPE_IBSS:
|
||||
+ if (sta->wme)
|
||||
+ arg->peer_flags |= WMI_PEER_QOS;
|
||||
+ break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n",
|
||||
+ sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
|
||||
}
|
||||
|
||||
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
|
@ -1,26 +0,0 @@ |
||||
From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
Date: Tue, 16 Dec 2014 09:53:00 +0100
|
||||
Subject: [PATCH] ath10k: send (re)assoc peer command when NSS changed
|
||||
|
||||
Assoc peer command contain information about NSS.
|
||||
When we will get IEEE80211_RC_NSS_CHANGED we should
|
||||
also send (re) assoc peer command to be sure firmware
|
||||
will know about it and RC will work correctly.
|
||||
|
||||
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
@@ -3497,8 +3497,9 @@ static void ath10k_sta_rc_update_wk(stru
|
||||
sta->addr, smps, err);
|
||||
}
|
||||
|
||||
- if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
|
||||
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
|
||||
+ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
|
||||
+ changed & IEEE80211_RC_NSS_CHANGED) {
|
||||
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
|
||||
sta->addr);
|
||||
|
||||
err = ath10k_station_assoc(ar, arvif->vif, sta, true);
|
@ -1,53 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Wed, 14 Jan 2015 14:13:15 +0100
|
||||
Subject: [PATCH] ath9k: fix race condition in irq processing during hardware
|
||||
reset
|
||||
|
||||
To fix invalid hardware accesses, the commit
|
||||
"ath9k: do not access hardware on IRQs during reset" made the irq
|
||||
handler ignore interrupts emitted after queueing a hardware reset (which
|
||||
disables the IRQ). This left a small time window for the IRQ to get
|
||||
re-enabled by the tasklet, which caused IRQ storms.
|
||||
Instead of returning IRQ_NONE when ATH_OP_HW_RESET is set, disable the
|
||||
IRQ entirely for the duration of the reset.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -285,6 +285,7 @@ static int ath_reset_internal(struct ath
|
||||
|
||||
__ath_cancel_work(sc);
|
||||
|
||||
+ disable_irq(sc->irq);
|
||||
tasklet_disable(&sc->intr_tq);
|
||||
tasklet_disable(&sc->bcon_tasklet);
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
@@ -331,6 +332,7 @@ static int ath_reset_internal(struct ath
|
||||
r = -EIO;
|
||||
|
||||
out:
|
||||
+ enable_irq(sc->irq);
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
tasklet_enable(&sc->bcon_tasklet);
|
||||
tasklet_enable(&sc->intr_tq);
|
||||
@@ -512,9 +514,6 @@ irqreturn_t ath_isr(int irq, void *dev)
|
||||
if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
|
||||
return IRQ_NONE;
|
||||
|
||||
- if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
|
||||
- return IRQ_NONE;
|
||||
-
|
||||
/* shared irq, not for us */
|
||||
if (!ath9k_hw_intrpend(ah))
|
||||
return IRQ_NONE;
|
||||
@@ -529,7 +528,7 @@ irqreturn_t ath_isr(int irq, void *dev)
|
||||
ath9k_debug_sync_cause(sc, sync_cause);
|
||||
status &= ah->imask; /* discard unasked-for bits */
|
||||
|
||||
- if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
|
||||
+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
@ -1,45 +0,0 @@ |
||||
From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
|
||||
Date: Tue, 3 Feb 2015 22:37:26 +0300
|
||||
Subject: [PATCH] ath5k: fix spontaneus AR5312 freezes
|
||||
|
||||
Sometimes while CPU have some load and ath5k doing the wireless
|
||||
interface reset the whole WiSoC completely freezes. Set of tests shows
|
||||
that using atomic delay function while we wait interface reset helps to
|
||||
avoid such freezes.
|
||||
|
||||
The easiest way to reproduce this issue: create a station interface,
|
||||
start continous scan with wpa_supplicant and load CPU by something. Or
|
||||
just create multiple station interfaces and put them all in continous
|
||||
scan.
|
||||
|
||||
This patch partially reverts the commit 1846ac3dbec0 ("ath5k: Use
|
||||
usleep_range where possible"), which replaces initial udelay()
|
||||
by usleep_range().
|
||||
|
||||
I do not know actual source of this issue, but all looks like that HW
|
||||
freeze is caused by transaction on internal SoC bus, while wireless
|
||||
block is in reset state.
|
||||
|
||||
Also I should note that I do not know how many chips are affected, but I
|
||||
did not see this issue with chips, other than AR5312.
|
||||
|
||||
CC: Jiri Slaby <jirislaby@gmail.com>
|
||||
CC: Nick Kossifidis <mickflemm@gmail.com>
|
||||
CC: Luis R. Rodriguez <mcgrof@do-not-panic.com>
|
||||
Fixes: 1846ac3dbec0 ("ath5k: Use usleep_range where possible")
|
||||
Reported-by: Christophe Prevotaux <c.prevotaux@rural-networks.com>
|
||||
Tested-by: Christophe Prevotaux <c.prevotaux@rural-networks.com>
|
||||
Tested-by: Eric Bree <ebree@nltinc.com>
|
||||
Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
|
||||
---
|
||||
--- a/drivers/net/wireless/ath/ath5k/reset.c
|
||||
+++ b/drivers/net/wireless/ath/ath5k/reset.c
|
||||
@@ -478,7 +478,7 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah
|
||||
regval = ioread32(reg);
|
||||
iowrite32(regval | val, reg);
|
||||
regval = ioread32(reg);
|
||||
- usleep_range(100, 150);
|
||||
+ udelay(100); /* NB: should be atomic */
|
||||
|
||||
/* Bring BB/MAC out of reset */
|
||||
iowrite32(regval & ~val, reg);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue